1
0
Fork 0
forked from lthn/blockchain

Merge branch 'release'

This commit is contained in:
sowle 2024-02-22 09:09:15 +01:00
commit 6b99449e21
No known key found for this signature in database
GPG key ID: C07A24B2D89D49FC
249 changed files with 33327 additions and 9754 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,17 +1,21 @@
cmake_minimum_required(VERSION 2.8.6)
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()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# if(POLICY CMP0020)
# cmake_policy(SET CMP0020 OLD)
# endif()
if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
add_definitions(-DMOBILE_WALLET_BUILD)
@ -50,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)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12)
endif()
set(USE_PCH FALSE CACHE BOOL "Use shared precompiled headers")
@ -60,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)
@ -69,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)
@ -90,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}}")
@ -106,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()
@ -138,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")
@ -182,6 +194,11 @@ else()
endif()
# 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()
if(MSVC)
set(Boost_USE_STATIC_LIBS ON)
endif()
@ -204,8 +221,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS")
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 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale)
else()
find_package(Boost 1.70 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()
@ -227,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

@ -13,13 +13,13 @@ Be sure to clone the repository properly:\
### Dependencies
| component / version | minimum <br>(not recommended but may work) | recommended | most recent of what we have ever tested |
|--|--|--|--|
| gcc (Linux) | 5.4.0 | 7.5.0 | 8.3.0 |
| 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.4.2) |
| [XCode](https://developer.apple.com/downloads/) (macOS) | 9.2 | 12.3 | 12.3 |
| [CMake](https://cmake.org/download/) | 2.8.6 | 3.15.5 | 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.1n |
| [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 |
Note:\
@ -30,27 +30,37 @@ Note:\
### Linux
Recommended OS version: Ubuntu 18.04 LTS.
Recommended OS versions: Ubuntu 20.04, 22.04 LTS.
1. Prerequisites
[*server version*]
sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git screen checkinstall zlib1g-dev
sudo apt-get install -y build-essential g++ curl autotools-dev libicu-dev libbz2-dev cmake git screen checkinstall zlib1g-dev
[*GUI version*]
sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git screen checkinstall zlib1g-dev mesa-common-dev libglu1-mesa-dev
2. Download and build Boost
2. Clone Zano into a local folder\
(If for some reason you need to use alternative Zano branch, change 'master' to the required branch name.)
git clone --recursive https://github.com/hyle-team/zano.git -b master
In the following steps we assume that you cloned Zano into '~/zano' folder in your home directory.
3. Download and build Boost\
(Assuming you have cloned Zano into the 'zano' folder. If you used a different location for Zano, **edit line 4** accordingly.)
curl -OL https://boostorg.jfrog.io/artifactory/main/release/1.70.0/source/boost_1_70_0.tar.bz2
echo "430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778 boost_1_70_0.tar.bz2" | shasum -c && tar -xjf boost_1_70_0.tar.bz2
cd boost_1_70_0
rm boost_1_70_0.tar.bz2 && cd boost_1_70_0
patch -p0 < ../zano/utils/boost_1.70_gcc_8.patch || cd ..
./bootstrap.sh --with-libraries=system,filesystem,thread,date_time,chrono,regex,serialization,atomic,program_options,locale,timer,log
./b2
./b2 && cd ..
Make sure that you see "The Boost C++ Libraries were successfully built!" message at the end.
3. Install Qt\
4. Install Qt\
(*GUI version only, skip this step if you're building server version*)
[*GUI version*]
@ -61,20 +71,19 @@ Recommended OS version: Ubuntu 18.04 LTS.
Then follow the instructions in Wizard. Don't forget to tick the WebEngine module checkbox!
4. Install OpenSSL
5. Install OpenSSL
We recommend installing OpenSSL v1.1.1n locally unless you would like to use the same version system-wide. Adjust the local path `/home/user/openssl` in the commands below according to your needs.
We recommend installing OpenSSL v1.1.1w locally unless you would like to use the same version system-wide.\
(Assuming that `$HOME` environment variable is set to your home directory. Otherwise, edit line 4 accordingly.)
curl -OL https://www.openssl.org/source/openssl-1.1.1n.tar.gz
echo "40dceb51a4f6a5275bde0e6bf20ef4b91bfc32ed57c0552e2e8e15463372b17a openssl-1.1.1n.tar.gz" | shasum -c && tar xaf openssl-1.1.1n.tar.gz
cd openssl-1.1.1n/
./config --prefix=/home/user/openssl --openssldir=/home/user/openssl shared zlib
make
make test
make install
curl -OL https://www.openssl.org/source/openssl-1.1.1w.tar.gz
echo "cf3098950cb4d853ad95c0841f1f9c6d3dc102dccfcacd521d93925208b76ac8 openssl-1.1.1w.tar.gz" | shasum -c && tar xaf openssl-1.1.1w.tar.gz
cd openssl-1.1.1w/
./config --prefix=$HOME/openssl --openssldir=$HOME/openssl shared zlib
make && make test && make install && cd ..
5. Set environment variables properly\
6. [*OPTIONAL*] Set global environment variables for convenient use\
For instance, by adding the following lines to `~/.bashrc`
[*server version*]
@ -89,18 +98,27 @@ For instance, by adding the following lines to `~/.bashrc`
export OPENSSL_ROOT_DIR=/home/user/openssl
export QT_PREFIX_PATH=/home/user/Qt5.11.2/5.11.2/gcc_64
6. Build the binaries
1. Build daemon and simplewallet:
cd zano/ && make -j1
or
**NOTICE: Please edit the lines above according to your actual paths.**
**NOTICE 2:** Make sure you've restarted your terminal session (by reopening the terminal window or reconnecting the server) to apply these changes.
8. Build the binaries
1. If you skipped step 6 and did not set the environment variables:
cd zano && mkdir build && cd build
BOOST_ROOT=$HOME/boost_1_70_0 OPENSSL_ROOT_DIR=$HOME/openssl cmake ..
make -j1 daemon simplewallet
2. If you set the variables in step 6:
cd zano && mkdir build && cd build
cmake ..
make -j1 daemon simplewallet
or simply:
cd zano && make -j1
**NOTICE**: If you are building on a machine with a relatively high amount of RAM or with the proper setting of virtual memory, then you can use `-j2` or `-j` option to speed up the building process. Use with caution.
**NOTICE 2**: If you'd like to build binaries for the testnet, use `cmake -D TESTNET=TRUE ..` instead of `cmake ..` .
@ -110,12 +128,12 @@ For instance, by adding the following lines to `~/.bashrc`
cd zano
utils/build_script_linux.sh
7. Look for the binaries in `build` folder
Look for the binaries in `build` folder
<br />
### Windows
Recommended OS version: Windows 7 x64.
Recommended OS version: Windows 7 x64, Windows 11 x64.
1. Install required prerequisites (Boost, Qt, CMake, OpenSSL).
2. Edit paths in `utils/configure_local_paths.cmd`.
3. Run one of `utils/configure_win64_msvsNNNN_gui.cmd` according to your MSVC version.

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,29 +116,29 @@ 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; \
});
#if defined(ENABLE_LOGGING_INTERNAL)
#define LOG_PRINT_CHANNEL_NO_PREFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
#define LOG_PRINT_CHANNEL_NO_PREFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
{TRY_ENTRY();std::stringstream ss________; ss________ << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str() , y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}}
#define LOG_PRINT_CHANNEL_NO_PREFIX_NO_POSTFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
#define LOG_PRINT_CHANNEL_NO_PREFIX_NO_POSTFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
{TRY_ENTRY();std::stringstream ss________; ss________ << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}}
#define LOG_PRINT_CHANNEL_NO_POSTFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
#define LOG_PRINT_CHANNEL_NO_POSTFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
{TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}}
#define LOG_PRINT_CHANNEL2_CB(log_channel, log_name, x, y, cb) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
#define LOG_PRINT_CHANNEL2_CB(log_channel, log_name, x, y, cb) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
{TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);cb(ss________.str());CATCH_ALL_DO_NOTHING();}}
#define LOG_PRINT_CHANNEL_COLOR2_CB(log_channel, log_name, x, y, color, cb) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
#define LOG_PRINT_CHANNEL_COLOR2_CB(log_channel, log_name, x, y, color, cb) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
{TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, color, false, log_name); cb(ss________.str());CATCH_ALL_DO_NOTHING();}}
#define LOG_PRINT_CHANNEL_2_JORNAL(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
#define LOG_PRINT_CHANNEL_2_JORNAL(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\
{TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, true, log_name);CATCH_ALL_DO_NOTHING();}}
#define LOG_ERROR2_CB(log_name, x, cb) { \
@ -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,13 +29,22 @@
#include "serialization/keyvalue_serialization.h"
#include "storages/portable_storage_template_helper.h"
#include "http_base.h"
#include "net/net_utils_base.h"
template<typename typename_t>
typename_t get_documentation_json_struct()
{
return AUTO_VAL_INIT_T(typename_t);
}
template<typename request_t, typename response_t>
bool auto_doc_t(const std::string& prefix_name, std::string& generate_reference)
{
if (!generate_reference.size()) return true;
request_t req = AUTO_VAL_INIT(req);
response_t res = AUTO_VAL_INIT(res);
request_t req = get_documentation_json_struct<request_t>();
response_t res = get_documentation_json_struct<response_t>();
std::stringstream ss;
ss << prefix_name << ENDL
<< "REQUEST: " << ENDL << epee::serialization::store_t_to_json(req) << ENDL << "--------------------------------" << ENDL
@ -51,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, \
@ -73,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
@ -117,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;}
@ -287,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"; \
@ -304,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"; \
@ -321,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"
@ -65,7 +65,7 @@ namespace epee
bool res = m_net_server.init_server(bind_port, bind_ip);
if(!res)
{
LOG_ERROR("Failed to bind server");
LOG_ERROR("Failed to bind to " << bind_ip << ":" << bind_port);
return false;
}
return true;
@ -74,14 +74,14 @@ namespace epee
bool run(size_t threads_count, bool wait = true)
{
//go to loop
LOG_PRINT("Run net_service loop( " << threads_count << " threads)...", LOG_LEVEL_0);
LOG_PRINT("Run net_service loop (" << threads_count << " threads)...", LOG_LEVEL_1);
if(!m_net_server.run_server(threads_count, wait))
{
LOG_ERROR("Failed to run net tcp server!");
}
if(wait)
LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0);
LOG_PRINT("net_service loop stopped.", LOG_LEVEL_1);
return true;
}

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

