1
0
Fork 0
forked from lthn/blockchain

This is it. Historic merge of branch 'develop' (with all new privacy update features) into release

This commit is contained in:
sowle 2024-02-20 15:36:20 +01:00
commit 226594f1d2
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
235 changed files with 32311 additions and 9599 deletions

View file

@ -4,22 +4,19 @@ AlignConsecutiveAssignments: 'true'
AlignConsecutiveDeclarations: 'false'
AlignEscapedNewlines: Right
AlignOperands: 'false'
AlignTrailingComments: 'true'
AlignTrailingComments: 'false'
AllowAllParametersOfDeclarationOnNextLine: 'false'
AllowShortBlocksOnASingleLine: 'false'
AllowShortCaseLabelsOnASingleLine: 'true'
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: 'true'
AllowShortLoopsOnASingleLine: 'false'
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: 'false'
AlwaysBreakTemplateDeclarations: 'true'
BinPackArguments: 'true'
BinPackParameters: 'true'
BreakAfterJavaFieldAnnotations: 'true'
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Stroustrup
BreakBeforeInheritanceComma: 'false'
BreakBeforeBraces: Allman
BreakBeforeTernaryOperators: 'false'
BreakConstructorInitializers: BeforeColon
BreakStringLiterals: 'false'
@ -56,4 +53,4 @@ SpacesInParentheses: 'false'
SpacesInSquareBrackets: 'false'
Standard: Cpp11
TabWidth: '2'
UseTab: Never
UseTab: Never

3
.gitignore vendored
View file

@ -5,4 +5,5 @@
._.DS_Store
Thumbs.db
._*
.idea
.idea
.vs/*

View file

@ -1,21 +1,22 @@
cmake_minimum_required(VERSION 3.1)
cmake_minimum_required(VERSION 3.5)
PROJECT(Zano)
set(VERSION "1.0")
# if(POLICY CMP0043)
# cmake_policy(SET CMP0043 OLD)
# endif()
if(POLICY CMP0043)
cmake_policy(SET CMP0043 NEW)
endif()
if(POLICY CMP0043)
cmake_policy(SET CMP0074 NEW)
endif()
# if(POLICY CMP0020)
# cmake_policy(SET CMP0020 OLD)
# endif()
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
add_definitions(-DMOBILE_WALLET_BUILD)
if(CMAKE_SYSTEM_NAME STREQUAL "iOS" )
@ -53,9 +54,12 @@ message("Generated with config types: ${CMAKE_CONFIGURATION_TYPES}, and built ty
enable_testing()
set(OPENSSL_USE_STATIC_LIBS TRUE) # link statically
find_package(OpenSSL REQUIRED)
if(APPLE)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.10.5 CACHE STRING "Minimum OS X deployment version")
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12)
endif()
set(USE_PCH FALSE CACHE BOOL "Use shared precompiled headers")
@ -63,7 +67,7 @@ set(DISABLE_TOR FALSE CACHE BOOL "Disable TOR library(and related tor-connect su
set(TESTNET FALSE CACHE BOOL "Compile for testnet")
set(BUILD_GUI FALSE CACHE BOOL "Build qt-daemon")
include_directories(src contrib/eos_portable_archive contrib contrib/epee/include "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib")
include_directories(src contrib/eos_portable_archive contrib contrib/epee/include ${OPENSSL_INCLUDE_DIR} "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib")
add_definitions(-DSTATICLIB)
@ -72,6 +76,11 @@ if(TESTNET)
add_definitions(-DTESTNET)
endif()
if(CAKEWALLET)
message("NOTICE: Building libraries for CAKEWALLET")
add_definitions(-DCAKEWALLET)
endif()
set(OPENSSL_USE_STATIC_LIBS TRUE) # link statically
find_package(OpenSSL REQUIRED)
@ -93,9 +102,9 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
endif()
if(MSVC)
add_definitions("/D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /D__SSE4_1__")
add_definitions("/D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0")
add_compile_options(/bigobj /Zm1000 /Z7 /MP2 /W3 /GS- /wd4996 /wd4503 /wd4345 /wd4091 /FIinline_c.h)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760 /DEBUG dbghelp.lib")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760 /DEBUG dbghelp.lib crypt32.lib")
if(STATIC)
foreach(VAR CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE)
string(REPLACE "/MD" "/MT" ${VAR} "${${VAR}}")
@ -109,7 +118,7 @@ else()
else()
set(ARCH_FLAG "-march=${ARCH}")
endif()
set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-aggregate-return")
set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-aggregate-return -Wno-comment -Wno-unknown-pragmas -Wno-pragmas")
# if(NOT APPLE)
# set(WARNINGS "${WARNINGS} -Werror")
# endif()
@ -141,16 +150,16 @@ else()
else()
set(APPLE_FLAG "")
endif()
set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wstrict-prototypes")
set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wstrict-prototypes -Wno-comment")
set(CXX_WARNINGS "-Wno-reorder -Wno-missing-field-initializers")
try_compile(STATIC_ASSERT_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/utils/test-static-assert.c" COMPILE_DEFINITIONS "-std=c11")
try_compile(STATIC_ASSERT_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/utils/test-static-assert.c" COMPILE_DEFINITIONS "-std=c++14")
if(STATIC_ASSERT_RES)
set(STATIC_ASSERT_FLAG "")
else()
set(STATIC_ASSERT_FLAG "-Dstatic_assert=_Static_assert")
endif()
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -ftemplate-depth-1024 -std=c++11 -D_GNU_SOURCE ${APPLE_FLAG} ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -ftemplate-depth-1024 -std=c++14 -D_GNU_SOURCE ${APPLE_FLAG} ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}")
if (NOT APPLE AND NOT MSVC)
if (CLANG)
set(LLVM_USE_LINKER "gold")
@ -185,7 +194,7 @@ else()
endif()
# always use system-wide Boost (unless ZANO_USE_SYSTEM_BOOST is defined for some reason, which is not recommended)
# always use local Boost installation rather than the system-wide (unless ZANO_USE_SYSTEM_BOOST is defined for some reason, which is not recommended)
if(NOT DEFINED ENV{ZANO_USE_SYSTEM_BOOST})
set(Boost_NO_SYSTEM_PATHS ON)
endif()
@ -213,9 +222,9 @@ elseif(CMAKE_SYSTEM_NAME STREQUAL "Android")
set(Boost_LIBRARY_DIRS "${Boost_LIBRARY_DIRS}/${CMAKE_ANDROID_ARCH_ABI}/")
set(Boost_LIBRARIES "${Boost_LIBRARY_DIRS}libboost_system.a;${Boost_LIBRARY_DIRS}libboost_filesystem.a;${Boost_LIBRARY_DIRS}libboost_thread.a;${Boost_LIBRARY_DIRS}libboost_timer.a;${Boost_LIBRARY_DIRS}libboost_date_time.a;${Boost_LIBRARY_DIRS}libboost_chrono.a;${Boost_LIBRARY_DIRS}libboost_regex.a;${Boost_LIBRARY_DIRS}libboost_serialization.a;${Boost_LIBRARY_DIRS}libboost_atomic.a;${Boost_LIBRARY_DIRS}libboost_program_options.a")
elseif(APPLE)
find_package(Boost 1.71 EXACT REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
find_package(Boost 1.71 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
else()
find_package(Boost 1.70 EXACT REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale log)
endif()
@ -237,7 +246,7 @@ elseif(NOT MSVC)
endif()
if(BUILD_GUI)
cmake_minimum_required(VERSION 2.8.11)
cmake_minimum_required(VERSION 3.1)
find_package(Qt5Widgets REQUIRED)
endif()

View file

@ -15,9 +15,9 @@ Be sure to clone the repository properly:\
|--|--|--|--|
| gcc (Linux) | 5.4.0 | 9.4.0 | 12.3.0 |
| llvm/clang (Linux) | UNKNOWN | 7.0.1 | 8.0.0 |
| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2015 (14.0 update 1) | 2017 (15.9.0) | 2022 (17.7.5) |
| [XCode](https://developer.apple.com/downloads/) (macOS) | 9.2 | 12.3 | 12.3 |
| [CMake](https://cmake.org/download/) | 3.1 | 3.22.1 | 3.26.3 |
| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2017 (15.9.30) | 2017 (15.9.30) | 2022 (17.7.5) |
| [XCode](https://developer.apple.com/downloads/) (macOS) | 12.3 | 14.3 | 14.3 |
| [CMake](https://cmake.org/download/) | 3.15.5 | 3.22.1 | 3.26.3 |
| [Boost](https://www.boost.org/users/download/) | 1.70 | 1.70 | 1.76 |
| [OpenSSL](https://www.openssl.org/source/) [(win)](https://slproweb.com/products/Win32OpenSSL.html) | 1.1.1n | 1.1.1w | 1.1.1w |
| [Qt](https://download.qt.io/archive/qt/) (*only for GUI*) | 5.8.0 | 5.11.2 | 5.15.2 |

View file

@ -28,7 +28,7 @@ endif()
set_property(TARGET upnpc-static mdbx_chk mdbx_copy mdbx_dump mdbx_load mdbx_stat PROPERTY FOLDER "unused")
if(MSVC)
set_property(TARGET ntdll_extra_target PROPERTY FOLDER "unused")
#set_property(TARGET ntdll_extra_target PROPERTY FOLDER "unused")
endif()

View file

@ -45,61 +45,6 @@ if(CC_HAS_VISIBILITY AND (LTO_ENABLED OR INTERPROCEDURAL_OPTIMIZATION))
set_target_properties(mdbx PROPERTIES LINK_FLAGS "-fvisibility=hidden")
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
if(MSVC)
if(NOT MSVC_LIB_EXE)
# Find lib.exe
get_filename_component(CL_NAME ${CMAKE_C_COMPILER} NAME)
string(REPLACE cl.exe lib.exe MSVC_LIB_EXE ${CL_NAME})
find_program(MSVC_LIB_EXE ${MSVC_LIB_EXE})
endif()
if(MSVC_LIB_EXE)
message(STATUS "Found MSVC's lib tool: ${MSVC_LIB_EXE}")
set(MDBX_NTDLL_EXTRA_IMPLIB ${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.lib)
add_custom_command(OUTPUT ${MDBX_NTDLL_EXTRA_IMPLIB}
COMMENT "Create extra-import-library for ntdll.dll"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def"
COMMAND ${MSVC_LIB_EXE} /def:"${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" /out:"${MDBX_NTDLL_EXTRA_IMPLIB}" ${INITIAL_CMAKE_STATIC_LINKER_FLAGS})
else()
message(SEND_ERROR "MSVC's lib tool not found")
endif()
elseif(MINGW OR MINGW64)
if(NOT DLLTOOL)
# Find dlltool
get_filename_component(GCC_NAME ${CMAKE_C_COMPILER} NAME)
string(REPLACE gcc dlltool DLLTOOL_NAME ${GCC_NAME})
find_program(DLLTOOL NAMES ${DLLTOOL_NAME})
endif()
if(DLLTOOL)
message(STATUS "Found dlltool: ${DLLTOOL}")
set(MDBX_NTDLL_EXTRA_IMPLIB "${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.a")
add_custom_command(OUTPUT ${MDBX_NTDLL_EXTRA_IMPLIB}
COMMENT "Create extra-import-library for ntdll.dll"
MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def"
COMMAND ${DLLTOOL} -d "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" -l "${MDBX_NTDLL_EXTRA_IMPLIB}")
else()
message(SEND_ERROR "dlltool not found")
endif()
endif()
endif()
target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ${CMAKE_THREAD_LIBS_INIT})
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ntdll.lib)
if(MDBX_NTDLL_EXTRA_IMPLIB)
# LY: Sometimes Cmake requires a nightmarish magic for simple things.
# 1) create a target out of the library compilation result
add_custom_target(ntdll_extra_target DEPENDS ${MDBX_NTDLL_EXTRA_IMPLIB})
# 2) create an library target out of the library compilation result
add_library(ntdll_extra STATIC IMPORTED GLOBAL)
add_dependencies(ntdll_extra ntdll_extra_target)
# 3) specify where the library is (and where to find the headers)
set_target_properties(ntdll_extra
PROPERTIES
IMPORTED_LOCATION ${MDBX_NTDLL_EXTRA_IMPLIB})
target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ntdll_extra)
endif()
endif()
set_target_properties(mdbx PROPERTIES
INTERPROCEDURAL_OPTIMIZATION $<BOOL:${INTERPROCEDURAL_OPTIMIZATION}>

View file

@ -54,7 +54,7 @@
#endif
#if MDBX_DISABLE_GNU_SOURCE
#undef _GNU_SOURCE
#elif defined(__linux__) || defined(__gnu_linux__)
#elif ( defined(__linux__) || defined(__gnu_linux__) ) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE
#endif

View file

@ -54,18 +54,19 @@
catch(const std::exception& ex) \
{ \
(void)(ex); \
LOG_ERROR("Exception at [" << location << "], what=" << ex.what()); \
custom_code; \
LOG_ERROR("Exception at [" << location << "], what=" << ex.what()); \
return return_val; \
} \
catch(...) \
{ \
LOG_ERROR("Exception at [" << location << "], generic exception \"...\""); \
custom_code; \
LOG_ERROR("Exception at [" << location << "], generic exception \"...\""); \
return return_val; \
}
#define CATCH_ENTRY(location, return_val) CATCH_ENTRY_CUSTOM(location, (void)0, return_val)
#define CATCH_ENTRY2(return_val) CATCH_ENTRY_CUSTOM(LOCATION_SS, (void)0, return_val)
#define CATCH_ENTRY_CUSTOM2(custom_code, return_val) CATCH_ENTRY_CUSTOM(LOCATION_SS, custom_code, return_val)
#define CATCH_ENTRY_L0(location, return_val) CATCH_ENTRY(location, return_val)
#define CATCH_ENTRY_L1(location, return_val) CATCH_ENTRY(location, return_val)

View file

@ -34,6 +34,7 @@
#include <algorithm>
#include <functional>
#include <boost/thread.hpp>
#include <boost/any.hpp>
#include "include_base_utils.h"
#include "auto_val_init.h"
@ -273,6 +274,21 @@ namespace misc_utils
}
}
uint64_t get_avg() const
{
CRITICAL_REGION_LOCAL(m_lock);
if (!queued_items.size())
return 0;
uint64_t summ = 0;
for (const auto& item : queued_items)
{
summ += *item.first;
}
return summ / queued_items.size();
}
template<typename key_t, typename associated_data_t>
friend std::ostream & operator<< (std::ostream &out, median_helper<key_t, associated_data_t> const &mh);
}; // class median_helper
@ -291,26 +307,25 @@ namespace misc_utils
/************************************************************************/
/* */
/************************************************************************/
template<class type_vec_type>
type_vec_type median(std::vector<type_vec_type> &v)
template<typename container_t>
typename container_t::value_type median(container_t &v)
{
//CRITICAL_REGION_LOCAL(m_lock);
typename container_t::value_type median{};
if(v.empty())
return boost::value_initialized<type_vec_type>();
return median;
if(v.size() == 1)
return v[0];
size_t n = (v.size()) / 2;
std::sort(v.begin(), v.end());
//nth_element(v.begin(), v.begin()+n-1, v.end());
if(v.size()%2)
{//1, 3, 5...
return v[n];
}else
{//2, 4, 6...
return (v[n-1] + v[n])/2;
auto median_it = v.begin() + v.size() / 2;
std::nth_element(v.begin(), median_it, v.end());
median = *median_it;
if (v.size() % 2 == 0)
{
auto max_it = std::max_element(v.begin(), median_it); // it's garanteed that after nth_element() the necessary element is in this interval
median = (median + *max_it) / 2; // average of [size/2-1] and [size/2] elements
}
return median;
}
/************************************************************************/
@ -372,6 +387,11 @@ namespace misc_utils
virtual void do_call(){};
};
template<typename param_t>
struct call_basic_param
{
virtual void do_call(param_t& p) {};
};
template<typename t_callback>
struct call_specific: public call_basic
@ -386,12 +406,34 @@ namespace misc_utils
t_callback m_cb;
};
template<typename param_t, typename t_callback>
struct call_specific_param : public call_basic_param<param_t>
{
call_specific_param(t_callback cb) :m_cb(cb)
{}
virtual void do_call(const param_t& p)
{
m_cb(p);
}
private:
t_callback m_cb;
};
template<typename t_callback>
auto build_abstract_callback(t_callback cb) -> std::shared_ptr<call_basic>
{
return std::shared_ptr<call_basic>(new call_specific<t_callback>(cb));
}
template<typename param_t, typename t_callback>
auto build_abstract_callback_param(t_callback cb) -> std::shared_ptr<call_basic_param<param_t>>
{
return std::shared_ptr<call_basic_param<param_t>>(new call_specific_param<param_t, t_callback>(cb));
}
template<class callback_type>
@ -427,6 +469,71 @@ namespace misc_utils
return res.first;
}
class events_dispatcher
{
public:
template<typename param_t>
struct callback_entry
{
std::shared_ptr<epee::misc_utils::call_basic_param<const param_t> > m_cb;
};
std::map<std::type_index, boost::any> m_callbacks;
template<typename param_t, typename callback_t>
void SUBSCIRBE_DEBUG_EVENT(callback_t cb)
{
std::type_index ti = typeid(param_t);
auto it = m_callbacks.find(ti);
if (it != m_callbacks.end())
{
throw std::runtime_error("Handler for this type already registered");
}
callback_entry<const param_t> cb_entry = { epee::misc_utils::build_abstract_callback_param<const param_t>(cb) };
m_callbacks[ti] = cb_entry;
}
template<typename param_t>
void UNSUBSCRIBE_DEBUG_EVENT()
{
std::type_index ti = typeid(param_t);
auto it = m_callbacks.find(ti);
if (it != m_callbacks.end())
{
m_callbacks.erase(it);
}
}
void UNSUBSCRIBE_ALL()
{
m_callbacks.clear();
}
template<typename param_t>
void RAISE_DEBUG_EVENT(const param_t& p)
{
std::type_index ti = typeid(param_t);
auto it = m_callbacks.find(ti);
if (it != m_callbacks.end())
{
callback_entry<const param_t >* pcallback_entry = boost::any_cast<callback_entry<const param_t >>(&it->second);
if (!pcallback_entry)
{
throw std::runtime_error("Unexpected error: registered tipe holding something else in boost::eny");
}
pcallback_entry->m_cb->do_call(p);
}
}
};
} // namespace misc_utils
} // namespace epee

View file

@ -116,7 +116,7 @@ DISABLE_VS_WARNINGS(4100)
#define ENABLE_CHANNEL_BY_DEFAULT(ch_name) \
static bool COMBINE(init_channel, __LINE__) UNUSED_ATTRIBUTE = epee::misc_utils::static_initializer([](){ \
epee::log_space::log_singletone::enable_channel(ch_name); return true; \
epee::log_space::log_singletone::enable_channel(ch_name, false); return true; \
});
@ -556,8 +556,11 @@ namespace log_space
else
m_have_to_kill_console = false;
::AllocConsole();
freopen("CONOUT$", "w", stdout);
if (m_have_to_kill_console)
{
::AllocConsole();
freopen("CONOUT$", "w", stdout);
}
std::cout.clear();
#endif
}
@ -1236,21 +1239,24 @@ namespace log_space
return genabled_channels.find(ch_name) != genabled_channels.end();
}
static void enable_channels(const std::string& channels_set)
static void enable_channels(const std::string& channels_set, bool verbose = true)
{
std::set<std::string>& genabled_channels = get_enabled_channels();
std::list<std::string> list_of_channels;
boost::split(list_of_channels, channels_set, boost::is_any_of(",;: "), boost::token_compress_on);
std::cout << "log channels: ";
if (verbose)
std::cout << "log channels: ";
for (const auto& ch : list_of_channels)
{
genabled_channels.insert(ch);
std::cout << ch << " ";
if (verbose)
std::cout << ch << " ";
}
std::cout << " enabled" << std::endl;
if (verbose)
std::cout << " enabled" << std::endl;
}
static void enable_channel(const std::string& ch_name)
static void enable_channel(const std::string& ch_name, bool verbose = true)
{
std::set<std::string>& genabled_channels = get_enabled_channels();
//lazy synchronization: just replace with modified copy of whole set
@ -1258,7 +1264,8 @@ namespace log_space
enabled_channels_local.insert(ch_name);
genabled_channels.swap(enabled_channels_local);
#ifndef ANDROID_BUILD
std::cout << "log channel '" << ch_name << "' enabled" << std::endl;
if (verbose)
std::cout << "log channel '" << ch_name << "' enabled" << std::endl;
#endif
}

File diff suppressed because it is too large Load diff

View file

@ -29,6 +29,7 @@
#include "serialization/keyvalue_serialization.h"
#include "storages/portable_storage_template_helper.h"
#include "http_base.h"
#include "net/net_utils_base.h"
@ -59,6 +60,20 @@ bool auto_doc(const std::string& prefix_name, std::string& generate_reference)
return auto_doc_t<typename command_type_t::request, typename command_type_t::response>(prefix_name, generate_reference);
}
namespace epee {
namespace net_utils {
namespace http {
struct i_chain_handler
{
virtual bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response_info,
epee::net_utils::connection_context_base& m_conn_context, bool& call_found, std::string& generate_reference) = 0;
};
}
}
}
#define CHAIN_HTTP_TO_MAP2(context_type) bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \
epee::net_utils::http::http_response_info& response, \
@ -81,6 +96,13 @@ bool auto_doc(const std::string& prefix_name, std::string& generate_reference)
call_found = false; \
if(false) return true; //just a stub to have "else if"
#define BEGIN_URI_MAP2_VIRTUAL() virtual bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \
epee::net_utils::http::http_response_info& response_info, \
epee::net_utils::connection_context_base& m_conn_context, bool& call_found, std::string& generate_reference) { \
call_found = false; \
if(false) return true; //just a stub to have "else if"
#define MAP_URI2(pattern, callback) else if(std::string::npos != query_info.m_URI.find(pattern)) return callback(query_info, response_info, m_conn_context);
#define MAP_URI_AUTO_XML2(s_pattern, callback_f, command_type) //TODO: don't think i ever again will use xml - ambiguous and "overtagged" format
@ -125,6 +147,8 @@ bool auto_doc(const std::string& prefix_name, std::string& generate_reference)
LOG_PRINT( "[HTTP/BIN][" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "][" << query_info.m_URI << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \
}
#define CHAIN_TO_PHANDLER(pi_chain_handler) else if (pi_chain_handler && pi_chain_handler->handle_http_request_map(query_info, response_info, m_conn_context, call_found, generate_reference) && call_found) { return true;}
#define CHAIN_URI_MAP2(callback) else {callback(query_info, response_info, m_conn_context);call_found = true;}
#define END_URI_MAP2() return true;}
@ -295,6 +319,7 @@ struct json_command_type_t
#define MAP_JON_RPC_WE(method_name, callback_f, command_type) \
else if(auto_doc<json_command_type_t<command_type>>("[" method_name "]", generate_reference) && callback_name == method_name) \
{ \
call_found = true; \
PREPARE_OBJECTS_FROM_JSON(command_type) \
epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
fail_resp.jsonrpc = "2.0"; \
@ -312,6 +337,7 @@ struct json_command_type_t
#define MAP_JON_RPC_WERI(method_name, callback_f, command_type) \
else if(auto_doc<json_command_type_t<command_type>>("[" method_name "]", generate_reference) && callback_name == method_name) \
{ \
call_found = true; \
PREPARE_OBJECTS_FROM_JSON(command_type) \
epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \
fail_resp.jsonrpc = "2.0"; \
@ -329,6 +355,7 @@ struct json_command_type_t
#define MAP_JON_RPC(method_name, callback_f, command_type) \
else if(auto_doc<json_command_type_t<command_type>>(std::string("[") + method_name + "]", generate_reference) && callback_name == method_name) \
{ \
call_found = true; \
PREPARE_OBJECTS_FROM_JSON(command_type) \
if(!callback_f(req.params, resp.result, m_conn_context)) \
{ \

View file

@ -31,7 +31,7 @@
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/bind/bind.hpp>
#include "net/http_server_cp2.h"
#include "net/http_server_handlers_map2.h"

File diff suppressed because it is too large Load diff

View file

@ -155,6 +155,13 @@ namespace net_utils
{
content.port = boost::lexical_cast<uint64_t>(result[6]);
}
else
{
if (content.schema == "http")
content.port = 80;
else if (content.schema == "https")
content.port = 443;
}
if(result[7].matched)
{
content.uri = result[7];

View file

@ -79,6 +79,8 @@ namespace net_utils
m_started(time(NULL))
{}
connection_context_base(const connection_context_base& a) = default;
connection_context_base& operator=(const connection_context_base& a)
{
set_details(a.m_connection_id, a.m_remote_ip, a.m_remote_port, a.m_is_income);

View file

@ -0,0 +1,55 @@
// Copyright (c) 2006-2022, Andrey N. Sabelnikov, www.sabelnikov.net
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Andrey N. Sabelnikov nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#pragma once
#include "keyvalue_helpers.h"
//should be done in global namespace
#define KV_ENABLE_POD_SERIALIZATION_AS_HEX(type_name) \
namespace epee \
{ \
namespace serialization \
{ \
template<class t_storage> \
bool kv_serialize(const type_name& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) \
{ \
std::string s = epee::transform_t_pod_to_str(d); \
return kv_serialize(s, stg, hparent_section, pname); \
} \
template<class t_storage> \
bool kv_unserialize(type_name& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) \
{ \
std::string s; \
bool r = kv_unserialize(s, stg, hparent_section, pname); \
if (r) \
{ \
d = epee::transform_str_to_t_pod<type_name>(s); \
} \
return r; \
} \
} \
}

View file

@ -429,6 +429,55 @@ namespace epee
bool kv_unserialize(std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
}
}
//-------------------------------------------------------------------------------------------------------------------
//boost::optional
template<class t_type, class t_storage>
bool kv_serialize(const boost::optional<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
if(d != boost::none)
{
return kv_serialize(*d, stg, hparent_section, pname);
}
return true;
}
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
bool kv_unserialize(boost::optional<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
d = t_type();
bool r = kv_unserialize(*d, stg, hparent_section, pname);
if (!r)
{
d = boost::none;
}
return r;
}
//-------------------------------------------------------------------------------------------------------------------
//boost::shared_ptr
template<class t_type, class t_storage>
bool kv_serialize(const boost::shared_ptr<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
if (d.get())
{
return kv_serialize(*d, stg, hparent_section, pname);
}
return true;
}
//-------------------------------------------------------------------------------------------------------------------
template<class t_type, class t_storage>
bool kv_unserialize(boost::shared_ptr<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
{
d.reset();
t_type* ptr = new t_type();
bool r = kv_unserialize(*ptr, stg, hparent_section, pname);
if (!r)
{
d.reset(ptr);
}
return r;
}
}
}

View file

@ -29,11 +29,25 @@
#include "portable_storage_template_helper.h"
#include "net/http_base.h"
#include "net/http_server_handlers_map2.h"
#include "net/http_client.h"
namespace epee
{
namespace net_utils
{
template<class t_response>
bool get_http_json_t(const std::string& url, t_response& result_struct, unsigned int timeout = 5000, const std::string& method = "GET")
{
std::string body;
if (!http::fetch_url(url, body, method, "", timeout))
{
return false;
}
return serialization::load_t_from_json(result_struct, body);
}
template<class t_request, class t_response, class t_transport>
bool invoke_http_json_remote_command2(const std::string& url, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& method = "GET")
{
@ -72,6 +86,8 @@ namespace epee
if(!serialization::store_t_to_binary(out_struct, req_param))
return false;
LOG_PRINT_L3("[HTTP_BIN] ---> " << "[" << &req_param << "][" << method << "][" << url << "] REQUEST BODY BASE64: " << ENDL << epee::string_encoding::base64_encode(req_param));
const http::http_response_info* pri = NULL;
if(!invoke_request(url, transport, timeout, &pri, method, req_param))
{
@ -85,6 +101,8 @@ namespace epee
return false;
}
LOG_PRINT_L3("[HTTP_BIN] <--- " << "[" << &req_param << "][" << method << "][" << url << "] RESPONSE(" << pri->m_response_code << ") BODY BASE64: " << ENDL << epee::string_encoding::base64_encode(pri->m_body));
if(pri->m_response_code != 200)
{
LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code);

View file

@ -30,7 +30,6 @@
namespace epee
{
using namespace misc_utils::parse;
namespace serialization
{
namespace json
@ -86,7 +85,7 @@ namespace epee
switch(*it)
{
case '"':
match_string2(it, buf_end, name);
misc_utils::parse::match_string2(it, buf_end, name);
state = match_state_waiting_separator;
break;
case '}':
@ -107,7 +106,7 @@ namespace epee
if(*it == '"')
{//just a named string value started
std::string val;
match_string2(it, buf_end, val);
misc_utils::parse::match_string2(it, buf_end, val);
//insert text value
stg.set_value(name, val, current_section);
state = match_state_wonder_after_value;
@ -115,7 +114,7 @@ namespace epee
{//just a named number value started
std::string val;
bool is_v_float = false;bool is_signed = false;
match_number2(it, buf_end, val, is_v_float, is_signed);
misc_utils::parse::match_number2(it, buf_end, val, is_v_float, is_signed);
if(!is_v_float)
{
if(is_signed)
@ -136,7 +135,7 @@ namespace epee
}else if(isalpha(*it) )
{// could be null, true or false
std::string word;
match_word2(it, buf_end, word);
misc_utils::parse::match_word2(it, buf_end, word);
if(boost::iequals(word, "null"))
{
state = match_state_wonder_after_value;
@ -191,7 +190,7 @@ namespace epee
{
//mean array of strings
std::string val;
match_string2(it, buf_end, val);
misc_utils::parse::match_string2(it, buf_end, val);
h_array = stg.insert_first_value(name, val, current_section);
CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values entry");
state = match_state_array_after_value;
@ -200,7 +199,7 @@ namespace epee
{//array of numbers value started
std::string val;
bool is_v_float = false;bool is_signed_val = false;
match_number2(it, buf_end, val, is_v_float, is_signed_val);
misc_utils::parse::match_number2(it, buf_end, val, is_v_float, is_signed_val);
if(!is_v_float)
{
int64_t nval = boost::lexical_cast<int64_t>(val);//bool res = string_tools::string_to_num_fast(val, nval);
@ -222,7 +221,7 @@ namespace epee
}else if(isalpha(*it) )
{// array of booleans
std::string word;
match_word2(it, buf_end, word);
misc_utils::parse::match_word2(it, buf_end, word);
if(boost::iequals(word, "true"))
{
h_array = stg.insert_first_value(name, true, current_section);
@ -266,7 +265,7 @@ namespace epee
if(*it == '"')
{
std::string val;
match_string2(it, buf_end, val);
misc_utils::parse::match_string2(it, buf_end, val);
bool res = stg.insert_next_value(h_array, val);
CHECK_AND_ASSERT_THROW_MES(res, "failed to insert values");
state = match_state_array_after_value;
@ -277,7 +276,7 @@ namespace epee
{//array of numbers value started
std::string val;
bool is_v_float = false;bool is_signed_val = false;
match_number2(it, buf_end, val, is_v_float, is_signed_val);
misc_utils::parse::match_number2(it, buf_end, val, is_v_float, is_signed_val);
bool insert_res = false;
if(!is_v_float)
{
@ -299,7 +298,7 @@ namespace epee
if(isalpha(*it) )
{// array of booleans
std::string word;
match_word2(it, buf_end, word);
misc_utils::parse::match_word2(it, buf_end, word);
if(boost::iequals(word, "true"))
{
bool r = stg.insert_next_value(h_array, true);

View file

@ -129,7 +129,20 @@ POP_VS_WARNINGS
template<typename from_type, typename to_type>
struct convert_to_integral<from_type, to_type, false>
{
static void convert(const from_type& from, to_type& to)
static void convert(const std::string& from, uint64_t& to)
{
//attempt to convert string to unsigned int
try
{
to = std::stoull(from);
}catch(...)
{
ASSERT_AND_THROW_WRONG_CONVERSION();
}
}
template<typename from_type_t, typename to_type_t>
static void convert(const from_type_t& from, to_type_t& to)
{
ASSERT_AND_THROW_WRONG_CONVERSION();
}

View file

@ -23,16 +23,12 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifndef _STRING_TOOLS_H_
#define _STRING_TOOLS_H_
//#include <objbase.h>
#include <locale>
#include <cstdlib>
//#include <strsafe.h>
#include <map>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <boost/lexical_cast.hpp>
@ -212,7 +208,7 @@ namespace string_tools
t_pod_type parse_tpod_from_hex_string(const std::string& str_hash)
{
t_pod_type t_pod = AUTO_VAL_INIT(t_pod);
parse_tpod_from_hex_string(str_hash, t_pod);
epee::string_tools::parse_tpod_from_hex_string(str_hash, t_pod); // using fully qualified name to avoid Argument-Dependent Lookup issues
return t_pod;
}
//----------------------------------------------------------------------------
@ -322,13 +318,6 @@ POP_GCC_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)
{
@ -803,6 +792,9 @@ POP_GCC_WARNINGS
return buff;
}
#endif
}
}
} // namespace stringtools
} // namwspace epee
namespace epst = epee::string_tools; // EPshort alias for convenience
#endif //_STRING_TOOLS_H_

View file

@ -84,6 +84,8 @@ namespace epee
template<typename t_proxy_object, typename t_proxy_lock_time_watching_policy>
friend class locked_object_proxy;
public:
typedef std::shared_ptr<locked_object_proxy<t_object, lock_time_watching_policy>> lock_shared_ptr;
std::shared_ptr<locked_object_proxy<t_object, lock_time_watching_policy>> lock()
{
std::shared_ptr<locked_object_proxy<t_object, lock_time_watching_policy>> res;

View file

@ -711,4 +711,4 @@ namespace epee
#define EXCLUSIVE_CRITICAL_REGION_BEGIN(x) { EXCLUSIVE_CRITICAL_REGION_LOCAL(x)
#define EXCLUSIVE_CRITICAL_REGION_END() }
}
} // namespace epee

View file

@ -12,9 +12,13 @@
#define DISABLE_GCC_WARNING(w)
#define DISABLE_CLANG_WARNING(w)
#define DISABLE_GCC_AND_CLANG_WARNING(w)
#define ATTRIBUTE_UNUSED
#else
#define ATTRIBUTE_UNUSED __attribute__((unused))
#include <boost/preprocessor/stringize.hpp>
#define PUSH_VS_WARNINGS

View file

@ -124,7 +124,7 @@ ENABLE_SHARED_PCH(currency_core CURRENCY_CORE)
add_library(wallet ${WALLET})
if(CMAKE_SYSTEM_NAME STREQUAL "Android" )
add_dependencies(wallet version ${PCH_LIB_NAME})
target_link_libraries(wallet currency_core crypto common zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} android log)
target_link_libraries(wallet currency_core crypto common zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} android log OpenSSL::SSL OpenSSL::Crypto)
else()
add_dependencies(wallet version ${PCH_LIB_NAME})
ENABLE_SHARED_PCH(wallet WALLET)
@ -162,19 +162,19 @@ target_link_libraries(currency_core lmdb mdbx)
add_executable(daemon ${DAEMON} ${P2P} ${CURRENCY_PROTOCOL})
add_dependencies(daemon version)
target_link_libraries(daemon rpc stratum currency_core crypto common libminiupnpc-static zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
target_link_libraries(daemon rpc stratum currency_core crypto common libminiupnpc-static zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
ENABLE_SHARED_PCH(daemon DAEMON)
ENABLE_SHARED_PCH_EXECUTABLE(daemon)
add_executable(connectivity_tool ${CONN_TOOL})
add_dependencies(connectivity_tool version)
target_link_libraries(connectivity_tool currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
target_link_libraries(connectivity_tool currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
ENABLE_SHARED_PCH(connectivity_tool CONN_TOOL)
ENABLE_SHARED_PCH_EXECUTABLE(connectivity_tool)
add_executable(simplewallet ${SIMPLEWALLET})
add_dependencies(simplewallet version)
target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
ENABLE_SHARED_PCH(simplewallet SIMPLEWALLET)
ENABLE_SHARED_PCH_EXECUTABLE(simplewallet)
@ -199,7 +199,7 @@ if(BUILD_GUI)
QT5_USE_MODULES(Zano WebEngineWidgets WebChannel)
find_package(Qt5PrintSupport REQUIRED)
target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic ethash Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic ethash Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto)
if (UNIX AND NOT APPLE)
target_link_libraries(Zano rt)
endif()

View file

@ -16,6 +16,7 @@
#define CHECK_PROJECT_NAME() std::string project_name = CURRENCY_NAME; ar & project_name; if(!(project_name == CURRENCY_NAME) ) {throw std::runtime_error(std::string("wrong storage file: project name in file: ") + project_name + ", expected: " + CURRENCY_NAME );}
namespace tools
{
template<class t_object>

View file

@ -0,0 +1,47 @@
// Copyright (c) 2014-2022 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#define BEGIN_BOOST_SERIALIZATION() template <class t_archive> inline void serialize(t_archive &_arch, const unsigned int ver) {
template<size_t A, size_t B> struct TAssertEquality {
static_assert(A == B, "Serialization map is not updated, sizeof() missmatch");
static constexpr bool _cResult = (A == B);
};
//experemental feature: self-validated serialization map, needed to not forget add new members to serialization maps
#define BEGIN_BOOST_SERIALIZATION_SV(sz) BEGIN_BOOST_SERIALIZATION() \
static constexpr bool _cIsEqual = TAssertEquality<sz, sizeof(*this)>::_cResult;
#define BOOST_SERIALIZE(x) _arch & x;
#define BOOST_SERIALIZE_BASE_CLASS(class_type) _arch & static_cast<class_type&>(*this);
#define BOOST_END_VERSION_UNDER(x) \
if(ver < x ) {return;}
#define END_BOOST_SERIALIZATION() }
/*
example of use:
struct tx_extra_info
{
crypto::public_key m_tx_pub_key;
extra_alias_entry m_alias;
std::string m_user_data_blob;
extra_attachment_info m_attachment_info;
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(m_tx_pub_key)
BOOST_SERIALIZE(m_alias)
if(ver < xxx) return;
BOOST_SERIALIZE(m_user_data_blob)
BOOST_SERIALIZE(m_attachment_info)
END_BOOST_SERIALIZATION()
};
*/

View file

@ -137,11 +137,17 @@ namespace tools
STACKFRAME64 frame;
memset(&frame, 0, sizeof frame);
#ifndef _M_ARM64
frame.AddrPC.Offset = context.Rip;
#endif
frame.AddrPC.Mode = AddrModeFlat;
#ifndef _M_ARM64
frame.AddrStack.Offset = context.Rsp;
#endif
frame.AddrStack.Mode = AddrModeFlat;
#ifndef _M_ARM64
frame.AddrFrame.Offset = context.Rbp;
#endif
frame.AddrFrame.Mode = AddrModeFlat;
IMAGEHLP_LINE64 line = { 0 };

View file

@ -37,6 +37,7 @@ namespace command_line
const arg_descriptor<bool> arg_no_predownload ( "no-predownload", "Do not pre-download blockchain database");
const arg_descriptor<bool> arg_force_predownload ( "force-predownload", "Pre-download blockchain database regardless of it's status");
const arg_descriptor<std::string> arg_process_predownload_from_path("predownload-from-local-path", "Instead of downloading file use downloaded local file");
const arg_descriptor<bool> arg_validate_predownload ( "validate-predownload", "Paranoid mode, re-validate each block from pre-downloaded database and rebuild own database");
const arg_descriptor<std::string> arg_predownload_link ( "predownload-link", "Override url for blockchain database pre-downloading");

View file

@ -229,6 +229,7 @@ namespace command_line
extern const arg_descriptor<std::string> arg_db_engine;
extern const arg_descriptor<bool> arg_no_predownload;
extern const arg_descriptor<bool> arg_force_predownload;
extern const arg_descriptor<std::string> arg_process_predownload_from_path;
extern const arg_descriptor<bool> arg_validate_predownload;
extern const arg_descriptor<std::string> arg_predownload_link;
extern const arg_descriptor<std::string> arg_deeplink;

View file

@ -1,57 +0,0 @@
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include <boost/serialization/vector.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/variant.hpp>
#include <boost/serialization/set.hpp>
#include <boost/serialization/map.hpp>
#include <boost/foreach.hpp>
#include <boost/serialization/is_bitwise_serializable.hpp>
#include "crypto/crypto.h"
namespace boost
{
namespace serialization
{
//---------------------------------------------------
template <class Archive>
inline void serialize(Archive &a, crypto::public_key &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::public_key)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::secret_key &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::secret_key)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::key_derivation &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::key_derivation)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::key_image &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::key_image)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::signature &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::signature)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::hash &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::hash)]>(x);
}
}
}
//}

View file

@ -0,0 +1,300 @@
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include <boost/serialization/vector.hpp>
#include <boost/serialization/utility.hpp>
#include <boost/serialization/variant.hpp>
#include <boost/serialization/set.hpp>
#include <boost/serialization/map.hpp>
#include <boost/foreach.hpp>
#include <boost/serialization/is_bitwise_serializable.hpp>
#include "serialization/serialization.h"
#include "serialization/debug_archive.h"
#include "crypto/chacha8.h"
#include "crypto/crypto.h"
#include "crypto/hash.h"
#include "crypto/range_proofs.h"
#include "crypto/clsag.h"
#include "crypto/zarcanum.h"
#include "crypto/one_out_of_many_proofs.h"
#include "boost_serialization_maps.h"
#include "serialization/keyvalue_enable_POD_serialize_as_string.h"
//
// binary serialization
//
namespace crypto
{
struct bpp_signature_serialized : public bpp_signature
{
BEGIN_SERIALIZE_OBJECT()
FIELD(L)
FIELD(R)
FIELD(A0)
FIELD(A)
FIELD(B)
FIELD(r)
FIELD(s)
FIELD(delta)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(L)
BOOST_SERIALIZE(R)
BOOST_SERIALIZE(A0)
BOOST_SERIALIZE(A)
BOOST_SERIALIZE(B)
BOOST_SERIALIZE(r)
BOOST_SERIALIZE(s)
BOOST_SERIALIZE(delta)
END_BOOST_SERIALIZATION()
};
struct bppe_signature_serialized : public bppe_signature
{
BEGIN_SERIALIZE_OBJECT()
FIELD(L)
FIELD(R)
FIELD(A0)
FIELD(A)
FIELD(B)
FIELD(r)
FIELD(s)
FIELD(delta_1)
FIELD(delta_2)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(L)
BOOST_SERIALIZE(R)
BOOST_SERIALIZE(A0)
BOOST_SERIALIZE(A)
BOOST_SERIALIZE(B)
BOOST_SERIALIZE(r)
BOOST_SERIALIZE(s)
BOOST_SERIALIZE(delta_1)
BOOST_SERIALIZE(delta_2)
END_BOOST_SERIALIZATION()
};
struct CLSAG_GG_signature_serialized : public CLSAG_GG_signature
{
BEGIN_SERIALIZE_OBJECT()
FIELD(c)
FIELD((std::vector<scalar_t>&)(r))
FIELD(K1)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(c)
BOOST_SERIALIZE((std::vector<scalar_t>&)(r))
BOOST_SERIALIZE(K1)
END_BOOST_SERIALIZATION()
};
struct CLSAG_GGX_signature_serialized : public CLSAG_GGX_signature
{
BEGIN_SERIALIZE_OBJECT()
FIELD(c)
FIELD((std::vector<scalar_t>&)(r_g))
FIELD((std::vector<scalar_t>&)(r_x))
FIELD(K1)
FIELD(K2)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(c)
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_g))
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_x))
BOOST_SERIALIZE(K1)
BOOST_SERIALIZE(K2)
END_BOOST_SERIALIZATION()
};
struct CLSAG_GGXXG_signature_serialized : public CLSAG_GGXXG_signature
{
BEGIN_SERIALIZE_OBJECT()
FIELD(c)
FIELD_N("r_g", (std::vector<scalar_t>&)(r_g))
FIELD_N("r_x", (std::vector<scalar_t>&)(r_x))
FIELD(K1)
FIELD(K2)
FIELD(K3)
FIELD(K4)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(c)
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_g))
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_x))
BOOST_SERIALIZE(K1)
BOOST_SERIALIZE(K2)
BOOST_SERIALIZE(K3)
BOOST_SERIALIZE(K4)
END_BOOST_SERIALIZATION()
};
struct vector_UG_aggregation_proof_serialized : public vector_UG_aggregation_proof
{
BEGIN_SERIALIZE_OBJECT()
FIELD(amount_commitments_for_rp_aggregation)
FIELD((std::vector<scalar_t>&)(y0s))
FIELD((std::vector<scalar_t>&)(y1s))
FIELD(c)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(amount_commitments_for_rp_aggregation)
BOOST_SERIALIZE((std::vector<scalar_t>&)(y0s))
BOOST_SERIALIZE((std::vector<scalar_t>&)(y1s))
BOOST_SERIALIZE(c)
END_BOOST_SERIALIZATION()
};
struct linear_composition_proof_s : public linear_composition_proof
{
BEGIN_SERIALIZE_OBJECT()
FIELD(c)
FIELD(y0)
FIELD(y1)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(c)
BOOST_SERIALIZE(y0)
BOOST_SERIALIZE(y1)
END_BOOST_SERIALIZATION()
};
struct generic_schnorr_sig_s : public generic_schnorr_sig
{
BEGIN_SERIALIZE_OBJECT()
FIELD(c)
FIELD(y)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(c)
BOOST_SERIALIZE(y)
END_BOOST_SERIALIZATION()
};
struct generic_double_schnorr_sig_s : public generic_double_schnorr_sig
{
BEGIN_SERIALIZE_OBJECT()
FIELD(c)
FIELD(y0)
FIELD(y1)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(c)
BOOST_SERIALIZE(y0)
BOOST_SERIALIZE(y1)
END_BOOST_SERIALIZATION()
};
struct BGE_proof_s : public BGE_proof
{
BEGIN_SERIALIZE_OBJECT()
FIELD(A)
FIELD(B)
FIELD(Pk)
FIELD_N("f", (std::vector<scalar_t>&)(f))
FIELD(y)
FIELD(z)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(A)
BOOST_SERIALIZE(B)
BOOST_SERIALIZE(Pk)
BOOST_SERIALIZE(f)
BOOST_SERIALIZE(y)
BOOST_SERIALIZE(z)
END_BOOST_SERIALIZATION()
};
} // namespace crypto
BLOB_SERIALIZER(crypto::chacha8_iv);
BLOB_SERIALIZER(crypto::hash);
BLOB_SERIALIZER(crypto::public_key);
BLOB_SERIALIZER(crypto::secret_key);
BLOB_SERIALIZER(crypto::key_derivation);
BLOB_SERIALIZER(crypto::key_image);
BLOB_SERIALIZER(crypto::signature);
BLOB_SERIALIZER(crypto::scalar_t);
BLOB_SERIALIZER(crypto::point_t);
VARIANT_TAG(debug_archive, crypto::hash, "hash");
VARIANT_TAG(debug_archive, crypto::public_key, "public_key");
VARIANT_TAG(debug_archive, crypto::secret_key, "secret_key");
VARIANT_TAG(debug_archive, crypto::key_derivation, "key_derivation");
VARIANT_TAG(debug_archive, crypto::key_image, "key_image");
VARIANT_TAG(debug_archive, crypto::signature, "signature");
//
// Key-value serialization
//
KV_ENABLE_POD_SERIALIZATION_AS_HEX(crypto::scalar_t);
KV_ENABLE_POD_SERIALIZATION_AS_HEX(crypto::hash);
//
// Boost serialization
//
namespace boost
{
namespace serialization
{
//---------------------------------------------------
template <class Archive>
inline void serialize(Archive &a, crypto::public_key &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::public_key)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::secret_key &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::secret_key)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::key_derivation &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::key_derivation)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::key_image &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::key_image)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::signature &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::signature)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::hash &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::hash)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::scalar_t &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::scalar_t)]>(x);
}
template <class Archive>
inline void serialize(Archive &a, crypto::point_t &x, const boost::serialization::version_type ver)
{
a & reinterpret_cast<char (&)[sizeof(crypto::point_t)]>(x);
}
} // namespace serialization
} // namespace boost

View file

@ -291,6 +291,10 @@ namespace tools
if (res == MDB_NOTFOUND)
return false;
if (res != MDB_SUCCESS)
{
return false;
}
CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_get, h: " << h << ", ks: " << ks);
res_buff.assign((const char*)data.mv_data, data.mv_size);

View file

@ -4,6 +4,7 @@
#pragma once
#include "../currency_core/basic_api_response_codes.h"
#define API_RETURN_CODE_OK BASIC_RESPONSE_STATUS_OK
#define API_RETURN_CODE_FAIL BASIC_RESPONSE_STATUS_FAILED
@ -23,6 +24,7 @@
#define API_RETURN_CODE_WALLET_WRONG_ID "WALLET_WRONG_ID"
#define API_RETURN_CODE_WALLET_WATCH_ONLY_NOT_SUPPORTED "WALLET_WATCH_ONLY_NOT_SUPPORTED"
#define API_RETURN_CODE_WALLET_AUDITABLE_NOT_SUPPORTED "WALLET_AUDITABLE_NOT_SUPPORTED"
#define API_RETURN_CODE_WALLET_FEE_TOO_LOW "API_RETURN_CODE_WALLET_FEE_TOO_LOW"
#define API_RETURN_CODE_FILE_NOT_FOUND "FILE_NOT_FOUND"
#define API_RETURN_CODE_ALREADY_EXISTS "ALREADY_EXISTS"
#define API_RETURN_CODE_CANCELED "CANCELED"
@ -40,4 +42,5 @@
#define API_RETURN_CODE_TX_IS_TOO_BIG "TX_IS_TOO_BIG"
#define API_RETURN_CODE_TX_REJECTED "TX_REJECTED"
#define API_RETURN_CODE_HTLC_ORIGIN_HASH_MISSMATCHED "HTLC_ORIGIN_HASH_MISSMATCHED"
#define API_RETURN_CODE_WRAP "WRAP"
#define API_RETURN_CODE_WRAP "WRAP"
#define API_RETURN_CODE_MISSING_ZC_INPUTS "MISSING_ZC_INPUTS"

View file

@ -1,4 +1,4 @@
// Copyright (c) 2019 Zano Project
// Copyright (c) 2019-2022 Zano Project
// Note: class udp_blocking_client is a slightly modified version of an example
// taken from https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/timeouts/blocking_udp_client.cpp
@ -13,7 +13,7 @@
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/udp.hpp>
#include <boost/bind.hpp>
#include <boost/bind/bind.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/array.hpp>
#include <epee/include/misc_log_ex.h>

View file

@ -21,8 +21,8 @@ namespace tools
};
#ifndef TESTNET
static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2390000.pak", "ffc8d2220a4d8b3fba51073a422cbb6139c60858469ea086623f9d16329eb5b4", 2767268964, 5368627200 };
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2390000.pak", "7e58951bc523eb12e0ec07171bc67b3f96bad4d5454dd2da56f642a872e230d3", 3618283035, 5156397056 };
static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2500000.pak", "8ffa2cb4213f4f96f97033c65a9e52bc350f683237808597784e79b24d5bfee7", 3242348793, 5905489920 };
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2500000.pak", "5509650e12c8f901e6731a2bfaf3abfd64409e3e1366d3d94cd11db8beddb0c3", 4239505801, 5893566464 };
#else
static constexpr pre_download_entry c_pre_download_mdbx = { "", "", 0, 0 };
static constexpr pre_download_entry c_pre_download_lmdb = { "", "", 0, 0 };
@ -50,6 +50,7 @@ namespace tools
boost::system::error_code ec;
uint64_t sz = boost::filesystem::file_size(db_main_file_path, ec);
if (ec) sz = 0;
bool flag_force_predownload = command_line::has_arg(vm, command_line::arg_force_predownload);
if (pre_download.unpacked_size == 0 || !(ec || (pre_download.unpacked_size > sz && pre_download.unpacked_size - sz > pre_download_min_size_difference) || flag_force_predownload) )
{
@ -59,53 +60,59 @@ namespace tools
// okay, let's download
std::string downloading_file_path = db_main_file_path + ".download";
LOG_PRINT_MAGENTA("Trying to download blockchain database from " << url << " ...", LOG_LEVEL_0);
epee::net_utils::http::interruptible_http_client cl;
crypto::stream_cn_hash hash_stream;
auto last_update = std::chrono::system_clock::now();
auto cb = [&hash_stream, &last_update, &cb_should_stop](const std::string& buff, uint64_t total_bytes, uint64_t received_bytes)
if (!command_line::has_arg(vm, command_line::arg_process_predownload_from_path))
{
if (cb_should_stop(total_bytes, received_bytes))
LOG_PRINT_MAGENTA("Trying to download blockchain database from " << url << " ...", LOG_LEVEL_0);
epee::net_utils::http::interruptible_http_client cl;
crypto::stream_cn_hash hash_stream;
auto last_update = std::chrono::system_clock::now();
auto cb = [&hash_stream, &last_update, &cb_should_stop](const std::string& buff, uint64_t total_bytes, uint64_t received_bytes)
{
LOG_PRINT_MAGENTA(ENDL << "Interrupting download", LOG_LEVEL_0);
return false;
if (cb_should_stop(total_bytes, received_bytes))
{
LOG_PRINT_MAGENTA(ENDL << "Interrupting download", LOG_LEVEL_0);
return false;
}
hash_stream.update(buff.data(), buff.size());
auto dif = std::chrono::system_clock::now() - last_update;
if (dif >= std::chrono::milliseconds(300))
{
boost::io::ios_flags_saver ifs(std::cout);
std::cout << "Received " << received_bytes / 1048576 << " of " << total_bytes / 1048576 << " MiB ( " << std::fixed << std::setprecision(1) << 100.0 * received_bytes / total_bytes << " %)\r";
last_update = std::chrono::system_clock::now();
}
return true;
};
tools::create_directories_if_necessary(working_folder);
r = cl.download_and_unzip(cb, downloading_file_path, url, 5000 /* timout */, "GET", std::string(), 30 /* fails count */);
if (!r)
{
LOG_PRINT_RED("Downloading failed", LOG_LEVEL_0);
return !flag_force_predownload; // fatal error only if force-predownload
}
hash_stream.update(buff.data(), buff.size());
auto dif = std::chrono::system_clock::now() - last_update;
if (dif >= std::chrono::milliseconds(300))
crypto::hash data_hash = hash_stream.calculate_hash();
if (epee::string_tools::pod_to_hex(data_hash) != pre_download.hash)
{
boost::io::ios_flags_saver ifs(std::cout);
std::cout << "Received " << received_bytes / 1048576 << " of " << total_bytes / 1048576 << " MiB ( " << std::fixed << std::setprecision(1) << 100.0 * received_bytes / total_bytes << " %)\r";
last_update = std::chrono::system_clock::now();
LOG_ERROR("hash missmatch in downloaded file, got: " << epee::string_tools::pod_to_hex(data_hash) << ", expected: " << pre_download.hash);
return !flag_force_predownload; // fatal error only if force-predownload
}
return true;
};
tools::create_directories_if_necessary(working_folder);
r = cl.download_and_unzip(cb, downloading_file_path, url, 5000 /* timout */, "GET", std::string(), 30 /* fails count */);
if (!r)
{
LOG_PRINT_RED("Downloading failed", LOG_LEVEL_0);
return !flag_force_predownload; // fatal error only if force-predownload
LOG_PRINT_GREEN("Download succeeded, hash " << pre_download.hash << " is correct", LOG_LEVEL_0);
}
crypto::hash data_hash = hash_stream.calculate_hash();
if (epee::string_tools::pod_to_hex(data_hash) != pre_download.hash)
else
{
LOG_ERROR("hash missmatch in downloaded file, got: " << epee::string_tools::pod_to_hex(data_hash) << ", expected: " << pre_download.hash);
return !flag_force_predownload; // fatal error only if force-predownload
downloading_file_path = command_line::get_arg(vm, command_line::arg_process_predownload_from_path);
}
LOG_PRINT_GREEN("Download succeeded, hash " << pre_download.hash << " is correct" , LOG_LEVEL_0);
if (!command_line::has_arg(vm, command_line::arg_validate_predownload))
{
boost::filesystem::remove(db_main_file_path, ec);
@ -138,11 +145,14 @@ namespace tools
std::string path_to_temp_blockchain_file = path_to_temp_blockchain + "/" + dbbs.get_db_main_file_name();
tools::create_directories_if_necessary(path_to_temp_blockchain);
boost::filesystem::rename(downloading_file_path, path_to_temp_blockchain_file, ec);
if (ec)
if (downloading_file_path != path_to_temp_blockchain_file)
{
LOG_ERROR("Rename failed: " << downloading_file_path << " -> " << path_to_temp_blockchain_file);
return false;
boost::filesystem::rename(downloading_file_path, path_to_temp_blockchain_file, ec);
if (ec)
{
LOG_ERROR("Rename failed: " << downloading_file_path << " -> " << path_to_temp_blockchain_file);
return false;
}
}
// remove old blockchain database from disk
@ -180,6 +190,28 @@ namespace tools
r = target_core.init(target_core_vm);
CHECK_AND_ASSERT_MES(r, false, "Failed to init target core");
if (true/*TODO: copnfigure with command line option*/)
{
//set checkpoints
{
currency::checkpoints checkpoints;
bool res = currency::create_checkpoints(checkpoints);
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints");
res = source_core.set_checkpoints(std::move(checkpoints));
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core");
}
{
currency::checkpoints checkpoints;
bool res = currency::create_checkpoints(checkpoints);
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints");
res = target_core.set_checkpoints(std::move(checkpoints));
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core");
}
}
CHECK_AND_ASSERT_MES(target_core.get_top_block_height() == 0, false, "Target blockchain initialized not empty");
uint64_t total_blocks = source_core.get_current_blockchain_size();

View file

@ -0,0 +1,58 @@
// Copyright (c) 2014-2018 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#define VARIANT_SWITCH_BEGIN(v_type_obj) {auto & local_reference_eokcmeokmeokcm ATTRIBUTE_UNUSED = v_type_obj; if(false) {;
#define VARIANT_CASE_CONST(v_type, typed_name) } else if(local_reference_eokcmeokmeokcm.type() == typeid(v_type)) { const v_type& typed_name ATTRIBUTE_UNUSED = boost::get<v_type>(local_reference_eokcmeokmeokcm);
#define VARIANT_CASE(v_type, typed_name) } else if(local_reference_eokcmeokmeokcm.type() == typeid(v_type)) { v_type& typed_name ATTRIBUTE_UNUSED = boost::get<v_type>(local_reference_eokcmeokmeokcm);
#define VARIANT_CASE_TV(v_type) VARIANT_CASE(v_type, tv)
#define VARIANT_CASE_OTHER() } else {
#define VARIANT_CASE_THROW_ON_OTHER() } else { ASSERT_MES_AND_THROW("Unknown type in switch statemet: " << local_reference_eokcmeokmeokcm.type().name());
#define VARIANT_CASE_THROW_ON_OTHER_MSG(err_msg) } else { ASSERT_MES_AND_THROW(err_msg << local_reference_eokcmeokmeokcm.type().name());
#define VARIANT_SWITCH_END() } }
/*
usage:
VARIANT_SWITCH_BEGIN(o);
VARIANT_CASE(tx_out_bare, o);
VARIANT_CASE_TV(tx_out_zarcanum);
//@#@
VARIANT_SWITCH_END();
VARIANT_SWITCH_BEGIN(o);
VARIANT_CASE_CONST(txout_to_key, o);
VARIANT_CASE_CONST(txout_multisig, ms);
VARIANT_CASE_CONST(txout_htlc, htlc);
VARIANT_CASE_THROW_ON_OTHER();
VARIANT_SWITCH_END();
VARIANT_SWITCH_BEGIN(s);
VARIANT_CASE(void_sig, v);
VARIANT_CASE(NLSAG_sig, signatures);
VARIANT_CASE(zarcanum_sig, s);
//@#@
VARIANT_CASE_THROW_ON_OTHER();
VARIANT_SWITCH_END();
VARIANT_SWITCH_BEGIN(o);
VARIANT_CASE(tx_out_bare, o)
VARIANT_CASE_TV(tx_out_zarcanum)
//@#@
VARIANT_CASE_THROW_ON_OTHER();
VARIANT_SWITCH_END();
*/

View file

@ -407,8 +407,12 @@ bool generate_genesis(const std::string& path_config, uint64_t premine_split_amo
ss.str("");
ss.clear();
const account_public_address dummy_address = AUTO_VAL_INIT(dummy_address);
std::cout << ENDL << "PROOF PHRASE: " << gcp.proof_string << ENDL;
construct_miner_tx(0, 0, 0, 0, 0, destinations, bl.miner_tx, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS);
uint64_t block_reward_without_fee = 0;
uint64_t block_reward = 0;
construct_miner_tx(0, 0, 0, 0, 0, dummy_address, dummy_address, bl.miner_tx, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS, false, pos_entry(), nullptr, nullptr, destinations);
currency::blobdata txb = tx_to_blob(bl.miner_tx);
//self validate block

View file

@ -1,9 +1,6 @@
// Copyright (c) 2020 The Zano developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include "RIPEMD160_helper.h"
#include "auto_val_init.h"
extern "C" {
@ -18,7 +15,7 @@ namespace crypto {
{
dword MDbuf[RMDsize / 32] = {0}; /* contains (A, B, C, D(, E)) */
byte* hashcode = (byte*)&h; /* hashcode[RMDsize / 8]; /* for final hash-value */
byte* hashcode = (byte*)&h; /* hashcode[RMDsize / 8]; for final hash-value */
dword X[16] = {0}; /* current 16-word chunk */
unsigned int i = 0; /* counter */
dword length = static_cast<dword>(length_size_t); /* length in bytes of message */

View file

@ -7,7 +7,7 @@
#include <assert.h>
#include <string.h>
#include "warnings.h"
//#include <compat/cpuid.h>
#if defined(__x86_64__) || defined(__amd64__) || defined(__i386__)
@ -462,6 +462,9 @@ namespace
TransformD64Type TransformD64_4way = nullptr;
TransformD64Type TransformD64_8way = nullptr;
PUSH_GCC_WARNINGS
DISABLE_GCC_AND_CLANG_WARNING(unused-function)
bool SelfTest() {
// Input state (equal to the initial SHA256 state)
static const uint32_t init[8] = {
@ -626,7 +629,7 @@ std::string SHA256AutoDetect()
assert(SelfTest());
return ret;
}
POP_GCC_WARNINGS
////// SHA-256
CSHA256::CSHA256() : bytes(0)

1132
src/crypto/clsag.cpp Normal file

File diff suppressed because it is too large Load diff

178
src/crypto/clsag.h Normal file
View file

@ -0,0 +1,178 @@
// Copyright (c) 2022-2024 Zano Project
// Copyright (c) 2022-2024 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// This file contains implementation of the original d-CLSAG (s.a. https://eprint.iacr.org/2019/654.pdf by Goodel at el)
// and the extended d/v-CLSAG version (s.a. https://github.com/hyle-team/docs/blob/master/zano/dv-CLSAG-extension/ by sowle)
//
#pragma once
#include "crypto-sugar.h"
namespace crypto
{
// 2-CLSAG signature where both dimensions are with respect to the group element G (that's why 'GG')
struct CLSAG_GG_signature
{
scalar_t c;
scalar_vec_t r; // size = size of the ring
public_key K1; // auxiliary key image for layer 1
};
inline bool operator==(const CLSAG_GG_signature& lhs, const CLSAG_GG_signature& rhs)
{
return
lhs.c == rhs.c &&
lhs.r == rhs.r &&
lhs.K1 == rhs.K1;
}
inline bool operator!=(const CLSAG_GG_signature& lhs, const CLSAG_GG_signature& rhs) { return !(lhs == rhs); }
struct CLSAG_GG_input_ref_t
{
CLSAG_GG_input_ref_t(const public_key& stealth_address, const public_key& amount_commitment)
: stealth_address(stealth_address), amount_commitment(amount_commitment)
{}
const public_key& stealth_address; // P, not premultiplied by 1/8, TODO @#@#: make sure it's okay
const public_key& amount_commitment; // A, premultiplied by 1/8
};
// pseudo_out_amount_commitment -- not premultiplied by 1/8
bool generate_CLSAG_GG(const hash& m, const std::vector<CLSAG_GG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const key_image& ki,
const scalar_t& secret_x, const scalar_t& secret_f, uint64_t secret_index, CLSAG_GG_signature& sig);
// pseudo_out_amount_commitment -- premultiplied by 1/8
bool verify_CLSAG_GG(const hash& m, const std::vector<CLSAG_GG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment, const key_image& ki,
const CLSAG_GG_signature& sig);
//
// Disclaimer: extensions to the CLSAG implemented below are non-standard and are in proof-of-concept state.
// They shouldn't be used in production code until formal security proofs are done and (ideally) the code is peer-reviewed.
// -- sowle
//
//
// 3/2-CLSAG
//
// 3/2-CLSAG signature (with respect to the group element G, G, X -- that's why 'GGX')
struct CLSAG_GGX_signature
{
scalar_t c;
scalar_vec_t r_g; // for G-components (layers 0, 1), size = size of the ring
scalar_vec_t r_x; // for X-component (layer 2), size = size of the ring
public_key K1; // auxiliary key image for layer 1 (G)
public_key K2; // auxiliary key image for layer 2 (X)
};
struct CLSAG_GGX_input_ref_t : public CLSAG_GG_input_ref_t
{
CLSAG_GGX_input_ref_t(const public_key& stealth_address, const public_key& amount_commitment, const public_key& blinded_asset_id)
: CLSAG_GG_input_ref_t(stealth_address, amount_commitment)
, blinded_asset_id(blinded_asset_id)
{}
const public_key& blinded_asset_id; // T, premultiplied by 1/8
};
// pseudo_out_amount_commitment -- not premultiplied by 1/8
// pseudo_out_asset_id -- not premultiplied by 1/8
bool generate_CLSAG_GGX(const hash& m, const std::vector<CLSAG_GGX_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const point_t& pseudo_out_asset_id, const key_image& ki,
const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_t, uint64_t secret_index, CLSAG_GGX_signature& sig);
// pseudo_out_amount_commitment -- premultiplied by 1/8
// pseudo_out_asset_id -- premultiplied by 1/8
// may throw an exception TODO @#@# make sure it's okay
bool verify_CLSAG_GGX(const hash& m, const std::vector<CLSAG_GGX_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment,
const public_key& pseudo_out_asset_id, const key_image& ki, const CLSAG_GGX_signature& sig);
/*
//
// 4/2-CLSAG (eventually, it's not used in Zano)
//
// 4/2-CLSAG signature (with respect to the group element G, G, X, G -- that's why 'GGXG')
struct CLSAG_GGXG_signature
{
scalar_t c;
scalar_vec_t r_g; // for G-components (layers 0, 1, 3), size = size of the ring
scalar_vec_t r_x; // for X-component (layer 2), size = size of the ring
public_key K1; // auxiliary key image for layer 1 (G)
public_key K2; // auxiliary key image for layer 2 (X)
public_key K3; // auxiliary key image for layer 3 (G)
};
struct CLSAG_GGXG_input_ref_t : public CLSAG_GG_input_ref_t
{
CLSAG_GGXG_input_ref_t(const public_key& stealth_address, const public_key& amount_commitment, const public_key& concealing_point)
: CLSAG_GG_input_ref_t(stealth_address, amount_commitment)
, concealing_point(concealing_point)
{}
const public_key& concealing_point; // Q, premultiplied by 1/8
};
// pseudo_out_amount_commitment -- not premultiplied by 1/8
// extended_amount_commitment -- not premultiplied by 1/8
bool generate_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const point_t& extended_amount_commitment, const key_image& ki,
const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_x, const scalar_t& secret_3_q, uint64_t secret_index, CLSAG_GGXG_signature& sig);
// pseudo_out_amount_commitment -- premultiplied by 1/8
// extended_amount_commitment -- premultiplied by 1/8
// may throw an exception TODO @#@# make sure it's okay
bool verify_CLSAG_GGXG(const hash& m, const std::vector<CLSAG_GGXG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment,
const public_key& extended_amount_commitment, const key_image& ki, const CLSAG_GGXG_signature& sig);
*/
//
// 5/2-CLSAG
//
// 5/2-CLSAG signature (with respect to the group element G, G, X, X, G -- that's why 'GGXXG')
struct CLSAG_GGXXG_signature
{
scalar_t c;
scalar_vec_t r_g; // for G-components (layers 0, 1, 4), size = size of the ring
scalar_vec_t r_x; // for X-component (layers 2, 3), size = size of the ring
public_key K1; // auxiliary key image for layer 1 (G)
public_key K2; // auxiliary key image for layer 2 (X)
public_key K3; // auxiliary key image for layer 2 (X)
public_key K4; // auxiliary key image for layer 3 (G)
};
struct CLSAG_GGXXG_input_ref_t : public CLSAG_GGX_input_ref_t
{
CLSAG_GGXXG_input_ref_t(const public_key& stealth_address, const public_key& amount_commitment, const public_key& blinded_asset_id, const public_key& concealing_point)
: CLSAG_GGX_input_ref_t(stealth_address, amount_commitment, blinded_asset_id)
, concealing_point(concealing_point)
{}
const public_key& concealing_point; // Q, premultiplied by 1/8
};
// pseudo_out_amount_commitment -- not premultiplied by 1/8
// pseudo_out_asset_id -- not premultiplied by 1/8
// extended_amount_commitment -- not premultiplied by 1/8
bool generate_CLSAG_GGXXG(const hash& m, const std::vector<CLSAG_GGXXG_input_ref_t>& ring, const point_t& pseudo_out_amount_commitment, const point_t& pseudo_out_blinded_asset_id, const point_t& extended_amount_commitment, const key_image& ki,
const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_r, const scalar_t& secret_3_x, const scalar_t& secret_4_q, uint64_t secret_index, CLSAG_GGXXG_signature& sig);
// pseudo_out_amount_commitment -- premultiplied by 1/8
// pseudo_out_asset_id -- premultiplied by 1/8
// extended_amount_commitment -- premultiplied by 1/8
// may throw an exception TODO @#@# make sure it's okay
bool verify_CLSAG_GGXXG(const hash& m, const std::vector<CLSAG_GGXXG_input_ref_t>& ring, const public_key& pseudo_out_amount_commitment, const public_key& pseudo_out_blinded_asset_id, const public_key& extended_amount_commitment, const key_image& ki,
const CLSAG_GGXXG_signature& sig);
} // namespace crypto

View file

@ -40,7 +40,6 @@ DISABLE_VS_WARNINGS(4146 4244)
void fe_mul(fe, const fe, const fe);
void fe_sq(fe, const fe);
void fe_tobytes(unsigned char *, const fe);
static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *);
static void ge_p2_0(ge_p2 *);
static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *);
@ -119,7 +118,7 @@ Postconditions:
|h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
*/
static void fe_add(fe h, const fe f, const fe g) {
void fe_add(fe h, const fe f, const fe g) {
int32_t f0 = f[0];
int32_t f1 = f[1];
int32_t f2 = f[2];
@ -1425,7 +1424,7 @@ int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) {
r = p + q
*/
static void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) {
fe t0;
fe_add(r->X, p->Y, p->X);
fe_sub(r->Y, p->Y, p->X);
@ -4314,3 +4313,171 @@ void ge_cached_to_p2(ge_p2 *r, const ge_cached *c)
fe_copy(r->Z, c->Z);
}
///////////////////////////
// EXPERIMENTAL
//
// With these select_vartime/ge_scalarmult_base_vartime I got ~25% speed up comparing to the select/ge_scalarmult_base -- sowle
static void select_vartime(ge_precomp *t, int pos, signed char b)
{
unsigned char bnegative = negative(b);
unsigned char babs = b - (((-bnegative) & b) << 1);
const ge_precomp* base;
if (babs == 0)
{
ge_precomp_0(t);
}
else if (bnegative == 0)
{
base = &ge_base[pos][babs - 1];
fe_copy(t->yplusx, base->yplusx);
fe_copy(t->yminusx, base->yminusx);
fe_copy(t->xy2d, base->xy2d);
}
else
{
base = &ge_base[pos][babs - 1];
fe_copy(t->yplusx, base->yminusx);
fe_copy(t->yminusx, base->yplusx);
fe_neg(t->xy2d, base->xy2d);
}
}
void ge_scalarmult_base_vartime(ge_p3 *h, const unsigned char *a)
{
signed char e[64];
signed char carry;
ge_p1p1 r;
ge_p2 s;
ge_precomp t;
int i;
for (i = 0; i < 32; ++i) {
e[2 * i + 0] = (a[i] >> 0) & 15;
e[2 * i + 1] = (a[i] >> 4) & 15;
}
/* each e[i] is between 0 and 15 */
/* e[63] is between 0 and 7 */
carry = 0;
for (i = 0; i < 63; ++i) {
e[i] += carry;
carry = e[i] + 8;
carry >>= 4;
e[i] -= carry << 4;
}
e[63] += carry;
/* each e[i] is between -8 and 8 */
ge_p3_0(h);
for (i = 1; i < 64; i += 2) {
select_vartime(&t, i / 2, e[i]);
ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
}
ge_p3_dbl(&r, h); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p3(h, &r);
for (i = 0; i < 64; i += 2) {
select_vartime(&t, i / 2, e[i]);
ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
}
}
static void select_custom_precomp_vartime(ge_precomp *t, const precomp_data_t base_precomp, int pos, signed char b)
{
unsigned char bnegative = negative(b);
unsigned char babs = b - (((-bnegative) & b) << 1);
const ge_precomp* base;
if (babs == 0)
{
ge_precomp_0(t);
}
else if (bnegative == 0)
{
base = &base_precomp[pos][babs - 1];
fe_copy(t->yplusx, base->yplusx);
fe_copy(t->yminusx, base->yminusx);
fe_copy(t->xy2d, base->xy2d);
}
else
{
base = &base_precomp[pos][babs - 1];
fe_copy(t->yplusx, base->yminusx);
fe_copy(t->yminusx, base->yplusx);
fe_neg(t->xy2d, base->xy2d);
}
}
void ge_scalarmult_precomp_vartime(ge_p3 *h, const precomp_data_t base_precomp, const unsigned char *a)
{
signed char e[64];
signed char carry;
ge_p1p1 r;
ge_p2 s;
ge_precomp t;
int i;
for (i = 0; i < 32; ++i) {
e[2 * i + 0] = (a[i] >> 0) & 15;
e[2 * i + 1] = (a[i] >> 4) & 15;
}
/* each e[i] is between 0 and 15 */
/* e[63] is between 0 and 7 */
carry = 0;
for (i = 0; i < 63; ++i) {
e[i] += carry;
carry = e[i] + 8;
carry >>= 4;
e[i] -= carry << 4;
}
e[63] += carry;
/* each e[i] is between -8 and 8 */
ge_p3_0(h);
for (i = 1; i < 64; i += 2) {
select_custom_precomp_vartime(&t, base_precomp, i / 2, e[i]);
ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
}
ge_p3_dbl(&r, h); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r);
ge_p2_dbl(&r, &s); ge_p1p1_to_p3(h, &r);
for (i = 0; i < 64; i += 2) {
select_custom_precomp_vartime(&t, base_precomp, i / 2, e[i]);
ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r);
}
}
void ge_p3_to_precomp(ge_precomp *r, const ge_p3* p)
{
fe recip;
fe x;
fe y;
//unsigned char s[32];
fe_invert(recip, p->Z);
fe_mul(x, p->X, recip);
fe_mul(y, p->Y, recip);
fe_sub(r->yminusx, y, x);
fe_add(r->yplusx, y, x);
fe_mul(r->xy2d, x, y);
fe_mul(r->xy2d, r->xy2d, fe_d2);
// to get canonical representation and obtain the very same beautiful numbers for ge_base in crypto-ops-data.c (maybe unnecessary, TODO -- sowle)
//fe_tobytes(s, r->yminusx); fe_frombytes(r->yminusx, s);
//fe_tobytes(s, r->yplusx); fe_frombytes(r->yplusx, s);
//fe_tobytes(s, r->xy2d); fe_frombytes(r->xy2d, s);
}

View file

@ -60,6 +60,7 @@ void ge_double_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const ge_
extern const fe fe_sqrtm1;
extern const fe fe_d;
extern const fe fe_d2;
int ge_frombytes_vartime(ge_p3 *, const unsigned char *);
/* From ge_p1p1_to_p2.c */
@ -112,12 +113,19 @@ void ge_p2_to_p3(ge_p3 *r, const ge_p2 *t);
void ge_bytes_hash_to_ec(ge_p3 *, const void *, size_t);
void ge_bytes_hash_to_ec_32(ge_p3 *, const unsigned char *);
void ge_cached_to_p2(ge_p2 *r, const ge_cached *c);
void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q);
void ge_p3_0(ge_p3 *h);
void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *);
void ge_double_scalarmult_base_vartime_p3(ge_p3 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b);
void ge_scalarmult_vartime_p3(ge_p3 *r, const unsigned char *a, const ge_p3 *A);
void ge_scalarmult_vartime_p3_v2(ge_p3 *r, const unsigned char *a, const ge_p3 *A);
void ge_scalarmult_base_vartime(ge_p3 *h, const unsigned char *a);
/* precomp_data[i][j] = (j + 1) * 256^i * G */
typedef ge_precomp (precomp_data_t)[32][8];
void ge_scalarmult_precomp_vartime(ge_p3 *h, const precomp_data_t base_precomp, const unsigned char *a);
void ge_p3_to_precomp(ge_precomp *r, const ge_p3* p);
extern const fe fe_ma2;
extern const fe fe_ma;
@ -139,6 +147,7 @@ void sc_invert(unsigned char*, const unsigned char*);
void fe_sq(fe h, const fe f);
int fe_isnonzero(const fe f);
void fe_add(fe h, const fe f, const fe g);
void fe_sub(fe h, const fe f, const fe g);
void fe_mul(fe, const fe, const fe);
void fe_frombytes(fe h, const unsigned char *s);

File diff suppressed because it is too large Load diff

View file

@ -1,5 +1,5 @@
// Copyright (c) 2020-2021 Zano Project
// Copyright (c) 2020-2021 sowle (val@zano.org, crypto.sowle@gmail.com)
// Copyright (c) 2020-2024 Zano Project
// Copyright (c) 2020-2024 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
@ -11,17 +11,45 @@
namespace crypto
{
namespace mp = boost::multiprecision;
extern "C"
{
#include "crypto/crypto-ops.h"
} // extern "C"
//
// Helpers
//
// returns greatest k, s.t. n**k <= v
// tests in crypto_tests_range_proofs.h
constexpr uint64_t constexpr_floor_log_n(uint64_t v, uint64_t n)
{
return (v < n || n <= 1) ? 0 : constexpr_floor_log_n(v / n, n) + 1;
}
// returns smallest k, s.t. v <= n**k
// tests in crypto_tests_range_proofs.h
constexpr uint64_t constexpr_ceil_log_n(uint64_t v, uint64_t n)
{
return (v <= 1 || n <= 1) ? 0 : constexpr_floor_log_n(v - 1, n) + 1;
}
// returns smallest k, s.t. v <= 2**k
// tests in crypto_tests_range_proofs.h
constexpr uint64_t constexpr_ceil_log2(uint64_t v)
{
return constexpr_ceil_log_n(v, 2);
}
// returns base ** k
constexpr uint64_t constexpr_pow(uint64_t k, uint64_t base)
{
return k == 0 ? 1 : base * constexpr_pow(k - 1, base);
}
template<class pod_t>
std::string pod_to_hex_reversed(const pod_t &h)
{
@ -30,7 +58,8 @@ namespace crypto
size_t len = sizeof h;
std::string s(len * 2, ' ');
for (size_t i = 0; i < len; ++i) {
for (size_t i = 0; i < len; ++i)
{
s[2 * i] = hexmap[data[len - 1 - i] >> 4];
s[2 * i + 1] = hexmap[data[len - 1 - i] & 0x0F];
}
@ -46,7 +75,8 @@ namespace crypto
size_t len = sizeof h;
std::string s(len * 2, ' ');
for (size_t i = 0; i < len; ++i) {
for (size_t i = 0; i < len; ++i)
{
s[2 * i] = hexmap[data[i] >> 4];
s[2 * i + 1] = hexmap[data[i] & 0x0F];
}
@ -70,6 +100,22 @@ namespace crypto
return ss.str();
}
template<class pod_t>
std::string pod_to_comma_separated_chars(const pod_t &h)
{
std::stringstream ss;
ss << std::hex << std::setfill('0');
size_t len = sizeof h;
const unsigned char* p = (const unsigned char*)&h;
for (size_t i = 0; i < len; ++i)
{
ss << "'\\x" << std::setw(2) << static_cast<unsigned int>(p[i]) << "'";
if (i + 1 != len)
ss << ", ";
}
return ss.str();
}
template<class pod_t>
std::string pod_to_hex_comma_separated_uint64(const pod_t &h)
{
@ -87,6 +133,22 @@ namespace crypto
return ss.str();
}
template<class pod_t>
std::string pod_to_comma_separated_int32(const pod_t &h)
{
static_assert((sizeof h) % 4 == 0, "size of h should be a multiple of 32 bit");
size_t len = (sizeof h) / 4;
std::stringstream ss;
const int32_t* p = (const int32_t*)&h;
for (size_t i = 0; i < len; ++i)
{
ss << static_cast<int32_t>(p[i]);
if (i + 1 != len)
ss << ", ";
}
return ss.str();
}
template<typename t_pod_type>
bool parse_tpod_from_hex_string(const std::string& hex_str, t_pod_type& t_pod)
{
@ -125,31 +187,28 @@ namespace crypto
t_pod_type parse_tpod_from_hex_string(const std::string& hex_str)
{
t_pod_type t_pod = AUTO_VAL_INIT(t_pod);
parse_tpod_from_hex_string(hex_str, t_pod);
crypto::parse_tpod_from_hex_string(hex_str, t_pod); // using fully qualified name to avoid Argument-Dependent Lookup issues
return t_pod;
}
//
// scalar_t - holds a 256-bit scalar, normally in [0..L-1]
//
struct alignas(32) scalar_t
struct /* TODO alignas(32) */ scalar_t
{
union
{
uint64_t m_u64[4];
unsigned char m_s[32];
uint64_t m_u64[4];
unsigned char m_s[32];
crypto::secret_key m_sk;
};
scalar_t()
{}
scalar_t() = default;
// won't check scalar range validity (< L)
scalar_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3)
constexpr scalar_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) noexcept
: m_u64{a0, a1, a2, a3}
{
m_u64[0] = a0;
m_u64[1] = a1;
m_u64[2] = a2;
m_u64[3] = a3;
}
// won't check scalar range validity (< L)
@ -205,28 +264,22 @@ namespace crypto
crypto::secret_key &as_secret_key()
{
return *(crypto::secret_key*)&m_s[0];
return m_sk;
}
const crypto::secret_key& as_secret_key() const
{
return *(const crypto::secret_key*)&m_s[0];
return m_sk;
}
operator crypto::secret_key() const
{
crypto::secret_key result;
memcpy(result.data, &m_s, sizeof result.data);
return result;
return m_sk;
}
void from_secret_key(const crypto::secret_key& sk)
{
uint64_t *p_sk64 = (uint64_t*)&sk;
m_u64[0] = p_sk64[0];
m_u64[1] = p_sk64[1];
m_u64[2] = p_sk64[2];
m_u64[3] = p_sk64[3];
m_sk = sk;
// assuming secret key is correct (< L), so we don't need to call reduce here
}
@ -315,6 +368,14 @@ namespace crypto
return *this;
}
scalar_t operator-() const
{
static unsigned char zero[32] = { 0 };
scalar_t result;
sc_sub(&result.m_s[0], zero, &m_s[0]);
return result;
}
// returns this = a * b
scalar_t& assign_mul(const scalar_t& a, const scalar_t& b)
{
@ -325,7 +386,7 @@ namespace crypto
/*
I think it has bad symantic (operator-like), consider rename/reimplement -- sowle
*/
// returns this * b + c
// returns c + this * b
scalar_t muladd(const scalar_t& b, const scalar_t& c) const
{
scalar_t result;
@ -333,13 +394,20 @@ namespace crypto
return result;
}
// returns this = a * b + c
// returns this = c + a * b
scalar_t& assign_muladd(const scalar_t& a, const scalar_t& b, const scalar_t& c)
{
sc_muladd(m_s, a.m_s, b.m_s, c.m_s);
return *this;
}
// returns this = c - a * b
scalar_t& assign_mulsub(const scalar_t& a, const scalar_t& b, const scalar_t& c)
{
sc_mulsub(m_s, a.m_s, b.m_s, c.m_s);
return *this;
}
scalar_t reciprocal() const
{
scalar_t result;
@ -449,6 +517,25 @@ namespace crypto
m_u64[bit_index >> 6] &= ~(1ull << (bit_index & 63));
}
// the result is guaranteed to be within [ 0; 2 ^ bits_count )
uint64_t get_bits(uint8_t bit_index_first, uint8_t bits_count) const
{
if (bits_count == 0 || bits_count > 64)
return 0;
uint8_t bits_count_m_1 = bits_count - 1;
unsigned int bit_index_last = bit_index_first + bits_count_m_1;
if (bit_index_last > 255)
bit_index_last = 255;
uint64_t result = m_u64[bit_index_first >> 6] >> (bit_index_first & 63);
if (bits_count_m_1 > (bit_index_last & 63))
result |= m_u64[bit_index_last >> 6] << (bits_count_m_1 - (bit_index_last & 63));
uint64_t result_mask = ((1ull << bits_count_m_1) - 1) << 1 | 1; // (just because 1ull << 64 in undefined behaviour, not a 0 as one would expect)
return result & result_mask;
}
// does not reduce
static scalar_t power_of_2(uint8_t exponent)
{
scalar_t result = 0;
@ -459,16 +546,20 @@ namespace crypto
}; // struct scalar_t
//
// Global constants
// Global constants (checked in crypto_constants)
//
extern const scalar_t c_scalar_1;
extern const scalar_t c_scalar_L;
extern const scalar_t c_scalar_Lm1;
extern const scalar_t c_scalar_P;
extern const scalar_t c_scalar_Pm1;
extern const scalar_t c_scalar_256m1;
extern const scalar_t c_scalar_1div8;
static constexpr scalar_t c_scalar_0 = { 0, 0, 0, 0 };
static constexpr scalar_t c_scalar_1 = { 1, 0, 0, 0 };
static constexpr scalar_t c_scalar_2p64 = { 0, 1, 0, 0 };
static constexpr scalar_t c_scalar_L = { 0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 };
static constexpr scalar_t c_scalar_Lm1 = { 0x5812631a5cf5d3ec, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 };
static constexpr scalar_t c_scalar_P = { 0xffffffffffffffed, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff };
static constexpr scalar_t c_scalar_Pm1 = { 0xffffffffffffffec, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff };
static constexpr scalar_t c_scalar_256m1 = { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff };
static constexpr scalar_t c_scalar_1div8 = { 0x6106e529e2dc2f79, 0x07d39db37d1cdad0, 0x0, 0x0600000000000000 };
static_assert(sizeof(scalar_t::m_sk) == sizeof(scalar_t::m_u64) && sizeof(scalar_t::m_u64) == sizeof(scalar_t::m_s), "size missmatch");
//
//
@ -481,31 +572,26 @@ namespace crypto
// with x = X / Z, y = Y / Z, x * y = T / Z.
ge_p3 m_p3;
point_t()
point_t() = default;
explicit point_t(const crypto::public_key& pk) // can throw std::runtime_error
{
CRYPTO_CHECK_AND_THROW_MES(from_public_key(pk), "invalid public key");
}
explicit point_t(const crypto::public_key& pk)
{
if (!from_public_key(pk))
zero();
}
point_t(const unsigned char(&v)[32])
point_t(const unsigned char(&v)[32]) // can throw std::runtime_error
{
static_assert(sizeof(crypto::public_key) == sizeof v, "size missmatch");
if (!from_public_key(*(const crypto::public_key*)v))
zero();
CRYPTO_CHECK_AND_THROW_MES(from_public_key(*(const crypto::public_key*)v), "invalid public key (char[32])");
}
point_t(const uint64_t(&v)[4])
point_t(const uint64_t(&v)[4]) // can throw std::runtime_error
{
static_assert(sizeof(crypto::public_key) == sizeof v, "size missmatch");
if (!from_public_key(*(const crypto::public_key*)v))
zero();
CRYPTO_CHECK_AND_THROW_MES(from_public_key(*(const crypto::public_key*)v), "invalid public key (uint64_t[4])");
}
point_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3)
point_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) // can throw std::runtime_error
{
crypto::public_key pk;
((uint64_t*)&pk)[0] = a0;
@ -513,8 +599,7 @@ namespace crypto
((uint64_t*)&pk)[2] = a2;
((uint64_t*)&pk)[3] = a3;
if (!from_public_key(pk))
zero();
CRYPTO_CHECK_AND_THROW_MES(from_public_key(pk), "invalid public key (four uint64_t)");
}
explicit point_t(tag_zero&&)
@ -522,6 +607,21 @@ namespace crypto
zero();
}
explicit point_t(const key_image& ki) // can throw std::runtime_error
: point_t(static_cast<const public_key&>(static_cast<const ec_point&>(ki)))
{
}
explicit constexpr point_t(const int32_t(&v)[40]) noexcept
: m_p3{
{v[ 0], v[ 1], v[ 2], v[ 3], v[ 4], v[ 5], v[ 6], v[ 7], v[ 8], v[9]},
{v[10], v[11], v[12], v[13], v[14], v[15], v[16], v[17], v[18], v[19]},
{v[20], v[21], v[22], v[23], v[24], v[25], v[26], v[27], v[28], v[29]},
{v[30], v[31], v[32], v[33], v[34], v[35], v[36], v[37], v[38], v[39]}
}
{
}
// as we're using additive notation, zero means identity group element (EC point (0, 1)) here and after
void zero()
{
@ -530,9 +630,13 @@ namespace crypto
bool is_zero() const
{
// (0, 1) ~ (0, z, z, 0)
// (0, 1) ~ (0, z, z, 0) for any non-zero z https://www.rfc-editor.org/rfc/rfc8032#page-17
if (fe_isnonzero(m_p3.X) != 0)
return false;
return false; // x != 0
if (fe_isnonzero(m_p3.Z) == 0)
return false; // z == 0
if (fe_isnonzero(m_p3.T) != 0)
return false; // t != 0
fe y_minus_z;
fe_sub(y_minus_z, m_p3.Y, m_p3.Z);
return fe_isnonzero(y_minus_z) == 0;
@ -625,14 +729,15 @@ namespace crypto
friend point_t operator*(const scalar_t& lhs, const point_t& rhs)
{
point_t result;
ge_scalarmult_p3(&result.m_p3, lhs.m_s, &rhs.m_p3);
//ge_scalarmult_p3(&result.m_p3, lhs.m_s, &rhs.m_p3);
ge_scalarmult_vartime_p3(&result.m_p3, lhs.m_s, &rhs.m_p3);
return result;
}
point_t& operator*=(const scalar_t& rhs)
{
// TODO: ge_scalarmult_vartime_p3
ge_scalarmult_p3(&m_p3, rhs.m_s, &m_p3);
//ge_scalarmult_p3(&m_p3, rhs.m_s, &m_p3);
ge_scalarmult_vartime_p3(&m_p3, rhs.m_s, &m_p3);
return *this;
}
@ -641,7 +746,17 @@ namespace crypto
point_t result;
scalar_t reciprocal;
sc_invert(&reciprocal.m_s[0], &rhs.m_s[0]);
ge_scalarmult_p3(&result.m_p3, &reciprocal.m_s[0], &lhs.m_p3);
//ge_scalarmult_p3(&result.m_p3, &reciprocal.m_s[0], &lhs.m_p3);
ge_scalarmult_vartime_p3(&result.m_p3, &reciprocal.m_s[0], &lhs.m_p3);
return result;
}
point_t operator-() const
{
point_t result = *this;
fe zero = {0};
fe_sub(result.m_p3.Y, zero, result.m_p3.Y);
fe_sub(result.m_p3.Z, zero, result.m_p3.Z);
return result;
}
@ -651,6 +766,24 @@ namespace crypto
return *this;
}
point_t modify_mul_pow_2(size_t power)
{
if (power > 0)
{
ge_p1p1 p1;
ge_p2 p2;
ge_p3_to_p2(&p2, &m_p3);
for (size_t i = 1; i < power; ++i)
{
ge_p2_dbl(&p1, &p2);
ge_p1p1_to_p2(&p2, &p1);
}
ge_p2_dbl(&p1, &p2);
ge_p1p1_to_p3(&m_p3, &p1);
}
return *this;
}
// returns a * this + G
point_t mul_plus_G(const scalar_t& a) const
{
@ -678,6 +811,8 @@ namespace crypto
friend bool operator==(const point_t& lhs, const point_t& rhs)
{
// TODO: @#@# (performance) consider checking (lhs - rhs).is_zero() instead
// convert to xy form, then compare components (because (x, y, z, t) representation is not unique)
fe lrecip, lx, ly;
fe rrecip, rx, ry;
@ -696,12 +831,32 @@ namespace crypto
return false;
return true;
};
}
friend bool operator!=(const point_t& lhs, const point_t& rhs)
{
return !(lhs == rhs);
};
}
friend bool operator==(const point_t& lhs, const public_key& rhs)
{
return lhs.to_public_key() == rhs;
}
friend bool operator!=(const point_t& lhs, const public_key& rhs)
{
return !(lhs == rhs);
}
friend bool operator==(const public_key& lhs, const point_t& rhs)
{
return lhs == rhs.to_public_key();
}
friend bool operator!=(const public_key& lhs, const point_t& rhs)
{
return !(lhs == rhs);
}
friend std::ostream& operator<<(std::ostream& ss, const point_t &v)
{
@ -733,6 +888,11 @@ namespace crypto
return pod_to_hex_comma_separated_uint64(pk);
}
std::string to_comma_separated_int32_str() const
{
return pod_to_comma_separated_int32(m_p3);
}
}; // struct point_t
@ -741,16 +901,16 @@ namespace crypto
//
struct point_g_t : public point_t
{
point_g_t()
explicit constexpr point_g_t(const int32_t(&v)[40]) noexcept
: point_t(v)
{
scalar_t one(1);
ge_scalarmult_base(&m_p3, &one.m_s[0]);
}
friend point_t operator*(const scalar_t& lhs, const point_g_t&)
{
point_t result;
ge_scalarmult_base(&result.m_p3, &lhs.m_s[0]);
//ge_scalarmult_base(&result.m_p3, &lhs.m_s[0]);
ge_scalarmult_base_vartime(&result.m_p3, &lhs.m_s[0]);
return result;
}
@ -759,7 +919,8 @@ namespace crypto
point_t result;
scalar_t reciprocal;
sc_invert(&reciprocal.m_s[0], &rhs.m_s[0]);
ge_scalarmult_base(&result.m_p3, &reciprocal.m_s[0]);
//ge_scalarmult_base(&result.m_p3, &reciprocal.m_s[0]);
ge_scalarmult_base_vartime(&result.m_p3, &reciprocal.m_s[0]);
return result;
}
@ -768,6 +929,42 @@ namespace crypto
}; // struct point_g_t
void construct_precomp_data(precomp_data_t precomp_data, const point_t& point);
//
// point_pc_t -- point with 30kB of precomputed data, which make possible to do very fast single scalar multiplication
//
struct point_pc_t : public point_t
{
constexpr point_pc_t(const int32_t(&v)[40], const precomp_data_t* precomp_data_p)
: point_t(v)
, m_precomp_data_p(precomp_data_p)
{
//construct_precomp_data(m_precomp_data, *this);
}
friend point_t operator*(const scalar_t& lhs, const point_pc_t& self)
{
point_t result;
ge_scalarmult_precomp_vartime(&result.m_p3, *self.m_precomp_data_p, &lhs.m_s[0]);
return result;
}
friend point_t operator/(const point_pc_t& self, const scalar_t& rhs)
{
point_t result;
scalar_t reciprocal;
sc_invert(&reciprocal.m_s[0], &rhs.m_s[0]);
ge_scalarmult_precomp_vartime(&result.m_p3, *self.m_precomp_data_p, &reciprocal.m_s[0]);
return result;
}
static_assert(sizeof(crypto::public_key) == 32, "size error");
const precomp_data_t* m_precomp_data_p;
}; // struct point_pc_t
//
// vector of scalars
//
@ -845,8 +1042,11 @@ namespace crypto
// zeroes all elements
void zero()
{
PUSH_GCC_WARNINGS
DISABLE_GCC_AND_CLANG_WARNING(class-memaccess)
size_t size_bytes = sizeof(scalar_t) * size();
memset(data(), 0, size_bytes);
POP_GCC_WARNINGS
}
// invert all elements in-place efficiently: 4*N muptiplications + 1 inversion
@ -885,6 +1085,19 @@ namespace crypto
scalar_t calc_hs() const;
void make_random()
{
for(size_t size = this->size(), i = 0; i < size; ++i)
at(i).make_random();
}
void resize_and_make_random(size_t size)
{
this->resize(size);
make_random();
}
}; // scalar_vec_t
@ -909,14 +1122,29 @@ namespace crypto
//
// Global constants
// Global constants (checked in crypto_constants and crypto_generators_precomp tests)
//
extern const point_g_t c_point_G;
namespace xdetails
{
extern const precomp_data_t c_point_H_precomp_data;
extern const precomp_data_t c_point_H2_precomp_data;
extern const precomp_data_t c_point_U_precomp_data;
extern const precomp_data_t c_point_X_precomp_data;
extern const precomp_data_t c_point_H_plus_G_precomp_data;
extern const precomp_data_t c_point_H_minus_G_precomp_data;
};
inline constexpr point_t c_point_0 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }};
inline constexpr point_g_t c_point_G {{ 25485296, 5318399, 8791791, -8299916, -14349720, 6939349, -3324311, -7717049, 7287234, -6577708, -758052, -1832720, 13046421, -4857925, 6576754, 14371947, -13139572, 6845540, -2198883, -4003719, -947565, 6097708, -469190, 10704810, -8556274, -15589498, -16424464, -16608899, 14028613, -5004649, 6966464, -2456167, 7033433, 6781840, 28785542, 12262365, -2659449, 13959020, -21013759, -5262166 }};
inline constexpr point_pc_t c_point_H {{ 20574939, 16670001, -29137604, 14614582, 24883426, 3503293, 2667523, 420631, 2267646, -4769165, -11764015, -12206428, -14187565, -2328122, -16242653, -788308, -12595746, -8251557, -10110987, 853396, -4982135, 6035602, -21214320, 16156349, 977218, 2807645, 31002271, 5694305, -16054128, 5644146, -15047429, -568775, -22568195, -8089957, -27721961, -10101877, -29459620, -13359100, -31515170, -6994674 }, &xdetails::c_point_H_precomp_data };
inline constexpr point_pc_t c_point_H2 {{ 1318371, 14804112, 12545972, -13482561, -12089798, -16020744, -21221907, -8410994, -33080606, 11275578, 3807637, 11185450, -23227561, -12892068, 1356866, -1025012, -8022738, -8139671, -20315029, -13916324, -6475650, -7025596, 12403179, -5139984, -12068178, 10445584, -14826705, -4927780, 13964546, 12525942, -2314107, -10566315, 32243863, 15603849, 5154154, 4276633, -20918372, -15718796, -26386151, 8434696 }, &xdetails::c_point_H2_precomp_data };
inline constexpr point_pc_t c_point_U {{ 30807552, 984924, 23426137, -5598760, 7545909, 16325843, 993742, 2594106, -31962071, -959867, 16454190, -4091093, 1197656, 13586872, -9269020, -14133290, 1869274, 13360979, -24627258, -10663086, 2212027, 1198856, 20515811, 15870563, -23833732, 9839517, -19416306, 11567295, -4212053, 348531, -2671541, 484270, -19128078, 1236698, -16002690, 9321345, 9776066, 10711838, 11187722, -16371275 }, &xdetails::c_point_U_precomp_data };
inline constexpr point_pc_t c_point_X {{ 25635916, -5459446, 5768861, 5666160, -6357364, -12939311, 29490001, -4543704, -31266450, -2582476, 23705213, 9562626, -716512, 16560168, 7947407, 2039790, -2752711, 4742449, 3356761, 16338966, 17303421, -5790717, -5684800, 12062431, -3307947, 8139265, -26544839, 12058874, 3452748, 3359034, 26514848, -6060876, 31255039, 11154418, -21741975, -3782423, -19871841, 5729859, 21754676, -12454027 }, &xdetails::c_point_X_precomp_data };
inline constexpr point_pc_t c_point_H_plus_G {{ 12291435, 3330843, -3390294, 13894858, -1099584, -6848191, 12040668, -15950068, -7494633, 12566672, -5526901, -16645799, -31081168, -1095427, -13082463, 4573480, -11255691, 4344628, 33477173, 11137213, -3837023, -12436594, -8471924, -814016, 10785607, 9492721, 10992667, 7406385, -5687296, -127915, -6229107, -9324867, 558657, 6493750, 4895261, 12642545, 9549220, 696086, 21894285, -10521807 }, &xdetails::c_point_H_plus_G_precomp_data };
inline constexpr point_pc_t c_point_H_minus_G {{ -28347682, 3523701, -3380175, -14453727, 4238027, -6032522, 20235758, 4091609, 12557126, -8064113, 4212476, -13419094, -114185, -7650727, -24238, 16663404, 23676363, -6819610, 18286466, 8714527, -3837023, -12436594, -8471924, -814016, 10785607, 9492721, 10992667, 7406385, -5687296, -127915, -20450317, 13815641, -11604061, -447489, 27380225, 9400847, -8551293, -1173627, -28110171, 14241295 }, &xdetails::c_point_H_minus_G_precomp_data };
extern const point_t c_point_H;
extern const point_t c_point_H2;
extern const point_t c_point_0;
//
// hash functions' helper
@ -938,11 +1166,17 @@ namespace crypto
return scalar_t(crypto::cn_fast_hash(str.c_str(), str.size())); // will reduce mod L
}
static hash h(const std::string& str)
{
return crypto::cn_fast_hash(str.c_str(), str.size());
}
struct hs_t
{
hs_t()
hs_t(size_t size_to_reserve = 0)
{
static_assert(sizeof(scalar_t) == sizeof(crypto::public_key), "unexpected size of data");
m_elements.reserve(size_to_reserve);
}
void reserve(size_t elements_count)
@ -984,6 +1218,11 @@ namespace crypto
m_elements.emplace_back(pk);
}
void add_key_image(const crypto::key_image& ki)
{
m_elements.emplace_back(ki);
}
scalar_t& access_scalar(size_t index)
{
return m_elements[index].scalar;
@ -1012,6 +1251,16 @@ namespace crypto
m_elements.emplace_back(key_image_array[i]);
}
void add_hash(const hash& h)
{
m_elements.emplace_back(h);
}
void add_32_chars(const char(&str32)[32])
{
m_elements.emplace_back(str32);
}
scalar_t calc_hash(bool clear = true)
{
size_t data_size_bytes = m_elements.size() * sizeof(item_t);
@ -1022,6 +1271,16 @@ namespace crypto
return scalar_t(hash); // this will reduce to L
}
hash calc_hash_no_reduce(bool clear = true)
{
size_t data_size_bytes = m_elements.size() * sizeof(item_t);
hash result;
crypto::cn_fast_hash(m_elements.data(), data_size_bytes, result);
if (clear)
this->clear();
return result;
}
void assign_calc_hash(scalar_t& result, bool clear = true)
{
static_assert(sizeof result == sizeof(crypto::hash), "size missmatch");
@ -1038,17 +1297,24 @@ namespace crypto
item_t(const scalar_t& scalar) : scalar(scalar) {}
item_t(const crypto::public_key& pk) : pk(pk) {}
item_t(const crypto::key_image& ki) : ki(ki) {}
item_t(const crypto::hash& h) : h(h) {}
item_t(const char(&str32)[32]) { memcpy(c, str32, sizeof c); }
scalar_t scalar;
crypto::public_key pk;
crypto::key_image ki;
crypto::hash h;
char c[32];
};
static_assert(sizeof(item_t::c) == sizeof(item_t::pk), "size missmatch");
static_assert(sizeof(item_t::h) == sizeof(item_t::pk), "size missmatch");
std::vector<item_t> m_elements;
};
static scalar_t hs(const scalar_t& s, const std::vector<point_t>& ps0, const std::vector<point_t>& ps1)
{
hs_t hs_calculator;
hs_t hs_calculator(3);
hs_calculator.add_scalar(s);
hs_calculator.add_points_array(ps0);
hs_calculator.add_points_array(ps1);
@ -1058,7 +1324,7 @@ namespace crypto
static scalar_t hs(const crypto::hash& s, const std::vector<crypto::public_key>& ps0, const std::vector<crypto::key_image>& ps1)
{
static_assert(sizeof(crypto::hash) == sizeof(scalar_t), "size missmatch");
hs_t hs_calculator;
hs_t hs_calculator(3);
hs_calculator.add_scalar(*reinterpret_cast<const scalar_t*>(&s));
hs_calculator.add_pub_keys_array(ps0);
hs_calculator.add_key_images_array(ps1);
@ -1067,12 +1333,79 @@ namespace crypto
static scalar_t hs(const std::vector<point_t>& ps0, const std::vector<point_t>& ps1)
{
hs_t hs_calculator;
hs_t hs_calculator(2);
hs_calculator.add_points_array(ps0);
hs_calculator.add_points_array(ps1);
return hs_calculator.calc_hash();
}
static scalar_t hs(const char(&str32)[32], const scalar_t& s)
{
hs_t hs_calculator(2);
hs_calculator.add_32_chars(str32);
hs_calculator.add_scalar(s);
return hs_calculator.calc_hash();
}
static scalar_t hs(const char(&str32)[32], const scalar_t& s, const crypto::public_key& pk)
{
hs_t hs_calculator(2);
hs_calculator.add_32_chars(str32);
hs_calculator.add_scalar(s);
hs_calculator.add_pub_key(pk);
return hs_calculator.calc_hash();
}
static scalar_t hs(const crypto::public_key& pk, const uint64_t i)
{
hs_t hs_calculator(2);
hs_calculator.add_pub_key(pk);
hs_calculator.add_scalar(scalar_t(i));
return hs_calculator.calc_hash();
}
static scalar_t hs(const crypto::secret_key& sk, const uint64_t i)
{
hs_t hs_calculator(2);
hs_calculator.add_scalar(sk);
hs_calculator.add_scalar(scalar_t(i));
return hs_calculator.calc_hash();
}
static scalar_t hs(const char(&str32)[32], const crypto::public_key& pk, const uint64_t i)
{
hs_t hs_calculator(3);
hs_calculator.add_32_chars(str32);
hs_calculator.add_pub_key(pk);
hs_calculator.add_scalar(scalar_t(i));
return hs_calculator.calc_hash();
}
static scalar_t hs(const char(&str32)[32], const crypto::hash& h)
{
hs_t hs_calculator(2);
hs_calculator.add_32_chars(str32);
hs_calculator.add_hash(h);
return hs_calculator.calc_hash();
}
static scalar_t hs(const char(&str32)[32], const crypto::point_t& p)
{
hs_t hs_calculator(2);
hs_calculator.add_32_chars(str32);
hs_calculator.add_point(p);
return hs_calculator.calc_hash();
}
static scalar_t hs(const char(&str32)[32], const crypto::key_derivation& derivation, uint64_t index)
{
hs_t hs_calculator(3);
hs_calculator.add_32_chars(str32);
hs_calculator.add_pub_key(reinterpret_cast<const crypto::public_key&>(derivation));
hs_calculator.add_scalar(index);
return hs_calculator.calc_hash();
}
static point_t hp(const point_t& p)
{
point_t result;
@ -1104,6 +1437,13 @@ namespace crypto
return result;
}
static point_t hp(const std::string& str)
{
point_t result;
ge_bytes_hash_to_ec(&result.m_p3, str.data(), str.size());
return result;
}
}; // hash_helper_t struct
@ -1111,7 +1451,6 @@ namespace crypto
{
// hs won't touch memory if size is 0, so it's safe
return hash_helper_t::hs(data(), sizeof(scalar_t) * size());
}
}
} // namespace crypto

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2019 Zano Project
// Copyright (c) 2014-2022 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -19,9 +19,9 @@
#include "hash.h"
#if !defined(NDEBUG)
# define crypto_assert(expression) assert(expression)
# define crypto_assert(expression) assert(expression); CRYPTO_CHECK_AND_THROW_MES(expression, #expression)
#else
# define crypto_assert(expression) ((void)0)
# define crypto_assert(expression) CRYPTO_CHECK_AND_THROW_MES(expression, #expression)
#endif
namespace crypto {
@ -187,7 +187,8 @@ namespace crypto {
return true;
}
static void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) {
void crypto_ops::derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res)
{
struct {
key_derivation derivation;
char output_index[(sizeof(size_t) * 8 + 6) / 7];

View file

@ -17,6 +17,9 @@
#include "hash.h"
#include "warnings.h"
#define CRYPTO_STR_(X) #X
#define CRYPTO_STR(X) CRYPTO_STR_(X)
#define CRYPTO_CHECK_AND_THROW_MES(cond, msg) if (!(cond)) { throw std::runtime_error(msg " @ " __FILE__ ":" CRYPTO_STR(__LINE__)); }
PUSH_GCC_WARNINGS
DISABLE_CLANG_WARNING(unused-private-field)
@ -86,6 +89,8 @@ namespace crypto {
friend bool secret_key_to_public_key(const secret_key &, public_key &);
static bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &);
friend bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &);
static void derivation_to_scalar(const key_derivation &, size_t, ec_scalar &);
friend void derivation_to_scalar(const key_derivation &, size_t, ec_scalar &);
static bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &);
friend bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &);
static void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &);
@ -174,6 +179,10 @@ namespace crypto {
inline bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation) {
return crypto_ops::generate_key_derivation(key1, key2, derivation);
}
inline void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &result) {
crypto::crypto_ops::derivation_to_scalar(derivation, output_index, result);
}
inline bool derive_public_key(const key_derivation &derivation, std::size_t output_index,
const public_key &base, public_key &derived_key) {
return crypto_ops::derive_public_key(derivation, output_index, base, derived_key);

25
src/crypto/msm.cpp Normal file
View file

@ -0,0 +1,25 @@
// Copyright (c) 2023-2023 Zano Project
// Copyright (c) 2023-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#include "epee/include/misc_log_ex.h"
//#include "zarcanum.h"
#include "msm.h"
//#include "../currency_core/crypto_config.h" // TODO: move it to the crypto
//#include "../common/crypto_stream_operators.h" // TODO: move it to the crypto
#if 0
# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl
# define DBG_PRINT(x) std::cout << x << std::endl
#else
# define DBG_VAL_PRINT(x) (void(0))
# define DBG_PRINT(x) (void(0))
#endif
namespace crypto
{
} // namespace crypto

173
src/crypto/msm.h Normal file
View file

@ -0,0 +1,173 @@
// Copyright (c) 2023-2023 Zano Project (https://zano.org/)
// Copyright (c) 2023-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
// This file contains Multi-Scalar Multiplication routines
#include "epee/include/misc_log_ex.h"
#include "crypto-sugar.h"
namespace crypto
{
template<typename CT>
bool msm_and_check_zero_naive(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand)
{
CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized");
CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized");
point_t result = summand;
for (size_t i = 0; i < g_scalars.size(); ++i)
result += g_scalars[i] * CT::get_generator(false, i);
for (size_t i = 0; i < h_scalars.size(); ++i)
result += h_scalars[i] * CT::get_generator(true, i);
if (!result.is_zero())
{
LOG_PRINT_L0("msm result is non zero: " << result);
return false;
}
return true;
}
// https://eprint.iacr.org/2022/999.pdf
// "Pippenger algorithm [1], and its variant that is widely used in the ZK space is called the bucket method"
template<typename CT>
bool msm_and_check_zero_pippenger_v3(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand, uint8_t c)
{
// TODO: with c = 8 and with direct access got much worse result than with c = 7 and get_bits() for N = 128..256, consider checking again for bigger datasets (N>256)
// TODO: consider preparing a cached generators' points
CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized");
CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized");
CHECK_AND_ASSERT_MES(c < 10, false, "c is too big");
size_t C = 1ull << c;
// k_max * c + (c-1) >= max_bit_idx
//
// max_bit_idx - (c - 1) max_bit_idx - (c - 1) + (c - 1) max_bit_idx
// k_max = ceil ( --------------------- ) = floor ( ------------------------------ ) = floor ( ----------- )
// c c c
const size_t b = 253; // the maximum number of bits in x https://eprint.iacr.org/2022/999.pdf TODO: we may also scan for maximum bit used in all the scalars if all the scalars are small
const size_t max_bit_idx = b - 1;
const size_t k_max = max_bit_idx / c;
const size_t K = k_max + 1;
std::vector<point_t> buckets(C * K);
std::vector<bool> buckets_inited(C * K);
std::vector<point_t> Sk(K);
std::vector<bool> Sk_inited(K);
std::vector<point_t> Gk(K);
std::vector<bool> Gk_inited(K);
// first loop, calculate partial bucket sums
for (size_t n = 0; n < g_scalars.size(); ++n)
{
for (size_t k = 0; k < K; ++k)
{
uint64_t l = g_scalars[n].get_bits((uint8_t)(k * c), c); // l in [0; 2^c-1]
if (l != 0)
{
size_t bucket_id = l * K + k;
if (buckets_inited[bucket_id])
buckets[bucket_id] += CT::get_generator(false, n);
else
{
buckets[bucket_id] = CT::get_generator(false, n);
buckets_inited[bucket_id] = true;
}
}
}
}
// still the first loop (continued)
for (size_t n = 0; n < h_scalars.size(); ++n)
{
for (size_t k = 0; k < K; ++k)
{
uint64_t l = h_scalars[n].get_bits((uint8_t)(k * c), c); // l in [0; 2^c-1]
if (l != 0)
{
size_t bucket_id = l * K + k;
if (buckets_inited[bucket_id])
buckets[bucket_id] += CT::get_generator(true, n);
else
{
buckets[bucket_id] = CT::get_generator(true, n);
buckets_inited[bucket_id] = true;
}
}
}
}
// the second loop
for (size_t l = C - 1; l > 0; --l)
{
for (size_t k = 0; k < K; ++k)
{
size_t bucket_id = l * K + k;
if (buckets_inited[bucket_id])
{
if (Sk_inited[k])
Sk[k] += buckets[bucket_id];
else
{
Sk[k] = buckets[bucket_id];
Sk_inited[k] = true;
}
}
if (Sk_inited[k])
{
if (Gk_inited[k])
Gk[k] += Sk[k];
else
{
Gk[k] = Sk[k];
Gk_inited[k] = true;
}
}
}
}
// the third loop: Horners rule
point_t result = Gk_inited[K - 1] ? Gk[K - 1] : c_point_0;
for (size_t k = K - 2; k != SIZE_MAX; --k)
{
result.modify_mul_pow_2(c);
if (Gk_inited[k])
result += Gk[k];
}
result += summand;
if (!result.is_zero())
{
LOG_PRINT_L0("multiexp result is non zero: " << result);
return false;
}
return true;
}
// Just switcher
template<typename CT>
bool msm_and_check_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand)
{
//return msm_and_check_zero_naive<CT>(g_scalars, h_scalars, summand);
return msm_and_check_zero_pippenger_v3<CT>(g_scalars, h_scalars, summand, 7);
}
} // namespace crypto

View file

@ -0,0 +1,322 @@
// Copyright (c) 2023 Zano Project
// Copyright (c) 2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#include "one_out_of_many_proofs.h"
#include "../currency_core/crypto_config.h"
#include "epee/include/misc_log_ex.h"
//DISABLE_GCC_AND_CLANG_WARNING(unused-function)
#if 0
# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl
# define DBG_PRINT(x) std::cout << x << std::endl
#else
# define DBG_VAL_PRINT(x) (void(0))
# define DBG_PRINT(x) (void(0))
#endif
namespace crypto
{
static const size_t N_max = 256;
static const size_t mn_max = 16;
const point_t& get_BGE_generator(size_t index, bool& ok)
{
static std::vector<point_t> precalculated_generators;
if (precalculated_generators.empty())
{
precalculated_generators.resize(mn_max * 2);
scalar_t hash_buf[2] = { hash_helper_t::hs("Zano BGE generator"), 0 };
for(size_t i = 0; i < precalculated_generators.size(); ++i)
{
hash_buf[1].m_u64[0] = i;
precalculated_generators[i] = hash_helper_t::hp(&hash_buf, sizeof hash_buf);
}
}
if (index >= mn_max * 2)
{
ok = false;
return c_point_0;
}
ok = true;
return precalculated_generators[index];
}
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("generate_BGE_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
bool generate_BGE_proof(const hash& context_hash, const std::vector<point_t>& ring, const scalar_t& secret, const size_t secret_index, BGE_proof& result, uint8_t* p_err /* = nullptr */)
{
static constexpr size_t n = 4; // TODO: @#@# move it out
DBG_PRINT(" - - - generate_BGE_proof - - -");
size_t ring_size = ring.size();
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(ring_size > 0, 0);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(secret_index < ring_size, 1);
#ifndef NDEBUG
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(ring[secret_index] == secret * crypto::c_point_X, 2);
#endif
const size_t m = std::max(static_cast<uint64_t>(1), constexpr_ceil_log_n(ring_size, n));
const size_t N = constexpr_pow(m, n);
const size_t mn = m * n;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(N <= N_max, 3);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(mn <= mn_max, 4);
scalar_mat_t<n> a_mat(mn); // m x n matrix
a_mat.zero();
std::vector<size_t> l_digits(m); // l => n-ary gidits
size_t l = secret_index;
for(size_t j = 0; j < m; ++j)
{
for(size_t i = n - 1; i != 0; --i) // [n - 1; 1]
{
a_mat(j, i).make_random();
a_mat(j, 0) -= a_mat(j, i); // a[j; 0] = -sum( a[j; i] ), i in [1; n-1]
}
size_t digit = l % n; // j-th digit of secret_index
l_digits[j] = digit;
l = l / n;
}
#ifndef NDEBUG
for(size_t j = 0; j < m; ++j)
{
scalar_t a_sum{};
for(size_t i = 0; i != n; ++i)
a_sum += a_mat(j, i);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(a_sum.is_zero(), 230);
}
#endif
//
// coeffs calculation (naive implementation, consider optimization in future)
//
scalar_vec_t coeffs(N * m); // m x N matrix
coeffs.zero();
for(size_t i = 0; i < N; ++i)
{
coeffs[i] = c_scalar_1; // first row is (1, ..., 1)
size_t i_tmp = i;
size_t m_bound = 1;
for(size_t j = 0; j < m; ++j)
{
size_t i_j = i_tmp % n; // j-th digit of i
i_tmp /= n;
if (i_j == l_digits[j]) // true if j-th digits of i and l matches
{
scalar_t carry{};
for(size_t k = 0; k < m_bound; ++k)
{
scalar_t old = coeffs[k * N + i];
coeffs[k * N + i] *= a_mat(j, i_j);
coeffs[k * N + i] += carry;
carry = old;
}
if (m_bound < m)
coeffs[m_bound * N + i] += carry;
++m_bound;
}
else
{
for(size_t k = 0; k < m_bound; ++k)
coeffs[k * N + i] *= a_mat(j, i_j);
}
}
}
scalar_t r_A = scalar_t::random();
scalar_t r_B = scalar_t::random();
scalar_vec_t ro(m);
ro.make_random();
point_t A = c_point_0;
point_t B = c_point_0;
result.Pk.clear();
bool r = false, r2 = false;
for(size_t j = 0; j < m; ++j)
{
for(size_t i = 0; i < n; ++i)
{
const point_t& gen_1 = get_BGE_generator((j * n + i) * 2 + 0, r);
const point_t& gen_2 = get_BGE_generator((j * n + i) * 2 + 1, r2);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(r && r2, 5);
const scalar_t& a = a_mat(j, i);
A += a * gen_1 - a * a * gen_2;
if (l_digits[j] == i)
B += gen_1 - a * gen_2;
else
B += a * gen_2;
}
point_t Pk = c_point_0;
for(size_t i = 0; i < ring_size; ++i)
Pk += coeffs[j * N + i] * ring[i];
for(size_t i = ring_size; i < N; ++i)
Pk += coeffs[j * N + i] * ring[ring_size - 1];
Pk += ro[j] * c_point_X;
result.Pk.emplace_back(std::move((c_scalar_1div8 * Pk).to_public_key()));
}
A += r_A * c_point_X;
result.A = (c_scalar_1div8 * A).to_public_key();
B += r_B * c_point_X;
result.B = (c_scalar_1div8 * B).to_public_key();
hash_helper_t::hs_t hsc(1 + ring_size + 2 + m);
hsc.add_hash(context_hash);
for(auto& ring_el : ring)
hsc.add_point(c_scalar_1div8 * ring_el);
hsc.add_pub_key(result.A);
hsc.add_pub_key(result.B);
hsc.add_pub_keys_array(result.Pk);
scalar_t x = hsc.calc_hash();
DBG_VAL_PRINT(x);
result.f.resize(m * (n - 1));
for(size_t j = 0; j < m; ++j)
{
for(size_t i = 1; i < n; ++i)
{
result.f[j * (n - 1) + i - 1] = a_mat(j, i);
if (l_digits[j] == i)
result.f[j * (n - 1) + i - 1] += x;
}
}
result.y = r_A + x * r_B;
result.z = 0;
scalar_t x_power = c_scalar_1;
for(size_t k = 0; k < m; ++k)
{
result.z -= x_power * ro[k];
x_power *= x;
}
result.z += secret * x_power;
return true;
}
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
//---------------------------------------------------------------
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("generate_BGE_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
bool verify_BGE_proof(const hash& context_hash, const std::vector<const public_key*>& ring, const BGE_proof& sig, uint8_t* p_err /* = nullptr */)
{
static constexpr size_t n = 4; // TODO: @#@# move it out
DBG_PRINT(" - - - verify_BGE_proof - - -");
size_t ring_size = ring.size();
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(ring_size > 0, 0);
const size_t m = std::max(static_cast<uint64_t>(1), constexpr_ceil_log_n(ring_size, n));
const size_t N = constexpr_pow(m, n);
//const size_t mn = m * n;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.Pk.size() == m, 1);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.f.size() == m * (n - 1), 2);
hash_helper_t::hs_t hsc(1 + ring_size + 2 + m);
hsc.add_hash(context_hash);
for(const public_key* ppk : ring)
hsc.add_pub_key(*ppk);
hsc.add_pub_key(sig.A);
hsc.add_pub_key(sig.B);
hsc.add_pub_keys_array(sig.Pk);
scalar_t x = hsc.calc_hash();
DBG_VAL_PRINT(x);
scalar_vec_t f0(m); // the first column f_{i,0} = x - sum{j=1}{n-1}( f_{i,j} )
for(size_t j = 0; j < m; ++j)
{
f0[j] = x;
for(size_t i = 1; i < n; ++i)
f0[j] -= sig.f[j * (n - 1) + i - 1];
}
//
// 1
//
point_t A = point_t(sig.A).modify_mul8();
point_t B = point_t(sig.B).modify_mul8();
point_t Z = A + x * B;
bool r = false, r2 = false;
for(size_t j = 0; j < m; ++j)
{
for(size_t i = 0; i < n; ++i)
{
const point_t& gen_1 = get_BGE_generator((j * n + i) * 2 + 0, r);
const point_t& gen_2 = get_BGE_generator((j * n + i) * 2 + 1, r2);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(r && r2, 5);
const scalar_t& f_ji = (i == 0) ? f0[j] : sig.f[j * (n - 1) + i - 1];
Z -= f_ji * gen_1 + f_ji * (x - f_ji) * gen_2;
}
}
Z -= sig.y * c_point_X;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(Z.is_zero(), 100);
//
// 2
//
scalar_vec_t p_vec(N);
for(size_t i = 0; i < N; ++i)
{
p_vec[i] = c_scalar_1;
size_t i_tmp = i;
for(size_t j = 0; j < m; ++j)
{
size_t i_j = i_tmp % n; // j-th digit of i
i_tmp /= n;
const scalar_t& f_jij = (i_j == 0) ? f0[j] : sig.f[j * (n - 1) + i_j - 1];
p_vec[i] *= f_jij;
}
}
for(size_t i = 0; i < ring_size; ++i)
Z += p_vec[i] * point_t(*ring[i]).modify_mul8();
for(size_t i = ring_size; i < N; ++i)
Z += p_vec[i] * point_t(*ring[ring_size - 1]).modify_mul8();
scalar_t x_power = c_scalar_1;
for(size_t k = 0; k < m; ++k)
{
Z -= x_power * point_t(sig.Pk[k]).modify_mul8();
x_power *= x;
}
Z -= sig.z * c_point_X;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(Z.is_zero(), 101);
return true;
}
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
} // namespace crypto

View file

@ -0,0 +1,47 @@
// Copyright (c) 2023 Zano Project
// Copyright (c) 2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#pragma once
#include "crypto-sugar.h"
namespace crypto
{
//
// BGE stands for Bootle, Groth, Esgin
//
// This is a proof-of-concept implementation of a log-size one-out-of-many proof based on ideas and approaches by Bootle et al, Groth et al and Esgin et al
//
// https://eprint.iacr.org/2014/764
// https://eprint.iacr.org/2015/643
// https://eprint.iacr.org/2019/1287
//
// Disclaimer: shouldn't be used in production code until the security proofs and the code are peer-reviewed.
//
// m+2 group elements, m(n-1)+2 field elements.
// Assuming fixed n=4, m = log4(ring_sz) the size is (log4(ring_sz) + 2) group elements and (3*log4(ring_sz) + 2) or, in total, (4*log4(ring_sz) + 4) 32-bytes words
// ring_sz = m (inputs number)
// sig_count = k (outputs number)
// thus:
// k * (log4(m) + 2) group elements and k * (3*log4(m) + 2) field elements
struct BGE_proof
{
public_key A; // premultiplied by 1/8
public_key B; // premultiplied by 1/8
std::vector<public_key> Pk; // premultiplied by 1/8, size = m
scalar_vec_t f; // size = m * (n - 1)
scalar_t y;
scalar_t z;
};
bool generate_BGE_proof(const hash& context_hash, const std::vector<point_t>& ring, const scalar_t& secret, const size_t secret_index, BGE_proof& result, uint8_t* p_err = nullptr);
bool verify_BGE_proof(const hash& context_hash, const std::vector<const public_key*>& ring, const BGE_proof& sig, uint8_t* p_err = nullptr);
} // namespace crypto

View file

@ -23,18 +23,26 @@ namespace crypto
scalar_t delta;
};
#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL
#define DBG_PRINT(x) std::cout << x << ENDL
#if 0
# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl
# define DBG_PRINT(x) std::cout << x << std::endl
#else
# define DBG_VAL_PRINT(x) (void(0))
# define DBG_PRINT(x) (void(0))
#endif
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("bpp_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
template<typename CT>
bool bpp_gen(const scalar_vec_t& values, const scalar_vec_t& masks, bpp_signature& sig, std::vector<point_t>& commitments, uint8_t* p_err = nullptr)
bool bpp_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const std::vector<const crypto::public_key*>& commitments_1div8, bpp_signature& sig, uint8_t* p_err = nullptr)
{
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("bpp_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
// Note: commitments_1div8 are supposed to be already calculated
static_assert(CT::c_bpp_n <= 255, "too big N");
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size(), 1);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size() && values.size() == commitments_1div8.size(), 1);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(masks.is_reduced(), 3);
const size_t c_bpp_log2_m = constexpr_ceil_log2(values.size());
@ -42,14 +50,14 @@ namespace crypto
const size_t c_bpp_mn = c_bpp_m * CT::c_bpp_n;
const size_t c_bpp_log2_mn = c_bpp_log2_m + CT::c_bpp_log2_n;
// pre-multiply all output points by c_scalar_1div8
// in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify())
// calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H
commitments.resize(values.size());
for (size_t i = 0; i < values.size(); ++i)
CT::calc_pedersen_commitment(values[i] * c_scalar_1div8, masks[i] * c_scalar_1div8, commitments[i]);
#ifndef NDEBUG
for(size_t i = 0; i < values.size(); ++i)
{
point_t V{};
CT::calc_pedersen_commitment(values[i], masks[i], V);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(point_t(*commitments_1div8[i]).modify_mul8() == V, 4);
}
#endif
// s.a. BP+ paper, page 15, eq. 11
// decompose v into aL and aR:
@ -85,7 +93,7 @@ namespace crypto
DBG_PRINT("initial transcript: " << e);
hash_helper_t::hs_t hsc;
CT::update_transcript(hsc, e, commitments);
CT::update_transcript(hsc, e, commitments_1div8);
// BP+ paper, page 15: The prover begins with sending A = g^aL h^aR h^alpha (group element)
// so we calculate A0 = alpha * H + SUM(aL_i * G_i) + SUM(aR_i * H_i)
@ -96,7 +104,8 @@ namespace crypto
for (size_t i = 0; i < c_bpp_mn; ++i)
A0 += aLs[i] * CT::get_generator(false, i) + aRs[i] * CT::get_generator(true, i);
// part of 1/8 defense scheme
// pre-multiply all output points by c_scalar_1div8
// in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify())
A0 *= c_scalar_1div8;
A0.to_public_key(sig.A0);
@ -147,7 +156,7 @@ namespace crypto
// aL_hat = aL - 1*z
scalar_vec_t aLs_hat = aLs - z;
// aL_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3)
// aR_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3)
scalar_vec_t aRs_hat = aRs + z;
for (size_t i = 0; i < c_bpp_mn; ++i)
aRs_hat[i] += d[i] * y_powers[c_bpp_mn - i];
@ -324,9 +333,27 @@ namespace crypto
DBG_VAL_PRINT(sig.delta);
return true;
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
} // bpp_gen()
// convenient overload for tests
template<typename CT>
bool bpp_gen(const scalar_vec_t& values, const scalar_vec_t& masks, bpp_signature& sig, std::vector<point_t>& commitments_1div8_to_be_generated, uint8_t* p_err = nullptr)
{
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() == masks.size(), 91);
commitments_1div8_to_be_generated.resize(values.size());
std::vector<crypto::public_key> commitments_1div8(values.size());
std::vector<const crypto::public_key*> commitments_1div8_pointers(values.size());
for(size_t i = 0; i < values.size(); ++i)
{
CT::calc_pedersen_commitment(c_scalar_1div8 * values[i], c_scalar_1div8 * masks[i], commitments_1div8_to_be_generated[i]);
commitments_1div8[i] = (commitments_1div8_to_be_generated[i]).to_public_key();
commitments_1div8_pointers[i] = &commitments_1div8[i];
}
return bpp_gen<CT>(values, masks, commitments_1div8_pointers, sig, p_err);
}
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
struct bpp_sig_commit_ref_t
{
@ -335,7 +362,7 @@ namespace crypto
, commitments(commitments)
{}
const bpp_signature& sig;
const std::vector<point_t>& commitments;
const std::vector<point_t>& commitments; // assumed to be premultiplied by 1/8
};
@ -343,7 +370,7 @@ namespace crypto
bool bpp_verify(const std::vector<bpp_sig_commit_ref_t>& sigs, uint8_t* p_err = nullptr)
{
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("bpp_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
if (!(cond)) { LOG_PRINT_RED("bpp_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
DBG_PRINT(ENDL << " . . . . bpp_verify() . . . . ");
@ -689,11 +716,14 @@ namespace crypto
point_t GH_exponents = c_point_0;
CT::calc_pedersen_commitment(G_scalar, H_scalar, GH_exponents);
bool result = multiexp_and_check_being_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
bool result = msm_and_check_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
if (result)
DBG_PRINT(ENDL << " . . . . bpp_verify() -- SUCCEEDED!!!" << ENDL);
return result;
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
}
#undef DBG_VAL_PRINT
#undef DBG_PRINT
} // namespace crypto

View file

@ -24,18 +24,25 @@ namespace crypto
scalar_t delta_2;
};
#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL
#define DBG_PRINT(x) std::cout << x << ENDL
#if 0
# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl
# define DBG_PRINT(x) std::cout << x << std::endl
#else
# define DBG_VAL_PRINT(x) (void(0))
# define DBG_PRINT(x) (void(0))
#endif
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("bppe_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
template<typename CT>
bool bppe_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const scalar_vec_t& masks2, bppe_signature& sig, std::vector<point_t>& commitments, uint8_t* p_err = nullptr)
bool bppe_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const scalar_vec_t& masks2, const std::vector<const crypto::public_key*>& commitments_1div8, bppe_signature& sig, uint8_t* p_err = nullptr)
{
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("bppe_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
// Note: commitments_1div8 are supposed to be already calculated
static_assert(CT::c_bpp_n <= 255, "too big N");
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size() && masks.size() == masks2.size(), 1);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size() && masks.size() == masks2.size() && values.size() == commitments_1div8.size(), 1);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(masks.is_reduced() && masks2.is_reduced(), 3);
const size_t c_bpp_log2_m = constexpr_ceil_log2(values.size());
@ -43,14 +50,14 @@ namespace crypto
const size_t c_bpp_mn = c_bpp_m * CT::c_bpp_n;
const size_t c_bpp_log2_mn = c_bpp_log2_m + CT::c_bpp_log2_n;
// pre-multiply all output points by c_scalar_1div8
// in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify())
// calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H + 1/8 * masks2[i] * H2
commitments.resize(values.size());
for (size_t i = 0; i < values.size(); ++i)
CT::calc_pedersen_commitment_2(values[i] * c_scalar_1div8, masks[i] * c_scalar_1div8, masks2[i] * c_scalar_1div8, commitments[i]);
#ifndef NDEBUG
for(size_t i = 0; i < values.size(); ++i)
{
point_t V{};
CT::calc_pedersen_commitment_2(values[i], masks[i], masks2[i], V);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(point_t(*commitments_1div8[i]).modify_mul8() == V, 4);
}
#endif
// s.a. BP+ paper, page 15, eq. 11
// decompose v into aL and aR:
@ -86,7 +93,7 @@ namespace crypto
DBG_PRINT("initial transcript: " << e);
hash_helper_t::hs_t hsc;
CT::update_transcript(hsc, e, commitments);
CT::update_transcript(hsc, e, commitments_1div8);
// Zarcanum paper, page 33, Fig. D.3: The prover chooses alpha_1, alpha_2 and computes A = g^aL h^aR h_1^alpha_1 h_2^alpha_2
// so we calculate A0 = alpha_1 * H + alpha_2 * H_2 + SUM(aL_i * G_i) + SUM(aR_i * H_i)
@ -149,7 +156,7 @@ namespace crypto
// aL_hat = aL - 1*z
scalar_vec_t aLs_hat = aLs - z;
// aL_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3)
// aR_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3)
scalar_vec_t aRs_hat = aRs + z;
for (size_t i = 0; i < c_bpp_mn; ++i)
aRs_hat[i] += d[i] * y_powers[c_bpp_mn - i];
@ -336,10 +343,28 @@ namespace crypto
DBG_VAL_PRINT(sig.delta_2);
return true;
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
} // bppe_gen()
// convenient overload for tests
template<typename CT>
bool bppe_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const scalar_vec_t& masks2, bppe_signature& sig, std::vector<point_t>& commitments_1div8_to_be_generated, uint8_t* p_err = nullptr)
{
// calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H + 1/8 * masks2[i] * H2
commitments_1div8_to_be_generated.resize(values.size());
std::vector<crypto::public_key> commitments_1div8(values.size());
std::vector<const crypto::public_key*> commitments_1div8_pointers(values.size());
for (size_t i = 0; i < values.size(); ++i)
{
CT::calc_pedersen_commitment_2(values[i] * c_scalar_1div8, masks[i] * c_scalar_1div8, masks2[i] * c_scalar_1div8, commitments_1div8_to_be_generated[i]);
commitments_1div8[i] = (commitments_1div8_to_be_generated[i]).to_public_key();
commitments_1div8_pointers[i] = &commitments_1div8[i];
}
return bppe_gen<CT>(values, masks, masks2, commitments_1div8_pointers, sig, p_err);
}
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
struct bppe_sig_commit_ref_t
{
bppe_sig_commit_ref_t(const bppe_signature& sig, const std::vector<point_t>& commitments)
@ -347,7 +372,7 @@ namespace crypto
, commitments(commitments)
{}
const bppe_signature& sig;
const std::vector<point_t>& commitments;
const std::vector<point_t>& commitments; // assumed to be premultiplied by 1/8
};
@ -355,7 +380,7 @@ namespace crypto
bool bppe_verify(const std::vector<bppe_sig_commit_ref_t>& sigs, uint8_t* p_err = nullptr)
{
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("bppe_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
if (!(cond)) { LOG_PRINT_RED("bppe_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
DBG_PRINT(ENDL << " . . . . bppe_verify() . . . . ");
@ -709,11 +734,14 @@ namespace crypto
point_t GH_exponents = c_point_0;
CT::calc_pedersen_commitment_2(G_scalar, H_scalar, H2_scalar, GH_exponents);
bool result = multiexp_and_check_being_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
bool result = msm_and_check_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
if (result)
DBG_PRINT(ENDL << " . . . . bppe_verify() -- SUCCEEDED!!!" << ENDL);
return result;
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
}
#undef DBG_VAL_PRINT
#undef DBG_PRINT
} // namespace crypto

View file

@ -6,4 +6,12 @@
namespace crypto
{
// TODO @#@# redesign needed, consider changing to inline constexpr
const point_t& bpp_ct_generators_HGX::bpp_G = c_point_H;
const point_t& bpp_ct_generators_HGX::bpp_H = c_point_G;
const point_t& bpp_ct_generators_HGX::bpp_H2 = c_point_X;
const point_t& bpp_ct_generators_UGX::bpp_G = c_point_U;
const point_t& bpp_ct_generators_UGX::bpp_H = c_point_G;
const point_t& bpp_ct_generators_UGX::bpp_H2 = c_point_X;
}

View file

@ -1,5 +1,5 @@
// Copyright (c) 2021-2022 Zano Project (https://zano.org/)
// Copyright (c) 2021-2022 sowle (val@zano.org, crypto.sowle@gmail.com)
// Copyright (c) 2021-2023 Zano Project (https://zano.org/)
// Copyright (c) 2021-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
@ -23,23 +23,6 @@ namespace crypto
return result;
}
// returns greatest k, s.t. 2**k <= v
// tests in crypto_tests_range_proofs.h
constexpr size_t constexpr_floor_log2(size_t v)
{
return v <= 1 ? 0 : constexpr_floor_log2(v >> 1) + 1;
}
// returns smallest k, s.t. v <= 2**k
// tests in crypto_tests_range_proofs.h
constexpr size_t constexpr_ceil_log2(size_t v)
{
return v <= 1 ? 0 : constexpr_floor_log2(v - 1) + 1;
}
// returns least significant bit uing de Bruijn sequence
// http://graphics.stanford.edu/~seander/bithacks.html
inline uint8_t calc_lsb_32(uint32_t v)
@ -56,8 +39,25 @@ namespace crypto
////////////////////////////////////////
// crypto trait for Zano
////////////////////////////////////////
template<size_t N = 64, size_t values_max = 16>
struct bpp_crypto_trait_zano
struct bpp_ct_generators_HGX
{
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators in range_proofs.cpp
static const point_t& bpp_G;
static const point_t& bpp_H;
static const point_t& bpp_H2;
};
struct bpp_ct_generators_UGX
{
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators in range_proofs.cpp
static const point_t& bpp_G;
static const point_t& bpp_H;
static const point_t& bpp_H2;
};
template<typename gen_trait_t, size_t N = 64, size_t values_max = 32>
struct bpp_crypto_trait_zano : gen_trait_t
{
static constexpr size_t c_bpp_n = N; // the upper bound for the witness's range
static constexpr size_t c_bpp_values_max = values_max; // maximum number of elements in BP+ proof, i.e. max allowed BP+ outputs
@ -66,12 +66,14 @@ namespace crypto
static void calc_pedersen_commitment(const scalar_t& value, const scalar_t& mask, point_t& commitment)
{
commitment = value * c_point_G + mask * c_point_H;
// commitment = value * bpp_G + mask * bpp_H
commitment = operator*(value, bpp_G) + mask * bpp_H;
}
static void calc_pedersen_commitment_2(const scalar_t& value, const scalar_t& mask1, const scalar_t& mask2, point_t& commitment)
{
commitment = value * c_point_G + mask1 * c_point_H + mask2 * c_point_H2;
// commitment = value * bpp_G + mask1 * bpp_H * mask2 * bpp_H2
commitment = operator*(value, bpp_G) + mask1 * bpp_H + mask2 * bpp_H2;
}
static const scalar_t& get_initial_transcript()
@ -88,7 +90,17 @@ namespace crypto
e = hsc.calc_hash();
}
// assumes hsc is cleared
static void update_transcript(hash_helper_t::hs_t& hsc, scalar_t& e, const std::vector<const public_key*>& pub_keys)
{
hsc.add_scalar(e);
for(auto p : pub_keys)
hsc.add_pub_key(*p);
e = hsc.calc_hash();
}
// TODO: refactor with proper OOB handling
// TODO: @#@# add domain separation
static const point_t& get_generator(bool select_H, size_t index)
{
if (index >= c_bpp_mn_max)
@ -116,42 +128,21 @@ namespace crypto
return result;
}
static const point_t& bpp_H;
static const point_t& bpp_H2;
using gen_trait_t::bpp_G;
using gen_trait_t::bpp_H;
using gen_trait_t::bpp_H2;
}; // struct bpp_crypto_trait_zano
template<size_t N, size_t values_max>
const point_t& bpp_crypto_trait_zano<N, values_max>::bpp_H = c_point_H;
template<size_t N, size_t values_max>
const point_t& bpp_crypto_trait_zano<N, values_max>::bpp_H2 = c_point_H2;
typedef bpp_crypto_trait_zano<bpp_ct_generators_UGX, 64, 32> bpp_crypto_trait_ZC_out;
// efficient multiexponentiation (naive stub implementation atm, TODO)
template<typename CT>
bool multiexp_and_check_being_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand)
{
CHECK_AND_ASSERT_MES(g_scalars.size() < CT::c_bpp_mn_max, false, "g_scalars oversized");
CHECK_AND_ASSERT_MES(h_scalars.size() < CT::c_bpp_mn_max, false, "h_scalars oversized");
point_t result = summand;
for (size_t i = 0; i < g_scalars.size(); ++i)
result += g_scalars[i] * CT::get_generator(false, i);
for (size_t i = 0; i < h_scalars.size(); ++i)
result += h_scalars[i] * CT::get_generator(true, i);
if (!result.is_zero())
{
LOG_PRINT_L0("multiexp result is non zero: " << result);
return false;
}
return true;
}
typedef bpp_crypto_trait_zano<bpp_ct_generators_HGX, 128, 16> bpp_crypto_trait_Zarcanum;
} // namespace crypto
#include "epee/include/profile_tools.h" // <- remove this, sowle
#include "msm.h"
#include "range_proof_bpp.h"
#include "range_proof_bppe.h"

View file

@ -8,6 +8,7 @@
#include <string.h>
#include "hash-ops.h"
#include "malloc.h"
void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) {
assert(count > 0);

425
src/crypto/zarcanum.cpp Normal file
View file

@ -0,0 +1,425 @@
// Copyright (c) 2022-2023 Zano Project
// Copyright (c) 2022-2023 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// Note: This file originates from tests/functional_tests/crypto_tests.cpp
#include "epee/include/misc_log_ex.h"
#include "zarcanum.h"
#include "range_proofs.h"
#include "../currency_core/crypto_config.h" // TODO: move it to the crypto
#include "../common/crypto_stream_operators.h" // TODO: move it to the crypto
#if 0
# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl
# define DBG_PRINT(x) std::cout << x << std::endl
#else
# define DBG_VAL_PRINT(x) (void(0))
# define DBG_PRINT(x) (void(0))
#endif
namespace crypto
{
const scalar_t c_zarcanum_z_coeff_s = { 0, 1, 0, 0 }; // c_scalar_2p64
const mp::uint256_t c_zarcanum_z_coeff_mp = c_zarcanum_z_coeff_s.as_boost_mp_type<mp::uint256_t>();
template<typename T>
inline std::ostream &operator <<(std::ostream &o, const std::vector<T> &v)
{
for(size_t i = 0, n = v.size(); i < n; ++i)
o << ENDL << " [" << std::setw(2) << i << "]: " << v[i];
return o;
}
mp::uint256_t zarcanum_precalculate_l_div_z_D(const mp::uint128_t& pos_difficulty)
{
//LOG_PRINT_GREEN_L0(ENDL << "floor( l / (z * D) ) = " << c_scalar_L.as_boost_mp_type<mp::uint256_t>() / (c_zarcanum_z_coeff_mp * pos_difficulty));
return c_scalar_L.as_boost_mp_type<mp::uint256_t>() / (c_zarcanum_z_coeff_mp * pos_difficulty); // == floor( l / (z * D) )
}
mp::uint256_t zarcanum_precalculate_z_l_div_z_D(const mp::uint128_t& pos_difficulty)
{
//LOG_PRINT_GREEN_L0(ENDL << "z * floor( l / (z * D) ) = " << c_zarcanum_z_coeff_mp * (c_scalar_L.as_boost_mp_type<mp::uint256_t>() / (c_zarcanum_z_coeff_mp * pos_difficulty)));
return c_zarcanum_z_coeff_mp * (c_scalar_L.as_boost_mp_type<mp::uint256_t>() / (c_zarcanum_z_coeff_mp * pos_difficulty)); // == z * floor( l / (z * D) )
}
bool zarcanum_check_main_pos_inequality(const hash& kernel_hash, const scalar_t& blinding_mask, const scalar_t& secret_q,
const scalar_t& last_pow_block_id_hashed, const mp::uint256_t& z_l_div_z_D, uint64_t stake_amount, mp::uint256_t& lhs, mp::uint512_t& rhs)
{
scalar_t lhs_s = scalar_t(kernel_hash) * (blinding_mask + secret_q + last_pow_block_id_hashed); // == h * (f + q + f') mod l
lhs = lhs_s.as_boost_mp_type<mp::uint256_t>();
rhs = static_cast<mp::uint512_t>(z_l_div_z_D) * stake_amount; // == floor( l / (z * D) ) * z * a
//LOG_PRINT_GREEN_L0(ENDL <<
// "z_l_div_z_D = " << z_l_div_z_D << ENDL <<
// "stake_amount = " << stake_amount << ENDL <<
// "lhs = " << lhs << ENDL <<
// "rhs = " << rhs);
return lhs < rhs; // h * (f + q + f') mod l < floor( l / (z * D) ) * z * a
}
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("zarcanum_generate_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector<CLSAG_GGXXG_input_ref_t>& ring,
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, uint64_t stake_amount,
const scalar_t& stake_out_asset_id_blinding_mask, const scalar_t& stake_out_amount_blinding_mask, const scalar_t& pseudo_out_amount_blinding_mask,
zarcanum_proof& result, uint8_t* p_err /* = nullptr */)
{
DBG_PRINT("zarcanum_generate_proof");
const scalar_t a = stake_amount;
const scalar_t h = scalar_t(kernel_hash);
const scalar_t f_plus_q = stake_out_amount_blinding_mask + secret_q;
const scalar_t f_plus_q_plus_fp = f_plus_q + last_pow_block_id_hashed;
const scalar_t lhs = h * f_plus_q_plus_fp; // == h * (f + q + f') mod l
const mp::uint256_t d_mp = lhs.as_boost_mp_type<mp::uint256_t>() / (c_zarcanum_z_coeff_mp * stake_amount) + 1;
result.d = scalar_t(d_mp);
const scalar_t dz = result.d * c_zarcanum_z_coeff_s;
const scalar_t ba = dz * a - lhs; // b_a = dza - h(f + q + f')
const scalar_t bf = dz * f_plus_q - h * a; // b_f = dz(f + q) - ha
const scalar_t x0 = scalar_t::random(), x1 = scalar_t::random(), x2 = scalar_t::random();
const scalar_t bx = x2 - h * x1 + dz * x0; // b_x = x'' - hx' + dzx
point_t C = x0 * c_point_X + a * c_point_H + f_plus_q * c_point_G;
point_t C_prime = x1 * c_point_X + f_plus_q * c_point_H + a * c_point_G;
point_t E = bx * c_point_X + ba * c_point_H + bf * c_point_G;
result.C = (c_scalar_1div8 * C).to_public_key();
result.C_prime = (c_scalar_1div8 * C_prime).to_public_key();
result.E = (c_scalar_1div8 * E).to_public_key();
// three proofs with a shared Fiat-Shamir challenge c
// 1) linear composition proof for the fact, that C + C' = lin(X, H + G) = (x + x') X + (a + f + q) (H + G)
// 2) linear composition proof for the fact, that C - C' = lin(X, H - G) = (x - x') X + (a - f - q) (H - G)
// 3) Schnorr proof for the fact, that hC' - dzC + E + f'hH = lin(X) = x'' X
point_t F = h * C_prime - dz * C + E + last_pow_block_id_hashed * h * c_point_H;
DBG_VAL_PRINT(h); DBG_VAL_PRINT(last_pow_block_id_hashed); DBG_VAL_PRINT(dz);
DBG_VAL_PRINT(C); DBG_VAL_PRINT(C_prime); DBG_VAL_PRINT(E); DBG_VAL_PRINT(F);
scalar_t r0 = scalar_t::random();
scalar_t r1 = scalar_t::random();
scalar_t r2 = scalar_t::random();
scalar_t r3 = scalar_t::random();
scalar_t r4 = scalar_t::random();
point_t R_01 = r0 * c_point_X + r1 * c_point_H_plus_G;
point_t R_23 = r2 * c_point_X + r3 * c_point_H_minus_G;
point_t R_4 = r4 * c_point_X;
hash_helper_t::hs_t hash_calc(7);
hash_calc.add_32_chars(CRYPTO_HDS_ZARCANUM_PROOF_HASH);
hash_calc.add_point(R_01);
hash_calc.add_point(R_23);
hash_calc.add_point(R_4);
hash_calc.add_point(C + C_prime);
hash_calc.add_point(C - C_prime);
hash_calc.add_point(F);
result.c = hash_calc.calc_hash();
result.y0 = r0 + result.c * (x0 + x1); // y_0 = r_0 + c (x + x')
result.y1 = r1 + result.c * (a + f_plus_q); // y_1 = r_1 + c (a + f + q)
result.y2 = r2 + result.c * (x0 - x1); // y_2 = r_2 + c (x - x')
result.y3 = r3 + result.c * (a - f_plus_q); // y_3 = r_3 + c (a - f - q)
result.y4 = r4 + result.c * x2; // y_4 = r_4 + c x''
// range proof for E
const scalar_vec_t values = { ba }; // H component
const scalar_vec_t masks = { bf }; // G component
const scalar_vec_t masks2 = { bx }; // X component
const std::vector<const public_key*> E_1div8_vec_ptr = { &result.E };
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_gen<bpp_crypto_trait_Zarcanum>(values, masks, masks2, E_1div8_vec_ptr, result.E_range_proof), 10);
// = five-layers ring signature data outline =
// (j in [0, ring_size-1])
// layer 0 ring
// A[j] ( = ring[j].stealth_address)
// layer 0 secret (with respect to G)
// secret_x
// layer 0 linkability
// stake_ki
//
// layer 1 ring
// ring[j].amount_commitment - pseudo_out_amount_commitment
// layer 1 secret (with respect to G)
// stake_out_amount_blinding_mask - pseudo_out_amount_blinding_mask ( = f_i - f'_i )
//
// additional layer for confidential assets:
//
// layer 2 ring
// ring[j].blinded_asset_id - pseudo_out_blinded_asset_id
// layer 2 secret (with respect to X)
// -pseudo_out_asset_id_blinding_mask ( = -r'_i )
//
// additional layers for Zarcanum:
//
// layer 3 ring
// C - A[j] - Q[j]
// layer 3 secret (with respect to X)
// x0 - a * stake_out_asset_id_blinding_mask ( = x - a * r_i )
//
// layer 4 ring
// Q[j]
// layer 4 secret (with respect to G)
// secret_q
// such pseudo_out_asset_id_blinding_mask effectively makes pseudo_out_blinded_asset_id == currency::native_coin_asset_id_pt == point_H
scalar_t pseudo_out_asset_id_blinding_mask = -stake_out_asset_id_blinding_mask; // T^p_i = T_i + (-r_i) * X = H
point_t stake_out_asset_id = c_point_H + stake_out_asset_id_blinding_mask * c_point_X; // T_i = H + r_i * X
point_t pseudo_out_amount_commitment = a * stake_out_asset_id + pseudo_out_amount_blinding_mask * c_point_G; // A^p_i = a_i * T_i + f'_i * G
result.pseudo_out_amount_commitment = (c_scalar_1div8 * pseudo_out_amount_commitment).to_public_key();
TRY_ENTRY()
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(generate_CLSAG_GGXXG(m, ring, pseudo_out_amount_commitment, c_point_H, C, stake_ki,
secret_x, stake_out_amount_blinding_mask - pseudo_out_amount_blinding_mask, -pseudo_out_asset_id_blinding_mask, x0 - a * stake_out_asset_id_blinding_mask, secret_q, secret_index,
result.clsag_ggxxg), 20);
CATCH_ENTRY2(false);
return true;
}
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("zarcanum_verify_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector<CLSAG_GGXXG_input_ref_t>& ring,
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
const mp::uint128_t& pos_difficulty,
const zarcanum_proof& sig, uint8_t* p_err /* = nullptr */) noexcept
{
TRY_ENTRY()
{
DBG_PRINT("zarcanum_verify_proof");
//bool r = false;
//std::cout << "===== zarcanum_verify_proof =====" << ENDL
// << "m: " << m << ENDL
// << "kernel_hash: " << kernel_hash << ENDL
// << "last_pow_block_id_hashed: " << last_pow_block_id_hashed << ENDL
// << "stake_ki: " << stake_ki << ENDL
// << "pos_difficulty: " << pos_difficulty << ENDL;
//size_t ii = 0;
//for(const auto& el : ring)
//{
// std::cout << "[" << ii << "]" << ENDL
// << " amount_commitment: " << el.amount_commitment << ENDL
// << " blinded_asset_id: " << el.blinded_asset_id << ENDL
// << " concealing_point: " << el.concealing_point << ENDL
// << " stealth_address: " << el.stealth_address << ENDL;
//}
// make sure 0 < d <= l / floor(z * D)
const mp::uint256_t l_div_z_D_mp = zarcanum_precalculate_l_div_z_D(pos_difficulty);
const scalar_t l_div_z_D(l_div_z_D_mp);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(!sig.d.is_zero() && sig.d < l_div_z_D, 2);
const scalar_t dz = sig.d * c_zarcanum_z_coeff_s;
// calculate h
const scalar_t h = scalar_t(kernel_hash);
// calculate F
point_t C_prime = point_t(sig.C_prime);
C_prime.modify_mul8();
point_t C = point_t(sig.C);
C.modify_mul8();
point_t E = point_t(sig.E);
E.modify_mul8();
point_t F = h * C_prime - dz * C + E + last_pow_block_id_hashed * h * c_point_H;
DBG_VAL_PRINT(h); DBG_VAL_PRINT(last_pow_block_id_hashed); DBG_VAL_PRINT(dz);
DBG_VAL_PRINT(C); DBG_VAL_PRINT(C_prime); DBG_VAL_PRINT(E); DBG_VAL_PRINT(F);
// check three proofs with a shared Fiat-Shamir challenge c
point_t C_plus_C_prime = C + C_prime;
point_t C_minus_C_prime = C - C_prime;
hash_helper_t::hs_t hash_calc(7);
hash_calc.add_32_chars(CRYPTO_HDS_ZARCANUM_PROOF_HASH);
hash_calc.add_point(sig.y0 * c_point_X + sig.y1 * c_point_H_plus_G - sig.c * C_plus_C_prime); // y_0 * X + y1 (H + G) - c (C + C')
hash_calc.add_point(sig.y2 * c_point_X + sig.y3 * c_point_H_minus_G - sig.c * C_minus_C_prime); // y_2 * X + y3 (H - G) - c (C - C')
hash_calc.add_point(sig.y4 * c_point_X - sig.c * F); // y_4 * X - c * F
hash_calc.add_point(C_plus_C_prime);
hash_calc.add_point(C_minus_C_prime);
hash_calc.add_point(F);
scalar_t c_prime = hash_calc.calc_hash();
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.c == c_prime, 3);
// check extended range proof for E
std::vector<point_t> E_for_range_proof = { point_t(sig.E) }; // consider changing to 8*sig.E to avoid additional conversion
std::vector<bppe_sig_commit_ref_t> range_proofs = { bppe_sig_commit_ref_t(sig.E_range_proof, E_for_range_proof) };
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_verify<bpp_crypto_trait_Zarcanum>(range_proofs), 10);
static public_key native_coin_asset_id = (c_scalar_1div8 * c_point_H).to_public_key(); // consider making it less ugly -- sowle
// check extended CLSAG-GGXG ring signature
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(verify_CLSAG_GGXXG(m, ring, sig.pseudo_out_amount_commitment, native_coin_asset_id, sig.C, stake_ki, sig.clsag_ggxxg), 1);
}
CATCH_ENTRY_CUSTOM2({if (p_err) *p_err = 100;}, false)
return true;
}
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("generate_vector_UG_aggregation_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
bool generate_vector_UG_aggregation_proof(const hash& m, const scalar_vec_t& u_secrets, const scalar_vec_t& g_secrets0, const scalar_vec_t& g_secrets1,
const std::vector<point_t>& amount_commitments,
const std::vector<point_t>& amount_commitments_for_rp_aggregation,
const std::vector<point_t>& blinded_asset_ids,
vector_UG_aggregation_proof& result, uint8_t* p_err /* = nullptr */)
{
// w - public random weighting factor
// proof of knowing e_j and y'' in zero knowledge in the following eq:
// E_j + w * E'_j = e_j * (T'_j + w * U) + (y_j + w * y'_j) * G
// where:
// e_j -- output's amount
// T'_j -- output's blinded asset tag
// E_j == e_j * T'_j + y_j * G -- output's amount commitments
// E'_j == e_j * U + y'_j * G -- additional commitment to the same amount for range proof aggregation
// amount_commitments[j] + w * amount_commitments_for_rp_aggregation[j]
// ==
// u_secrets[j] * (blinded_asset_ids[j] + w * U) + (g_secrets0[j] + w * g_secrets1[j]) * G
const size_t n = u_secrets.size();
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n != 0, 1);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n == g_secrets0.size(), 2);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n == g_secrets1.size(), 3);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n == amount_commitments.size(), 4);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n == amount_commitments_for_rp_aggregation.size(), 5);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n == blinded_asset_ids.size(), 6);
hash_helper_t::hs_t hash_calculator(1 + 3 * n);
hash_calculator.add_hash(m);
hash_calculator.add_points_array(amount_commitments);
hash_calculator.add_points_array(amount_commitments_for_rp_aggregation);
scalar_t w = hash_calculator.calc_hash(false); // don't clean the buffer
DBG_VAL_PRINT(w);
#ifndef NDEBUG
for(size_t j = 0; j < n; ++j)
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(amount_commitments[j] + w * amount_commitments_for_rp_aggregation[j] == u_secrets[j] * (blinded_asset_ids[j] + w * c_point_U) + (g_secrets0[j] + w * g_secrets1[j]) * c_point_G, 20);
#endif
result.amount_commitments_for_rp_aggregation.clear();
result.y0s.clear();
result.y1s.clear();
scalar_vec_t r0, r1;
r0.resize_and_make_random(n);
r1.resize_and_make_random(n);
std::vector<point_t> asset_tag_plus_U_vec(n);
for(size_t j = 0; j < n; ++j)
asset_tag_plus_U_vec[j] = blinded_asset_ids[j] + w * c_point_U;
std::vector<point_t> R(n);
for(size_t j = 0; j < n; ++j)
R[j].assign_mul_plus_G(r0[j], asset_tag_plus_U_vec[j], r1[j]); // R[j] = r0[j] * asset_tag_plus_U_vec[j] + r1[j] * G
hash_calculator.add_points_array(R);
result.c = hash_calculator.calc_hash();
DBG_VAL_PRINT(asset_tag_plus_U_vec); DBG_VAL_PRINT(m); DBG_VAL_PRINT(amount_commitments); DBG_VAL_PRINT(amount_commitments_for_rp_aggregation); DBG_VAL_PRINT(R);
DBG_VAL_PRINT(result.c);
for(size_t j = 0; j < n; ++j)
{
result.y0s.emplace_back(r0[j] - result.c * u_secrets[j]);
result.y1s.emplace_back(r1[j] - result.c * (g_secrets0[j] + w * g_secrets1[j]));
result.amount_commitments_for_rp_aggregation.emplace_back((c_scalar_1div8 * amount_commitments_for_rp_aggregation[j]).to_public_key());
}
return true;
}
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("verify_vector_UG_aggregation_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
bool verify_vector_UG_aggregation_proof(const hash& m, const std::vector<const public_key*> amount_commitments_1div8, const std::vector<const public_key*> blinded_asset_ids_1div8,
const vector_UG_aggregation_proof& sig, uint8_t* p_err /* = nullptr */) noexcept
{
TRY_ENTRY()
{
const size_t n = amount_commitments_1div8.size();
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n > 0, 1);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(blinded_asset_ids_1div8.size() == n, 2);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.amount_commitments_for_rp_aggregation.size() == n, 3);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.y0s.size() == n, 4);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.y1s.size() == n, 5);
hash_helper_t::hs_t hash_calculator(1 + 3 * n);
hash_calculator.add_hash(m);
DBG_VAL_PRINT(m);
std::vector<point_t> amount_commitments_pt;
for(size_t j = 0; j < n; ++j)
{
point_t A = point_t(*amount_commitments_1div8[j]).modify_mul8();
hash_calculator.add_point(A);
amount_commitments_pt.emplace_back(A);
DBG_VAL_PRINT(A);
}
std::vector<point_t> amount_commitments_for_rp_aggregation_pt;
for(size_t j = 0; j < n; ++j)
{
point_t Arpa = point_t(sig.amount_commitments_for_rp_aggregation[j]).modify_mul8();
hash_calculator.add_point(Arpa); // TODO @#@ performance: consider adding premultiplied by 1/8 points to the hash
amount_commitments_for_rp_aggregation_pt.emplace_back(Arpa);
DBG_VAL_PRINT(Arpa);
}
scalar_t w = hash_calculator.calc_hash(false); // don't clear the buffer
DBG_VAL_PRINT(w);
std::vector<point_t> asset_tag_plus_U_vec(n);
for(size_t j = 0; j < n; ++j)
asset_tag_plus_U_vec[j] = point_t(*blinded_asset_ids_1div8[j]).modify_mul8() + w * c_point_U;
DBG_VAL_PRINT(asset_tag_plus_U_vec);
for(size_t j = 0; j < n; ++j)
{
hash_calculator.add_pub_key(point_t(
sig.y0s[j] * asset_tag_plus_U_vec[j] +
sig.y1s[j] * c_point_G +
sig.c * (amount_commitments_pt[j] + w * amount_commitments_for_rp_aggregation_pt[j])
).to_public_key());
DBG_VAL_PRINT(hash_calculator.m_elements.back().pk);
}
scalar_t c = hash_calculator.calc_hash();
DBG_VAL_PRINT(c); DBG_VAL_PRINT(sig.c);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.c == c, 0);
}
CATCH_ENTRY_CUSTOM2({if (p_err) *p_err = 100; }, false)
return true;
}
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
} // namespace crypto

295
src/crypto/zarcanum.h Normal file
View file

@ -0,0 +1,295 @@
// Copyright (c) 2022-2024 Zano Project
// Copyright (c) 2022-2024 sowle (val@zano.org, crypto.sowle@gmail.com)
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// Note: This file originates from tests/functional_tests/crypto_tests.cpp
#pragma once
#include "crypto-sugar.h"
#include "range_proofs.h"
#include "clsag.h"
namespace crypto
{
extern const mp::uint256_t c_zarcanum_z_coeff_mp;
extern const scalar_t c_zarcanum_z_coeff_s;
mp::uint256_t zarcanum_precalculate_l_div_z_D(const mp::uint128_t& pos_difficulty);
mp::uint256_t zarcanum_precalculate_z_l_div_z_D(const mp::uint128_t& pos_difficulty);
bool zarcanum_check_main_pos_inequality(const hash& kernel_hash, const scalar_t& blinding_mask, const scalar_t& secret_q,
const scalar_t& last_pow_block_id_hashed, const mp::uint256_t& z_l_div_z_D_, uint64_t stake_amount, mp::uint256_t& lhs, mp::uint512_t& rhs);
struct zarcanum_proof
{
scalar_t d = 0;
public_key C; // premultiplied by 1/8
public_key C_prime; // premultiplied by 1/8
public_key E; // premultiplied by 1/8
scalar_t c; // shared Fiat-Shamir challenge for the following three proofs
scalar_t y0; // 1st linear composition proof
scalar_t y1; // ( C + C' = lin(X, H + G) )
scalar_t y2; // 2nd linear composition proof
scalar_t y3; // ( C - C' = lin(X, H - G) )
scalar_t y4; // Schnorr proof (F = lin(X))
bppe_signature E_range_proof;
public_key pseudo_out_amount_commitment; // premultiplied by 1/8
CLSAG_GGXXG_signature clsag_ggxxg;
};
bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector<CLSAG_GGXXG_input_ref_t>& ring,
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, uint64_t stake_amount,
const scalar_t& stake_out_asset_id_blinding_mask, const scalar_t& stake_out_amount_blinding_mask, const scalar_t& pseudo_out_amount_blinding_mask,
zarcanum_proof& result, uint8_t* p_err = nullptr);
bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector<CLSAG_GGXXG_input_ref_t>& ring,
const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki,
const mp::uint128_t& pos_difficulty,
const zarcanum_proof& sig, uint8_t* p_err = nullptr) noexcept;
// TODO @#@#: make sure it is used, implement, then move it to an appropriate place
struct linear_composition_proof
{
scalar_t c;
scalar_t y0;
scalar_t y1;
};
enum generator_tag { gt_void = 0, gt_G = 1, gt_H = 2, gt_H2 = 3, gt_X = 4, gt_U = 5 };
template<generator_tag gen0 = gt_H, generator_tag gen1 = gt_G>
bool generate_linear_composition_proof(const hash& m, const public_key& A, const scalar_t& secret_a, const scalar_t& secret_b, linear_composition_proof& result, uint8_t* p_err = nullptr)
{
// consider embedding generators' tags into random entropy to distinguish proofs made with different generators during verification
return false;
}
template<generator_tag gen0 = gt_H, generator_tag gen1 = gt_G>
bool verify_linear_composition_proof(const hash& m, const public_key& A, const linear_composition_proof& sig, uint8_t* p_err = nullptr)
{
return false;
}
struct generic_schnorr_sig
{
scalar_t c;
scalar_t y;
};
template<typename generator_t>
inline bool generate_schnorr_sig_custom_generator(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result, const generator_t& g_point_g)
{
#ifndef NDEBUG
if (A != secret_a * g_point_g)
return false;
#endif
scalar_t r = scalar_t::random();
point_t R = r * g_point_g;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(R);
result.c = hsc.calc_hash();
result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a
return true;
}
template<generator_tag gen = gt_G>
inline bool generate_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result);
template<>
inline bool generate_schnorr_sig<gt_G>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result)
{
return generate_schnorr_sig_custom_generator(m, A, secret_a, result, c_point_G);
}
template<>
inline bool generate_schnorr_sig<gt_X>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result)
{
return generate_schnorr_sig_custom_generator(m, A, secret_a, result, c_point_X);
}
inline bool generate_schnorr_sig(const hash& m, const public_key& A, const secret_key& secret_a, generic_schnorr_sig& result)
{
return generate_schnorr_sig(m, point_t(A), scalar_t(secret_a), result);
}
template<generator_tag gen = gt_G>
inline bool verify_schnorr_sig(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept;
// TODO @#@# make optimized version inline bool verify_schnorr_sig(const hash& m, const point_t& A, const generic_schnorr_sig& sig) noexcept;
// and change check_tx_balance() accordingly
template<>
inline bool verify_schnorr_sig<gt_G>(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept
{
try
{
if (!sig.c.is_reduced() || !sig.y.is_reduced())
return false;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_pub_key(A);
hsc.add_point(point_t(A).mul_plus_G(sig.c, sig.y)); // sig.y * G + sig.c * A
return sig.c == hsc.calc_hash();
}
catch(...)
{
return false;
}
}
template<>
inline bool verify_schnorr_sig<gt_X>(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept
{
try
{
if (!sig.c.is_reduced() || !sig.y.is_reduced())
return false;
hash_helper_t::hs_t hsc(3);
hsc.add_hash(m);
hsc.add_pub_key(A);
hsc.add_point(sig.y * c_point_X + sig.c * point_t(A));
return sig.c == hsc.calc_hash();
}
catch(...)
{
return false;
}
}
// --------------------------------------------
// multi-base Schnorr-like proof (two generators, two secrets, one Fiat-Shamir challenge)
struct generic_double_schnorr_sig
{
scalar_t c;
scalar_t y0;
scalar_t y1;
};
template<generator_tag gen0, generator_tag gen1>
inline bool generate_double_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result);
template<>
inline bool generate_double_schnorr_sig<gt_G, gt_G>(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result)
{
#ifndef NDEBUG
if (A != secret_a * c_point_G || B != secret_b * c_point_G)
return false;
#endif
scalar_t r0 = scalar_t::random();
scalar_t r1 = scalar_t::random();
point_t R0 = r0 * c_point_G;
point_t R1 = r1 * c_point_G;
hash_helper_t::hs_t hsc(5);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(B);
hsc.add_point(R0);
hsc.add_point(R1);
result.c = hsc.calc_hash();
result.y0.assign_mulsub(result.c, secret_a, r0); // y0 = r0 - c * secret_a
result.y1.assign_mulsub(result.c, secret_b, r1); // y1 = r1 - c * secret_b
return true;
}
template<>
inline bool generate_double_schnorr_sig<gt_X, gt_G>(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result)
{
#ifndef NDEBUG
if (A != secret_a * c_point_X || B != secret_b * c_point_G)
return false;
#endif
scalar_t r0 = scalar_t::random();
scalar_t r1 = scalar_t::random();
point_t R0 = r0 * c_point_X;
point_t R1 = r1 * c_point_G;
hash_helper_t::hs_t hsc(5);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_point(B);
hsc.add_point(R0);
hsc.add_point(R1);
result.c = hsc.calc_hash();
result.y0.assign_mulsub(result.c, secret_a, r0); // y0 = r0 - c * secret_a
result.y1.assign_mulsub(result.c, secret_b, r1); // y1 = r1 - c * secret_b
return true;
}
template<generator_tag gen0, generator_tag gen1>
inline bool verify_double_schnorr_sig(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept;
template<>
inline bool verify_double_schnorr_sig<gt_G, gt_G>(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept
{
try
{
if (!sig.c.is_reduced() || !sig.y0.is_reduced() || !sig.y1.is_reduced())
return false;
hash_helper_t::hs_t hsc(5);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_pub_key(B);
hsc.add_point(A.mul_plus_G(sig.c, sig.y0)); // sig.y0 * G + sig.c * A
hsc.add_point(point_t(B).mul_plus_G(sig.c, sig.y1)); // sig.y1 * G + sig.c * B
return sig.c == hsc.calc_hash();
}
catch(...)
{
return false;
}
}
template<>
inline bool verify_double_schnorr_sig<gt_X, gt_G>(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept
{
try
{
if (!sig.c.is_reduced() || !sig.y0.is_reduced() || !sig.y1.is_reduced())
return false;
hash_helper_t::hs_t hsc(5);
hsc.add_hash(m);
hsc.add_point(A);
hsc.add_pub_key(B);
hsc.add_point(sig.y0 * c_point_X + sig.c * A);
hsc.add_point(point_t(B).mul_plus_G(sig.c, sig.y1)); // sig.y1 * G + sig.c * B
return sig.c == hsc.calc_hash();
}
catch(...)
{
return false;
}
}
// TODO: improve this proof using random weightning factor
struct vector_UG_aggregation_proof
{
std::vector<public_key> amount_commitments_for_rp_aggregation; // E' = e * U + y' * G, premultiplied by 1/8
scalar_vec_t y0s;
scalar_vec_t y1s;
scalar_t c; // common challenge
};
bool generate_vector_UG_aggregation_proof(const hash& m, const scalar_vec_t& u_secrets, const scalar_vec_t& g_secrets0, const scalar_vec_t& g_secrets1,
const std::vector<point_t>& amount_commitments,
const std::vector<point_t>& amount_commitments_for_rp_aggregation,
const std::vector<point_t>& blinded_asset_ids,
vector_UG_aggregation_proof& result, uint8_t* p_err = nullptr);
bool verify_vector_UG_aggregation_proof(const hash& m, const std::vector<const public_key*> amount_commitments_1div8, const std::vector<const public_key*> blinded_asset_ids_1div8,
const vector_UG_aggregation_proof& sig, uint8_t* p_err = nullptr) noexcept;
} // namespace crypto

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -8,14 +8,54 @@
namespace bc_services
{
template<typename T>
struct is_boost_variant : std::false_type {};
template<typename... Args>
struct is_boost_variant<boost::variant<Args...>> : std::true_type {};
template<bool is_variant>
struct type_selector;
template<>
struct type_selector<true>
{
template<typename t_type>
static const std::type_info& get_type(const t_type& t)
{
return t.type();
}
template<typename t_type, typename t_return_type>
static const t_return_type& get(const t_type& t)
{
return boost::get<t_return_type>(t);
}
};
template<>
struct type_selector<false>
{
template<typename t_type>
static const std::type_info& get_type(const t_type& t)
{
return typeid(t);
}
template<typename t_type, typename t_return_type>
static const t_return_type& get(const t_type& t)
{
return t;
}
};
template<class t_attachment_type_container_t>
bool get_first_service_attachment_by_id(const t_attachment_type_container_t& tx_items, const std::string& id, const std::string& instruction, currency::tx_service_attachment& res)
{
for (const auto& item : tx_items)
{
if (item.type() == typeid(currency::tx_service_attachment))
typedef type_selector<is_boost_variant<typename t_attachment_type_container_t::value_type>::value> TS;
if (TS::get_type(item) == typeid(currency::tx_service_attachment))
{
const currency::tx_service_attachment& tsa = boost::get<currency::tx_service_attachment>(item);
const currency::tx_service_attachment& tsa = TS::template get<decltype(item), currency::tx_service_attachment>(item);
if (tsa.service_id == id && tsa.instruction == instruction)
{
res = tsa;
@ -25,4 +65,5 @@ namespace bc_services
}
return false;
}
}
}

View file

@ -13,7 +13,7 @@
#include <boost/foreach.hpp>
#include <boost/serialization/is_bitwise_serializable.hpp>
#include "common/unordered_containers_boost_serialization.h"
#include "common/crypto_boost_serialization.h"
#include "common/crypto_serialization.h"
#include "offers_service_basics.h"
#include "offers_services_helpers.h"

File diff suppressed because it is too large Load diff

View file

@ -39,7 +39,7 @@
#include "dispatch_core_events.h"
#include "bc_attachments_service_manager.h"
#include "common/median_db_cache.h"
#include "common/variant_helper.h"
MARK_AS_POD_C11(crypto::key_image);
@ -68,10 +68,20 @@ namespace currency
epee::math_helper::average<uint64_t, 5> etc_stuff_6;
epee::math_helper::average<uint64_t, 5> insert_time_4;
epee::math_helper::average<uint64_t, 5> raise_block_core_event;
epee::math_helper::average<uint64_t, 5> validate_miner_transaction_time;
epee::math_helper::average<uint64_t, 5> collect_rangeproofs_data_from_tx_time;
epee::math_helper::average<uint64_t, 5> verify_multiple_zc_outs_range_proofs_time;
//target_calculating_time_2
epee::math_helper::average<uint64_t, 5> target_calculating_enum_blocks;
epee::math_helper::average<uint64_t, 5> target_calculating_calc;
//longhash_calculating_time_3
epee::math_helper::average<uint64_t, 1> pos_validate_ki_search;
epee::math_helper::average<uint64_t, 1> pos_validate_get_out_keys_for_inputs;
epee::math_helper::average<uint64_t, 1> pos_validate_zvp;
//tx processing zone
epee::math_helper::average<uint64_t, 1> tx_check_inputs_time;
epee::math_helper::average<uint64_t, 1> tx_add_one_tx_time;
@ -139,6 +149,7 @@ namespace currency
{
bool htlc_is_expired;
std::list<txout_htlc> htlc_outs;
std::list<tx_out_zarcanum> zc_outs;
};
// == Output indexes local lookup table conception ==
@ -239,11 +250,11 @@ namespace currency
template<class visitor_t>
bool scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_to_key& tx_in_to_key, visitor_t& vis)
bool scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_v& in_v, visitor_t& vis)
{
scan_for_keys_context cntx_stub = AUTO_VAL_INIT(cntx_stub);
uint64_t stub = 0;
return scan_outputkeys_for_indexes(validated_tx, tx_in_to_key, vis, stub, cntx_stub);
return scan_outputkeys_for_indexes(validated_tx, in_v, vis, stub, cntx_stub);
}
template<class visitor_t>
bool scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_v& verified_input, visitor_t& vis, uint64_t& max_related_block_height, scan_for_keys_context& /*scan_context*/) const;
@ -259,8 +270,8 @@ namespace currency
wide_difficulty_type get_cached_next_difficulty(bool pos) const;
bool create_block_template(block& b, const account_public_address& miner_address, const account_public_address& stakeholder_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe, fill_block_template_func_t custom_fill_block_template_func = nullptr) const;
bool create_block_template(block& b, const account_public_address& miner_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce) const;
bool create_block_template(const account_public_address& miner_address, const blobdata& ex_nonce, block& b, wide_difficulty_type& di, uint64_t& height) const;
bool create_block_template(const account_public_address& miner_address, const account_public_address& stakeholder_address, const blobdata& ex_nonce, bool pos, const pos_entry& pe, fill_block_template_func_t custom_fill_block_template_func, block& b, wide_difficulty_type& di, uint64_t& height, tx_generation_context* miner_tx_tgc_ptr = nullptr) const;
bool create_block_template(const create_block_template_params& params, create_block_template_response& resp) const;
bool have_block(const crypto::hash& id) const;
@ -275,6 +286,7 @@ namespace currency
bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp)const;
bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const;
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)const;
bool get_random_outs_for_amounts2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res)const;
bool get_backward_blocks_sizes(size_t from_height, std::vector<size_t>& sz, size_t count)const;
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& indexs)const;
bool get_alias_info(const std::string& alias, extra_alias_entry_base& info)const;
@ -287,25 +299,27 @@ namespace currency
uint64_t get_aliases_count()const;
uint64_t get_block_h_older_then(uint64_t timestamp) const;
bool validate_tx_service_attachmens_in_services(const tx_service_attachment& a, size_t i, const transaction& tx)const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase)const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height)const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, uint64_t& max_related_block_height)const;
bool get_asset_info(const crypto::public_key& asset_id, asset_descriptor_base& info)const;
uint64_t get_assets_count() const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase)const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const;
bool check_tx_input(const transaction& tx, size_t in_index, const txin_zc_input& zc_in, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, bool& all_tx_ins_have_explicit_native_asset_ids) const;
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height)const;
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash) const;
bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height, crypto::hash& max_used_block_id)const;
bool check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const transaction& source_tx, size_t out_n) const;
bool check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const transaction& source_tx, size_t out_n) const;
bool validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id, uint64_t block_height) const;
bool validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id) const;
bool get_output_keys_for_input_with_checks(const transaction& tx, const txin_v& verified_input, std::vector<crypto::public_key>& output_keys, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase, scan_for_keys_context& scan_context) const;
bool get_output_keys_for_input_with_checks(const transaction& tx, const txin_v& verified_input, std::vector<crypto::public_key>& output_keys, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) const;
bool check_input_signature(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<crypto::signature>& sig, const std::vector<const crypto::public_key*>& output_keys_ptrs) const;
bool check_input_signature(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector<const crypto::public_key*>& output_keys_ptrs) const;
bool check_input_signature(const transaction& tx,
size_t in_index,
uint64_t in_amount,
const crypto::key_image& k_image,
const std::vector<txin_etc_details_v>& in_etc_details,
const crypto::hash& tx_prefix_hash,
const std::vector<crypto::signature>& sig,
const std::vector<const crypto::public_key*>& output_keys_ptrs) const;
uint64_t get_current_comulative_blocksize_limit()const;
@ -316,6 +330,7 @@ namespace currency
boost::multiprecision::uint128_t total_coins()const;
bool is_pos_allowed()const;
uint64_t get_tx_fee_median()const;
uint64_t get_tx_fee_window_value_median() const;
uint64_t get_tx_expiration_median() const;
uint64_t validate_alias_reward(const transaction& tx, const std::string& ai)const;
void set_event_handler(i_core_event_handler* event_handler) const;
@ -329,6 +344,11 @@ namespace currency
bool is_tx_expired(const transaction& tx) const;
std::shared_ptr<const transaction_chain_entry> find_key_image_and_related_tx(const crypto::key_image& ki, crypto::hash& id_result) const;
// returns true as soon as the hardfork is active for the NEXT upcoming block (not for the top block in the blockchain storage)
bool is_hardfork_active(size_t hardfork_id) const;
bool fill_tx_rpc_inputs(tx_rpc_extended_info& tei, const transaction& tx) const;
bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short = false) const;
wide_difficulty_type block_difficulty(size_t i)const;
bool forecast_difficulty(std::vector<std::pair<uint64_t, wide_difficulty_type>> &out_height_2_diff_vector, bool pos) const;
bool prune_aged_alt_blocks();
@ -336,14 +356,12 @@ namespace currency
bool check_keyimages(const std::list<crypto::key_image>& images, std::list<uint64_t>& images_stat)const;//true - unspent, false - spent
bool build_kernel(const block& bl, stake_kernel& kernel, uint64_t& amount, const stake_modifier_type& stake_modifier)const;
// --- PoS ---
bool build_kernel(uint64_t amount,
const crypto::key_image& ki,
bool build_kernel(const crypto::key_image& ki,
stake_kernel& kernel,
const stake_modifier_type& stake_modifier,
uint64_t timestamp)const;
bool build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0, crypto::hash *p_last_block_hash = nullptr) const;
uint64_t timestamp) const;
bool build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0, crypto::hash* p_last_block_hash = nullptr, uint64_t* p_last_pow_block_height = nullptr) const;
bool scan_pos(const COMMAND_RPC_SCAN_POS::request& sp, COMMAND_RPC_SCAN_POS::response& rsp)const;
bool validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t source_max_unlock_time)const;
bool validate_pos_block(const block& b, const crypto::hash& id, bool for_altchain)const;
bool validate_pos_block(const block& b, wide_difficulty_type basic_diff, const crypto::hash& id, bool for_altchain)const;
@ -351,7 +369,7 @@ namespace currency
wide_difficulty_type basic_diff,
uint64_t& amount,
wide_difficulty_type& final_diff,
crypto::hash& proof_hash,
crypto::hash& kernel_hash,
const crypto::hash& id,
bool for_altchain,
const alt_chain_type& alt_chain = alt_chain_type(),
@ -396,7 +414,7 @@ namespace currency
missed_bs.push_back(bl_id);
else
{
CHECK_AND_ASSERT_MES(*block_ind_ptr < m_db_blocks.size(), false, "Internal error: bl_id=" << string_tools::pod_to_hex(bl_id)
CHECK_AND_ASSERT_MES(*block_ind_ptr < m_db_blocks.size(), false, "Internal error: bl_id=" << epst::pod_to_hex(bl_id)
<< " have index record with offset=" << *block_ind_ptr << ", bigger then m_db_blocks.size()=" << m_db_blocks.size());
blocks.push_back(m_db_blocks[*block_ind_ptr]->bl);
}
@ -488,6 +506,9 @@ namespace currency
typedef tools::db::cached_key_value_accessor<crypto::hash, ms_output_entry, false, false> multisig_outs_container;// ms out id => ms_output_entry
typedef tools::db::cached_key_value_accessor<uint64_t, uint64_t, false, true> solo_options_container;
typedef tools::db::basic_key_value_accessor<uint32_t, block_gindex_increments, true> per_block_gindex_increments_container; // height => [(amount, gindex_increment), ...]
typedef tools::db::cached_key_value_accessor<crypto::public_key, std::list<asset_descriptor_operation>, true, false> assets_container; // TODO @#@# consider storing tx_id as well for reference -- sowle
//-----------------------------------------
@ -529,13 +550,14 @@ namespace currency
address_to_aliases_container m_db_addr_to_alias;
per_block_gindex_increments_container m_db_per_block_gindex_incs;
assets_container m_db_assets;
mutable critical_section m_invalid_blocks_lock;
mutable epee::critical_section m_invalid_blocks_lock;
blocks_ext_by_hash m_invalid_blocks; // crypto::hash -> block_extended_info
mutable critical_section m_alternative_chains_lock;
mutable epee::critical_section m_alternative_chains_lock;
alt_chain_container m_alternative_chains; // crypto::hash -> alt_block_extended_info
std::unordered_map<crypto::hash, size_t> m_alternative_chains_txs; // tx_id -> how many alt blocks it related to (always >= 1)
std::unordered_map<crypto::key_image, std::list<crypto::hash>> m_altblocks_keyimages; // key image -> list of alt blocks hashes where it appears in inputs
@ -559,7 +581,7 @@ namespace currency
mutable wide_difficulty_type m_cached_next_pow_difficulty;
mutable wide_difficulty_type m_cached_next_pos_difficulty;
mutable critical_section m_targetdata_cache_lock;
mutable epee::critical_section m_targetdata_cache_lock;
mutable std::list <std::pair<wide_difficulty_type, uint64_t>> m_pos_targetdata_cache;
mutable std::list <std::pair<wide_difficulty_type, uint64_t>> m_pow_targetdata_cache;
//work like a cache to avoid recalculation on read operations
@ -569,8 +591,8 @@ namespace currency
mutable std::atomic<bool> m_deinit_is_done;
mutable uint64_t m_blockchain_launch_timestamp;
bool init_tx_fee_median();
bool update_tx_fee_median();
//bool init_tx_fee_median();
//bool update_tx_fee_median();
void store_db_solo_options_values();
bool set_lost_tx_unmixable();
bool set_lost_tx_unmixable_for_height(uint64_t height);
@ -586,11 +608,12 @@ namespace currency
wide_difficulty_type get_next_difficulty_for_alternative_chain(const alt_chain_type& alt_chain, block_extended_info& bei, bool pos) const;
bool handle_block_to_main_chain(const block& bl, block_verification_context& bvc);
bool handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc);
bool collect_rangeproofs_data_from_tx(const transaction& tx, const crypto::hash& tx_id, std::vector<zc_outs_range_proofs_with_commitments>& agregated_proofs);
std::string print_alt_chain(alt_chain_type alt_chain);
bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc);
bool is_reorganize_required(const block_extended_info& main_chain_bei, const alt_chain_type& alt_chain, const crypto::hash& proof_alt);
wide_difficulty_type get_x_difficulty_after_height(uint64_t height, bool is_pos);
bool purge_keyimage_from_big_heap(const crypto::key_image& ki, const crypto::hash& id);
bool purge_keyimage_from_big_heap(const crypto::key_image& ki, const crypto::hash& block_id);
bool purge_altblock_keyimages_from_big_heap(const block& b, const crypto::hash& id);
bool append_altblock_keyimages_to_big_heap(const crypto::hash& block_id, const std::unordered_set<crypto::key_image>& alt_block_keyimages);
bool validate_alt_block_input(const transaction& input_tx,
@ -599,13 +622,17 @@ namespace currency
const crypto::hash& bl_id,
const crypto::hash& input_tx_hash,
size_t input_index,
const std::vector<crypto::signature>& input_sigs,
uint64_t split_height,
const alt_chain_type& alt_chain,
const std::unordered_set<crypto::hash>& alt_chain_block_ids,
uint64_t& ki_lookuptime,
uint64_t* p_max_related_block_height = nullptr) const;
bool validate_alt_block_ms_input(const transaction& input_tx, const crypto::hash& input_tx_hash, size_t input_index, const std::vector<crypto::signature>& input_sigs, uint64_t split_height, const alt_chain_type& alt_chain) const;
bool validate_alt_block_ms_input(const transaction& input_tx,
const crypto::hash& input_tx_hash,
size_t input_index,
//const signature_v& input_sigs,//const std::vector<crypto::signature>& input_sigs,
uint64_t split_height,
const alt_chain_type& alt_chain) const;
bool validate_alt_block_txs(const block& b, const crypto::hash& id, std::unordered_set<crypto::key_image>& collected_keyimages, alt_block_extended_info& abei, const alt_chain_type& alt_chain, uint64_t split_height, uint64_t& ki_lookup_time_total) const;
bool update_alt_out_indexes_for_tx_in_block(const transaction& tx, alt_block_extended_info& abei)const;
bool get_transaction_from_pool_or_db(const crypto::hash& tx_id, std::shared_ptr<transaction>& tx_ptr, uint64_t min_allowed_block_height = 0) const;
@ -615,14 +642,15 @@ namespace currency
bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height, uint64_t timestamp);
bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector<uint64_t>& global_indexes);
bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id);
bool add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix = false) const;
bool add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix = false, uint64_t height_upper_limit = 0) const;
bool get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map<uint64_t, uint64_t>& amounts_to_up_index_limit_cache) const;
bool get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map<uint64_t, uint64_t>& amounts_to_up_index_limit_cache) const;
bool add_block_as_invalid(const block& bl, const crypto::hash& h);
bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h);
size_t find_end_of_allowed_index(uint64_t amount)const;
bool check_block_timestamp_main(const block& b)const;
bool check_block_timestamp(std::vector<uint64_t> timestamps, const block& b)const;
std::vector<uint64_t> get_last_n_blocks_timestamps(size_t n)const;
const std::vector<txin_etc_details_v>& get_txin_etc_options(const txin_v& in)const;
void on_block_added(const block_extended_info& bei, const crypto::hash& id, const std::list<crypto::key_image>& bsk);
void on_block_removed(const block_extended_info& bei);
void update_targetdata_cache_on_block_added(const block_extended_info& bei);
@ -631,22 +659,26 @@ namespace currency
uint64_t get_tx_fee_median_effective_index(uint64_t h) const;
void on_abort_transaction();
void load_targetdata_cache(bool is_pos) const;
uint64_t get_adjusted_time()const;
bool complete_timestamps_vector(uint64_t start_height, std::vector<uint64_t>& timestamps);
bool update_next_comulative_size_limit();
bool process_blockchain_tx_extra(const transaction& tx);
bool process_blockchain_tx_extra(const transaction& tx, const crypto::hash& tx_id);
bool unprocess_blockchain_tx_extra(const transaction& tx);
bool process_blockchain_tx_attachments(const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp);
bool unprocess_blockchain_tx_attachments(const transaction& tx, uint64_t h, uint64_t timestamp);
bool validate_ado_ownership(asset_op_verification_context& avc);
bool pop_alias_info(const extra_alias_entry& ai);
bool put_alias_info(const transaction& tx, extra_alias_entry& ai);
bool pop_asset_info(const crypto::public_key& asset_id);
bool put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado);
void fill_addr_to_alias_dict();
//bool resync_spent_tx_flags();
bool prune_ring_signatures_and_attachments_if_need();
bool prune_ring_signatures_and_attachments(uint64_t height, uint64_t& transactions_pruned, uint64_t& signatures_pruned, uint64_t& attachments_pruned);
// bool build_stake_modifier_for_alt(const alt_chain_type& alt_chain, stake_modifier_type& sm);
template<class visitor_t>
bool enum_blockchain(visitor_t& v, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0) const;
bool update_spent_tx_flags_for_input(uint64_t amount, const txout_ref_v& o, bool spent);
@ -663,13 +695,7 @@ namespace currency
bool is_output_allowed_for_input(const output_key_or_htlc_v& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const;
bool is_output_allowed_for_input(const txout_to_key& out_v, const txin_v& in_v)const;
bool is_output_allowed_for_input(const txout_htlc& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const;
bool is_after_hardfork_1_zone()const;
bool is_after_hardfork_1_zone(uint64_t height)const;
bool is_after_hardfork_2_zone()const;
bool is_after_hardfork_2_zone(uint64_t height)const;
bool is_after_hardfork_3_zone()const;
bool is_after_hardfork_3_zone(uint64_t height)const;
bool is_output_allowed_for_input(const tx_out_zarcanum& out, const txin_v& in_v) const;
@ -716,10 +742,10 @@ namespace currency
template<class visitor_t>
bool blockchain_storage::scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_v& verified_input, visitor_t& vis, uint64_t& max_related_block_height, scan_for_keys_context& scan_context) const
{
const txin_to_key& input_to_key = get_to_key_input_from_txin_v(verified_input);
bool hf4 = this->is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM);
uint64_t amount = input_to_key.amount;
const std::vector<txout_ref_v>& key_offsets = input_to_key.key_offsets;
uint64_t amount = get_amount_from_variant(verified_input);
const std::vector<txout_ref_v>& key_offsets = get_key_offsets_from_txin_v(verified_input);
CRITICAL_REGION_LOCAL(m_read_lock);
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_get_item_size);
@ -733,7 +759,7 @@ namespace currency
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_relative_to_absolute);
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop);
size_t output_index = 0;
for(const txout_ref_v& o : absolute_offsets)
for (const txout_ref_v& o : absolute_offsets)
{
crypto::hash tx_id = null_hash;
size_t n = 0;
@ -758,7 +784,7 @@ namespace currency
}
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_find_tx);
auto tx_ptr = m_db_transactions.find(tx_id);
CHECK_AND_ASSERT_MES(tx_ptr, false, "Wrong transaction id in output indexes: " << string_tools::pod_to_hex(tx_id));
CHECK_AND_ASSERT_MES(tx_ptr, false, "Wrong transaction id in output indexes: " << epst::pod_to_hex(tx_id));
CHECK_AND_ASSERT_MES(n < tx_ptr->tx.vout.size(), false,
"Wrong index in transaction outputs: " << n << ", expected less then " << tx_ptr->tx.vout.size());
//check mix_attr
@ -776,57 +802,109 @@ namespace currency
TO_KEY | TO_KEY | YES
*/
bool r = is_output_allowed_for_input(tx_ptr->tx.vout[n].target, verified_input, get_current_blockchain_size() - tx_ptr->m_keeper_block_height);
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
if (tx_ptr->tx.vout[n].target.type() == typeid(txout_to_key))
VARIANT_SWITCH_BEGIN(tx_ptr->tx.vout[n]);
VARIANT_CASE_CONST(tx_out_bare, o)
{
CHECKED_GET_SPECIFIC_VARIANT(tx_ptr->tx.vout[n].target, const txout_to_key, outtk, false);
//fix for burned money
patch_out_if_needed(const_cast<txout_to_key&>(outtk), tx_id, n);
bool r = is_output_allowed_for_input(o.target, verified_input, get_current_blockchain_size() - tx_ptr->m_keeper_block_height);
CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type");
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(outtk.mix_attr, key_offsets.size() - 1);
CHECK_AND_ASSERT_MES(mixattr_ok, false, "tx output #" << output_index << " violates mixin restrictions: mix_attr = " << static_cast<uint32_t>(outtk.mix_attr) << ", key_offsets.size = " << key_offsets.size());
}
else if (tx_ptr->tx.vout[n].target.type() == typeid(txout_htlc))
{
//check for spend flags
CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() > n, false,
"Internal error: tx_ptr->m_spent_flags.size(){" << tx_ptr->m_spent_flags.size() << "} > n{" << n << "}");
CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags[n] == false, false, "HTLC out already spent, double spent attempt detected");
const txout_htlc& htlc_out = boost::get<txout_htlc>(tx_ptr->tx.vout[n].target);
if (htlc_out.expiration > get_current_blockchain_size() - tx_ptr->m_keeper_block_height)
if (o.target.type() == typeid(txout_to_key))
{
//HTLC IS NOT expired, can be used ONLY by pkey_before_expiration and ONLY by HTLC input
scan_context.htlc_is_expired = false;
}
else
{
//HTLC IS expired, can be used ONLY by pkey_after_expiration and ONLY by to_key input
scan_context.htlc_is_expired = true;
}
}else
{
LOG_ERROR("[scan_outputkeys_for_indexes]: Wrong output type in : " << tx_ptr->tx.vout[n].target.type().name());
return false;
}
CHECKED_GET_SPECIFIC_VARIANT(o.target, const txout_to_key, outtk, false);
//fix for burned money
patch_out_if_needed(const_cast<txout_to_key&>(outtk), tx_id, n);
bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(tx_ptr->tx.version, outtk.mix_attr, key_offsets.size() - 1, this->get_core_runtime_config());
CHECK_AND_ASSERT_MES(mixattr_ok, false, "tx input ref #" << output_index << " violates mixin restrictions: tx.version = " << tx_ptr->tx.version << ", mix_attr = " << static_cast<uint32_t>(outtk.mix_attr) << ", key_offsets.size = " << key_offsets.size());
if (hf4)
{
bool legit_output_key = validate_output_key_legit(outtk.key);
CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << outtk.key);
}
}
else if (o.target.type() == typeid(txout_htlc))
{
//check for spend flags
CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() > n, false,
"Internal error: tx_ptr->m_spent_flags.size(){" << tx_ptr->m_spent_flags.size() << "} > n{" << n << "}");
CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags[n] == false, false, "HTLC out already spent, double spent attempt detected");
const txout_htlc& htlc_out = boost::get<txout_htlc>(o.target);
if (htlc_out.expiration > get_current_blockchain_size() - tx_ptr->m_keeper_block_height)
{
//HTLC IS NOT expired, can be used ONLY by pkey_before_expiration and ONLY by HTLC input
scan_context.htlc_is_expired = false;
}
else
{
//HTLC IS expired, can be used ONLY by pkey_after_expiration and ONLY by to_key input
scan_context.htlc_is_expired = true;
}
if (hf4)
{
bool legit_output_key = validate_output_key_legit(scan_context.htlc_is_expired ? htlc_out.pkey_refund : htlc_out.pkey_redeem);
CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << static_cast<const crypto::public_key&>(scan_context.htlc_is_expired ? htlc_out.pkey_refund : htlc_out.pkey_redeem));
}
}
else
{
LOG_ERROR("[scan_outputkeys_for_indexes]: Wrong output type in : " << o.target.type().name());
return false;
}
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
if (!vis.handle_output(tx_ptr->tx, validated_tx, o, n))
{
size_t verified_input_index = std::find(validated_tx.vin.begin(), validated_tx.vin.end(), verified_input) - validated_tx.vin.begin();
LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id << " referenced by input #" << verified_input_index << " in tx " << get_transaction_hash(validated_tx));
return false;
}
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
}
VARIANT_CASE_CONST(tx_out_zarcanum, out_zc)
bool r = is_output_allowed_for_input(out_zc, verified_input);
CHECK_AND_ASSERT_MES(r, false, "Input and output are incompatible");
r = is_mixattr_applicable_for_fake_outs_counter(tx_ptr->tx.version, out_zc.mix_attr, key_offsets.size() - 1, this->get_core_runtime_config());
CHECK_AND_ASSERT_MES(r, false, "tx input ref #" << output_index << " violates mixin restrictions: tx.version = " << tx_ptr->tx.version << ", mix_attr = " << static_cast<uint32_t>(out_zc.mix_attr) << ", key_offsets.size = " << key_offsets.size());
bool legit_output_key = validate_output_key_legit(out_zc.stealth_address);
CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << out_zc.stealth_address);
TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
if (!vis.handle_output(tx_ptr->tx, validated_tx, tx_ptr->tx.vout[n], n))
if (!vis.handle_output(tx_ptr->tx, validated_tx, out_zc, n))
{
LOG_PRINT_L0("Failed to handle_output for output id = " << tx_id << ", no " << n);
size_t verified_input_index = std::find(validated_tx.vin.begin(), validated_tx.vin.end(), verified_input) - validated_tx.vin.begin();
LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id << " referenced by input #" << verified_input_index << " in tx " << get_transaction_hash(validated_tx));
return false;
}
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output);
VARIANT_CASE_THROW_ON_OTHER();
VARIANT_SWITCH_END();
if (max_related_block_height < tx_ptr->m_keeper_block_height)
max_related_block_height = tx_ptr->m_keeper_block_height;
if (max_related_block_height < tx_ptr->m_keeper_block_height)
max_related_block_height = tx_ptr->m_keeper_block_height;
++output_index;
}
if (m_core_runtime_config.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, this->get_current_blockchain_size()))
{
//with hard fork 4 make it network rule to have at least 10 confirmations
if (this->get_current_blockchain_size() - max_related_block_height < CURRENCY_HF4_MANDATORY_MIN_COINAGE)
{
LOG_ERROR("Coinage rule broken(mainblock): h = " << this->get_current_blockchain_size() << ", max_related_block_height=" << max_related_block_height << ", tx: " << get_transaction_hash(validated_tx));
return false;
}
}
TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop);
return true;
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2023 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Copyright (c) 2012-2013 The Boolberry developers
@ -19,6 +19,8 @@
#include "currency_basic.h"
#include "difficulty.h"
#include "currency_protocol/blobdatatype.h"
#include "currency_format_utils_transactions.h" // only for output_generation_context
namespace currency
{
@ -46,9 +48,9 @@ namespace currency
block bl;
uint64_t height;
uint64_t block_cumulative_size;
wide_difficulty_type cumulative_diff_adjusted;
wide_difficulty_type cumulative_diff_adjusted; // used only before hardfork 1
wide_difficulty_type cumulative_diff_precise;
wide_difficulty_type cumulative_diff_precise_adjusted;
wide_difficulty_type cumulative_diff_precise_adjusted; //used after hardfork 1 (cumulative difficulty adjusted only by sequence factor)
wide_difficulty_type difficulty;
boost::multiprecision::uint128_t already_generated_coins;
crypto::hash stake_hash; //TODO: unused field for PoW blocks, subject for refactoring
@ -144,6 +146,10 @@ namespace currency
block b;
wide_difficulty_type diffic;
uint64_t height;
tx_generation_context miner_tx_tgc; // bad design, a lot of copying, consider redesign -- sowle
uint64_t block_reward_without_fee;
uint64_t block_reward; // == block_reward_without_fee + txs_fee if fees are given to the miner, OR block_reward_without_fee if fees are burnt
uint64_t txs_fee; // sum of transactions' fee if any
};
typedef std::unordered_map<crypto::hash, transaction> transactions_map;
@ -178,4 +184,4 @@ namespace currency
END_KV_SERIALIZE_MAP()
};
}
} // namespace currency

View file

@ -5,13 +5,97 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include "boost/serialization/array.hpp"
#include "misc_language.h"
#include "string_tools.h"
namespace currency
{
struct hard_forks_descriptor
{
constexpr static size_t m_total_count = ZANO_HARDFORKS_TOTAL;
std::array<uint64_t, m_total_count> m_height_the_hardfork_n_active_after;
hard_forks_descriptor()
{
clear();
}
void clear()
{
m_height_the_hardfork_n_active_after.fill(CURRENCY_MAX_BLOCK_NUMBER);
}
void set_hardfork_height(size_t hardfork_id, uint64_t height_the_hardfork_is_active_after)
{
CHECK_AND_ASSERT_THROW_MES(hardfork_id < m_total_count, "invalid hardfork id: " << hardfork_id);
m_height_the_hardfork_n_active_after[hardfork_id] = height_the_hardfork_is_active_after;
// set all unset previous hardforks to this height
for(size_t hid = hardfork_id - 1; hid + 1 != 0; --hid)
{
if (m_height_the_hardfork_n_active_after[hid] == CURRENCY_MAX_BLOCK_NUMBER)
m_height_the_hardfork_n_active_after[hid] = height_the_hardfork_is_active_after;
}
}
bool is_hardfork_active_for_height(size_t hardfork_id, uint64_t height) const
{
if (hardfork_id == 0)
return true; // hardfork #0 is a special case that is considered always active
CHECK_AND_ASSERT_THROW_MES(hardfork_id < m_total_count, "invalid hardfork id: " << hardfork_id);
return height > m_height_the_hardfork_n_active_after[hardfork_id];
}
std::string get_str_height_the_hardfork_active_after(size_t hardfork_id) const
{
if (hardfork_id == 0)
return "0"; // hardfork #0 is a special case that is considered always active
CHECK_AND_ASSERT_THROW_MES(hardfork_id < m_total_count, "invalid hardfork id: " << hardfork_id);
return epee::string_tools::num_to_string_fast(m_height_the_hardfork_n_active_after[hardfork_id]);
}
size_t get_the_most_recent_hardfork_id_for_height(uint64_t height) const
{
for(size_t hid = m_total_count - 1; hid != 0; --hid) // 0 is not including
{
if(is_hardfork_active_for_height(hid, height))
return hid;
}
return 0;
}
uint8_t get_block_major_version_by_height(uint64_t height) const
{
if (!this->is_hardfork_active_for_height(1, height))
return BLOCK_MAJOR_VERSION_INITIAL;
else if (!this->is_hardfork_active_for_height(3, height))
return HF1_BLOCK_MAJOR_VERSION;
else if (!this->is_hardfork_active_for_height(4, height))
return HF3_BLOCK_MAJOR_VERSION;
else
return CURRENT_BLOCK_MAJOR_VERSION;
}
uint8_t get_block_minor_version_by_height(uint64_t height) const
{
return HF3_BLOCK_MINOR_VERSION;
}
bool operator==(const hard_forks_descriptor& rhs) const
{
return m_height_the_hardfork_n_active_after == rhs.m_height_the_hardfork_n_active_after;
}
bool operator!=(const hard_forks_descriptor& rhs) const
{
return ! operator==(rhs);
}
};
typedef uint64_t (*core_time_func_t)();
struct core_runtime_config
{
uint64_t min_coinstake_age;
@ -21,21 +105,13 @@ namespace currency
uint64_t max_alt_blocks;
crypto::public_key alias_validation_pubkey;
core_time_func_t get_core_time;
uint64_t hf4_minimum_mixins;
uint64_t hard_fork_01_starts_after_height;
uint64_t hard_fork_02_starts_after_height;
uint64_t hard_fork_03_starts_after_height;
hard_forks_descriptor hard_forks;
bool is_hardfork_active_for_height(size_t hardfork_id, uint64_t height) const
{
switch (hardfork_id)
{
case 0: return true;
case 1: return height > hard_fork_01_starts_after_height;
case 2: return height > hard_fork_02_starts_after_height;
case 3: return height > hard_fork_03_starts_after_height;
default: return false;
}
return hard_forks.is_hardfork_active_for_height(hardfork_id, height);
}
static uint64_t _default_core_time_function()
@ -52,10 +128,13 @@ namespace currency
pc.tx_pool_min_fee = TX_MINIMUM_FEE;
pc.tx_default_fee = TX_DEFAULT_FEE;
pc.max_alt_blocks = CURRENCY_ALT_BLOCK_MAX_COUNT;
pc.hf4_minimum_mixins = CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE;
pc.hard_fork_01_starts_after_height = ZANO_HARDFORK_01_AFTER_HEIGHT;
pc.hard_fork_02_starts_after_height = ZANO_HARDFORK_02_AFTER_HEIGHT;
pc.hard_fork_03_starts_after_height = ZANO_HARDFORK_03_AFTER_HEIGHT;
// TODO: refactor the following
pc.hard_forks.set_hardfork_height(1, ZANO_HARDFORK_01_AFTER_HEIGHT);
pc.hard_forks.set_hardfork_height(2, ZANO_HARDFORK_02_AFTER_HEIGHT);
pc.hard_forks.set_hardfork_height(3, ZANO_HARDFORK_03_AFTER_HEIGHT);
pc.hard_forks.set_hardfork_height(4, ZANO_HARDFORK_04_AFTER_HEIGHT);
pc.get_core_time = &core_runtime_config::_default_core_time_function;
bool r = epee::string_tools::hex_to_pod(ALIAS_SHORT_NAMES_VALIDATION_PUB_KEY, pc.alias_validation_pubkey);

View file

@ -0,0 +1,43 @@
// Copyright (c) 2022-2023 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#pragma once
// hash domain separation strings, 32 bytes long (31 chars + \0)
//
#define CRYPTO_HDS_OUT_AMOUNT_MASK "ZANO_HDS_OUT_AMOUNT_MASK_______"
#define CRYPTO_HDS_OUT_AMOUNT_BLINDING_MASK "ZANO_HDS_OUT_AMOUNT_BLIND_MASK_"
#define CRYPTO_HDS_OUT_ASSET_BLINDING_MASK "ZANO_HDS_OUT_ASSET_BLIND_MASK__"
#define CRYPTO_HDS_OUT_CONCEALING_POINT "ZANO_HDS_OUT_CONCEALING_POINT__"
#define CRYPTO_HDS_CLSAG_GG_LAYER_0 "ZANO_HDS_CLSAG_GG_LAYER_ZERO___"
#define CRYPTO_HDS_CLSAG_GG_LAYER_1 "ZANO_HDS_CLSAG_GG_LAYER_ONE____"
#define CRYPTO_HDS_CLSAG_GG_CHALLENGE "ZANO_HDS_CLSAG_GG_CHALLENGE____"
#define CRYPTO_HDS_CLSAG_GGX_LAYER_0 "ZANO_HDS_CLSAG_GGX_LAYER_ZERO__"
#define CRYPTO_HDS_CLSAG_GGX_LAYER_1 "ZANO_HDS_CLSAG_GGX_LAYER_ONE___"
#define CRYPTO_HDS_CLSAG_GGX_LAYER_2 "ZANO_HDS_CLSAG_GGX_LAYER_TWO___"
#define CRYPTO_HDS_CLSAG_GGX_CHALLENGE "ZANO_HDS_CLSAG_GGX_CHALLENGE___"
#define CRYPTO_HDS_CLSAG_GGXG_LAYER_0 "ZANO_HDS_CLSAG_GGXG_LAYER_ZERO_"
#define CRYPTO_HDS_CLSAG_GGXG_LAYER_1 "ZANO_HDS_CLSAG_GGXG_LAYER_ONE__"
#define CRYPTO_HDS_CLSAG_GGXG_LAYER_2 "ZANO_HDS_CLSAG_GGXG_LAYER_TWO__"
#define CRYPTO_HDS_CLSAG_GGXG_LAYER_3 "ZANO_HDS_CLSAG_GGXG_LAYER_THREE"
#define CRYPTO_HDS_CLSAG_GGXG_CHALLENGE "ZANO_HDS_CLSAG_GGXG_CHALLENGE__"
#define CRYPTO_HDS_CLSAG_GGXXG_LAYER_0 "ZANO_HDS_CLSAG_GGXXG_LAYER_ZERO"
#define CRYPTO_HDS_CLSAG_GGXXG_LAYER_1 "ZANO_HDS_CLSAG_GGXXG_LAYER_ONE_"
#define CRYPTO_HDS_CLSAG_GGXXG_LAYER_2 "ZANO_HDS_CLSAG_GGXXG_LAYER_TWO_"
#define CRYPTO_HDS_CLSAG_GGXXG_LAYER_3 "ZANO_HDS_CLSAG_GGXXG_LAYER_3___"
#define CRYPTO_HDS_CLSAG_GGXXG_LAYER_4 "ZANO_HDS_CLSAG_GGXXG_LAYER_FOUR"
#define CRYPTO_HDS_CLSAG_GGXXG_CHALLENGE "ZANO_HDS_CLSAG_GGXXG_CHALLENGE_"
#define CRYPTO_HDS_ZARCANUM_LAST_POW_HASH "ZANO_HDS_ZARCANUM_LAST_POW_HASH"
#define CRYPTO_HDS_ZARCANUM_PROOF_HASH "ZANO_HDS_ZARCANUM_PROOF_HASH___"
#define CRYPTO_HDS_ASSET_CONTROL_KEY "ZANO_HDS_ASSET_CONTROL_KEY_____"
#define CRYPTO_HDS_ASSET_CONTROL_ABM "ZANO_HDS_ASSET_CONTROL_ABM_____"
#define CRYPTO_HDS_ASSET_ID "ZANO_HDS_ASSET_ID______________"
#define CRYPTO_HDS_DETERMINISTIC_TX_KEY "ZANO_HDS_DETERMINISTIC_TX_KEY__"

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2019 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Copyright (c) 2014-2015 The Boolberry developers
@ -26,10 +26,11 @@
#include "include_base_utils.h"
#include "serialization/binary_archive.h"
#include "serialization/crypto.h"
#include "common/crypto_serialization.h"
#include "serialization/stl_containers.h"
#include "serialization/serialization.h"
#include "serialization/variant.h"
#include "serialization/boost_types.h"
#include "serialization/json_archive.h"
#include "serialization/debug_archive.h"
#include "serialization/keyvalue_serialization.h" // epee key-value serialization
@ -37,9 +38,12 @@
#include "currency_config.h"
#include "crypto/crypto.h"
#include "crypto/hash.h"
#include "crypto/range_proofs.h"
#include "crypto/zarcanum.h"
#include "misc_language.h"
#include "block_flags.h"
#include "etc_custom_serialization.h"
#include "difficulty.h"
namespace currency
{
@ -53,6 +57,16 @@ namespace currency
const static crypto::hash gdefault_genesis = epee::string_tools::hex_to_pod<crypto::hash>("CC608F59F8080E2FBFE3C8C80EB6E6A953D47CF2D6AEBD345BADA3A1CAB99852");
// Using C++17 extended aggregate initialization (P0017R1). C++17, finally! -- sowle
const static crypto::public_key native_coin_asset_id = {{'\xd6', '\x32', '\x9b', '\x5b', '\x1f', '\x7c', '\x08', '\x05', '\xb5', '\xc3', '\x45', '\xf4', '\x95', '\x75', '\x54', '\x00', '\x2a', '\x2f', '\x55', '\x78', '\x45', '\xf6', '\x4d', '\x76', '\x45', '\xda', '\xe0', '\xe0', '\x51', '\xa6', '\x49', '\x8a'}}; // == crypto::c_point_H, checked in crypto_constants
const static crypto::public_key native_coin_asset_id_1div8 = {{'\x74', '\xc3', '\x2d', '\x3e', '\xaa', '\xfa', '\xfc', '\x62', '\x3b', '\xf4', '\x83', '\xe8', '\x58', '\xd4', '\x2e', '\x8b', '\xf4', '\xec', '\x7d', '\xf0', '\x64', '\xad', '\xa2', '\xe3', '\x49', '\x34', '\x46', '\x9c', '\xff', '\x6b', '\x62', '\x68'}}; // == 1/8 * crypto::c_point_H, checked in crypto_constants
const static crypto::point_t native_coin_asset_id_pt {{ 20574939, 16670001, -29137604, 14614582, 24883426, 3503293, 2667523, 420631, 2267646, -4769165, -11764015, -12206428, -14187565, -2328122, -16242653, -788308, -12595746, -8251557, -10110987, 853396, -4982135, 6035602, -21214320, 16156349, 977218, 2807645, 31002271, 5694305, -16054128, 5644146, -15047429, -568775, -22568195, -8089957, -27721961, -10101877, -29459620, -13359100, -31515170, -6994674 }}; // c_point_H
const static wide_difficulty_type global_difficulty_pow_starter = DIFFICULTY_POW_STARTER;
const static wide_difficulty_type global_difficulty_pos_starter = DIFFICULTY_POS_STARTER;
const static uint64_t global_difficulty_pos_target = DIFFICULTY_POS_TARGET;
const static uint64_t global_difficulty_pow_target = DIFFICULTY_POW_TARGET;
typedef std::string payment_id_t;
@ -208,16 +222,21 @@ namespace currency
typedef boost::variant<signed_parts, extra_attachment_info> txin_etc_details_v;
struct txin_to_key
struct referring_input
{
std::vector<txout_ref_v> key_offsets;
};
struct txin_to_key : public referring_input
{
uint64_t amount;
std::vector<txout_ref_v> key_offsets;
crypto::key_image k_image; // double spending protection
std::vector<txin_etc_details_v> etc_details; //this flag used when TX_FLAG_SIGNATURE_MODE_SEPARATE flag is set, point to which amount of outputs(starting from zero) used in signature
std::vector<txin_etc_details_v> etc_details; // see also TX_FLAG_SIGNATURE_MODE_SEPARATE
BEGIN_SERIALIZE_OBJECT()
VARINT_FIELD(amount)
FIELD(key_offsets)
FIELD(key_offsets) // from referring_input
FIELD(k_image)
FIELD(etc_details)
END_SERIALIZE()
@ -247,6 +266,7 @@ namespace currency
END_SERIALIZE()
};
struct txout_multisig
{
uint32_t minimum_sigs;
@ -277,12 +297,10 @@ namespace currency
END_SERIALIZE()
};
typedef boost::variant<txin_gen, txin_to_key, txin_multisig, txin_htlc> txin_v;
typedef boost::variant<txout_to_key, txout_multisig, txout_htlc> txout_target_v;
//typedef std::pair<uint64_t, txout> out_t;
struct tx_out
struct tx_out_bare
{
uint64_t amount;
txout_target_v target;
@ -294,6 +312,192 @@ namespace currency
};
/////////////////////////////////////////////////////////////////////////////
// Zarcanum structures
//
struct txin_zc_input : public referring_input
{
txin_zc_input() {}
// Boost's Assignable concept
txin_zc_input(const txin_zc_input&) = default;
txin_zc_input& operator=(const txin_zc_input&)= default;
crypto::key_image k_image;
std::vector<txin_etc_details_v> etc_details;
BEGIN_SERIALIZE_OBJECT()
FIELD(key_offsets) // referring_input
FIELD(k_image)
FIELD(etc_details)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(key_offsets) // referring_input
BOOST_SERIALIZE(k_image)
BOOST_SERIALIZE(etc_details)
END_BOOST_SERIALIZATION()
};
struct tx_out_zarcanum
{
tx_out_zarcanum() {}
// Boost's Assignable concept
tx_out_zarcanum(const tx_out_zarcanum&) = default;
tx_out_zarcanum& operator=(const tx_out_zarcanum&) = default;
crypto::public_key stealth_address;
crypto::public_key concealing_point; // group element Q, see also Zarcanum paper, premultiplied by 1/8
crypto::public_key amount_commitment; // premultiplied by 1/8
crypto::public_key blinded_asset_id; // group element T, premultiplied by 1/8
uint64_t encrypted_amount = 0;
uint8_t mix_attr = 0;
BEGIN_SERIALIZE_OBJECT()
FIELD(stealth_address)
FIELD(concealing_point)
FIELD(amount_commitment)
FIELD(blinded_asset_id)
FIELD(encrypted_amount)
FIELD(mix_attr)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(stealth_address)
BOOST_SERIALIZE(concealing_point)
BOOST_SERIALIZE(amount_commitment)
BOOST_SERIALIZE(blinded_asset_id)
BOOST_SERIALIZE(encrypted_amount)
BOOST_SERIALIZE(mix_attr)
END_BOOST_SERIALIZATION()
};
struct zarcanum_tx_data_v1
{
uint64_t fee;
BEGIN_SERIALIZE_OBJECT()
FIELD(fee)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(fee)
END_BOOST_SERIALIZATION()
};
struct zc_asset_surjection_proof
{
std::vector<crypto::BGE_proof_s> bge_proofs; // one per output, non-aggregated version of Groth-Bootle-Esgin yet, need to be upgraded later -- sowle
BEGIN_SERIALIZE_OBJECT()
FIELD(bge_proofs)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(bge_proofs)
END_BOOST_SERIALIZATION()
};
// non-consoditated txs must have one of this objects in the attachments (elements count == vout.size())
// consolidated -- one pre consolidated part (sum(elements count) == vout.size())
struct zc_outs_range_proof
{
crypto::bpp_signature_serialized bpp; // for commitments in form: amount * U + mask * G
crypto::vector_UG_aggregation_proof_serialized aggregation_proof; // E'_j = e_j * U + y'_j * G + vector Shnorr
BEGIN_SERIALIZE_OBJECT()
FIELD(bpp)
FIELD(aggregation_proof)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(bpp)
BOOST_SERIALIZE(aggregation_proof)
END_BOOST_SERIALIZATION()
};
// Zarcanum-aware CLSAG signature (one per ZC input)
struct ZC_sig
{
crypto::public_key pseudo_out_amount_commitment = null_pkey; // premultiplied by 1/8
crypto::public_key pseudo_out_blinded_asset_id = null_pkey; // premultiplied by 1/8
crypto::CLSAG_GGX_signature_serialized clsags_ggx;
BEGIN_SERIALIZE_OBJECT()
FIELD(pseudo_out_amount_commitment)
FIELD(pseudo_out_blinded_asset_id)
FIELD(clsags_ggx)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(pseudo_out_amount_commitment)
BOOST_SERIALIZE(pseudo_out_blinded_asset_id)
BOOST_SERIALIZE(clsags_ggx)
END_BOOST_SERIALIZATION()
};
// First part of a double Schnorr proof:
// 1) for txs without ZC inputs: proves that balance point = lin(G) (cancels out G component of outputs' amount commitments, asset tags assumed to be H (native coin) and non-blinded)
// 2) for txs with ZC inputs: proves that balance point = lin(X) (cancels out X component of blinded asset tags within amount commitments for both outputs and inputs (pseudo outs))
// Second part:
// proof of knowing transaction secret key (with respect to G)
struct zc_balance_proof
{
crypto::generic_double_schnorr_sig_s dss;
BEGIN_SERIALIZE_OBJECT()
FIELD(dss)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(dss)
END_BOOST_SERIALIZATION()
};
struct zarcanum_sig : public crypto::zarcanum_proof
{
BEGIN_SERIALIZE_OBJECT()
FIELD(d)
FIELD(C)
FIELD(C_prime);
FIELD(E);
FIELD(c);
FIELD(y0);
FIELD(y1);
FIELD(y2);
FIELD(y3);
FIELD(y4);
FIELD_N("E_range_proof", (crypto::bppe_signature_serialized&)E_range_proof);
FIELD(pseudo_out_amount_commitment);
FIELD_N("clsag_ggxxg", (crypto::CLSAG_GGXXG_signature_serialized&)clsag_ggxxg);
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(d)
BOOST_SERIALIZE(C)
BOOST_SERIALIZE(C_prime);
BOOST_SERIALIZE(E);
BOOST_SERIALIZE(c);
BOOST_SERIALIZE(y0);
BOOST_SERIALIZE(y1);
BOOST_SERIALIZE(y2);
BOOST_SERIALIZE(y3);
BOOST_SERIALIZE(y4);
BOOST_SERIALIZE((crypto::bppe_signature_serialized&)E_range_proof);
BOOST_SERIALIZE(pseudo_out_amount_commitment);
BOOST_SERIALIZE((crypto::CLSAG_GGXXG_signature_serialized&)clsag_ggxxg);
END_BOOST_SERIALIZATION()
};
//#pragma pack(pop)
typedef boost::variant<txin_gen, txin_to_key, txin_multisig, txin_htlc, txin_zc_input> txin_v;
typedef boost::variant<tx_out_bare, tx_out_zarcanum> tx_out_v;
struct tx_comment
{
@ -470,8 +674,7 @@ namespace currency
extra_alias_entry(const extra_alias_entry_old& old)
: extra_alias_entry_base(old)
, m_alias(old.m_alias)
{
}
{}
std::string m_alias;
@ -493,6 +696,142 @@ namespace currency
};
struct asset_descriptor_base
{
uint64_t total_max_supply = 0;
uint64_t current_supply = 0;
uint8_t decimal_point = 12;
std::string ticker;
std::string full_name;
std::string meta_info;
crypto::public_key owner = currency::null_pkey; // consider premultipling by 1/8
bool hidden_supply = false;
uint8_t version = 0;
BEGIN_VERSIONED_SERIALIZE(0, version)
FIELD(total_max_supply)
FIELD(current_supply)
FIELD(decimal_point)
FIELD(ticker)
FIELD(full_name)
FIELD(meta_info)
FIELD(owner)
FIELD(hidden_supply)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(total_max_supply)
BOOST_SERIALIZE(current_supply)
BOOST_SERIALIZE(decimal_point)
BOOST_SERIALIZE(ticker)
BOOST_SERIALIZE(full_name)
BOOST_SERIALIZE(meta_info)
BOOST_SERIALIZE(owner)
BOOST_SERIALIZE(hidden_supply)
END_BOOST_SERIALIZATION()
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(total_max_supply)
KV_SERIALIZE(current_supply)
KV_SERIALIZE(decimal_point)
KV_SERIALIZE(ticker)
KV_SERIALIZE(full_name)
KV_SERIALIZE(meta_info)
KV_SERIALIZE_POD_AS_HEX_STRING(owner)
KV_SERIALIZE(hidden_supply)
END_KV_SERIALIZE_MAP()
};
struct asset_descriptor_with_id: public asset_descriptor_base
{
crypto::public_key asset_id = currency::null_pkey;
/*
BEGIN_VERSIONED_SERIALIZE()
FIELD(*static_cast<asset_descriptor_base>(this))
FIELD(asset_id)
END_SERIALIZE()
*/
BEGIN_KV_SERIALIZE_MAP()
KV_CHAIN_BASE(asset_descriptor_base)
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id)
END_KV_SERIALIZE_MAP()
};
#define ASSET_DESCRIPTOR_OPERATION_UNDEFINED 0
#define ASSET_DESCRIPTOR_OPERATION_REGISTER 1
#define ASSET_DESCRIPTOR_OPERATION_EMIT 2
#define ASSET_DESCRIPTOR_OPERATION_UPDATE 3
#define ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN 4
#define ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER 1
struct asset_descriptor_operation
{
uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED;
asset_descriptor_base descriptor;
crypto::public_key amount_commitment; // premultiplied by 1/8
boost::optional<crypto::public_key> opt_asset_id; // target asset_id - for update/emit
uint8_t verion = ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER;
BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER, verion)
FIELD(operation_type)
FIELD(descriptor)
FIELD(amount_commitment)
END_VERSION_UNDER(1)
FIELD(opt_asset_id)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(operation_type)
BOOST_SERIALIZE(descriptor)
BOOST_SERIALIZE(amount_commitment)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(opt_asset_id)
END_BOOST_SERIALIZATION()
};
struct asset_operation_proof
{
// linear composition proof for the fact amount_commitment = lin(asset_id, G)
boost::optional<crypto::linear_composition_proof_s> opt_amount_commitment_composition_proof; // for hidden supply
boost::optional<crypto::signature> opt_amount_commitment_g_proof; // for non-hidden supply, proofs that amount_commitment - supply * asset_id = lin(G)
uint8_t version = 0;
BEGIN_VERSIONED_SERIALIZE(0, version)
FIELD(opt_amount_commitment_composition_proof)
FIELD(opt_amount_commitment_g_proof)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(opt_amount_commitment_composition_proof)
BOOST_SERIALIZE(opt_amount_commitment_g_proof)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(version)
END_BOOST_SERIALIZATION()
};
struct asset_operation_ownership_proof
{
crypto::generic_schnorr_sig_s gss;
uint8_t version = 0;
BEGIN_VERSIONED_SERIALIZE(0, version)
FIELD(gss)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(gss)
BOOST_END_VERSION_UNDER(1)
BOOST_SERIALIZE(version)
END_BOOST_SERIALIZATION()
};
struct extra_padding
{
@ -558,10 +897,10 @@ namespace currency
END_SERIALIZE()
};
typedef boost::mpl::vector21<
typedef boost::mpl::vector23<
tx_service_attachment, tx_comment, tx_payer_old, tx_receiver_old, tx_derivation_hint, std::string, tx_crypto_checksum, etc_tx_time, etc_tx_details_unlock_time, etc_tx_details_expiration_time,
etc_tx_details_flags, crypto::public_key, extra_attachment_info, extra_alias_entry_old, extra_user_data, extra_padding, etc_tx_flags16_t, etc_tx_details_unlock_time2,
tx_payer, tx_receiver, extra_alias_entry
tx_payer, tx_receiver, extra_alias_entry, zarcanum_tx_data_v1, asset_descriptor_operation
> all_payload_types;
typedef boost::make_variant_over<all_payload_types>::type payload_items_v;
@ -569,26 +908,57 @@ namespace currency
typedef payload_items_v attachment_v;
//classic CryptoNote signature by Nicolas Van Saberhagen
struct NLSAG_sig
{
std::vector<crypto::signature> s;
BEGIN_SERIALIZE_OBJECT()
FIELD(s)
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
BOOST_SERIALIZE(s)
END_BOOST_SERIALIZATION()
};
struct void_sig
{
//TODO:
BEGIN_SERIALIZE_OBJECT()
END_SERIALIZE()
BEGIN_BOOST_SERIALIZATION()
END_BOOST_SERIALIZATION()
};
typedef boost::variant<NLSAG_sig, void_sig, ZC_sig, zarcanum_sig> signature_v;
typedef boost::variant<zc_asset_surjection_proof, zc_outs_range_proof, zc_balance_proof, asset_operation_proof, asset_operation_ownership_proof> proof_v;
//include backward compatibility defintions
#include "currency_basic_backward_comp.inl"
class transaction_prefix
{
public:
// tx version information
uint64_t version{};
//extra
std::vector<extra_v> extra;
uint64_t version = 0;
std::vector<txin_v> vin;
std::vector<tx_out> vout;
std::vector<extra_v> extra;
std::vector<tx_out_v> vout;
BEGIN_SERIALIZE()
VARINT_FIELD(version)
CHAIN_TRANSITION_VER(TRANSACTION_VERSION_INITAL, transaction_prefix_v1)
CHAIN_TRANSITION_VER(TRANSACTION_VERSION_PRE_HF4, transaction_prefix_v1)
if(CURRENT_TRANSACTION_VERSION < version) return false;
FIELD(vin)
FIELD(vout)
FIELD(extra)
FIELD(vout)
END_SERIALIZE()
protected:
transaction_prefix(){}
};
/*
@ -604,55 +974,23 @@ namespace currency
class transaction: public transaction_prefix
{
public:
std::vector<std::vector<crypto::signature> > signatures; //count signatures always the same as inputs count
std::vector<attachment_v> attachment;
transaction();
std::vector<signature_v> signatures;
std::vector<proof_v> proofs;
BEGIN_SERIALIZE_OBJECT()
FIELDS(*static_cast<transaction_prefix *>(this))
FIELD(signatures)
CHAIN_TRANSITION_VER(TRANSACTION_VERSION_INITAL, transaction_v1)
CHAIN_TRANSITION_VER(TRANSACTION_VERSION_PRE_HF4, transaction_v1)
FIELD(attachment)
FIELD(signatures)
FIELD(proofs)
END_SERIALIZE()
};
inline
transaction::transaction()
{
version = 0;
vin.clear();
vout.clear();
extra.clear();
signatures.clear();
attachment.clear();
}
/*
inline
transaction::~transaction()
{
//set_null();
}
inline
void transaction::set_null()
{
version = 0;
unlock_time = 0;
vin.clear();
vout.clear();
extra.clear();
signatures.clear();
}
*/
/************************************************************************/
/* */
@ -714,8 +1052,6 @@ namespace currency
*/
//-------------------------------------------------------------------------------------------------------------------
#pragma pack(push, 1)
struct stake_modifier_type
{
@ -725,7 +1061,6 @@ namespace currency
struct stake_kernel
{
stake_modifier_type stake_modifier;
uint64_t block_timestamp; //this block timestamp
crypto::key_image kimage;
@ -735,22 +1070,45 @@ namespace currency
struct pos_entry
{
uint64_t amount;
uint64_t index;
uint64_t g_index; // global output index. (could be WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED)
crypto::key_image keyimage;
uint64_t block_timestamp;
uint64_t stake_unlock_time;
crypto::hash tx_id; // stake output source tx id
uint64_t tx_out_index; // stake output local index in its tx
//not for serialization
uint64_t wallet_index;
uint64_t wallet_index; // transfer id index
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(amount)
KV_SERIALIZE(index)
KV_SERIALIZE(g_index)
KV_SERIALIZE(stake_unlock_time)
KV_SERIALIZE(block_timestamp)
KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(keyimage)
KV_SERIALIZE(tx_id)
KV_SERIALIZE(tx_out_index)
END_KV_SERIALIZE_MAP()
};
bool operator ==(const currency::transaction& a, const currency::transaction& b);
bool operator ==(const currency::block& a, const currency::block& b);
bool operator ==(const currency::extra_attachment_info& a, const currency::extra_attachment_info& b);
bool operator ==(const currency::NLSAG_sig& a, const currency::NLSAG_sig& b);
bool operator ==(const currency::void_sig& a, const currency::void_sig& b);
bool operator ==(const currency::ZC_sig& a, const currency::ZC_sig& b);
bool operator ==(const currency::zarcanum_sig& a, const currency::zarcanum_sig& b);
bool operator ==(const currency::ref_by_id& a, const currency::ref_by_id& b);
// TODO: REPLACE all of the following operators to "bool operator==(..) const = default" once we moved to C++20 -- sowle
bool operator ==(const currency::signed_parts& a, const currency::signed_parts& b);
bool operator ==(const currency::txin_gen& a, const currency::txin_gen& b);
bool operator ==(const currency::txin_to_key& a, const currency::txin_to_key& b);
bool operator ==(const currency::txin_multisig& a, const currency::txin_multisig& b);
bool operator ==(const currency::txin_htlc& a, const currency::txin_htlc& b);
bool operator ==(const currency::txin_zc_input& a, const currency::txin_zc_input& b);
} // namespace currency
POD_MAKE_HASHABLE(currency, account_public_address);
@ -763,6 +1121,10 @@ BLOB_SERIALIZER(currency::txout_to_key);
VARIANT_TAG(json_archive, type_name, json_tag)
BOOST_CLASS_VERSION(currency::asset_descriptor_operation, 1);
BOOST_CLASS_VERSION(currency::asset_operation_proof, 1);
BOOST_CLASS_VERSION(currency::asset_operation_ownership_proof, 1);
// txin_v variant currency
SET_VARIANT_TAGS(currency::txin_gen, 0, "gen");
@ -814,6 +1176,27 @@ SET_VARIANT_TAGS(currency::extra_alias_entry, 33, "alias_entry2");
SET_VARIANT_TAGS(currency::txin_htlc, 34, "txin_htlc");
SET_VARIANT_TAGS(currency::txout_htlc, 35, "txout_htlc");
SET_VARIANT_TAGS(currency::tx_out_bare, 36, "tx_out_bare");
// Zarcanum
SET_VARIANT_TAGS(currency::txin_zc_input, 37, "txin_zc_input");
SET_VARIANT_TAGS(currency::tx_out_zarcanum, 38, "tx_out_zarcanum");
SET_VARIANT_TAGS(currency::zarcanum_tx_data_v1, 39, "zarcanum_tx_data_v1");
SET_VARIANT_TAGS(crypto::bpp_signature_serialized, 40, "bpp_signature_serialized");
SET_VARIANT_TAGS(crypto::bppe_signature_serialized, 41, "bppe_signature_serialized");
SET_VARIANT_TAGS(currency::NLSAG_sig, 42, "NLSAG_sig");
SET_VARIANT_TAGS(currency::ZC_sig, 43, "ZC_sig");
SET_VARIANT_TAGS(currency::void_sig, 44, "void_sig");
SET_VARIANT_TAGS(currency::zarcanum_sig, 45, "zarcanum_sig");
SET_VARIANT_TAGS(currency::zc_asset_surjection_proof, 46, "zc_asset_surjection_proof");
SET_VARIANT_TAGS(currency::zc_outs_range_proof, 47, "zc_outs_range_proof");
SET_VARIANT_TAGS(currency::zc_balance_proof, 48, "zc_balance_proof");
SET_VARIANT_TAGS(currency::asset_descriptor_operation, 49, "asset_descriptor_base");
SET_VARIANT_TAGS(currency::asset_operation_proof, 50, "asset_operation_proof");
SET_VARIANT_TAGS(currency::asset_operation_ownership_proof, 51, "asset_operation_ownership_proof");
#undef SET_VARIANT_TAGS

View file

@ -0,0 +1,118 @@
// Copyright (c) 2014-2022 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
class transaction_prefix_v1
{
public:
// tx version information
uint64_t version{};
//extra
std::vector<extra_v> extra;
std::vector<txin_v> vin;
std::vector<tx_out_bare> vout;//std::vector<tx_out> vout;
BEGIN_SERIALIZE()
//VARINT_FIELD(version) <-- this already unserialized
if (TRANSACTION_VERSION_PRE_HF4 < version) return false;
FIELD(vin)
FIELD(vout)
FIELD(extra)
END_SERIALIZE()
};
/*
class transaction_prefix_v1_full
{
public:
// tx version information
uint64_t version{};
//extra
std::vector<extra_v> extra;
std::vector<txin_v> vin;
std::vector<tx_out_old> vout;//std::vector<tx_out> vout;
BEGIN_SERIALIZE()
VARINT_FIELD(version)
if (TRANSACTION_VERSION_PRE_HF4 < version) return false;
FIELD(vin)
FIELD(vout)
FIELD(extra)
END_SERIALIZE()
};
*/
template<typename transaction_prefix_current_t>
bool transition_convert(const transaction_prefix_current_t& from, transaction_prefix_v1& to)
{
to.extra = from.extra;
to.vin = from.vin;
for (const auto& v : from.vout)
{
if (v.type() == typeid(tx_out_bare))
{
to.vout.push_back(boost::get<tx_out_bare>(v));
}
else {
throw std::runtime_error("Unexpected type in tx_out_v");
}
}
return true;
}
template<typename transaction_prefix_current_t>
bool transition_convert(const transaction_prefix_v1& from, transaction_prefix_current_t& to)
{
to.extra = from.extra;
to.vin = from.vin;
for (const auto& v : from.vout)
{
to.vout.push_back(v);
}
return true;
}
class transaction_v1
{
public:
std::vector<std::vector<crypto::signature> > signatures; //count signatures always the same as inputs count
std::vector<attachment_v> attachment;
BEGIN_SERIALIZE_OBJECT()
FIELD(signatures)
FIELD(attachment)
END_SERIALIZE()
};
template<typename transaction_current_t>
bool transition_convert(const transaction_current_t& from, transaction_v1& to)
{
to.attachment = from.attachment;
for (const auto& s : from.signatures)
{
if (s.type() == typeid(NLSAG_sig))
{
to.signatures.push_back(boost::get<NLSAG_sig>(s).s);
}
else
{
throw std::runtime_error(std::string("Unexpected type in tx.signatures during transition_convert: ") + s.type().name());
}
}
return true;
}
template<typename transaction_current_t>
bool transition_convert(const transaction_v1& from, transaction_current_t& to)
{
// TODO: consider using move semantic for 'from'
to.attachment = from.attachment;
to.signatures.resize(from.signatures.size());
for (size_t i = 0; i != from.signatures.size(); i++)
{
boost::get<NLSAG_sig>(to.signatures[i]).s = from.signatures[i];
}
return true;
}

View file

@ -15,7 +15,7 @@
#include <boost/serialization/is_bitwise_serializable.hpp>
#include "currency_basic.h"
#include "common/unordered_containers_boost_serialization.h"
#include "common/crypto_boost_serialization.h"
#include "common/crypto_serialization.h"
#include "offers_services_helpers.h"
#define CURRENT_BLOCK_ARCHIVE_VER 2
@ -104,13 +104,22 @@ namespace boost
}
template <class Archive>
inline void serialize(Archive &a, currency::tx_out &x, const boost::serialization::version_type ver)
inline void serialize(Archive &a, currency::tx_out_bare &x, const boost::serialization::version_type ver)
{
a & x.amount;
a & x.target;
}
template <class Archive>
inline void serialize(Archive &a, currency::tx_out_zarcanum &x, const boost::serialization::version_type ver)
{
a & x.stealth_address;
a & x.concealing_point;
a & x.amount_commitment;
a & x.blinded_asset_id;
a & x.encrypted_amount;
a & x.mix_attr;
}
template <class Archive>
inline void serialize(Archive &a, currency::tx_comment &x, const boost::serialization::version_type ver)

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2019 Zano Project
// Copyright (c) 2014-2024 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -10,7 +10,7 @@
#ifndef TESTNET
#define CURRENCY_FORMATION_VERSION 84
#else
#define CURRENCY_FORMATION_VERSION 88
#define CURRENCY_FORMATION_VERSION 97
#endif
#define CURRENCY_GENESIS_NONCE (CURRENCY_FORMATION_VERSION + 101011010121) //bender's nightmare
@ -20,17 +20,25 @@
#define CURRENCY_MAX_BLOCK_NUMBER 500000000
#define CURRENCY_MAX_BLOCK_SIZE 500000000 // block header blob limit, never used!
#define CURRENCY_TX_MAX_ALLOWED_OUTS 2000
#define CURRENCY_TX_MIN_ALLOWED_OUTS 2 // effective starting HF4 Zarcanum
#define CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX 0xc5 // addresses start with 'Zx'
#define CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX 0x3678 // integrated addresses start with 'iZ'
#define CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX 0x36f8 // integrated addresses start with 'iZ' (new format)
#define CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX 0x98c8 // auditable addresses start with 'aZx'
#define CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX 0x8a49 // auditable integrated addresses start with 'aiZX'
#define CURRENCY_MINED_MONEY_UNLOCK_WINDOW 10
#define CURRENT_TRANSACTION_VERSION 1
#define CURRENT_TRANSACTION_VERSION 2
#define TRANSACTION_VERSION_INITAL 0
#define TRANSACTION_VERSION_PRE_HF4 1
#define TRANSACTION_VERSION_POST_HF4 2
#define HF1_BLOCK_MAJOR_VERSION 1
#define CURRENT_BLOCK_MAJOR_VERSION 2
#define HF3_BLOCK_MAJOR_VERSION 2
#define HF3_BLOCK_MINOR_VERSION 0
#define CURRENT_BLOCK_MAJOR_VERSION 3
#define CURRENCY_DEFAULT_DECOY_SET_SIZE 10
#define CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE 15
#define CURRENCY_HF4_MANDATORY_MIN_COINAGE 10
#define CURRENT_BLOCK_MINOR_VERSION 0
#define CURRENCY_BLOCK_FUTURE_TIME_LIMIT 60*60*2
@ -60,8 +68,9 @@
#define WALLET_MAX_ALLOWED_OUTPUT_AMOUNT ((uint64_t)0xffffffffffffffffLL)
#define CURRENCY_MINER_TX_MAX_OUTS CURRENCY_TX_MAX_ALLOWED_OUTS
#define CURRENCY_TX_OUTS_RND_SPLIT_DIGITS_TO_KEEP 3
#define DIFFICULTY_STARTER 1
#define DIFFICULTY_POW_STARTER 1
#define DIFFICULTY_POS_TARGET 120 // seconds
#define DIFFICULTY_POW_TARGET 120 // seconds
#define DIFFICULTY_TOTAL_TARGET ((DIFFICULTY_POS_TARGET + DIFFICULTY_POW_TARGET) / 4)
@ -106,6 +115,7 @@
#define STRATUM_DEFAULT_PORT 11777
#define P2P_NETWORK_ID_TESTNET_FLAG 0
#define P2P_MAINTAINERS_PUB_KEY "8f138bb73f6d663a3746a542770781a09579a7b84cb4125249e95530824ee607"
#define DIFFICULTY_POS_STARTER 1
#else
#define P2P_DEFAULT_PORT (11112 + CURRENCY_FORMATION_VERSION)
#define RPC_DEFAULT_PORT 12111
@ -113,6 +123,7 @@
#define STRARUM_DEFAULT_PORT 51113
#define P2P_NETWORK_ID_TESTNET_FLAG 1
#define P2P_MAINTAINERS_PUB_KEY "aaa2d7aabc8d383fd53a3ae898697b28f236ceade6bafc1eecff413a6a02272a"
#define DIFFICULTY_POS_STARTER 1
#endif
#define P2P_NETWORK_ID_VER (CURRENCY_FORMATION_VERSION+0)
@ -147,6 +158,15 @@
#define POS_WALLET_MINING_SCAN_INTERVAL POS_SCAN_STEP //seconds
#define POS_MINIMUM_COINSTAKE_AGE 10 // blocks count
#ifndef TESTNET
# define BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION 57000
#else
# define BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION 18000
#endif
#define BLOCK_POS_STRICT_SEQUENCE_LIMIT 20 // the highest allowed sequence factor for a PoS block (i.e., the max total number of sequential PoS blocks is BLOCK_POS_STRICT_SEQUENCE_LIMIT + 1)
#define CORE_FEE_BLOCKS_LOOKUP_WINDOW 60 //number of blocks used to check if transaction flow is big enought to rise default fee
#define WALLET_FILE_SIGNATURE_OLD 0x1111012101101011LL // Bender's nightmare
#define WALLET_FILE_SIGNATURE_V2 0x1111011201101011LL // another Bender's nightmare
@ -207,7 +227,7 @@
#define CURRENCY_POOLDATA_FOLDERNAME_PREFIX "poolstate_"
#define CURRENCY_POOLDATA_FOLDERNAME_SUFFIX "_v1"
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX "blockchain_"
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX "_v1"
#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX "_v2"
#define P2P_NET_DATA_FILENAME "p2pstate.bin"
#define MINER_CONFIG_FILENAME "miner_conf.json"
@ -230,9 +250,11 @@
#define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin"
#ifndef TESTNET
#define WALLET_FILE_SERIALIZATION_VERSION 153
#define WALLET_FILE_SERIALIZATION_VERSION 162
#define WALLET_FILE_LAST_SUPPORTED_VERSION 162
#else
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+69)
#define WALLET_FILE_LAST_SUPPORTED_VERSION (CURRENCY_FORMATION_VERSION+76)
#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+76)
#endif
#define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31)
@ -242,19 +264,39 @@
#define BLOCK_MINOR_VERSION_GENESIS 0
#define BLOCK_MAJOR_VERSION_INITIAL 0
#ifndef TESTNET
#define ZANO_HARDFORK_01_AFTER_HEIGHT 194624
#define ZANO_HARDFORK_02_AFTER_HEIGHT 999999
#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577
#define ZANO_HARDFORK_01_AFTER_HEIGHT 194624 // 2019-09-21 20:25:16
#define ZANO_HARDFORK_02_AFTER_HEIGHT 999999 // 2021-04-05 09:11:45
#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577 // 2021-06-01 23:28:10
#define ZANO_HARDFORK_04_AFTER_HEIGHT 2555000 // 2024-03-21 10:16:46 (expected)
#else
#define ZANO_HARDFORK_01_AFTER_HEIGHT 1440
#define ZANO_HARDFORK_02_AFTER_HEIGHT 1800
#define ZANO_HARDFORK_03_AFTER_HEIGHT 1801
/////// Zarcanum Testnet //////////////////////////////
#define ZANO_HARDFORK_01_AFTER_HEIGHT 0
#define ZANO_HARDFORK_02_AFTER_HEIGHT 0
#define ZANO_HARDFORK_03_AFTER_HEIGHT 0
#define ZANO_HARDFORK_04_AFTER_HEIGHT 2440
#endif
#define ZANO_HARDFORK_00_INITAL 0
#define ZANO_HARDFORK_01 1
#define ZANO_HARDFORK_02 2
#define ZANO_HARDFORK_03 3
#define ZANO_HARDFORK_04_ZARCANUM 4
#define ZANO_HARDFORKS_TOTAL 5
static_assert(CURRENCY_MINER_TX_MAX_OUTS <= CURRENCY_TX_MAX_ALLOWED_OUTS, "Miner tx must obey normal tx max outs limit");
static_assert(PREMINE_AMOUNT / WALLET_MAX_ALLOWED_OUTPUT_AMOUNT < CURRENCY_MINER_TX_MAX_OUTS, "Premine can't be divided into reasonable number of outs");
#define CURRENCY_RELAY_TXS_MAX_COUNT 5
#define CURRENCY_RELAY_TXS_MAX_COUNT 5
#ifndef TESTNET
#define WALLET_ASSETS_WHITELIST_URL "https://api.zano.org/assets_whitelist.json"
#else
#define WALLET_ASSETS_WHITELIST_URL "https://api.zano.org/assets_whitelist_testnet.json"
#endif
#define WALLET_ASSETS_WHITELIST_VALIDATION_PUBLIC_KEY "" //TODO@#@

View file

@ -76,7 +76,10 @@ namespace currency
bool core::handle_command_line(const boost::program_options::variables_map& vm)
{
m_config_folder = command_line::get_arg(vm, command_line::arg_data_dir);
m_stop_after_height = static_cast<uint64_t>(command_line::get_arg(vm, command_line::arg_stop_after_height));
m_stop_after_height = 0;
if(command_line::has_arg(vm, command_line::arg_stop_after_height))
m_stop_after_height = static_cast<uint64_t>(command_line::get_arg(vm, command_line::arg_stop_after_height));
if (m_stop_after_height != 0)
{
LOG_PRINT_YELLOW("Daemon will STOP after block " << m_stop_after_height, LOG_LEVEL_0);
@ -89,6 +92,11 @@ namespace currency
return m_blockchain_storage.get_current_blockchain_size();
}
//-----------------------------------------------------------------------------------------------
uint64_t core::get_current_tx_version() const
{
return get_tx_version(m_blockchain_storage.get_current_blockchain_size(), m_blockchain_storage.get_core_runtime_config().hard_forks);
}
//-----------------------------------------------------------------------------------------------
uint64_t core::get_top_block_height() const
{
return m_blockchain_storage.get_top_block_height();
@ -350,7 +358,7 @@ namespace currency
//-----------------------------------------------------------------------------------------------
bool core::get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe)
{
return m_blockchain_storage.create_block_template(b, adr, stakeholder_address, diffic, height, ex_nonce, pos, pe);
return m_blockchain_storage.create_block_template(adr, stakeholder_address, ex_nonce, pos, pe, nullptr, b, diffic, height);
}
//-----------------------------------------------------------------------------------------------
bool core::get_block_template(const create_block_template_params& params, create_block_template_response& resp)
@ -511,12 +519,25 @@ namespace currency
bool r = m_blockchain_storage.add_new_block(b, bvc);
if (r && bvc.m_added_to_main_chain)
{
h = get_block_height(b);
auto& crc = m_blockchain_storage.get_core_runtime_config();
if (h == crc.hard_fork_01_starts_after_height + 1)
{ LOG_PRINT_GREEN("Hardfork 1 activated at height " << h, LOG_LEVEL_0); }
else if (h == crc.hard_fork_02_starts_after_height + 1)
{ LOG_PRINT_GREEN("Hardfork 2 activated at height " << h, LOG_LEVEL_0); }
uint64_t h = get_block_height(b);
if (h > 0)
{
auto& crc = m_blockchain_storage.get_core_runtime_config();
size_t hardfork_id_for_prev_block = crc.hard_forks.get_the_most_recent_hardfork_id_for_height(h);
size_t hardfork_id_for_curr_block = crc.hard_forks.get_the_most_recent_hardfork_id_for_height(h + 1);
if (hardfork_id_for_prev_block != hardfork_id_for_curr_block)
{
LOG_PRINT_GREEN("Hardfork " << hardfork_id_for_curr_block << " has been activated after the block at height " << h, LOG_LEVEL_0);
}
}
if (h == m_stop_after_height)
{
LOG_PRINT_YELLOW("Reached block " << h << ", the daemon will now stop as requested", LOG_LEVEL_0);
if (m_critical_error_handler)
return m_critical_error_handler->on_immediate_stop_requested();
return false;
}
}
return r;
}

View file

@ -63,6 +63,7 @@ namespace currency
bool set_genesis_block(const block& b);
bool deinit();
uint64_t get_current_blockchain_size() const;
uint64_t get_current_tx_version() const;
uint64_t get_top_block_height() const;
std::string get_config_folder();
bool get_blockchain_top(uint64_t& heeight, crypto::hash& top_id) const;
@ -139,18 +140,18 @@ namespace currency
tx_memory_pool m_mempool;
i_currency_protocol* m_pprotocol;
i_critical_error_handler* m_critical_error_handler;
critical_section m_incoming_tx_lock;
epee::critical_section m_incoming_tx_lock;
miner m_miner;
account_public_address m_miner_address;
std::string m_config_folder;
uint64_t m_stop_after_height;
currency_protocol_stub m_protocol_stub;
math_helper::once_a_time_seconds<60*60*12, false> m_prune_alt_blocks_interval;
math_helper::once_a_time_seconds<60, true> m_check_free_space_interval;
epee::math_helper::once_a_time_seconds<60*60*12, false> m_prune_alt_blocks_interval;
epee::math_helper::once_a_time_seconds<60, true> m_check_free_space_interval;
friend class tx_validate_inputs;
std::atomic<bool> m_starter_message_showed;
critical_section m_blockchain_update_listeners_lock;
epee::critical_section m_blockchain_update_listeners_lock;
std::vector<i_blockchain_update_listener*> m_blockchain_update_listeners;
};
}

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2023 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Copyright (c) 2012-2013 The Boolberry developers
@ -29,6 +29,9 @@
#include "currency_format_utils_transactions.h"
#include "core_runtime_config.h"
#include "wallet/wallet_public_structs_defs.h"
#include "bc_attachments_helpers.h"
#include "bc_payments_id_service.h"
#include "bc_offers_service_basic.h"
// ------ get_tx_type_definition -------------
@ -53,11 +56,6 @@
namespace currency
{
bool operator ==(const currency::transaction& a, const currency::transaction& b);
bool operator ==(const currency::block& a, const currency::block& b);
bool operator ==(const currency::extra_attachment_info& a, const currency::extra_attachment_info& b);
typedef boost::multiprecision::uint128_t uint128_tl;
@ -68,6 +66,7 @@ namespace currency
extra_alias_entry m_alias;
std::string m_user_data_blob;
extra_attachment_info m_attachment_info;
asset_descriptor_operation m_asset_operation;
};
//---------------------------------------------------------------------------------------------------------------
@ -135,11 +134,15 @@ namespace currency
END_KV_SERIALIZE_MAP()
};
struct htlc_info
{
bool hltc_our_out_is_before_expiration;
};
struct htlc_info
{
bool hltc_our_out_is_before_expiration;
};
struct thirdparty_sign_handler
{
virtual bool sign(const crypto::hash& h, const crypto::public_key& owner_public_key, crypto::generic_schnorr_sig& sig);
};
struct finalize_tx_param
{
@ -156,6 +159,17 @@ namespace currency
std::vector<currency::tx_destination_entry> prepared_destinations;
uint64_t expiration_time;
crypto::public_key spend_pub_key; // only for validations
uint64_t tx_version;
uint64_t mode_separate_fee = 0;
epee::misc_utils::events_dispatcher* pevents_dispatcher;
tx_generation_context gen_context{}; // solely for consolidated txs
//crypto::secret_key asset_control_key = currency::null_skey;
crypto::public_key ado_current_asset_owner = null_pkey;
thirdparty_sign_handler* pthirdparty_sign_handler = nullptr;
mutable bool need_to_generate_ado_proof = false;
BEGIN_SERIALIZE_OBJECT()
FIELD(unlock_time)
@ -171,6 +185,14 @@ namespace currency
FIELD(prepared_destinations)
FIELD(expiration_time)
FIELD(spend_pub_key)
FIELD(tx_version)
FIELD(mode_separate_fee)
if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)
{
FIELD(gen_context);
}
FIELD(ado_current_asset_owner)
FIELD(need_to_generate_ado_proof)
END_SERIALIZE()
};
@ -181,6 +203,8 @@ namespace currency
finalize_tx_param ftp;
std::string htlc_origin;
std::vector<serializable_pair<uint64_t, crypto::key_image>> outs_key_images; // pairs (out_index, key_image) for each change output
crypto::key_derivation derivation;
bool was_not_prepared = false; // true if tx was not prepared/created for some good reason (e.g. not enough outs for UTXO defragmentation tx). Because we decided not to throw exceptions for non-error cases. -- sowle
BEGIN_SERIALIZE_OBJECT()
FIELD(tx)
@ -188,37 +212,94 @@ namespace currency
FIELD(ftp)
FIELD(htlc_origin)
FIELD(outs_key_images)
FIELD(derivation)
FIELD(was_not_prepared)
END_SERIALIZE()
};
struct wallet_out_info
{
wallet_out_info() = default;
wallet_out_info(size_t index, uint64_t amount)
: index(index)
, amount(amount)
{}
wallet_out_info(size_t index, uint64_t amount, const crypto::scalar_t& amount_blinding_mask, const crypto::scalar_t& asset_id_blinding_mask, const crypto::public_key& asset_id)
: index(index)
, amount(amount)
, amount_blinding_mask(amount_blinding_mask)
, asset_id_blinding_mask(asset_id_blinding_mask)
, asset_id(asset_id)
{}
size_t index = SIZE_MAX;
uint64_t amount = 0;
crypto::scalar_t amount_blinding_mask = 0;
crypto::scalar_t asset_id_blinding_mask = 0;
crypto::public_key asset_id = currency::native_coin_asset_id; // use point_t instead as this is for internal use only?
bool is_native_coin() const { return asset_id == currency::native_coin_asset_id; }
};
// TODO @#@# consider refactoring to eliminate redundant coping and to imporve performance
struct zc_outs_range_proofs_with_commitments
{
zc_outs_range_proofs_with_commitments(const zc_outs_range_proof& range_proof, const std::vector<crypto::point_t>& amount_commitments)
: range_proof(range_proof)
, amount_commitments(amount_commitments)
{}
zc_outs_range_proofs_with_commitments(const zc_outs_range_proof& range_proof)
: range_proof(range_proof)
{}
zc_outs_range_proof range_proof;
std::vector<crypto::point_t> amount_commitments;
};
struct asset_op_verification_context
{
const transaction& tx;
const crypto::hash& tx_id;
const asset_descriptor_operation& ado;
crypto::public_key asset_id = currency::null_pkey;
crypto::point_t asset_id_pt = crypto::c_point_0;
uint64_t amount_to_validate = 0;
std::shared_ptr< const std::list<asset_descriptor_operation> > asset_op_history;
};
bool verify_multiple_zc_outs_range_proofs(const std::vector<zc_outs_range_proofs_with_commitments>& range_proofs);
bool generate_asset_surjection_proof(const crypto::hash& context_hash, bool has_non_zc_inputs, tx_generation_context& ogc, zc_asset_surjection_proof& result);
bool verify_asset_surjection_proof(const transaction& tx, const crypto::hash& tx_id);
bool generate_tx_balance_proof(const transaction &tx, const crypto::hash& tx_id, const tx_generation_context& ogc, uint64_t block_reward_for_miner_tx, zc_balance_proof& proof);
bool generate_zc_outs_range_proof(const crypto::hash& context_hash, size_t out_index_start, const tx_generation_context& outs_gen_context,
const std::vector<tx_out_v>& vouts, zc_outs_range_proof& result);
bool check_tx_bare_balance(const transaction& tx, uint64_t additional_inputs_amount_and_fees_for_mining_tx = 0);
bool check_tx_balance(const transaction& tx, const crypto::hash& tx_id, uint64_t additional_inputs_amount_and_fees_for_mining_tx = 0);
bool validate_asset_operation_amount_commitment(asset_op_verification_context& context);
const char* get_asset_operation_type_string(size_t asset_operation_type, bool short_name = false);
//---------------------------------------------------------------
bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins,
size_t current_block_size,
uint64_t fee,
const account_public_address &miner_address,
const account_public_address &stakeholder_address,
transaction& tx,
const blobdata& extra_nonce = blobdata(),
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,
bool pos = false,
const pos_entry& pe = pos_entry());
bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins,
size_t current_block_size,
uint64_t fee,
const std::vector<tx_destination_entry>& destinations,
transaction& tx,
const blobdata& extra_nonce = blobdata(),
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,
bool pos = false,
const pos_entry& pe = pos_entry());
transaction& tx,
uint64_t& block_reward_without_fee,
uint64_t& block_reward,
uint64_t tx_version,
const blobdata& extra_nonce = blobdata(),
size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS,
bool pos = false,
const pos_entry& pe = pos_entry(),
tx_generation_context* ogc_ptr = nullptr,
const keypair* tx_one_time_key_to_use = nullptr,
const std::vector<tx_destination_entry>& destinations = std::vector<tx_destination_entry>()
);
//---------------------------------------------------------------
uint64_t get_string_uint64_hash(const std::string& str);
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, finalized_tx& result, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, crypto::scalar_t& asset_blinding_mask, crypto::scalar_t& amount_blinding_mask, crypto::point_t& blinded_asset_id, crypto::point_t& amount_commitment, finalized_tx& result, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
bool validate_alias_name(const std::string& al);
bool validate_password(const std::string& password);
void get_attachment_extra_info_details(const std::vector<attachment_v>& attachment, extra_attachment_info& eai);
@ -227,6 +308,7 @@ namespace currency
const std::vector<tx_destination_entry>& destinations,
const std::vector<attachment_v>& attachments,
transaction& tx,
uint64_t tx_version,
uint64_t unlock_time,
uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED,
bool shuffle = true);
@ -236,6 +318,7 @@ namespace currency
const std::vector<extra_v>& extra,
const std::vector<attachment_v>& attachments,
transaction& tx,
uint64_t tx_version,
crypto::secret_key& one_time_secret_key,
uint64_t unlock_time,
uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED,
@ -248,6 +331,7 @@ namespace currency
const std::vector<extra_v>& extra,
const std::vector<attachment_v>& attachments,
transaction& tx,
uint64_t tx_version,
crypto::secret_key& one_time_secret_key,
uint64_t unlock_time,
const account_public_address& crypt_account,
@ -256,8 +340,10 @@ namespace currency
bool shuffle = true,
uint64_t flags = 0);
uint64_t get_tx_version(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd); // returns tx version based on the height of the block where the transaction is expected to be
bool construct_tx(const account_keys& sender_account_keys, const finalize_tx_param& param, finalized_tx& result);
bool get_or_calculate_asset_id(const asset_descriptor_operation& ado, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key);
const asset_descriptor_base& get_native_coin_asset_descriptor();
bool sign_multisig_input_in_tx(currency::transaction& tx, size_t ms_input_index, const currency::account_keys& keys, const currency::transaction& source_tx, bool *p_is_input_fully_signed = nullptr);
@ -268,32 +354,40 @@ namespace currency
bool parse_and_validate_tx_extra(const transaction& tx, 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_tx_fee_amount_to_extra(transaction& tx, uint64_t fee, bool make_sure_its_unique = true);
bool add_tx_extra_userdata(transaction& tx, const blobdata& extra_nonce);
crypto::hash get_multisig_out_id(const transaction& tx, size_t n);
bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index);
bool is_out_to_acc(const account_keys& acc, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, 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, crypto::key_derivation& derivation);
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, crypto::key_derivation& derivation, std::list<htlc_info>& htlc_info_list);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation);
bool decode_output_amount_and_asset_id(const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, const size_t output_index, uint64_t& decoded_amount, crypto::public_key& decoded_asset_id, crypto::scalar_t& amount_blinding_mask, crypto::scalar_t& asset_id_blinding_mask, crypto::scalar_t* derived_h_ptr = nullptr);
bool is_out_to_acc(const account_public_address& addr, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index);
bool is_out_to_acc(const account_public_address& addr, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index);
bool is_out_to_acc(const account_public_address& addr, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount, crypto::public_key& decoded_asset_id, crypto::scalar_t& amount_blinding_mask, crypto::scalar_t& asset_id_blinding_mask);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, crypto::key_derivation& derivation);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector<wallet_out_info>& outs, crypto::key_derivation& derivation, std::list<htlc_info>& htlc_info_list);
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<wallet_out_info>& outs, crypto::key_derivation& derivation);
bool get_tx_fee(const transaction& tx, uint64_t & fee);
uint64_t get_tx_fee(const transaction& tx);
bool derive_ephemeral_key_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral);
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 derive_public_key_from_target_address(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t index, crypto::public_key& out_eph_public_key, crypto::key_derivation& derivation);
bool derive_public_key_from_target_address(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t index, crypto::public_key& out_eph_public_key);
bool derive_key_pair_from_key_pair(const crypto::public_key& src_pub_key, const crypto::secret_key& src_sec_key, crypto::secret_key& derived_sec_key, crypto::public_key& derived_pub_key, const char(&hs_domain)[32], uint64_t index = 0);
uint16_t get_derivation_hint(const crypto::key_derivation& derivation);
tx_derivation_hint make_tx_derivation_hint_from_uint16(uint16_t hint);
std::string short_hash_str(const crypto::hash& h);
bool is_mixattr_applicable_for_fake_outs_counter(uint8_t mix_attr, uint64_t fake_attr_count);
bool is_mixattr_applicable_for_fake_outs_counter(uint64_t out_tx_version, uint8_t out_mix_attr, uint64_t fake_outputs_count, const core_runtime_config& rtc);
bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t current_blockchain_size, uint64_t current_time);
crypto::key_derivation get_encryption_key_derivation(bool is_income, const transaction& tx, const account_keys& acc_keys);
bool decrypt_payload_items(bool is_income, const transaction& tx, const account_keys& acc_keys, std::vector<payload_items_v>& decrypted_items);
void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation);
void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key);
bool is_derivation_used_to_encrypt(const transaction& tx, const crypto::key_derivation& derivation);
bool is_address_like_wrapped(const std::string& addr);
void load_wallet_transfer_info_flags(tools::wallet_public::wallet_transfer_info& x);
uint64_t get_tx_type(const transaction& tx);
uint64_t get_tx_type_ex(const transaction& tx, tx_out& htlc_out, txin_htlc& htlc_in);
size_t get_multisig_out_index(const std::vector<tx_out>& outs);
uint64_t get_tx_type_ex(const transaction& tx, tx_out_bare& htlc_out, txin_htlc& htlc_in);
size_t get_multisig_out_index(const std::vector<tx_out_v>& outs);
size_t get_multisig_in_index(const std::vector<txin_v>& inputs);
uint64_t get_reward_from_miner_tx(const transaction& tx);
@ -304,7 +398,7 @@ namespace currency
bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b);
uint64_t get_inputs_money_amount(const transaction& tx);
bool get_inputs_money_amount(const transaction& tx, uint64_t& money);
uint64_t get_outs_money_amount(const transaction& tx);
uint64_t get_outs_money_amount(const transaction& tx, const currency::account_keys& acc_keys_for_hidden_amounts = currency::null_acc_keys);
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);
@ -325,29 +419,31 @@ namespace currency
uint64_t get_block_height(const transaction& coinbase);
uint64_t get_block_height(const block& b);
std::vector<txout_ref_v> relative_output_offsets_to_absolute(const std::vector<txout_ref_v>& off);
std::vector<txout_ref_v> absolute_output_offsets_to_relative(const std::vector<txout_ref_v>& off);
bool absolute_sorted_output_offsets_to_relative_in_place(std::vector<txout_ref_v>& offsets) noexcept;
bool validate_output_key_legit(const crypto::public_key& k);
// prints amount in format "3.14", "0.0"
std::string print_money_brief(uint64_t amount);
uint64_t get_actual_timestamp(const block& b); // obsolete and depricated, use get_block_datetime
std::string print_money_brief(uint64_t amount, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT);
uint64_t get_block_timestamp_from_miner_tx_extra(const block& b); // remove this function after HF4 -- sowle
uint64_t get_block_datetime(const block& b);
void set_block_datetime(uint64_t datetime, block& b);
bool addendum_to_hexstr(const std::vector<crypto::hash>& add, std::string& hex_buff);
bool hexstr_to_addendum(const std::string& hex_buff, std::vector<crypto::hash>& add);
bool set_payment_id_to_tx(std::vector<attachment_v>& att, const std::string& payment_id);
bool set_payment_id_to_tx(std::vector<attachment_v>& att, const std::string& payment_id, bool is_in_hardfork4 = false);
bool add_padding_to_tx(transaction& tx, size_t count);
bool is_service_tx(const transaction& tx);
bool does_tx_have_only_mixin_inputs(const transaction& tx);
uint64_t get_hf4_inputs_key_offsets_count(const transaction& tx);
bool is_showing_sender_addres(const transaction& tx);
uint64_t get_amount_for_zero_pubkeys(const transaction& tx);
//std::string get_comment_from_tx(const transaction& tx);
bool check_native_coins_amount_burnt_in_outs(const transaction& tx, const uint64_t amount, uint64_t* p_amount_burnt = nullptr);
std::string print_stake_kernel_info(const stake_kernel& sk);
std::string dump_ring_sig_data(const crypto::hash& hash_for_sig, const crypto::key_image& k_image, const std::vector<const crypto::public_key*>& output_keys_ptrs, const std::vector<crypto::signature>& sig);
//PoS
bool is_pos_block(const block& b);
bool is_pos_block(const transaction& tx);
bool is_pos_miner_tx(const transaction& tx);
wide_difficulty_type correct_difficulty_with_sequence_factor(size_t sequence_factor, wide_difficulty_type diff);
void print_currency_details();
std::string print_reward_change_first_blocks(size_t n_of_first_blocks);
@ -357,8 +453,7 @@ namespace currency
update_alias_rpc_details alias_info_to_rpc_update_alias_info(const currency::extra_alias_entry& ai, const std::string& old_address);
size_t get_service_attachments_count_in_tx(const transaction& tx);
bool fill_tx_rpc_outputs(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce);
bool fill_tx_rpc_inputs(tx_rpc_extended_info& tei, const transaction& tx);
bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short = false);
bool fill_block_rpc_details(block_rpc_extended_info& pei_rpc, const block_extended_info& bei_chain, const crypto::hash& h);
void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map<uint64_t, uint32_t>& gindices);
std::string get_word_from_timstamp(uint64_t timestamp, bool use_password);
@ -367,24 +462,47 @@ namespace currency
bool parse_vote(const std::string& buff, std::list<std::pair<std::string, bool>>& votes);
std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys);
bool validate_ado_update_allowed(const asset_descriptor_base& a, const asset_descriptor_base& b);
void normalize_asset_operation_for_hashing(asset_descriptor_operation& op);
crypto::hash get_signature_hash_for_asset_operation(const asset_descriptor_operation& ado);
template<class t_txin_v>
typename std::conditional<std::is_const<t_txin_v>::value, const std::vector<txin_etc_details_v>, std::vector<txin_etc_details_v> >::type& get_txin_etc_options(t_txin_v& in)
{
static typename std::conditional<std::is_const<t_txin_v>::value, const std::vector<txin_etc_details_v>, std::vector<txin_etc_details_v> >::type stub;
//static stub;
if (in.type() == typeid(txin_to_key))
return boost::get<txin_to_key>(in).etc_details;
else if (in.type() == typeid(txin_htlc))
return boost::get<txin_htlc>(in).etc_details;
else if (in.type() == typeid(txin_multisig))
return boost::get<txin_multisig>(in).etc_details;
else
else if (in.type() == typeid(txin_htlc))
return boost::get<txin_htlc>(in).etc_details;
else if (in.type() == typeid(txin_zc_input))
return boost::get<txin_zc_input>(in).etc_details;
else
return stub;
}
template<typename out_t>
inline bool is_out_burned(const out_t& out) { CHECK_AND_ASSERT_THROW_MES(false, "incorrect out type: " << typeid(out).name()); }
template<>
inline bool is_out_burned(const txout_to_key& o) { return o.key == null_pkey; }
template<>
inline bool is_out_burned(const tx_out_zarcanum& o) { return o.stealth_address == null_pkey; }
struct zz_is_out_burned_helper_visitor : boost::static_visitor<bool>
{
template<typename T>
bool operator()(const T& v) const { return is_out_burned(v); }
};
template<>
inline bool is_out_burned(const txout_target_v& v) { return boost::apply_visitor(zz_is_out_burned_helper_visitor(), v); }
template<>
inline bool is_out_burned(const tx_out_v& v) { return boost::apply_visitor(zz_is_out_burned_helper_visitor(), v); }
template<>
inline bool is_out_burned(const tx_out_bare& o) { return is_out_burned(o.target); }
template<class t_extra_container>
bool add_attachments_info_to_extra(t_extra_container& extra_container, const std::vector<attachment_v>& attachments)
{
@ -413,6 +531,7 @@ namespace currency
bool parse_payment_id_from_hex_str(const std::string& payment_id_str, payment_id_t& payment_id);
bool is_coinbase(const transaction& tx);
bool is_coinbase(const transaction& tx, bool& pos_coinbase);
bool is_pos_coinbase(const transaction& tx);
bool have_attachment_service_in_container(const std::vector<attachment_v>& av, const std::string& service_id, const std::string& instruction);
crypto::hash prepare_prefix_hash_for_sign(const transaction& tx, uint64_t in_index, const crypto::hash& tx_id);
@ -475,16 +594,34 @@ namespace currency
return true;
}
//---------------------------------------------------------------
// outputs "1391306.970000000000"
template<typename t_number>
std::string print_fixed_decimal_point(t_number amount, size_t decimal_point)
{
return epee::string_tools::print_fixed_decimal_point(amount, decimal_point);
}
//---------------------------------------------------------------
// outputs "1391306.97 "
template<typename t_number>
std::string print_money(t_number amount)
std::string print_fixed_decimal_point_with_trailing_spaces(t_number amount, size_t decimal_point)
{
return print_fixed_decimal_point(amount, CURRENCY_DISPLAY_DECIMAL_POINT);
std::string s = epee::string_tools::print_fixed_decimal_point(amount, decimal_point);
for(size_t n = s.size() - 1; n != 0 && s[n] == '0' && s[n-1] != '.'; --n)
s[n] = ' ';
return s;
}
//---------------------------------------------------------------
template<typename t_number>
std::string print_money(t_number amount, uint64_t decimals = CURRENCY_DISPLAY_DECIMAL_POINT)
{
return print_fixed_decimal_point(amount, decimals);
}
//---------------------------------------------------------------
template<typename t_number>
std::string print_asset_money(t_number amount, size_t decimal_point)
{
return print_fixed_decimal_point(amount, decimal_point);
}
//---------------------------------------------------------------
template<class alias_rpc_details_t>
@ -534,38 +671,8 @@ namespace currency
return get_or_add_field_to_variant_vector<extra_t>(extra);
}
//---------------------------------------------------------------
template<class variant_t, class variant_type_t>
void update_or_add_field_to_extra(std::vector<variant_t>& variant_container, const variant_type_t& v)
{
for (auto& ev : variant_container)
{
if (ev.type() == typeid(variant_type_t))
{
boost::get<variant_type_t>(ev) = v;
return;
}
}
variant_container.push_back(v);
}
//---------------------------------------------------------------
template<class variant_type_t, class variant_t>
void remove_field_of_type_from_extra(std::vector<variant_t>& variant_container)
{
for (size_t i = 0; i != variant_container.size();)
{
if (variant_container[i].type() == typeid(variant_type_t))
{
variant_container.erase(variant_container.begin()+i);
}
else
{
i++;
}
}
}
//---------------------------------------------------------------
template<typename t_container>
bool get_payment_id_from_tx(const t_container& att, std::string& payment_id)
bool get_payment_id_from_decrypted_container(const t_container& att, std::string& payment_id)
{
tx_service_attachment sa = AUTO_VAL_INIT(sa);
if (bc_services::get_first_service_attachment_by_id(att, BC_PAYMENT_ID_SERVICE_ID, "", sa))
@ -650,59 +757,136 @@ namespace currency
{
decompose_amount_into_digits(amount, dust_threshold, chunk_handler, dust_handler, max_output_allowed, CURRENCY_TX_MAX_ALLOWED_OUTS, 0);
}
// num_digits_to_keep -- how many digits to keep in chunks, 0 means all digits
// Ex.: num_digits_to_keep == 3, number_of_outputs == 2 then 1.0 may be decomposed into 0.183 + 0.817
// num_digits_to_keep == 0, number_of_outputs == 2 then 1.0 may be decomposed into 0.183374827362 + 0.816625172638
template<typename chunk_handler_t>
void decompose_amount_randomly(uint64_t amount, chunk_handler_t chunk_cb, size_t number_of_outputs = CURRENCY_TX_MIN_ALLOWED_OUTS, size_t num_digits_to_keep = CURRENCY_TX_OUTS_RND_SPLIT_DIGITS_TO_KEEP)
{
if (amount < number_of_outputs)
return;
uint64_t boundary = 1000;
if (num_digits_to_keep != CURRENCY_TX_OUTS_RND_SPLIT_DIGITS_TO_KEEP)
{
boundary = 1;
for(size_t i = 0; i < num_digits_to_keep; ++i)
boundary *= 10;
}
auto trim_digits_and_add_variance = [boundary, num_digits_to_keep](uint64_t& v){
if (num_digits_to_keep != 0 && v > 1)
{
uint64_t multiplier = 1;
while(v >= boundary)
{
v /= 10;
multiplier *= 10;
}
v = v / 2 + crypto::rand<uint64_t>() % (v + 1);
v *= multiplier;
}
};
uint64_t amount_remaining = amount;
for(size_t i = 1; i < number_of_outputs && amount_remaining > 1; ++i) // starting from 1 for one less iteration
{
uint64_t chunk_amount = amount_remaining / (number_of_outputs - i + 1);
trim_digits_and_add_variance(chunk_amount);
amount_remaining -= chunk_amount;
chunk_cb(chunk_amount);
}
chunk_cb(amount_remaining);
}
//---------------------------------------------------------------
/*
inline size_t get_input_expected_signatures_count(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_key& txin) const { return txin.key_offsets.size(); }
size_t operator()(const txin_multisig& txin) const { return txin.sigs_count; }
size_t operator()(const txin_htlc& txin) const { return 1; }
size_t operator()(const txin_gen& txin) const { return 0; }
size_t operator()(const txin_to_key& txin) const { return txin.key_offsets.size(); }
size_t operator()(const txin_multisig& txin) const { return txin.sigs_count; }
size_t operator()(const txin_htlc& txin) const { return 1; }
size_t operator()(const txin_zc_input& txin) const { throw std::runtime_error("Not implemented yet"); }
};
return boost::apply_visitor(txin_signature_size_visitor(), tx_in);
}
}*/
//---------------------------------------------------------------
inline const std::vector<txin_etc_details_v>* get_input_etc_details(const txin_v& in)
inline size_t get_input_expected_signature_size(const txin_v& tx_in, bool last_input_in_separately_signed_tx)
{
if (in.type().hash_code() == typeid(txin_to_key).hash_code())
return &boost::get<txin_to_key>(in).etc_details;
if (in.type().hash_code() == typeid(txin_htlc).hash_code())
return &boost::get<txin_htlc>(in).etc_details;
if (in.type().hash_code() == typeid(txin_multisig).hash_code())
return &boost::get<txin_multisig>(in).etc_details;
return nullptr;
}
//---------------------------------------------------------------
inline std::vector<txin_etc_details_v>* get_input_etc_details(txin_v& in)
{
if (in.type().hash_code() == typeid(txin_to_key).hash_code())
return &boost::get<txin_to_key>(in).etc_details;
if (in.type().hash_code() == typeid(txin_htlc).hash_code())
return &boost::get<txin_htlc>(in).etc_details;
if (in.type().hash_code() == typeid(txin_multisig).hash_code())
return &boost::get<txin_multisig>(in).etc_details;
return nullptr;
}
//---------------------------------------------------------------
struct txin_signature_size_visitor : public boost::static_visitor<size_t>
{
txin_signature_size_visitor(size_t add) : a(add) {}
size_t a;
size_t operator()(const txin_gen& /*txin*/) const { return 0; }
size_t operator()(const txin_to_key& txin) const { return tools::get_varint_packed_size(txin.key_offsets.size() + a) + sizeof(crypto::signature) * (txin.key_offsets.size() + a); }
size_t operator()(const txin_multisig& txin) const { return tools::get_varint_packed_size(txin.sigs_count + a) + sizeof(crypto::signature) * (txin.sigs_count + a); }
size_t operator()(const txin_htlc& txin) const { return tools::get_varint_packed_size(1 + a) + sizeof(crypto::signature) * (1 + a); }
size_t operator()(const txin_zc_input& txin) const { return 97 + tools::get_varint_packed_size(txin.key_offsets.size()) + txin.key_offsets.size() * 32; }
};
return boost::apply_visitor(txin_signature_size_visitor(last_input_in_separately_signed_tx ? 1 : 0), tx_in);
}
//---------------------------------------------------------------
template<class txin_t>
typename std::conditional<std::is_const<txin_t>::value, const std::vector<txin_etc_details_v>, std::vector<txin_etc_details_v> >::type*
get_input_etc_details(txin_t& in)
{
if (in.type() == typeid(txin_to_key))
return &boost::get<txin_to_key>(in).etc_details;
if (in.type() == typeid(txin_multisig))
return &boost::get<txin_multisig>(in).etc_details;
if (in.type() == typeid(txin_htlc))
return &boost::get<txin_htlc>(in).etc_details;
if (in.type() == typeid(txin_zc_input))
return &boost::get<txin_zc_input>(in).etc_details;
return nullptr;
}
//---------------------------------------------------------------
struct input_amount_getter : public boost::static_visitor<uint64_t>
{
template<class t_input>
uint64_t operator()(const t_input& i) const{return i.amount;}
uint64_t operator()(const txin_gen& i) const {return 0;}
uint64_t operator()(const t_input& i) const { return i.amount; }
uint64_t operator()(const txin_zc_input&) const { return 0; }
uint64_t operator()(const txin_gen& i) const { return 0; }
};
inline uint64_t get_amount_from_variant(const txin_v& v)
inline uint64_t get_amount_from_variant(const txin_v& v) noexcept
{
return boost::apply_visitor(input_amount_getter(), v);
try
{
return boost::apply_visitor(input_amount_getter(), v);
}
catch(...)
{
return 0;
}
}
//---------------------------------------------------------------
struct output_amount_getter : public boost::static_visitor<uint64_t>
{
template<class out_t>
uint64_t operator()(const out_t&) const { return 0; }
uint64_t operator()(const tx_out_bare& ob) const { return ob.amount; }
};
inline uint64_t get_amount_from_variant(const tx_out_v& out_v)
{
return boost::apply_visitor(output_amount_getter(), out_v);
}
//---------------------------------------------------------------
inline const tx_out_bare& get_tx_out_bare_from_out_v(const tx_out_v& o)
{
//this function will throw if type is not matching
return boost::get<tx_out_bare>(o);
}
//---------------------------------------------------------------
template <typename container_t>
void create_and_add_tx_payer_to_container_from_address(container_t& container, const account_public_address& addr, uint64_t top_block_height, const core_runtime_config& crc)
{
if (top_block_height > crc.hard_fork_02_starts_after_height)
if (crc.is_hardfork_active_for_height(2, top_block_height))
{
// after hardfork 2
tx_payer result = AUTO_VAL_INIT(result);
@ -724,7 +908,7 @@ namespace currency
template <typename container_t>
void create_and_add_tx_receiver_to_container_from_address(container_t& container, const account_public_address& addr, uint64_t top_block_height, const core_runtime_config& crc)
{
if (top_block_height > crc.hard_fork_02_starts_after_height)
if (crc.is_hardfork_active_for_height(2, top_block_height))
{
// after hardfork 2
tx_receiver result = AUTO_VAL_INIT(result);
@ -764,5 +948,243 @@ namespace currency
const difficulties& b_diff
);
boost::multiprecision::uint1024_t get_a_to_b_relative_cumulative_difficulty_hf4(const wide_difficulty_type& difficulty_pos_at_split_point,
const wide_difficulty_type& difficulty_pow_at_split_point,
const difficulties& a_diff,
const difficulties& b_diff
);
struct rpc_tx_payload_handler : public boost::static_visitor<bool>
{
tx_extra_rpc_entry& tv;
rpc_tx_payload_handler(tx_extra_rpc_entry& t) : tv(t)
{}
bool operator()(const tx_service_attachment& ee)
{
tv.type = "service";
tv.short_view = ee.service_id + ":" + ee.instruction;
if (ee.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY)
tv.short_view += "(encrypted)";
else
{
std::string deflated_buff;
const std::string* pfinalbuff = &ee.body;
if (ee.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY)
{
bool r = epee::zlib_helper::unpack(ee.body, deflated_buff);
CHECK_AND_ASSERT_MES(r, false, "Failed to unpack");
pfinalbuff = &deflated_buff;
}
if (ee.service_id == BC_PAYMENT_ID_SERVICE_ID || ee.service_id == BC_OFFERS_SERVICE_ID)
tv.details_view = *pfinalbuff;
else
tv.details_view = "BINARY DATA";
}
return true;
}
bool operator()(const tx_crypto_checksum& ee)
{
tv.type = "crypto_checksum";
tv.short_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash);
tv.details_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash) + "\n"
+ "encrypted_key_derivation: " + epee::string_tools::pod_to_hex(ee.encrypted_key_derivation);
return true;
}
bool operator()(const etc_tx_time& ee)
{
tv.type = "pos_time";
tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v);
return true;
}
bool operator()(const etc_tx_details_unlock_time& ee)
{
tv.type = "unlock_time";
if (ee.v < CURRENCY_MAX_BLOCK_NUMBER)
tv.short_view = std::string("height: ") + std::to_string(ee.v);
else
tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v);
return true;
}
bool operator()(const etc_tx_details_unlock_time2& ee)
{
tv.type = "unlock_time";
std::stringstream ss;
ss << "[";
for (auto v : ee.unlock_time_array)
{
ss << " " << v;
}
ss << "]";
tv.short_view = ss.str();
return true;
}
bool operator()(const etc_tx_details_expiration_time& ee)
{
tv.type = "expiration_time";
if (ee.v < CURRENCY_MAX_BLOCK_NUMBER)
tv.short_view = std::string("height: ") + std::to_string(ee.v);
else
tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v);
return true;
}
bool operator()(const etc_tx_details_flags& ee)
{
tv.type = "details_flags";
tv.short_view = epee::string_tools::pod_to_hex(ee.v);
return true;
}
bool operator()(const crypto::public_key& ee)
{
tv.type = "pub_key";
tv.short_view = epee::string_tools::pod_to_hex(ee);
return true;
}
bool operator()(const extra_attachment_info& ee)
{
tv.type = "attachment_info";
tv.short_view = std::to_string(ee.sz) + " bytes";
tv.details_view = currency::obj_to_json_str(ee);
return true;
}
bool operator()(const extra_alias_entry& ee)
{
tv.type = "alias_info";
tv.short_view = ee.m_alias + "-->" + get_account_address_as_str(ee.m_address);
tv.details_view = currency::obj_to_json_str(ee);
return true;
}
bool operator()(const extra_alias_entry_old& ee)
{
return operator()(static_cast<const extra_alias_entry&>(ee));
}
bool operator()(const extra_user_data& ee)
{
tv.type = "user_data";
tv.short_view = std::to_string(ee.buff.size()) + " bytes";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.buff);
return true;
}
bool operator()(const extra_padding& ee)
{
tv.type = "extra_padding";
tv.short_view = std::to_string(ee.buff.size()) + " bytes";
if (!ee.buff.empty())
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast<const char*>(&ee.buff[0]), ee.buff.size()));
return true;
}
bool operator()(const tx_comment& ee)
{
tv.type = "comment";
tv.short_view = std::to_string(ee.comment.size()) + " bytes(encrypted)";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.comment);
return true;
}
bool operator()(const tx_payer& ee)
{
//const tx_payer& ee = boost::get<tx_payer>(extra);
tv.type = "payer";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_payer_old&)
{
tv.type = "payer_old";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_receiver& ee)
{
//const tx_payer& ee = boost::get<tx_payer>(extra);
tv.type = "receiver";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_receiver_old& ee)
{
tv.type = "receiver_old";
tv.short_view = "(encrypted)";
return true;
}
bool operator()(const tx_derivation_hint& ee)
{
tv.type = "derivation_hint";
tv.short_view = std::to_string(ee.msg.size()) + " bytes";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.msg);
return true;
}
bool operator()(const std::string& ee)
{
tv.type = "string";
tv.short_view = std::to_string(ee.size()) + " bytes";
tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee);
return true;
}
bool operator()(const etc_tx_flags16_t& dh)
{
tv.type = "FLAGS16";
tv.short_view = epee::string_tools::pod_to_hex(dh);
tv.details_view = epee::string_tools::pod_to_hex(dh);
return true;
}
bool operator()(const zarcanum_tx_data_v1& ztxd)
{
tv.type = "zarcanum_tx_data_v1";
tv.short_view = "fee = " + print_money_brief(ztxd.fee);
tv.details_view = tv.short_view;
return true;
}
bool operator()(const zc_outs_range_proof& rp)
{
tv.type = "zc_outs_range_proof";
// TODO @#@#
//tv.short_view = "outputs_count = " + std::to_string(rp.outputs_count);
return true;
}
bool operator()(const zc_balance_proof& bp)
{
tv.type = "zc_balance_proof";
return true;
}
template<typename t_type>
bool operator()(const t_type& t_t)
{
tv.type = typeid(t_t).name();
return true;
}
};
//------------------------------------------------------------------
template<class t_container>
bool fill_tx_rpc_payload_items(std::vector<tx_extra_rpc_entry>& target_vector, const t_container& tc)
{
//handle extra
for (auto& extra : tc)
{
target_vector.push_back(tx_extra_rpc_entry());
tx_extra_rpc_entry& tv = target_vector.back();
rpc_tx_payload_handler vstr(tv);
boost::apply_visitor(vstr, extra);
}
return true;
}
} // namespace currency

View file

@ -42,7 +42,7 @@ namespace currency
/* */
/************************************************************************/
template<class t_array>
struct array_hasher : std::unary_function<t_array&, std::size_t>
struct array_hasher
{
std::size_t operator()(const t_array& val) const
{
@ -91,22 +91,66 @@ namespace currency
++result;
}
return result;
}
}
//---------------------------------------------------------------
template<typename specific_type_t, typename variant_t_container>
bool get_type_in_variant_container(const variant_t_container& av, specific_type_t& a)
specific_type_t* get_type_in_variant_container(variant_t_container& av)
{
for (auto& ai : av)
{
if (ai.type() == typeid(specific_type_t))
{
a = boost::get<specific_type_t>(ai);
return true;
return &boost::get<specific_type_t>(ai);
}
}
return nullptr;
}
//---------------------------------------------------------------
template<typename specific_type_t, typename variant_t_container>
bool get_type_in_variant_container(variant_t_container& av, specific_type_t& a)
{
const specific_type_t* pa = get_type_in_variant_container<const specific_type_t>(av);
if (pa)
{
a = *pa;
return true;
}
return false;
}
//---------------------------------------------------------------
//---------------------------------------------------------------
template<typename specific_type_t, typename variant_t_container>
specific_type_t& get_type_in_variant_container_by_ref(variant_t_container& av)
{
for (auto& ai : av)
{
if (ai.type() == typeid(specific_type_t))
{
return boost::get<specific_type_t>(ai);
}
}
ASSERT_MES_AND_THROW("Object with type " << typeid(specific_type_t).name() << " was not found in a container");
}
//---------------------------------------------------------------
// if cb returns true, it means "continue", false -- means "stop"
template<typename specific_type_t, typename variant_container_t, typename callback_t>
bool process_type_in_variant_container(const variant_container_t& av, callback_t& cb, bool return_value_if_none_found = true)
{
bool found = false;
for (auto& ai : av)
{
if (ai.type() == typeid(specific_type_t))
{
found = true;
if (!cb(boost::get<specific_type_t>(ai)))
return false;
}
}
if (found)
return true;
return return_value_if_none_found;
}
//---------------------------------------------------------------
// callback should return true to continue iterating through the container
template <typename A, typename B, typename container_t, typename callback_t>
bool handle_2_alternative_types_in_variant_container(const container_t& container, callback_t cb)
@ -131,20 +175,158 @@ namespace currency
}
//---------------------------------------------------------------
inline
const txin_to_key& get_to_key_input_from_txin_v(const txin_v& in_v)
bool get_key_image_from_txin_v(const txin_v& in_v, crypto::key_image& result) noexcept
{
try
{
if (in_v.type() == typeid(txin_to_key))
{
result = boost::get<txin_to_key>(in_v).k_image;
return true;
}
if (in_v.type() == typeid(txin_htlc))
{
result = boost::get<txin_htlc>(in_v).k_image;
return true;
}
if (in_v.type() == typeid(txin_zc_input))
{
result = boost::get<txin_zc_input>(in_v).k_image;
return true;
}
}
catch(...)
{
// should never go here, just precaution
}
return false;
}
//---------------------------------------------------------------
inline
const crypto::key_image& get_key_image_from_txin_v(const txin_v& in_v)
{
if (in_v.type() == typeid(txin_to_key))
return boost::get<txin_to_key>(in_v).k_image;
if (in_v.type() == typeid(txin_htlc))
return boost::get<txin_htlc>(in_v).k_image;
if (in_v.type() == typeid(txin_zc_input))
return boost::get<txin_zc_input>(in_v).k_image;
CHECK_AND_ASSERT_THROW_MES(false, "[get_key_image_from_txin_v] Wrong type: " << in_v.type().name());
}
//---------------------------------------------------------------
inline
const std::vector<currency::txout_ref_v>& get_key_offsets_from_txin_v(const txin_v& in_v)
{
if (in_v.type() == typeid(txin_to_key))
return boost::get<txin_to_key>(in_v).key_offsets;
if (in_v.type() == typeid(txin_htlc))
return boost::get<txin_htlc>(in_v).key_offsets;
if (in_v.type() == typeid(txin_zc_input))
return boost::get<txin_zc_input>(in_v).key_offsets;
CHECK_AND_ASSERT_THROW_MES(false, "[get_key_offsets_from_txin_v] Wrong type: " << in_v.type().name());
}
//---------------------------------------------------------------
inline
bool get_mix_attr_from_tx_out_v(const tx_out_v& out_v, uint8_t& result) noexcept
{
try
{
return boost::get<txin_to_key>(in_v);
if (out_v.type() == typeid(tx_out_bare))
{
const tx_out_bare& ob = boost::get<tx_out_bare>(out_v);
if (ob.target.type() == typeid(txout_to_key))
{
result = boost::get<txout_to_key>(ob.target).mix_attr;
return true;
}
}
if (out_v.type() == typeid(tx_out_zarcanum))
{
result = boost::get<tx_out_zarcanum>(out_v).mix_attr;
return true;
}
}
else if (in_v.type() == typeid(txin_htlc))
catch(...)
{
const txin_htlc& in = boost::get<txin_htlc>(in_v);
return static_cast<const txin_to_key&>(in);
// should never go here, just precaution
}
else {
ASSERT_MES_AND_THROW("[get_to_key_input_from_txin_v] Wrong type " << in_v.type().name());
return false;
}
//---------------------------------------------------------------
//, txin_htlc, txin_zc_input
inline bool compare_variant_by_types(const txin_multisig& left, const txin_multisig& right)
{
return (left.multisig_out_id < right.multisig_out_id);
}
//---------------------------------------------------------------
inline bool compare_variant_by_types(const txin_gen& left, const txin_gen& right)
{
//actually this should never happen, should we leave it in case it happen in unit tests? @sowle
return (left.height < right.height);
}
//---------------------------------------------------------------
template<typename type_with_kimage_t>
bool compare_variant_by_types(const type_with_kimage_t& left, const type_with_kimage_t& right)
{
return (left.k_image < right.k_image);
}
//---------------------------------------------------------------
template<typename t_type_left, typename t_type_right>
bool compare_variant_by_types(const t_type_left& left, const t_type_right& right)
{
if (typeid(t_type_left) == typeid(t_type_right))
{
ASSERT_MES_AND_THROW("[compare_varian_by_types] Left and Right types matched type " << typeid(t_type_left).name());
}
typedef binary_archive<true> bin_archive;
typedef variant_serialization_traits<bin_archive, t_type_left> traits_left;
typedef variant_serialization_traits<bin_archive, t_type_right> traits_right;
return (traits_left::get_tag() < traits_right::get_tag());
}
//---------------------------------------------------------------
template<typename t_type_left>
struct right_visitor : public boost::static_visitor<bool>
{
const t_type_left& m_rleft;
right_visitor(const t_type_left& left) : m_rleft(left)
{}
template<typename t_type_right>
bool operator()(const t_type_right& right)const
{
return compare_variant_by_types(m_rleft, right);
}
};
struct left_visitor : public boost::static_visitor<bool>
{
const txin_v& m_rright;
left_visitor(const txin_v& right) : m_rright(right)
{}
template<typename t_type_left>
bool operator()(const t_type_left& left)const
{
return boost::apply_visitor(right_visitor<t_type_left>(left), m_rright);
}
};
//---------------------------------------------------------------
inline bool less_txin_v(const txin_v& left, const txin_v& right)
{
//predefined type hierarchy based on it's tags defined in currency_basic.h, call compare_variant_by_types via 2-level visitor
return boost::apply_visitor(left_visitor(right), left);
}
//---------------------------------------------------------------
template<typename variant_container_t>
@ -247,6 +429,26 @@ namespace currency
size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size);
inline
void put_t_to_buff(std::string& buff)
{}
template <typename T, typename... Types>
void put_t_to_buff(std::string& buff, const T& var1, Types&... var2)
{
static_assert(std::is_pod<T>::value, "T must be a POD type.");
buff.append((const char*)&var1, sizeof(var1));
put_t_to_buff(buff, var2...);
}
template <typename... Types>
crypto::hash get_hash_from_POD_objects(Types&... var1)
{
std::string buff;
put_t_to_buff(buff, var1...);
return crypto::cn_fast_hash(buff.data(), buff.size());
}
#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

@ -8,6 +8,7 @@
#include "serialization/serialization.h"
#include "currency_format_utils.h"
#include "currency_format_utils_abstract.h"
#include "common/variant_helper.h"
namespace currency
{
@ -24,6 +25,8 @@ namespace currency
//------------------------------------------------------------------
bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median)
{
if (expiration_ts_median == 0)
return false;
/// tx expiration condition (tx is ok if the following is true)
/// tx_expiration_time - TX_EXPIRATION_MEDIAN_SHIFT > get_last_n_blocks_timestamps_median(TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW)
uint64_t expiration_time = get_tx_expiration_time(tx);
@ -37,11 +40,17 @@ namespace currency
uint64_t res = 0;
for (auto& o : tx.vout)
{
if (o.target.type() == typeid(txout_to_key))
{
if (boost::get<txout_to_key>(o.target).key == null_pkey)
res += o.amount;
}
VARIANT_SWITCH_BEGIN(o);
VARIANT_CASE_CONST(tx_out_bare, o)
if (o.target.type() == typeid(txout_to_key))
{
if (boost::get<txout_to_key>(o.target).key == null_pkey)
res += o.amount;
}
VARIANT_CASE_CONST(tx_out_zarcanum, o)
//@#@# TODO obtain info about public burn of native coins in ZC outputs
VARIANT_CASE_THROW_ON_OTHER();
VARIANT_SWITCH_END();
}
return res;
}
@ -203,12 +212,35 @@ namespace currency
return total;
}
//---------------------------------------------------------------
inline size_t get_input_expected_signature_size_local(const txin_v& tx_in, bool last_input_in_separately_signed_tx)
{
struct txin_signature_size_visitor : public boost::static_visitor<size_t>
{
txin_signature_size_visitor(size_t add) : a(add) {}
size_t a;
size_t operator()(const txin_gen& /*txin*/) const { return 0; }
size_t operator()(const txin_to_key& txin) const { return tools::get_varint_packed_size(txin.key_offsets.size() + a) + sizeof(crypto::signature) * (txin.key_offsets.size() + a); }
size_t operator()(const txin_multisig& txin) const { return tools::get_varint_packed_size(txin.sigs_count + a) + sizeof(crypto::signature) * (txin.sigs_count + a); }
size_t operator()(const txin_htlc& txin) const { return tools::get_varint_packed_size(1 + a) + sizeof(crypto::signature) * (1 + a); }
size_t operator()(const txin_zc_input& txin) const { return 96 + tools::get_varint_packed_size(txin.key_offsets.size()) + txin.key_offsets.size() * 32; }
};
return boost::apply_visitor(txin_signature_size_visitor(last_input_in_separately_signed_tx ? 1 : 0), tx_in);
}
//---------------------------------------------------------------
size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size)
{
size_t tx_blob_size = prefix_blob_size;
if (is_coinbase(t))
{
if (is_pos_miner_tx(t) && t.version > TRANSACTION_VERSION_PRE_HF4)
{
// Zarcanum
return tx_blob_size;
}
return tx_blob_size;
}
// for purged tx, with empty signatures and attachments, this function should return the blob size
// which the tx would have if the signatures and attachments were correctly filled with actual data
@ -217,14 +249,13 @@ namespace currency
bool separately_signed_tx = get_tx_flags(t) & TX_FLAG_SIGNATURE_MODE_SEPARATE;
tx_blob_size += tools::get_varint_packed_size(t.vin.size()); // size of transaction::signatures (equals to total inputs count)
if (t.version > TRANSACTION_VERSION_PRE_HF4)
tx_blob_size += t.vin.size(); // for HF4 txs 'signatures' is a verctor of variants, so it's +1 byte per signature (assuming sigs count equals to inputs count)
for (size_t i = 0; i != t.vin.size(); i++)
{
size_t sig_count = get_input_expected_signatures_count(t.vin[i]);
if (separately_signed_tx && i == t.vin.size() - 1)
++sig_count; // count in one more signature for the last input in a complete separately signed tx
tx_blob_size += tools::get_varint_packed_size(sig_count); // size of transaction::signatures[i]
tx_blob_size += sizeof(crypto::signature) * sig_count; // size of signatures' data itself
size_t sig_size = get_input_expected_signature_size_local(t.vin[i], separately_signed_tx && i == t.vin.size() - 1);
tx_blob_size += sig_size;
}
// 2. attachments (try to find extra_attachment_info in tx prefix and count it in if succeed)
@ -260,16 +291,134 @@ namespace currency
bool read_keyimages_from_tx(const transaction& tx, std::list<crypto::key_image>& kil)
{
std::unordered_set<crypto::key_image> ki;
BOOST_FOREACH(const auto& in, tx.vin)
for(const auto& in : tx.vin)
{
if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc))
if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc) || in.type() == typeid(txin_zc_input))
{
if (!ki.insert(get_to_key_input_from_txin_v(in).k_image).second)
if (!ki.insert(get_key_image_from_txin_v(in)).second)
return false;
}
}
return true;
}
//---------------------------------------------------------------
bool validate_inputs_sorting(const transaction& tx)
{
if (get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE)
return true;
size_t i = 0;
for(; i+1 < tx.vin.size(); i++)
{
//same less_txin_v() function should be used for sorting inputs during transacction creation
if (less_txin_v(tx.vin[i+1], tx.vin[i]))
{
return false;
}
}
return true;
}
//---------------------------------------------------------------
bool is_asset_emitting_transaction(const transaction& tx, asset_descriptor_operation* p_ado /* = nullptr */)
{
if (tx.version <= TRANSACTION_VERSION_PRE_HF4)
return false;
asset_descriptor_operation local_ado{};
if (p_ado == nullptr)
p_ado = &local_ado;
if (!get_type_in_variant_container(tx.extra, *p_ado))
return false;
if (p_ado->operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER || p_ado->operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT)
return true;
return false;
}
//---------------------------------------------------------------
// Prepapres vector of output_entry to be used in key_offsets in a transaction input:
// 1) sort all entries by gindex (while moving all ref_by_id to the end, keeping they relative order)
// 2) convert absolute global indices to relative key_offsets
std::vector<tx_source_entry::output_entry> prepare_outputs_entries_for_key_offsets(const std::vector<tx_source_entry::output_entry>& outputs, size_t old_real_index, size_t& new_real_index) noexcept
{
TRY_ENTRY()
std::vector<tx_source_entry::output_entry> result = outputs;
if (outputs.size() < 2)
{
new_real_index = old_real_index;
return result;
}
std::sort(result.begin(), result.end(), [](const tx_source_entry::output_entry& lhs, const tx_source_entry::output_entry& rhs)
{
if (lhs.out_reference.type() == typeid(uint64_t))
{
if (rhs.out_reference.type() == typeid(uint64_t))
return boost::get<uint64_t>(lhs.out_reference) < boost::get<uint64_t>(rhs.out_reference);
if (rhs.out_reference.type() == typeid(ref_by_id))
return true;
CHECK_AND_ASSERT_THROW_MES(false, "unexpected type in out_reference 1: " << rhs.out_reference.type().name());
}
else if (lhs.out_reference.type() == typeid(ref_by_id))
{
if (rhs.out_reference.type() == typeid(uint64_t))
return false;
if (rhs.out_reference.type() == typeid(ref_by_id))
return false; // don't change the order of ref_by_id elements
CHECK_AND_ASSERT_THROW_MES(false, "unexpected type in out_reference 2: " << rhs.out_reference.type().name());
}
return false;
});
// restore index of the selected element, if needed
if (old_real_index != SIZE_MAX)
{
CHECK_AND_ASSERT_THROW_MES(old_real_index < outputs.size(), "old_real_index is OOB");
auto it = std::find(result.begin(), result.end(), outputs[old_real_index]);
CHECK_AND_ASSERT_THROW_MES(it != result.end(), "internal error: cannot find old_real_index");
new_real_index = it - result.begin();
}
// find the last uint64_t entry - skip ref_by_id entries goint from the end to the beginnning
size_t i = result.size() - 1;
while (i != 0 && result[i].out_reference.type() == typeid(ref_by_id))
--i;
for (; i != 0; i--)
{
boost::get<uint64_t>(result[i].out_reference) -= boost::get<uint64_t>(result[i - 1].out_reference);
}
return result;
CATCH_ENTRY2(std::vector<tx_source_entry::output_entry>{});
}
//---------------------------------------------------------------
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context)
{
//TODO: Implement this function before mainnet
#ifdef TESTNET
return true;
#else
return true;
#endif
}
//----------------------------------------------------------------------------------------------------
std::string transform_tx_to_str(const currency::transaction& tx)
{
return currency::obj_to_json_str(tx);
}
//----------------------------------------------------------------------------------------------------
transaction transform_str_to_tx(const std::string& tx_str)
{
CHECK_AND_ASSERT_THROW_MES(false, "transform_str_to_tx shoruld never be called");
return transaction();
}
}

View file

@ -1,4 +1,4 @@
// Copyright (c) 2018-2019 Zano Project
// Copyright (c) 2018-2023 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@ -16,26 +16,60 @@ namespace currency
{
struct tx_source_entry
{
typedef serializable_pair<txout_ref_v, crypto::public_key> output_entry; // txout_v is either global output index or ref_by_id; public_key - is output ephemeral pub key
struct output_entry
{
output_entry() = default;
output_entry(const output_entry &) = default;
output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address)
: out_reference(out_reference), stealth_address(stealth_address), concealing_point(null_pkey), amount_commitment(null_pkey) {}
output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address, const crypto::public_key& concealing_point, const crypto::public_key& amount_commitment, const crypto::public_key& blinded_asset_id)
: out_reference(out_reference), stealth_address(stealth_address), concealing_point(concealing_point), amount_commitment(amount_commitment), blinded_asset_id(blinded_asset_id) {}
std::vector<output_entry> outputs; //index + key
uint64_t real_output; //index in outputs vector of real output_entry
crypto::public_key real_out_tx_key; //real output's transaction's public key
size_t real_output_in_tx_index; //index in transaction outputs vector
uint64_t amount; //money
uint64_t transfer_index; //money
crypto::hash multisig_id; //if txin_multisig: multisig output id
size_t ms_sigs_count; //if txin_multisig: must be equal to output's minimum_sigs
size_t ms_keys_count; //if txin_multisig: must be equal to size of output's keys container
bool separately_signed_tx_complete; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation
std::string htlc_origin; //for htlc, specify origin
txout_ref_v out_reference; // either global output index or ref_by_id
crypto::public_key stealth_address; // a.k.a output's one-time public key
crypto::public_key concealing_point; // only for ZC outputs
crypto::public_key amount_commitment; // only for ZC outputs
crypto::public_key blinded_asset_id; // only for ZC outputs
bool is_multisig() const { return ms_sigs_count > 0; }
bool operator==(const output_entry& rhs) const { return out_reference == rhs.out_reference; } // used in prepare_outputs_entries_for_key_offsets, it's okay to do partially comparison
BEGIN_SERIALIZE_OBJECT()
FIELD(out_reference)
FIELD(stealth_address)
FIELD(concealing_point)
FIELD(amount_commitment)
FIELD(blinded_asset_id)
END_SERIALIZE()
};
//typedef serializable_pair<txout_ref_v, crypto::public_key> output_entry; // txout_ref_v is either global output index or ref_by_id; public_key - is output's stealth address
std::vector<output_entry> outputs;
uint64_t real_output = 0; //index in outputs vector of real output_entry
crypto::public_key real_out_tx_key = currency::null_pkey; //real output's transaction's public key
crypto::scalar_t real_out_amount_blinding_mask = 0; //blinding mask of real out's amount committment (only for ZC inputs, otherwise must be 0)
crypto::scalar_t real_out_asset_id_blinding_mask = 0; //blinding mask of real out's asset_od (only for ZC inputs, otherwise must be 0)
size_t real_output_in_tx_index = 0; //index in transaction outputs vector
uint64_t amount = 0; //money
uint64_t transfer_index = 0; //index in m_transfers
crypto::hash multisig_id = currency::null_hash; //if txin_multisig: multisig output id
size_t ms_sigs_count = 0; //if txin_multisig: must be equal to output's minimum_sigs
size_t ms_keys_count = 0; //if txin_multisig: must be equal to size of output's keys container
bool separately_signed_tx_complete = false; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation
std::string htlc_origin; //for htlc, specify origin
crypto::public_key asset_id = currency::native_coin_asset_id; //asset id (not blinded, not premultiplied by 1/8) TODO @#@# consider changing to crypto::point_t
bool is_multisig() const { return ms_sigs_count > 0; }
bool is_zc() const { return !real_out_amount_blinding_mask.is_zero(); }
bool is_native_coin() const { return asset_id == currency::native_coin_asset_id; }
uint64_t amount_for_global_output_index() const { return is_zc() ? 0 : amount; } // amount value for global outputs index, it's zero for outputs with hidden amounts
BEGIN_SERIALIZE_OBJECT()
FIELD(outputs)
FIELD(real_output)
FIELD(real_out_tx_key)
FIELD(real_out_amount_blinding_mask)
FIELD(real_out_asset_id_blinding_mask)
FIELD(real_output_in_tx_index)
FIELD(amount)
FIELD(transfer_index)
@ -51,8 +85,8 @@ namespace currency
//if this struct is present, then creating htlc out, expiration -> number of blocks that htlc proposal is active
struct destination_option_htlc_out
{
uint64_t expiration;
crypto::hash htlc_hash;
uint64_t expiration = 0;
crypto::hash htlc_hash = currency::null_hash;
BEGIN_SERIALIZE_OBJECT()
FIELD(expiration)
@ -61,20 +95,34 @@ namespace currency
};
enum tx_destination_entry_flags
{
tdef_none = 0,
tdef_explicit_native_asset_id = 0x0001,
tdef_explicit_amount_to_provide = 0x0002,
tdef_zero_amount_blinding_mask = 0x0004 // currently it's only used for burning native coins
};
struct tx_destination_entry
{
uint64_t amount; //money
std::list<account_public_address> addr; //destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig
size_t minimum_sigs; //if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used
uint64_t amount_to_provide; //amount money that provided by initial creator of tx, used with partially created transactions
uint64_t unlock_time;
destination_option_htlc_out htlc_options; //htlc options
uint64_t amount = 0; // money
std::list<account_public_address> addr; // destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig
size_t minimum_sigs = 0; // if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used
uint64_t amount_to_provide = 0; // amount money that provided by initial creator of tx, used with partially created transactions
uint64_t unlock_time = 0;
destination_option_htlc_out htlc_options; // htlc options
crypto::public_key asset_id = currency::native_coin_asset_id; // not blinded, not premultiplied
uint64_t flags = 0; // set of flags (see tx_destination_entry_flags)
tx_destination_entry() : amount(0), minimum_sigs(0), amount_to_provide(0), unlock_time(0), htlc_options(destination_option_htlc_out()){}
tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(0), htlc_options(destination_option_htlc_out()) {}
tx_destination_entry(uint64_t a, const account_public_address& ad, uint64_t ut) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(ut), htlc_options(destination_option_htlc_out()) {}
tx_destination_entry(uint64_t a, const std::list<account_public_address>& addr) : amount(a), addr(addr), minimum_sigs(addr.size()), amount_to_provide(0), unlock_time(0), htlc_options(destination_option_htlc_out()) {}
tx_destination_entry() = default;
tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad) {}
tx_destination_entry(uint64_t a, const account_public_address& ad, const crypto::public_key& aid) : amount(a), addr(1, ad), asset_id(aid) {}
tx_destination_entry(uint64_t a, const account_public_address& ad, uint64_t ut) : amount(a), addr(1, ad), unlock_time(ut) {}
tx_destination_entry(uint64_t a, const std::list<account_public_address>& addr) : amount(a), addr(addr), minimum_sigs(addr.size()){}
tx_destination_entry(uint64_t a, const std::list<account_public_address>& addr, const crypto::public_key& aid) : amount(a), addr(addr), minimum_sigs(addr.size()), asset_id(aid) {}
bool is_native_coin() const { return asset_id == currency::native_coin_asset_id; }
BEGIN_SERIALIZE_OBJECT()
FIELD(amount)
@ -83,9 +131,41 @@ namespace currency
FIELD(amount_to_provide)
FIELD(unlock_time)
FIELD(htlc_options)
FIELD(asset_id)
FIELD(flags)
END_SERIALIZE()
};
//---------------------------------------------------------------
template<class variant_t, class variant_type_t>
void update_or_add_field_to_extra(std::vector<variant_t>& variant_container, const variant_type_t& v)
{
for (auto& ev : variant_container)
{
if (ev.type() == typeid(variant_type_t))
{
boost::get<variant_type_t>(ev) = v;
return;
}
}
variant_container.push_back(v);
}
//---------------------------------------------------------------
template<class variant_type_t, class variant_t>
void remove_field_of_type_from_extra(std::vector<variant_t>& variant_container)
{
for (size_t i = 0; i != variant_container.size();)
{
if (variant_container[i].type() == typeid(variant_type_t))
{
variant_container.erase(variant_container.begin()+i);
}
else
{
i++;
}
}
}
//---------------------------------------------------------------
template<class extra_type_t>
uint64_t get_tx_x_detail(const transaction& tx)
{
@ -93,6 +173,7 @@ namespace currency
get_type_in_variant_container(tx.extra, e);
return e.v;
}
//---------------------------------------------------------------
template<class extra_type_t>
void set_tx_x_detail(transaction& tx, uint64_t v)
{
@ -100,7 +181,7 @@ namespace currency
e.v = v;
update_or_add_field_to_extra(tx.extra, e);
}
//---------------------------------------------------------------
uint64_t get_tx_unlock_time(const transaction& tx, uint64_t o_i);
uint64_t get_tx_max_unlock_time(const transaction& tx);
bool get_tx_max_min_unlock_time(const transaction& tx, uint64_t& max_unlock_time, uint64_t& min_unlock_time);
@ -128,6 +209,145 @@ namespace currency
blobdata tx_to_blob(const transaction& b);
bool tx_to_blob(const transaction& b, blobdata& b_blob);
bool read_keyimages_from_tx(const transaction& tx, std::list<crypto::key_image>& kil);
bool validate_inputs_sorting(const transaction& tx);
bool is_asset_emitting_transaction(const transaction& tx, asset_descriptor_operation* p_ado = nullptr);
std::vector<tx_source_entry::output_entry> prepare_outputs_entries_for_key_offsets(const std::vector<tx_source_entry::output_entry>& outputs, size_t old_real_index, size_t& new_real_index) noexcept;
}
struct tx_generation_context
{
tx_generation_context() = default;
void resize(size_t zc_ins_count, size_t outs_count)
{
asset_ids.resize(outs_count);
blinded_asset_ids.resize(outs_count);
amount_commitments.resize(outs_count);
asset_id_blinding_masks.resize(outs_count);
amounts.resize(outs_count);
amount_blinding_masks.resize(outs_count);
zc_input_amounts.resize(zc_ins_count);
}
// TODO @#@# reconsider this check -- sowle
bool check_sizes(size_t zc_ins_count, size_t outs_count) const
{
return
pseudo_outs_blinded_asset_ids.size() == zc_ins_count &&
asset_ids.size() == outs_count &&
blinded_asset_ids.size() == outs_count &&
amount_commitments.size() == outs_count &&
asset_id_blinding_masks.size() == outs_count &&
amounts.size() == outs_count &&
amount_blinding_masks.size() == outs_count;
}
void set_tx_key(const keypair& kp)
{
tx_key = kp;
tx_pub_key_p = crypto::point_t(tx_key.pub);
}
// per output data
std::vector<crypto::point_t> asset_ids;
std::vector<crypto::point_t> blinded_asset_ids; // generate_zc_outs_range_proof
std::vector<crypto::point_t> amount_commitments; // generate_zc_outs_range_proof construct_tx_out
crypto::scalar_vec_t asset_id_blinding_masks; // construct_tx_out
crypto::scalar_vec_t amounts; // generate_zc_outs_range_proof
crypto::scalar_vec_t amount_blinding_masks; // generate_zc_outs_range_proof
// per zc input data
std::vector<crypto::point_t> pseudo_outs_blinded_asset_ids; // generate_asset_surjection_proof
crypto::scalar_vec_t pseudo_outs_plus_real_out_blinding_masks; // r_pi + r'_j // generate_asset_surjection_proof
std::vector<crypto::point_t> real_zc_ins_asset_ids; // H_i // generate_asset_surjection_proof
std::vector<uint64_t> zc_input_amounts; // ZC only input amounts
// common data: inputs
crypto::point_t pseudo_out_amount_commitments_sum = crypto::c_point_0; // generate_tx_balance_proof generate_ZC_sig
crypto::scalar_t pseudo_out_amount_blinding_masks_sum = 0; // generate_ZC_sig
crypto::scalar_t real_in_asset_id_blinding_mask_x_amount_sum = 0; // = sum( real_out_blinding_mask[i] * amount[i] ) generate_tx_balance_proof generate_ZC_sig
// common data: outputs
crypto::point_t amount_commitments_sum = crypto::c_point_0; // generate_tx_balance_proof
crypto::scalar_t amount_blinding_masks_sum = 0; // construct_tx_out generate_tx_balance_proof generate_ZC_sig
crypto::scalar_t asset_id_blinding_mask_x_amount_sum = 0; // = sum( blinding_mask[j] * amount[j] ) generate_tx_balance_proof
// data for ongoing asset operation in tx (if applicable, tx extra should contain asset_descriptor_operation)
crypto::public_key ao_asset_id {};
crypto::point_t ao_asset_id_pt = crypto::c_point_0;
crypto::point_t ao_amount_commitment = crypto::c_point_0;
crypto::scalar_t ao_amount_blinding_mask {}; // generate_tx_balance_proof generate_ZC_sig
bool ao_commitment_in_outputs = false;
// per tx data
keypair tx_key {}; //
crypto::point_t tx_pub_key_p = crypto::c_point_0; // == tx_key.pub
// consider redesign, some data may possibly be excluded from kv serialization -- sowle
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(blinded_asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amount_commitments)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_id_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amounts)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amount_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_blinded_asset_ids)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_plus_real_out_blinding_masks)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(real_zc_ins_asset_ids)
KV_SERIALIZE(zc_input_amounts)
KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_commitments_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_blinding_masks_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(real_in_asset_id_blinding_mask_x_amount_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(amount_commitments_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(amount_blinding_masks_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(asset_id_blinding_mask_x_amount_sum)
KV_SERIALIZE_POD_AS_HEX_STRING(ao_asset_id)
KV_SERIALIZE_POD_AS_HEX_STRING(ao_asset_id_pt)
KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_commitment)
KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_blinding_mask)
KV_SERIALIZE_POD_AS_HEX_STRING(ao_commitment_in_outputs)
KV_SERIALIZE_POD_AS_HEX_STRING(tx_key)
KV_SERIALIZE_POD_AS_HEX_STRING(tx_pub_key_p)
END_KV_SERIALIZE_MAP()
// solely for consolidated txs, asset opration fields are not serialized
BEGIN_SERIALIZE_OBJECT()
VERSION(0)
FIELD(asset_ids)
FIELD(blinded_asset_ids)
FIELD(amount_commitments)
FIELD((std::vector<crypto::scalar_t>&)(asset_id_blinding_masks))
FIELD((std::vector<crypto::scalar_t>&)(amounts))
FIELD((std::vector<crypto::scalar_t>&)(amount_blinding_masks))
FIELD(pseudo_outs_blinded_asset_ids)
FIELD((std::vector<crypto::scalar_t>&)(pseudo_outs_plus_real_out_blinding_masks))
FIELD(real_zc_ins_asset_ids)
FIELD(zc_input_amounts)
FIELD(pseudo_out_amount_commitments_sum)
FIELD(pseudo_out_amount_blinding_masks_sum)
FIELD(real_in_asset_id_blinding_mask_x_amount_sum)
FIELD(amount_commitments_sum)
FIELD(amount_blinding_masks_sum)
FIELD(asset_id_blinding_mask_x_amount_sum)
// no asset operation fields here
//ao_asset_id
//ao_asset_id_pt
//ao_amount_commitment
//ao_amount_blinding_mask
//ao_commitment_in_outputs
FIELD(tx_key.pub) // TODO: change to sane serialization FIELD(tx_key)
FIELD(tx_key.sec)
FIELD(tx_pub_key_p)
END_SERIALIZE()
}; // struct tx_generation_context
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context);
std::string transform_tx_to_str(const transaction& tx);
transaction transform_str_to_tx(const std::string& tx_str);
} // namespace currency

View file

@ -179,7 +179,7 @@ namespace currency {
return res.convert_to<wide_difficulty_type>();
}
wide_difficulty_type next_difficulty_1(vector<uint64_t>& timestamps, vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds)
wide_difficulty_type next_difficulty_1(vector<uint64_t>& timestamps, vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds, const wide_difficulty_type& difficulty_starter)
{
// timestamps - first is latest, back - is oldest timestamps
@ -194,7 +194,7 @@ namespace currency {
CHECK_AND_ASSERT_MES(length == cumulative_difficulties.size(), 0, "Check \"length == cumulative_difficulties.size()\" failed");
if (length <= 1)
{
return DIFFICULTY_STARTER;
return difficulty_starter;
}
static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small");
@ -221,7 +221,7 @@ namespace currency {
return summ / devider;
}
wide_difficulty_type next_difficulty_2(vector<uint64_t>& timestamps, vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds)
wide_difficulty_type next_difficulty_2(vector<uint64_t>& timestamps, vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds, const wide_difficulty_type& difficulty_starter)
{
// timestamps - first is latest, back - is oldest timestamps
@ -236,7 +236,7 @@ namespace currency {
CHECK_AND_ASSERT_MES(length == cumulative_difficulties.size(), 0, "Check \"length == cumulative_difficulties.size()\" failed");
if (length <= 1)
{
return DIFFICULTY_STARTER;
return difficulty_starter;
}
static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small");

View file

@ -19,8 +19,8 @@ namespace currency
typedef boost::multiprecision::uint128_t wide_difficulty_type;
bool check_hash(const crypto::hash &hash, wide_difficulty_type difficulty);
wide_difficulty_type next_difficulty_1(std::vector<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds);
wide_difficulty_type next_difficulty_2(std::vector<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds);
wide_difficulty_type next_difficulty_1(std::vector<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds, const wide_difficulty_type& difficulty_starter);
wide_difficulty_type next_difficulty_2(std::vector<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds, const wide_difficulty_type& difficulty_starter);
uint64_t difficulty_to_boundary(wide_difficulty_type difficulty);
void difficulty_to_boundary_long(wide_difficulty_type difficulty, crypto::hash& result);
}

View file

@ -17,6 +17,7 @@
#define CORE_EVENT_ADD_ALIAS "CORE_EVENT_ADD_ALIAS"
#define CORE_EVENT_UPDATE_ALIAS "CORE_EVENT_UPDATE_ALIAS"
#define CORE_EVENT_BLOCK_ADDED "CORE_EVENT_BLOCK_ADDED"
#define CORE_EVENT_ADD_ASSET "CORE_EVENT_ADD_ASSET"
namespace currency

View file

@ -68,7 +68,7 @@ namespace currency
crypto::hash h = get_block_longhash(height, bd_hash, bl.nonce);
if(check_hash(h, diffic))
{
LOG_PRINT_L0("Found nonce for block: " << get_block_hash(bl) << "[" << height << "]: PoW:" << h << "(diff:" << diffic << "), ts: " << bl.timestamp);
LOG_PRINT_L1("Found nonce for block: " << get_block_hash(bl) << "[" << height << "]: PoW:" << h << " (diff:" << diffic << "), ts: " << bl.timestamp);
return true;
}
}
@ -92,7 +92,7 @@ namespace currency
volatile uint32_t m_stop;
::critical_section m_template_lock;
epee::critical_section m_template_lock;
block m_template;
std::atomic<uint32_t> m_template_no;
std::atomic<uint32_t> m_starter_nonce;
@ -101,15 +101,15 @@ namespace currency
volatile uint32_t m_thread_index;
volatile uint32_t m_threads_total;
std::atomic<int32_t> m_pausers_count;
::critical_section m_miners_count_lock;
epee::critical_section m_miners_count_lock;
std::list<boost::thread> m_threads;
::critical_section m_threads_lock;
epee::critical_section m_threads_lock;
i_miner_handler* m_phandler;
//blockchain_storage& m_bc;
account_public_address m_mine_address;
math_helper::once_a_time_seconds<5> m_update_block_template_interval;
math_helper::once_a_time_seconds<2> m_update_merge_hr_interval;
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;
miner_config m_config;
std::string m_config_folder;

View file

@ -19,9 +19,9 @@ namespace bc_services
{
//fields filled in UI
uint8_t offer_type; // OFFER_TYPE_PRIMARY_TO_TARGET(SELL ORDER) - 0, OFFER_TYPE_TARGET_TO_PRIMARY(BUY ORDER) - 1 etc.
uint64_t amount_primary; // amount of the currency
uint64_t amount_target; // amount of other currency or goods
uint8_t offer_type = 0; // OFFER_TYPE_PRIMARY_TO_TARGET(SELL ORDER) - 0, OFFER_TYPE_TARGET_TO_PRIMARY(BUY ORDER) - 1 etc.
uint64_t amount_primary = 0; // amount of the currency
uint64_t amount_target = 0; // amount of other currency or goods
std::string bonus; //
std::string target; // [] currency / goods
std::string primary; // currency for goods
@ -33,7 +33,7 @@ namespace bc_services
std::string deal_option; // []full amount, by parts
std::string category; // []
std::string preview_url; // []
uint8_t expiration_time; // n-days
uint8_t expiration_time = 0; // n-days
//-----------------
BEGIN_KV_SERIALIZE_MAP()

View file

@ -0,0 +1,108 @@
// Copyright (c) 2022 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#include "currency_basic.h"
#include "difficulty.h"
#include "pos_mining.h"
#include "wallet/wallet2.h"
#include "crypto/zarcanum.h"
#include "crypto_config.h"
namespace currency
{
void pos_mining_context::init(const wide_difficulty_type& pos_diff, const stake_modifier_type& sm, bool is_zarcanum)
{
this->basic_diff = pos_diff;
this->sk.stake_modifier = sm;
this->zarcanum = is_zarcanum;
if (is_zarcanum)
{
this->last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, this->sk.stake_modifier.last_pow_id);
this->z_l_div_z_D = crypto::zarcanum_precalculate_z_l_div_z_D(this->basic_diff);
}
}
void pos_mining_context::prepare_entry(uint64_t stake_amount, const crypto::key_image& stake_out_ki, const crypto::public_key& stake_source_tx_pub_key, uint64_t stake_out_in_tx_index,
const crypto::scalar_t& stake_out_amount_blinding_mask, const crypto::secret_key& view_secret)
{
this->stake_amount = stake_amount;
this->sk.kimage = stake_out_ki;
if (this->zarcanum)
{
crypto::scalar_t v = view_secret;
crypto::key_derivation derivation = AUTO_VAL_INIT(derivation);
bool r = crypto::generate_key_derivation(stake_source_tx_pub_key, view_secret, derivation); // 8 * v * R
CHECK_AND_ASSERT_MES_NO_RET(r, "generate_key_derivation failed");
crypto::scalar_t h = AUTO_VAL_INIT(h);
crypto::derivation_to_scalar(derivation, stake_out_in_tx_index, h.as_secret_key()); // h = Hs(8 * v * R, i)
// q = Hs(domain_sep, Hs(8 * v * R, i) ) * 8 * v
this->secret_q = v * 8 * crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h);
this->stake_out_amount_blinding_mask = stake_out_amount_blinding_mask;
}
}
bool pos_mining_context::do_iteration(uint64_t ts)
{
// update stake kernel and calculate it's hash
this->sk.block_timestamp = ts;
{
PROFILE_FUNC("calc_hash");
this->kernel_hash = crypto::cn_fast_hash(&this->sk, sizeof(this->sk));
}
bool found = false;
if (this->zarcanum /* && td.is_zc() */)
{
crypto::mp::uint256_t lhs;
crypto::mp::uint512_t rhs;
{
PROFILE_FUNC("check_zarcanum");
found = crypto::zarcanum_check_main_pos_inequality(this->kernel_hash, this->stake_out_amount_blinding_mask, this->secret_q, this->last_pow_block_id_hashed, this->z_l_div_z_D, this->stake_amount, lhs, rhs);
}
if (found)
{
found = true;
const boost::multiprecision::uint256_t d_mp = lhs / (crypto::c_zarcanum_z_coeff_mp * this->stake_amount) + 1;
const boost::multiprecision::uint256_t ba = d_mp * crypto::c_zarcanum_z_coeff_mp * this->stake_amount - lhs;
const boost::multiprecision::uint256_t l_div_z_D = this->z_l_div_z_D / crypto::c_zarcanum_z_coeff_mp;
LOG_PRINT_GREEN("Found Zarcanum kernel: amount: " << currency::print_money_brief(this->stake_amount) << /* ", gindex: " << td.m_global_output_index << */ ENDL
<< "difficulty: " << this->basic_diff << ENDL
<< "kernel info: " << ENDL
<< print_stake_kernel_info(this->sk)
<< "kernel_hash: " << this->kernel_hash << ENDL
<< "lhs: 0x" << crypto::scalar_t(lhs).to_string_as_hex_number() << " = 0x" << std::hex << d_mp << " * 2^64 * " << this->stake_amount << " - 0x" << std::hex << ba << ENDL
<< "rhs: 0x" << crypto::scalar_t(rhs).to_string_as_hex_number() << ENDL
<< "d: 0x" << std::hex << d_mp << ENDL
<< "l / floor(z * D): 0x" << std::hex << l_div_z_D
, LOG_LEVEL_0);
}
}
else
{
// old PoS with non-hidden amounts
currency::wide_difficulty_type final_diff = this->basic_diff / this->stake_amount;
{
PROFILE_FUNC("check_hash");
found = currency::check_hash(this->kernel_hash, final_diff);
}
if (found)
{
LOG_PRINT_GREEN("Found kernel: amount: " << currency::print_money_brief(this->stake_amount)<< /* ", gindex: " << td.m_global_output_index << */ ENDL
<< "difficulty: " << this->basic_diff << ", final_diff: " << final_diff << ENDL
<< "kernel info: " << ENDL
<< print_stake_kernel_info(this->sk)
<< "kernel_hash(proof): " << this->kernel_hash,
LOG_LEVEL_0);
}
}
return found;
}
}; // namespace currency

View file

@ -0,0 +1,32 @@
// Copyright (c) 2022 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
#pragma once
namespace currency
{
struct pos_mining_context
{
// Zarcanum notation:
wide_difficulty_type basic_diff; // D
stake_kernel sk;
crypto::scalar_t last_pow_block_id_hashed; // f'
crypto::scalar_t secret_q; // q
boost::multiprecision::uint256_t z_l_div_z_D; // z * floor( l / (z * D) ) (max possible value (assuming z=2^64) : z * 2^252 / (z * 1) ~= 2^252)
crypto::hash kernel_hash; // h
crypto::scalar_t stake_out_amount_blinding_mask; // f
uint64_t stake_amount; // a
bool zarcanum; // false for pre-HF4 classic PoS with explicit amounts
void init(const wide_difficulty_type& pos_diff, const stake_modifier_type& sm, bool is_zarcanum);
void prepare_entry(uint64_t stake_amount, const crypto::key_image& stake_out_ki, const crypto::public_key& stake_source_tx_pub_key, uint64_t stake_out_in_tx_index,
const crypto::scalar_t& stake_out_blinding_mask, const crypto::secret_key& view_secret);
bool do_iteration(uint64_t ts);
};
};

View file

@ -21,6 +21,7 @@
#include "crypto/hash.h"
#include "profile_tools.h"
#include "common/db_backend_selector.h"
#include "tx_semantic_validation.h"
DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated name length exceeded, name was truncated
@ -40,6 +41,8 @@ DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated
#define LOG_DEFAULT_CHANNEL "tx_pool"
ENABLE_CHANNEL_BY_DEFAULT("tx_pool");
using namespace epee;
namespace currency
{
//---------------------------------------------------------------------------------
@ -90,8 +93,23 @@ namespace currency
return true;
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::check_tx_fee(const transaction &tx, uint64_t amount_fee)
{
if (amount_fee < m_blockchain.get_core_runtime_config().tx_pool_min_fee)
return false;
//m_blockchain.get
return true;
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::add_tx(const transaction &tx, const crypto::hash &id, uint64_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool from_core)
{
{
bool r = false;
// defaults
tvc.m_added_to_pool = false;
tvc.m_verification_failed = true;
if (!kept_by_block && !from_core && m_blockchain.is_in_checkpoint_zone())
{
// BCS is in CP zone, tx verification is impossible until it gets synchronized
@ -102,21 +120,13 @@ namespace currency
return false;
}
if (!m_blockchain.validate_tx_for_hardfork_specific_terms(tx, id))
{
//
LOG_ERROR("Transaction " << id <<" doesn't fit current hardfork");
tvc.m_verification_failed = true;
return false;
}
r = m_blockchain.validate_tx_for_hardfork_specific_terms(tx, id);
CHECK_AND_ASSERT_MES(r, false, "Transaction " << id <<" doesn't fit current hardfork");
TIME_MEASURE_START_PD(tx_processing_time);
TIME_MEASURE_START_PD(check_inputs_types_supported_time);
if(!check_inputs_types_supported(tx))
{
tvc.m_verification_failed = true;
return false;
}
r = check_inputs_types_supported(tx);
CHECK_AND_ASSERT_MES(r, false, "tx " << id << " has wrong inputs types");
TIME_MEASURE_FINISH_PD(check_inputs_types_supported_time);
TIME_MEASURE_START_PD(expiration_validate_time);
@ -132,61 +142,60 @@ namespace currency
}
TIME_MEASURE_FINISH_PD(expiration_validate_time);
TIME_MEASURE_START_PD(validate_amount_time);
uint64_t inputs_amount = 0;
if(!get_inputs_money_amount(tx, inputs_amount))
{
tvc.m_verification_failed = true;
return false;
}
CHECK_AND_ASSERT_MES(tx.vout.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS, false, "transaction has too many outs = " << tx.vout.size());
CHECK_AND_ASSERT_MES_CUSTOM(tx.vout.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS, false, tvc.m_verification_failed = true, "transaction has too many outs = " << tx.vout.size());
uint64_t tx_fee = 0;
r = get_tx_fee(tx, tx_fee);
CHECK_AND_ASSERT_MES(r, false, "get_tx_fee failed");
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 " << outputs_amount << ", have " << inputs_amount);
tvc.m_verification_failed = true;
return false;
}
// @#@# consider removing the following
//if (!check_tx_balance(tx)) // TODO (performance): check_tx_balance calls get_tx_fee as well, consider refactoring -- sowle
//{
// LOG_PRINT_L0("balance check failed for tx " << id);
// tvc.m_verification_failed = true;
// return false;
//}
TIME_MEASURE_FINISH_PD(validate_amount_time);
TIME_MEASURE_START_PD(validate_alias_time);
if (!from_core && !validate_alias_info(tx, kept_by_block))
{
LOG_PRINT_RED_L0("validate_alias_info failed");
tvc.m_verification_failed = true;
return false;
}
r = from_core || validate_alias_info(tx, kept_by_block);
CHECK_AND_ASSERT_MES(r, false, "validate_alias_info failed");
TIME_MEASURE_FINISH_PD(validate_alias_time);
TIME_MEASURE_START_PD(check_keyimages_ws_ms_time);
//check key images for transaction if it is not kept by block
if(!from_core && !kept_by_block)
{
crypto::key_image spent_ki = AUTO_VAL_INIT(spent_ki);
if(have_tx_keyimges_as_spent(tx, &spent_ki))
{
LOG_ERROR("Transaction " << id << " uses already spent key image " << spent_ki);
if(!validate_tx_semantic(tx, blob_size))
{
// tx semantics check failed
LOG_PRINT_RED_L0("Transaction " << id << " semantics check failed ");
tvc.m_verification_failed = true;
tvc.m_should_be_relayed = false;
tvc.m_added_to_pool = false;
return false;
}
crypto::key_image spent_ki = AUTO_VAL_INIT(spent_ki);
r = !have_tx_keyimges_as_spent(tx, &spent_ki);
CHECK_AND_ASSERT_MES(r, false, "Transaction " << id << " uses already spent key image " << spent_ki);
//transaction spam protection, soft rule
uint64_t tx_fee = inputs_amount - outputs_amount;
if (tx_fee < m_blockchain.get_core_runtime_config().tx_pool_min_fee)
if (!check_tx_fee(tx, tx_fee))
{
if (is_valid_contract_finalization_tx(tx))
{
//if (is_valid_contract_finalization_tx(tx))
//{
// that means tx has less fee then allowed by current tx pull rules, but this transaction is actually
// a finalization of contract, and template of this contract finalization tx was prepared actually before
// fee rules had been changed, so it's ok, let it in.
}
else
//}
//else
{
// this tx has no fee
LOG_PRINT_RED_L0("Transaction with id= " << id << " has too small fee: " << tx_fee << ", expected fee: " << m_blockchain.get_core_runtime_config().tx_pool_min_fee);
LOG_PRINT_RED_L0("Transaction " << id << " has too small fee: " << print_money_brief(tx_fee) << ", minimum fee: " << print_money_brief(m_blockchain.get_core_runtime_config().tx_pool_min_fee));
tvc.m_verification_failed = false;
tvc.m_should_be_relayed = false;
tvc.m_added_to_pool = false;
@ -209,13 +218,13 @@ namespace currency
bool ch_inp_res = m_blockchain.check_tx_inputs(tx, id, max_used_block_height, max_used_block_id);
if (!ch_inp_res && !kept_by_block && !from_core)
{
LOG_PRINT_L0("tx used wrong inputs, rejected");
LOG_PRINT_L0("check_tx_inputs failed, tx rejected");
tvc.m_verification_failed = true;
return false;
}
TIME_MEASURE_FINISH_PD(check_inputs_time);
do_insert_transaction(tx, id, blob_size, kept_by_block, inputs_amount - outputs_amount, ch_inp_res ? max_used_block_id : null_hash, ch_inp_res ? max_used_block_height : 0);
do_insert_transaction(tx, id, blob_size, kept_by_block, tx_fee, ch_inp_res ? max_used_block_id : null_hash, ch_inp_res ? max_used_block_height : 0);
TIME_MEASURE_FINISH_PD(tx_processing_time);
tvc.m_added_to_pool = true;
@ -477,10 +486,10 @@ namespace currency
should_be_spent_before_height -= CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL;
for (auto& in : tx_entry.tx.vin)
{
if (in.type() == typeid(txin_to_key))
crypto::key_image ki = AUTO_VAL_INIT(ki);
if (get_key_image_from_txin_v(in, ki))
{
// if at least one key image is spent deep enought -- remove such tx
const crypto::key_image& ki = boost::get<txin_to_key>(in).k_image;
if (m_blockchain.have_tx_keyimg_as_spent(ki, should_be_spent_before_height))
{
LOG_PRINT_L0("tx " << h << " is about to be removed from tx pool, reason: ki was spent in the blockchain before height " << should_be_spent_before_height << ", tx age: " << misc_utils::get_time_interval_string(tx_age));
@ -528,7 +537,7 @@ namespace currency
txs.push_back(tx_rpc_extended_info());
tx_rpc_extended_info& trei = txs.back();
trei.blob_size = tx_entry.blob_size;
fill_tx_rpc_details(trei, tx_entry.tx, nullptr, h, tx_entry.receive_time, true);
m_blockchain.fill_tx_rpc_details(trei, tx_entry.tx, nullptr, h, tx_entry.receive_time, true);
return true;
});
@ -580,7 +589,7 @@ namespace currency
txs.push_back(tx_rpc_extended_info());
tx_rpc_extended_info& trei = txs.back();
trei.blob_size = ptei->blob_size;
fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false);
m_blockchain.fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false);
}
return true;
}
@ -617,7 +626,7 @@ namespace currency
if (!ptei)
return false;
fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false);
m_blockchain.fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false);
return true;
}
//---------------------------------------------------------------------------------
@ -707,16 +716,15 @@ namespace currency
{
for(const auto& in : tx.vin)
{
if (in.type() == typeid(txin_to_key))
crypto::key_image k_image = AUTO_VAL_INIT(k_image);
if (get_key_image_from_txin_v(in, k_image))
{
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))
if (have_tx_keyimg_as_spent(k_image))
{
if (p_spent_ki)
*p_spent_ki = tokey_in.k_image;
*p_spent_ki = k_image;
return true;
}
}
}
return false;
@ -727,13 +735,13 @@ namespace currency
CRITICAL_REGION_LOCAL(m_key_images_lock);
for(const auto& in : tx.vin)
{
if (in.type() == typeid(txin_to_key))
crypto::key_image k_image = AUTO_VAL_INIT(k_image);
if (get_key_image_from_txin_v(in, k_image))
{
const txin_to_key& tokey_in = boost::get<txin_to_key>(in);
auto& id_set = m_key_images[tokey_in.k_image];
auto& id_set = m_key_images[k_image];
size_t sz_before = id_set.size();
id_set.insert(tx_id);
LOG_PRINT_L2("tx pool: key image added: " << tokey_in.k_image << ", from tx " << tx_id << ", counter: " << sz_before << " -> " << id_set.size());
LOG_PRINT_L2("tx pool: key image added: " << k_image << ", from tx " << tx_id << ", counter: " << sz_before << " -> " << id_set.size());
}
}
return false;
@ -787,11 +795,10 @@ namespace currency
CRITICAL_REGION_LOCAL(m_key_images_lock);
for(const auto& in : tx.vin)
{
if (in.type() == typeid(txin_to_key))
crypto::key_image k_image = AUTO_VAL_INIT(k_image);
if (get_key_image_from_txin_v(in, k_image))
{
const txin_to_key& tokey_in = boost::get<txin_to_key>(in);
auto it_map = epee::misc_utils::it_get_or_insert_value_initialized(m_key_images, tokey_in.k_image);
auto it_map = epee::misc_utils::it_get_or_insert_value_initialized(m_key_images, k_image);
auto& id_set = it_map->second;
size_t count_before = id_set.size();
auto it_set = id_set.find(tx_id);
@ -802,22 +809,22 @@ namespace currency
if (id_set.size() == 0)
m_key_images.erase(it_map);
LOG_PRINT_L2("tx pool: key image removed: " << tokey_in.k_image << ", from tx " << tx_id << ", counter: " << count_before << " -> " << count_after);
LOG_PRINT_L2("tx pool: key image removed: " << k_image << ", from tx " << tx_id << ", counter: " << count_before << " -> " << count_after);
}
}
return false;
}
//---------------------------------------------------------------------------------
bool tx_memory_pool::get_key_images_from_tx_pool(key_image_cache& key_images) const
{
{
m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry)
{
for (auto& in : tx_entry.tx.vin)
{
if (in.type() == typeid(txin_to_key))
crypto::key_image k_image = AUTO_VAL_INIT(k_image);
if (get_key_image_from_txin_v(in, k_image))
{
key_images[boost::get<txin_to_key>(in).k_image].insert(h);
key_images[k_image].insert(h);
}
}
return true;
@ -921,10 +928,10 @@ namespace currency
LOCAL_READONLY_TRANSACTION();
for(size_t i = 0; i!= tx.vin.size(); i++)
{
if (tx.vin[i].type() == typeid(txin_to_key))
crypto::key_image k_image = AUTO_VAL_INIT(k_image);
if (get_key_image_from_txin_v(tx.vin[i], k_image))
{
CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, false);
if (k_images.count(itk.k_image))
if (k_images.count(k_image))
return true;
}
}
@ -933,13 +940,13 @@ namespace currency
//---------------------------------------------------------------------------------
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++)
for(size_t i = 0; i != tx.vin.size(); i++)
{
if (tx.vin[i].type() == typeid(txin_to_key))
crypto::key_image k_image = AUTO_VAL_INIT(k_image);
if (get_key_image_from_txin_v(tx.vin[i], k_image))
{
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);
auto i_res = k_images.insert(k_image);
CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: key images pool cache - inserted duplicate image in set: " << k_image);
}
}
return true;
@ -959,8 +966,8 @@ namespace currency
return "(no transactions, the pool is empty)";
// sort output by receive time
txs.sort([](const std::pair<crypto::hash, tx_details>& lhs, const std::pair<crypto::hash, tx_details>& rhs) -> bool { return lhs.second.receive_time < rhs.second.receive_time; });
ss << "# | transaction id | size | fee | ins | outs | outs money | live_time | max used block | last failed block | kept by a block?" << ENDL;
// 1234 <f99fe6d4335fc0ddd69e6880a4d95e0f6ea398de0324a6837021a61c6a31cacd> 87157 0.10000111 2000 2000 112000.12345678 d0.h10.m16.s17 123456 <12345..> 123456 <12345..> YES
ss << "# | transaction id | size | fee | ins | outs | outs money | live_time | max used block | last failed block | kept by a block?" << ENDL;
// 1234 f99fe6d4335fc0ddd69e6880a4d95e0f6ea398de0324a6837021a61c6a31cacd 87157 0.10000111 2000 2000 112000.12345678 d0.h10.m16.s17 123456 <12345..> 123456 <12345..> YES
size_t i = 0;
for (auto& tx : txs)
{
@ -1328,8 +1335,11 @@ namespace currency
idx = 0;
for (const auto& out : tx.vout)
{
if (out.target.type() == typeid(txout_multisig))
result.push_back(ms_out_info({ get_multisig_out_id(tx, idx), idx, false }));
VARIANT_SWITCH_BEGIN(out);
VARIANT_CASE_CONST(tx_out_bare, o)
if (o.target.type() == typeid(txout_multisig))
result.push_back(ms_out_info({ get_multisig_out_id(tx, idx), idx, false }));
VARIANT_SWITCH_END();
++idx;
}
}
@ -1345,8 +1355,11 @@ namespace currency
size_t idx = 0;
for (const auto& out : tx.vout)
{
if (out.target.type() == typeid(txout_multisig) && get_multisig_out_id(tx, idx) == multisig_id)
return true;
VARIANT_SWITCH_BEGIN(out);
VARIANT_CASE_CONST(tx_out_bare, o)
if (o.target.type() == typeid(txout_multisig) && get_multisig_out_id(tx, idx) == multisig_id)
return true;
VARIANT_SWITCH_END();
++idx;
}

View file

@ -6,7 +6,6 @@
#pragma once
#include "include_base_utils.h"
using namespace epee;
#include <set>
@ -146,6 +145,7 @@ namespace currency
bool remove_key_images(const crypto::hash &tx_id, const transaction& tx, bool kept_by_block);
bool insert_alias_info(const transaction& tx);
bool remove_alias_info(const transaction& tx);
bool check_tx_fee(const transaction &tx, uint64_t amount_fee);
bool is_valid_contract_finalization_tx(const transaction &tx)const;
void store_db_solo_options_values();

View file

@ -21,27 +21,27 @@ namespace currency
//-----------------------------------------------------------------------------------------------
bool check_tx_inputs_keyimages_diff(const transaction& tx)
{
std::unordered_set<crypto::key_image> ki;
BOOST_FOREACH(const auto& in, tx.vin)
std::unordered_set<crypto::key_image> key_images;
crypto::key_image ki{};
for(const auto& in_v : tx.vin)
{
if (in.type() == typeid(txin_to_key))
if (get_key_image_from_txin_v(in_v, ki))
{
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false);
if (!ki.insert(tokey_in.k_image).second)
return false;
}
else if (in.type() == typeid(txin_htlc))
{
CHECKED_GET_SPECIFIC_VARIANT(in, const txin_htlc, htlc_in, false);
if (!ki.insert(htlc_in.k_image).second)
if (!key_images.insert(ki).second)
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------------------------
bool validate_tx_semantic(const transaction& tx, size_t tx_block_size)
bool validate_tx_semantic(const transaction& tx, size_t tx_blob_size)
{
if (tx_blob_size >= CURRENCY_MAX_TRANSACTION_BLOB_SIZE)
{
LOG_PRINT_RED_L0("tx blob size is " << tx_blob_size << ", it is greater than or equal to allowed maximum of " << CURRENCY_MAX_TRANSACTION_BLOB_SIZE);
return false;
}
if (!tx.vin.size())
{
LOG_PRINT_RED_L0("tx with empty inputs, rejected for tx id= " << get_transaction_hash(tx));
@ -56,7 +56,7 @@ namespace currency
if (!check_outs_valid(tx))
{
LOG_PRINT_RED_L0("tx with invalid outputs, rejected for tx id= " << get_transaction_hash(tx));
LOG_PRINT_RED_L0("tx has invalid outputs, rejected for tx id= " << get_transaction_hash(tx));
return false;
}
@ -66,22 +66,6 @@ namespace currency
return false;
}
uint64_t amount_in = 0;
get_inputs_money_amount(tx, amount_in);
uint64_t amount_out = get_outs_money_amount(tx);
if (amount_in < amount_out)
{
LOG_PRINT_RED_L0("tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << get_transaction_hash(tx));
return false;
}
if (tx_block_size >= CURRENCY_MAX_TRANSACTION_BLOB_SIZE)
{
LOG_PRINT_RED_L0("tx has too big size " << tx_block_size << ", expected no bigger than " << CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE);
return false;
}
//check if tx use different key images
if (!check_tx_inputs_keyimages_diff(tx))
{
@ -95,6 +79,17 @@ namespace currency
return false;
}
// inexpensive check for pre-HF4 txs
// post-HF4 txs balance are being checked in check_tx_balance()
if (tx.version <= TRANSACTION_VERSION_PRE_HF4)
{
if (!check_tx_bare_balance(tx))
{
LOG_PRINT_RED_L0("balance check failed for tx " << get_transaction_hash(tx));
return false;
}
}
return true;
}
}

View file

@ -1,16 +1,14 @@
// Copyright (c) 2018-2019 Zano Project
// Copyright (c) 2018-2023 Zano Project
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#pragma once
#include "include_base_utils.h"
#include "currency_format_utils_transactions.h"
namespace currency
{
//check correct values, amounts and all lightweight checks not related with database
//check correct values, ins and outs types, amounts and all lightweight checks not related to the database
bool validate_tx_semantic(const transaction& tx, size_t tx_block_size);
}

View file

@ -107,7 +107,7 @@ namespace currency
std::stringstream conn_ss;
time_t livetime = time(NULL) - cntxt.m_started;
conn_ss << std::setw(29) << std::left << std::string(cntxt.m_is_income ? "[INC]":"[OUT]") +
string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port)
epst::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port)
<< std::setw(20) << std::hex << peer_id
<< std::setw(25) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")"
<< std::setw(25) << get_protocol_state_string(cntxt.m_state)
@ -523,7 +523,7 @@ namespace currency
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"
<< string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection");
<< epst::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection");
m_p2p->drop_connection(context);
m_p2p->add_ip_fail(context.m_remote_ip);
return 1;
@ -547,20 +547,22 @@ namespace currency
auto req_it = context.m_priv.m_requested_objects.find(get_block_hash(b));
if(req_it == context.m_priv.m_requested_objects.end())
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << string_tools::pod_to_hex(get_blob_hash(block_entry.block))
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epst::pod_to_hex(get_blob_hash(block_entry.block))
<< " wasn't requested, dropping connection");
m_p2p->drop_connection(context);
return 1;
}
if(b.tx_hashes.size() != block_entry.txs.size())
{
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << string_tools::pod_to_hex(get_blob_hash(block_entry.block))
LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epst::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");
m_p2p->drop_connection(context);
return 1;
}
context.m_priv.m_requested_objects.erase(req_it);
LOG_PRINT_L4("[NOTIFY_RESPONSE_GET_OBJECTS] BLOCK " << get_block_hash(b) << "[" << get_block_height(b) << "/" << count << "], txs: " << b.tx_hashes.size());
}
LOG_PRINT_CYAN("Block parsing time avr: " << (count > 0 ? total_blocks_parsing_time / count : 0) << " mcs, total for " << count << " blocks: " << total_blocks_parsing_time / 1000 << " ms", LOG_LEVEL_2);
@ -575,29 +577,31 @@ namespace currency
{
m_core.pause_mine();
misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler(
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));
size_t count = 0;
for (const block_complete_entry& block_entry : arg.blocks)
{
CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET(1, "Blocks processing interrupted, connection dropped");
block_verification_context bvc = boost::value_initialized<block_verification_context>();
//process transactions
size_t count_txs = 0;
TIME_MEASURE_START(transactions_process_time);
for (const auto& tx_blob : block_entry.txs)
{
LOG_PRINT_L4("[NOTIFY_RESPONSE_GET_OBJECTS] BL/TX ["<< count << "/" << count_txs << "]: " << epst::buff_to_hex_nodelimer(tx_blob));
CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET(1, "Block txs processing interrupted, connection dropped");
crypto::hash tx_id = null_hash;
transaction tx = AUTO_VAL_INIT(tx);
if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_id))
{
LOG_ERROR_CCONTEXT("failed to parse tx: "
<< string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection");
<< epst::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection");
m_p2p->drop_connection(context);
return 1;
}
bvc.m_onboard_transactions[tx_id] = tx;
count_txs++;
// tx_verification_context tvc = AUTO_VAL_INIT(tvc);
// m_core.handle_incoming_tx(tx_blob, tvc, true);
// if(tvc.m_verification_failed)
@ -742,7 +746,7 @@ namespace currency
<< "\r\nm_remote_blockchain_height=" << context.m_remote_blockchain_height
<< "\r\nm_needed_objects.size()=" << context.m_priv.m_needed_objects.size()
<< "\r\nm_requested_objects.size()=" << context.m_priv.m_requested_objects.size()
<< "\r\non connection [" << net_utils::print_connection_context_short(context)<< "]");
<< "\r\non connection [" << epee::net_utils::print_connection_context_short(context)<< "]");
context.m_state = currency_connection_context::state_normal;
LOG_PRINT_GREEN("[REQUEST_MISSING_OBJECTS]: SYNCHRONIZED OK", LOG_LEVEL_0);
@ -919,7 +923,7 @@ namespace currency
void t_currency_protocol_handler<t_core>::set_to_debug_mode(uint32_t ip)
{
m_debug_ip_address = ip;
LOG_PRINT_L0("debug mode is set for IP " << epee::string_tools::get_ip_string_from_int32(m_debug_ip_address));
LOG_PRINT_L0("debug mode is set for IP " << epst::get_ip_string_from_int32(m_debug_ip_address));
}
//------------------------------------------------------------------------------------------------------------------------
template<class t_core>
@ -944,7 +948,7 @@ namespace currency
if(!m_core.have_block(arg.m_block_ids.front().h))
{
LOG_ERROR_CCONTEXT("sent m_block_ids starting from unknown id: "
<< string_tools::pod_to_hex(arg.m_block_ids.front()) << " , dropping connection");
<< epst::pod_to_hex(arg.m_block_ids.front()) << " , dropping connection");
m_p2p->drop_connection(context);
m_p2p->add_ip_fail(context.m_remote_ip);
return 1;

View file

@ -125,7 +125,7 @@ int main(int argc, char* argv[])
#endif
log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0);
log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL);
log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,wallet");
log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,wallet", false);
LOG_PRINT_L0("Starting...");
tools::signal_handler::install_fatal([](int sig_number, void* address) {
@ -162,6 +162,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_cmd_sett, command_line::arg_no_predownload);
command_line::add_arg(desc_cmd_sett, command_line::arg_force_predownload);
command_line::add_arg(desc_cmd_sett, command_line::arg_process_predownload_from_path);
command_line::add_arg(desc_cmd_sett, command_line::arg_validate_predownload);
command_line::add_arg(desc_cmd_sett, command_line::arg_predownload_link);
command_line::add_arg(desc_cmd_sett, command_line::arg_disable_ntp);

View file

@ -665,9 +665,9 @@ private:
if (ptx->signatures.size() == 0)
pruned_txs += 1;
signatures += ptx->signatures.size();
txs += 1;
signatures += ptx->signatures.size();
attachments += ptx->attachment.size();
}
}

View file

@ -18,6 +18,7 @@
#define PREPARE_ARG_FROM_JSON(arg_type, var_name) \
arg_type var_name = AUTO_VAL_INIT(var_name); \
view::api_response default_ar = AUTO_VAL_INIT(default_ar); \
LOG_PRINT_BLUE("[REQUEST]: " << param.toStdString(), LOG_LEVEL_3); \
if (!epee::serialization::load_t_from_json(var_name, param.toStdString())) \
{ \
default_ar.error_code = API_RETURN_CODE_BAD_ARG; \
@ -28,6 +29,7 @@ template<typename T>
QString make_response(const T& r)
{
std::string str = epee::serialization::store_t_to_json(r);
LOG_PRINT_BLUE("[RESPONSE]: " << str, LOG_LEVEL_3);
return str.c_str();
}
@ -142,6 +144,8 @@ bool MainWindow::init_window()
m_view->page()->setWebChannel(m_channel);
QWidget* central_widget_to_be_set = m_view;
double zoom_factor_test = 0.75;
m_view->setZoomFactor(zoom_factor_test);
std::string qt_dev_tools_option = m_backend.get_qt_dev_tools_option();
if (!qt_dev_tools_option.empty())
@ -265,7 +269,28 @@ QString MainWindow::request_dummy()
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::call_rpc(const QString& params)
{
TRY_ENTRY();
epee::net_utils::http::http_request_info query_info = AUTO_VAL_INIT(query_info);
epee::net_utils::http::http_response_info response_info = AUTO_VAL_INIT(response_info);
currency::core_rpc_server::connection_context dummy_context = AUTO_VAL_INIT(dummy_context);
query_info.m_URI = "/json_rpc";
query_info.m_body = params.toStdString();
m_backend.get_rpc_server().handle_http_request(query_info, response_info, dummy_context);
if (response_info.m_response_code != 200)
{
epee::json_rpc::error_response rsp;
rsp.jsonrpc = "2.0";
rsp.error.code = response_info.m_response_code;
rsp.error.message = response_info.m_response_comment;
return QString::fromStdString(epee::serialization::store_t_to_json(static_cast<epee::json_rpc::error_response&>(rsp)));
}
return QString::fromStdString(response_info.m_body);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::get_default_fee()
{
TRY_ENTRY();
@ -547,6 +572,14 @@ void MainWindow::store_pos(bool consider_showed)
void MainWindow::restore_pos(bool consider_showed)
{
TRY_ENTRY();
if (consider_showed)
{
if (m_config.is_showed)
this->showNormal();
else
this->showMinimized();
}
if (m_config.is_maximazed)
{
this->setWindowState(windowState() | Qt::WindowMaximized);
@ -578,14 +611,6 @@ void MainWindow::restore_pos(bool consider_showed)
}
}
if (consider_showed)
{
if (m_config.is_showed)
this->showNormal();
else
this->showMinimized();
}
CATCH_ENTRY2(void());
}
void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason)
@ -1055,9 +1080,9 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei)
if (!m_tray_icon)
return true;
if (!tei.ti.is_income)
if (tei.ti.has_outgoing_entries())
return true;
if (!tei.ti.amount)
if (!tei.ti.get_native_amount())
return true;
// if (tei.ti.is_mining && m_wallet_states->operator [](tei.wallet_id) != view::wallet_status_info::wallet_state_ready)
// return true;
@ -1071,9 +1096,9 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei)
return true;
}
auto amount_str = currency::print_money_brief(tei.ti.amount);
auto amount_str = currency::print_money_brief(tei.ti.get_native_amount()); //@#@ add handling of assets
std::string title, msg;
if (tei.ti.height == 0) // unconfirmed trx
if (tei.ti.height == 0) // unconfirmed tx
{
msg = amount_str + " " + CURRENCY_NAME_ABR + " " + m_localization[localization_id_is_received];
title = m_localization[localization_id_income_transfer_unconfirmed];
@ -1914,6 +1939,17 @@ QString MainWindow::restore_wallet(const QString& param)
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::use_whitelisting(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
//return que_call2<view::restore_wallet_request>("restore_wallet", param, [this](const view::restore_wallet_request& owd, view::api_response& ar){
PREPARE_ARG_FROM_JSON(view::api_request_t<bool>, owd);
PREPARE_RESPONSE(view::api_responce_return_code, ar);
ar.error_code = m_backend.use_whitelisting(owd.wallet_id, owd.req_data);
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::open_wallet(const QString& param)
{
TRY_ENTRY();
@ -2127,6 +2163,70 @@ QString MainWindow::get_mining_estimate(const QString& param)
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::add_custom_asset_id(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::wallet_and_asset_id, waid);
PREPARE_RESPONSE(currency::COMMAND_RPC_GET_ASSET_INFO::response, ar);
ar.error_code = m_backend.add_custom_asset_id(waid.wallet_id, waid.asset_id, ar.response_data.asset_descriptor);
ar.response_data.status = ar.error_code;
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::remove_custom_asset_id(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::wallet_and_asset_id, waid);
default_ar.error_code = m_backend.delete_custom_asset_id(waid.wallet_id, waid.asset_id);
return MAKE_RESPONSE(default_ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::get_wallet_info(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::wallet_id_obj, waid);
PREPARE_RESPONSE(view::wallet_info, ar);
ar.error_code = m_backend.get_wallet_info(waid.wallet_id, ar.response_data);
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::create_ionic_swap_proposal(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::create_ionic_swap_proposal_request, cispr);
PREPARE_RESPONSE(std::string, ar);
ar.error_code = m_backend.create_ionic_swap_proposal(cispr.wallet_id, cispr, ar.response_data);
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::get_ionic_swap_proposal_info(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::api_request_t<std::string>, tx_raw_hex);
PREPARE_RESPONSE(tools::wallet_public::ionic_swap_proposal_info, ar);
ar.error_code = m_backend.get_ionic_swap_proposal_info(tx_raw_hex.wallet_id, tx_raw_hex.req_data, ar.response_data);
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::accept_ionic_swap_proposal(const QString& param)
{
TRY_ENTRY();
LOG_API_TIMING();
PREPARE_ARG_FROM_JSON(view::api_request_t<std::string>, tx_raw_hex);
PREPARE_RESPONSE(std::string, ar);
ar.error_code = m_backend.accept_ionic_swap_proposal(tx_raw_hex.wallet_id, tx_raw_hex.req_data, ar.response_data);
return MAKE_RESPONSE(ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
QString MainWindow::backup_wallet_keys(const QString& param)
{
TRY_ENTRY();
@ -2184,6 +2284,7 @@ QString MainWindow::toggle_autostart(const QString& param)
return MAKE_RESPONSE(default_ar);
CATCH_ENTRY_FAIL_API_RESPONCE();
}
/*
QString MainWindow::check_available_sources(const QString& param)
{
TRY_ENTRY();
@ -2192,6 +2293,7 @@ QString MainWindow::check_available_sources(const QString& param)
return m_backend.check_available_sources(sources.wallet_id, sources.req_data).c_str();
CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR);
}
*/
QString MainWindow::open_url_in_browser(const QString& param)
{

View file

@ -144,6 +144,7 @@ public:
QString webkit_launched_script();
QString get_smart_wallet_info(const QString& param);
QString restore_wallet(const QString& param);
QString use_whitelisting(const QString& param);
QString is_pos_allowed();
QString store_to_file(const QString& path, const QString& buff);
QString load_from_file(const QString& path);
@ -168,12 +169,19 @@ public:
QString get_default_fee();
QString get_options();
void bool_toggle_icon(const QString& param);
QString add_custom_asset_id(const QString& param);
QString remove_custom_asset_id(const QString& param);
QString get_wallet_info(const QString& param);
QString create_ionic_swap_proposal(const QString& param);
QString get_ionic_swap_proposal_info(const QString& param);
QString accept_ionic_swap_proposal(const QString& param);
bool get_is_disabled_notifications();
bool set_is_disabled_notifications(const bool& param);
QString export_wallet_history(const QString& param);
QString get_log_file();
QString check_available_sources(const QString& param);
//QString check_available_sources(const QString& param);
QString open_url_in_browser(const QString& param);
void trayIconActivated(QSystemTrayIcon::ActivationReason reason);
@ -188,6 +196,8 @@ public:
//for test purposes onlys
QString request_dummy();
QString call_rpc(const QString& params);
signals:
void quit_requested(const QString str);
void update_daemon_state(const QString str);

@ -1 +1 @@
Subproject commit 6027b2fc4f596d922dbde107dec090b3e3967623
Subproject commit f040b10090a0246ee5f68a37bb4fcc13e6abebcc

View file

@ -56,7 +56,7 @@ int main(int argc, char *argv[])
#ifdef _MSC_VER
#if _MSC_VER >= 1910
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); //HiDPI pixmaps
qputenv("QT_SCALE_FACTOR", "0.75");
//qputenv("QT_SCALE_FACTOR", "0.75");
#endif
#endif

View file

@ -6,7 +6,7 @@
#pragma once
#include "p2p_protocol_defs.h"
#include "common/crypto_boost_serialization.h"
#include "common/crypto_serialization.h"
namespace boost
{

View file

@ -6,7 +6,7 @@
#pragma once
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/bind/bind.hpp>
#include <boost/foreach.hpp>
#include <boost/bimap.hpp>
#include <boost/multi_index_container.hpp>

View file

@ -32,7 +32,7 @@ namespace nodetool
const command_line::arg_descriptor<bool> arg_p2p_allow_local_ip ("allow-local-ip", "Allow local ip add to peer list, mostly in debug purposes");
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_peer ("add-peer", "Manually add peer to local peerlist");
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_add_priority_node ("add-priority-node", "Specify list of peers to connect to and attempt to keep the connection open");
const command_line::arg_descriptor<bool> arg_p2p_use_only_priority_nodes ("use-only-priority-nodes", "Try to connect only to priority nodes");
const command_line::arg_descriptor<bool> arg_p2p_use_only_priority_nodes ("use-only-priority-nodes", "Connect only to priority nodes");
const command_line::arg_descriptor<std::vector<std::string> > arg_p2p_seed_node ("seed-node", "Connect to a node to retrieve peer addresses, and disconnect");
const command_line::arg_descriptor<bool> arg_p2p_hide_my_port ("hide-my-port", "Do not announce yourself as peerlist candidate");
const command_line::arg_descriptor<bool> arg_p2p_offline_mode ( "offline-mode", "Don't connect to any node and reject any connections");
@ -321,11 +321,15 @@ namespace nodetool
ADD_HARDCODED_SEED_NODE("159.69.76.144", P2P_DEFAULT_PORT);
ADD_HARDCODED_SEED_NODE("144.76.183.143", P2P_DEFAULT_PORT);
#else
//TODO:
// TESTNET
ADD_HARDCODED_SEED_NODE("95.217.43.225", P2P_DEFAULT_PORT);
ADD_HARDCODED_SEED_NODE("94.130.137.230", P2P_DEFAULT_PORT);
ADD_HARDCODED_SEED_NODE("95.217.42.247", P2P_DEFAULT_PORT);
ADD_HARDCODED_SEED_NODE("94.130.160.115", P2P_DEFAULT_PORT);
ADD_HARDCODED_SEED_NODE("195.201.107.230", P2P_DEFAULT_PORT);
ADD_HARDCODED_SEED_NODE("95.217.46.49", P2P_DEFAULT_PORT);
ADD_HARDCODED_SEED_NODE("159.69.76.144", P2P_DEFAULT_PORT);
ADD_HARDCODED_SEED_NODE("144.76.183.143", P2P_DEFAULT_PORT);
#endif
bool res = handle_command_line(vm);
@ -846,7 +850,7 @@ namespace nodetool
if (m_offline_mode)
return true;
if(!m_peerlist.get_white_peers_count() && m_seed_nodes.size() && !m_priority_peers.size())
if(!m_peerlist.get_white_peers_count() && m_seed_nodes.size() && !m_priority_peers.size() && !m_use_only_priority_peers)
{
size_t try_count = 0;
size_t current_index = crypto::rand<size_t>()%m_seed_nodes.size();

View file

@ -1,4 +1,4 @@
// Copyright (c) 2014-2018 Zano Project
// Copyright (c) 2014-2022 Zano Project
// Copyright (c) 2014-2018 The Louisdor Project
// Copyright (c) 2012-2013 The Cryptonote developers
// Distributed under the MIT/X11 software license, see the accompanying
@ -35,8 +35,11 @@ namespace currency
}
//------------------------------------------------------------------------------------------------------------------------------
core_rpc_server::core_rpc_server(core& cr, nodetool::node_server<currency::t_currency_protocol_handler<currency::core> >& p2p,
bc_services::bc_offers_service& of
) :m_core(cr), m_p2p(p2p), m_of(of), m_session_counter(0), m_ignore_status(false)
bc_services::bc_offers_service& of)
: m_core(cr)
, m_p2p(p2p)
, m_of(of)
, m_ignore_status(false)
{}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::handle_command_line(const boost::program_options::variables_map& vm)
@ -114,6 +117,12 @@ namespace currency
res.default_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_default_fee;
res.minimum_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_pool_min_fee;
auto & hf = m_core.get_blockchain_storage().get_core_runtime_config().hard_forks.m_height_the_hardfork_n_active_after;
for (size_t i = 0; i != hf.size(); i++)
{
res.is_hardfok_active.push_back(m_core.get_blockchain_storage().is_hardfork_active(i));
}
//conditional values
if (req.flags&COMMAND_RPC_GET_INFO_FLAG_NET_TIME_DELTA_MEDIAN)
{
@ -353,13 +362,15 @@ namespace currency
bool core_rpc_server::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx)
{
CHECK_CORE_READY();
res.status = "Failed";
res.status = API_RETURN_CODE_FAIL;
if(!m_core.get_random_outs_for_amounts(req, res))
{
return true;
}
res.status = API_RETURN_CODE_OK;
/*
std::stringstream ss;
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outs_for_amount;
typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry;
@ -375,6 +386,19 @@ namespace currency
});
std::string s = ss.str();
LOG_PRINT_L2("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " << ENDL << s);
*/
return true;
}
bool core_rpc_server::on_get_random_outs2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res, connection_context& cntx)
{
CHECK_CORE_READY();
res.status = API_RETURN_CODE_FAIL;
if (!m_core.get_blockchain_storage().get_random_outs_for_amounts2(req, res))
{
return true;
}
res.status = API_RETURN_CODE_OK;
return true;
}
@ -431,13 +455,6 @@ namespace currency
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_scan_pos(const COMMAND_RPC_SCAN_POS::request& req, COMMAND_RPC_SCAN_POS::response& res, connection_context& cntx)
{
CHECK_CORE_READY();
m_core.get_blockchain_storage().scan_pos(req, res);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_check_keyimages(const COMMAND_RPC_CHECK_KEYIMAGES::request& req, COMMAND_RPC_CHECK_KEYIMAGES::response& res, connection_context& cntx)
{
m_core.get_blockchain_storage().check_keyimages(req.images, res.images_stat);
@ -495,6 +512,39 @@ namespace currency
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_validate_signature(const COMMAND_VALIDATE_SIGNATURE::request& req, COMMAND_VALIDATE_SIGNATURE::response& res, epee::json_rpc::error& er, connection_context& cntx)
{
if (!m_p2p.get_connections_count())
{
res.status = API_RETURN_CODE_DISCONNECTED;
return true;
}
std::string buff = epee::string_encoding::base64_decode(req.buff);
crypto::public_key pkey = req.pkey;
if(pkey == currency::null_pkey)
{
//need to load pkey from alias
extra_alias_entry_base eaeb = AUTO_VAL_INIT(eaeb);
if (!m_core.get_blockchain_storage().get_alias_info(req.alias, eaeb))
{
res.status = API_RETURN_CODE_NOT_FOUND;
return true;
}
pkey = eaeb.m_address.spend_public_key;
}
crypto::hash h = crypto::cn_fast_hash(buff.data(), buff.size());
bool sig_check_res = crypto::check_signature(h, pkey, req.sig);
if (!sig_check_res)
{
res.status = API_RETURN_CODE_FAIL;
return true;
}
res.status = API_RETURN_CODE_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_pos_mining_details(const COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, COMMAND_RPC_GET_POS_MINING_DETAILS::response& res, connection_context& cntx)
{
if (!m_p2p.get_connections_count())
@ -509,6 +559,12 @@ namespace currency
return true;
}
res.pos_sequence_factor_is_good = true;
uint64_t new_block_expected_height = m_core.get_blockchain_storage().get_top_block_height() + 1;
size_t new_block_expected_sequence_factor = m_core.get_blockchain_storage().get_current_sequence_factor(true);
if (new_block_expected_height > BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION && new_block_expected_sequence_factor > BLOCK_POS_STRICT_SEQUENCE_LIMIT)
res.pos_sequence_factor_is_good = false;
res.pos_basic_difficulty = m_core.get_blockchain_storage().get_next_diff_conditional(true).convert_to<std::string>();
m_core.get_blockchain_storage().build_stake_modifier(res.sm, blockchain_storage::alt_chain_type(), 0, &res.last_block_hash);// , &res.height);
@ -623,7 +679,7 @@ namespace currency
{
std::list<currency::extra_alias_entry> al_list;
m_core.get_tx_pool().get_aliases_from_tx_pool(al_list);
for (const auto a : al_list)
for (const auto& a : al_list)
{
res.aliases_que.push_back(alias_info_to_rpc_alias_info(a));
}
@ -643,6 +699,17 @@ namespace currency
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_asset_info(const COMMAND_RPC_GET_ASSET_INFO::request& req, COMMAND_RPC_GET_ASSET_INFO::response& res, connection_context& cntx)
{
if (!m_core.get_blockchain_storage().get_asset_info(req.asset_id, res.asset_descriptor))
{
res.status = API_RETURN_CODE_NOT_FOUND;
return true;
}
res.status = API_RETURN_CODE_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
{
if (!m_core.get_blockchain_storage().get_main_block_rpc_details(req.id, res.block_details))
@ -849,9 +916,7 @@ namespace currency
params.stakeholder_address = stakeholder_address;
params.ex_nonce = req.extra_text;
params.pos = req.pos_block;
params.pe.amount = req.pos_amount;
params.pe.index = req.pos_index;
params.pe.stake_unlock_time = req.stake_unlock_time;
params.pe = req.pe;
//params.pe.keyimage key image will be set in the wallet
//params.pe.wallet_index is not included in serialization map, TODO: refactoring here
params.pcustom_fill_block_template_func = nullptr;
@ -881,7 +946,11 @@ namespace currency
blobdata block_blob = t_serializable_object_to_blob(resp.b);
res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob);
res.prev_hash = string_tools::pod_to_hex(resp.b.prev_id);
res.miner_tx_tgc = resp.miner_tx_tgc;
res.height = resp.height;
res.block_reward_without_fee = resp.block_reward_without_fee;
res.block_reward = resp.block_reward;
res.txs_fee = resp.txs_fee;
//calculate epoch seed
res.seed = currency::ethash_epoch_to_seed(currency::ethash_height_to_epoch(res.height));
@ -982,9 +1051,14 @@ namespace currency
uint64_t core_rpc_server::get_block_reward(const block& blk)
{
uint64_t reward = 0;
BOOST_FOREACH(const tx_out& out, blk.miner_tx.vout)
BOOST_FOREACH(const auto& out, blk.miner_tx.vout)
{
reward += out.amount;
VARIANT_SWITCH_BEGIN(out);
VARIANT_CASE_CONST(tx_out_bare, out)
reward += out.amount;
VARIANT_CASE_CONST(tx_out_zarcanum, out)
//@#@
VARIANT_SWITCH_END();
}
return reward;
}
@ -1168,122 +1242,11 @@ namespace currency
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::get_current_hi(mining::height_info& hi)
{
block prev_block = AUTO_VAL_INIT(prev_block);
m_core.get_blockchain_storage().get_top_block(prev_block);
hi.block_id = string_tools::pod_to_hex(currency::get_block_hash(prev_block));
hi.height = get_block_height(prev_block);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
void core_rpc_server::set_session_blob(const std::string& session_id, const currency::block& blob)
{
CRITICAL_REGION_LOCAL(m_session_jobs_lock);
m_session_jobs[session_id] = blob;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::get_session_blob(const std::string& session_id, currency::block& blob)
{
CRITICAL_REGION_LOCAL(m_session_jobs_lock);
auto it = m_session_jobs.find(session_id);
if(it == m_session_jobs.end())
return false;
blob = it->second;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::get_job(const std::string& job_id, mining::job_details& job, epee::json_rpc::error& err, connection_context& cntx)
{
COMMAND_RPC_GETBLOCKTEMPLATE::request bt_req = AUTO_VAL_INIT(bt_req);
COMMAND_RPC_GETBLOCKTEMPLATE::response bt_res = AUTO_VAL_INIT(bt_res);
// !!!!!!!! SET YOUR WALLET ADDRESS HERE !!!!!!!!
bt_req.wallet_address = "1HNJjUsofq5LYLoXem119dd491yFAb5g4bCHkecV4sPqigmuxw57Ci9am71fEN4CRmA9jgnvo5PDNfaq8QnprWmS5uLqnbq";
if(!on_getblocktemplate(bt_req, bt_res, err, cntx))
return false;
//patch block blob if you need(bt_res.blocktemplate_blob), and than load block from blob template
//important: you can't change block size, since it could touch reward and block became invalid
block b = AUTO_VAL_INIT(b);
std::string bin_buff;
bool r = string_tools::parse_hexstr_to_binbuff(bt_res.blocktemplate_blob, bin_buff);
CHECK_AND_ASSERT_MES(r, false, "internal error, failed to parse hex block");
r = currency::parse_and_validate_block_from_blob(bin_buff, b);
CHECK_AND_ASSERT_MES(r, false, "internal error, failed to parse block");
set_session_blob(job_id, b);
job.blob = string_tools::buff_to_hex_nodelimer(currency::get_block_hashing_blob(b));
//TODO: set up share difficulty here!
job.difficulty = bt_res.difficulty; //difficulty leaved as string field since it will be refactored into 128 bit format
job.job_id = "SOME_JOB_ID";
get_current_hi(job.prev_hi);
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_login(const mining::COMMAND_RPC_LOGIN::request& req, mining::COMMAND_RPC_LOGIN::response& res, connection_context& cntx)
{
if(!check_core_ready())
{
res.status = API_RETURN_CODE_BUSY;
return true;
}
//TODO: add login information here
res.id = std::to_string(m_session_counter++); //session id
if(req.hi.height)
{
epee::json_rpc::error err = AUTO_VAL_INIT(err);
if(!get_job(res.id, res.job, err, cntx))
{
res.status = err.message;
return true;
}
}
res.status = API_RETURN_CODE_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_getjob(const mining::COMMAND_RPC_GETJOB::request& req, mining::COMMAND_RPC_GETJOB::response& res, connection_context& cntx)
{
if(!check_core_ready())
{
res.status = API_RETURN_CODE_BUSY;
return true;
}
/*epee::json_rpc::error err = AUTO_VAL_INIT(err);
if(!get_job(req.id, res.jd, err, cntx))
{
res.status = err.message;
return true;
}*/
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_alias_reward(const COMMAND_RPC_GET_ALIAS_REWARD::request& req, COMMAND_RPC_GET_ALIAS_REWARD::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
{
uint64_t default_tx_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_default_fee;
uint64_t current_median_fee = m_core.get_blockchain_storage().get_tx_fee_median();
res.reward = get_alias_coast_from_fee(req.alias, std::max(default_tx_fee, current_median_fee));
if (res.reward)
res.status = API_RETURN_CODE_OK;
else
res.status = API_RETURN_CODE_NOT_FOUND;
res.reward = m_core.get_blockchain_storage().get_alias_coast(req.alias);
res.status = API_RETURN_CODE_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
@ -1336,45 +1299,6 @@ namespace currency
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_submit(const mining::COMMAND_RPC_SUBMITSHARE::request& req, mining::COMMAND_RPC_SUBMITSHARE::response& res, connection_context& cntx)
{
if(!check_core_ready())
{
res.status = API_RETURN_CODE_BUSY;
return true;
}
block b = AUTO_VAL_INIT(b);
if(!get_session_blob(req.id, b))
{
res.status = "Wrong session id";
return true;
}
b.nonce = req.nonce;
if(!m_core.handle_block_found(b))
{
res.status = "Block not accepted";
LOG_ERROR("Submited block not accepted");
return true;
}
res.status = API_RETURN_CODE_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_get_addendums(const COMMAND_RPC_GET_ADDENDUMS::request& req, COMMAND_RPC_GET_ADDENDUMS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx)
{
if (!check_core_ready())
{
res.status = API_RETURN_CODE_BUSY;
return true;
}
res.status = API_RETURN_CODE_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
bool core_rpc_server::on_reset_transaction_pool(const COMMAND_RPC_RESET_TX_POOL::request& req, COMMAND_RPC_RESET_TX_POOL::response& res, connection_context& cntx)
{
m_core.get_tx_pool().purge_transactions();
@ -1385,4 +1309,4 @@ namespace currency
#undef LOG_DEFAULT_CHANNEL
#define LOG_DEFAULT_CHANNEL NULL
#define LOG_DEFAULT_CHANNEL NULL

Some files were not shown because too many files have changed in this diff Show more