@ -62,6 +62,8 @@ namespace epee
t_pod_type transform_str_to_t_pod(const std::string& a)
{
t_pod_type res = AUTO_VAL_INIT(res);
if (a.empty())
return res;
if (!epee::string_tools::hex_to_pod(a, res))
throw std::runtime_error(std::string("Unable to transform \"") + a + "\" to pod type " + typeid(t_pod_type).name());
return res;

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

@ -77,8 +77,7 @@ namespace epee
bool insert_next_section(harray hSecArray, hsection& hinserted_childsection);
//------------------------------------------------------------------------
//delete entry (section, value or array)
bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr);
bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr);
//-------------------------------------------------------------------------------
bool store_to_binary(binarybuffer& target);
bool load_from_binary(const binarybuffer& target);
@ -87,6 +86,8 @@ namespace epee
bool dump_as_json(std::string& targetObj, size_t indent = 0, end_of_line_t eol = eol_crlf);
bool load_from_json(const std::string& source);
template<typename cb_t>
bool enum_entries(hsection hparent_section, cb_t cb);
private:
section m_root;
hsection get_root_section() {return &m_root;}
@ -384,6 +385,20 @@ namespace epee
CATCH_ENTRY("portable_storage::insert_first_value", nullptr);
}
//---------------------------------------------------------------------------------------------------------------
template<typename cb_t>
bool portable_storage::enum_entries(hsection hparent_section, cb_t cb)
{
TRY_ENTRY();
if (!hparent_section) hparent_section = &m_root;
for (const auto& e : hparent_section->m_entries)
{
if (!cb(e.first, e.second))
break;
}
return true;
CATCH_ENTRY("portable_storage::enum_entries", false);
}
template<class t_value>
bool portable_storage::insert_next_value(harray hval_array, const t_value& target)
{

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

@ -37,6 +37,7 @@
#endif
#include <windows.h>
#endif
#include <cctype>
#include "warnings.h"
@ -310,7 +311,14 @@ namespace string_encoding
return get_md5_as_hexstring(src.data(), src.size());
}
#endif
inline
std::string toupper(std::string s)
{
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c) { return std::toupper(c); } // correct
);
return s;
}
}
}

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_2200000.pak", "c3bd64c62495c3f266759750952519f13f32fc161b59547beaa8202b6e26d516", 2628767033, 5100195840 };
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2200000.pak", "fcbf0ab3b23836e1a51fa675e719900fb94110cfb74790b3323cebce7fb9f5bd", 3426025872, 4954472448 };
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,7 +8,9 @@
#include <string.h>
#include "hash-ops.h"
#ifdef _M_ARM64
#include "malloc.h"
#endif
void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) {
assert(count > 0);
if (count == 1) {

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,10 +286,12 @@ 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;
std::string get_alias_by_address(const account_public_address& addr)const;
std::set<std::string> get_aliases_by_address(const account_public_address& addr)const;
template<typename cb_t>
bool enumerate_aliases(cb_t cb) const;
template<typename cb_t>
@ -286,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;
@ -315,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;
@ -328,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();
@ -335,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;
@ -350,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(),
@ -395,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);
}
@ -450,6 +469,7 @@ namespace currency
void serialize(archive_t & ar, const unsigned int version);
bool get_est_height_from_date(uint64_t date, uint64_t& res_h)const;
bool get_pos_votes(uint64_t start_h, uint64_t end_h, vote_results& r);
//debug functions
bool validate_blockchain_prev_links(size_t last_n_blocks_to_check = 10) const;
@ -486,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
//-----------------------------------------
@ -527,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
@ -557,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
@ -567,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);
@ -584,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,
@ -597,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;
@ -613,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);
@ -629,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);
@ -661,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;
@ -714,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);
@ -731,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;
@ -756,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
@ -774,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;
@ -154,6 +160,28 @@ namespace currency
transactions_map onboard_transactions;
};
struct vote_on_proposal
{
std::string proposal_id;
uint64_t yes;
uint64_t no;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(proposal_id)
KV_SERIALIZE(yes)
KV_SERIALIZE(no)
END_KV_SERIALIZE_MAP()
};
}
struct vote_results
{
uint64_t total_pos_blocks; //total pos blocks in a given range
std::list<vote_on_proposal> votes;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(total_pos_blocks)
KV_SERIALIZE(votes)
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,15 +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
@ -58,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)
@ -104,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
@ -111,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)
@ -145,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
@ -205,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"
@ -214,6 +236,7 @@
#define GUI_INTERNAL_CONFIG2 "gui_internal_config.json"
#define GUI_IPC_MESSAGE_CHANNEL_NAME CURRENCY_NAME_BASE "_message_que"
#define CURRENCY_VOTING_CONFIG_DEFAULT_FILENAME "voting_config.json"
#define CURRENT_TRANSACTION_CHAIN_ENTRY_ARCHIVE_VER 3
@ -227,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)
@ -239,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,31 +453,56 @@ 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);
uint64_t get_timstamp_from_word(std::string word, bool& password_used, const std::string& buff);
uint64_t get_timstamp_from_word(std::string word, bool& password_used);
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)
{
@ -410,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);
@ -472,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>
@ -531,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))
@ -647,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);
@ -721,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);
@ -761,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 047a4602748e0d3e40456f9d2fc2eeef1bc89b06
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
{

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