diff options
86 files changed, 1701 insertions, 978 deletions
@@ -48,7 +48,7 @@ all: release-all depends: cd contrib/depends && $(MAKE) HOST=$(target) && cd ../.. && mkdir -p build/$(target)/release - cd build/$(target)/release && cmake -DCMAKE_TOOLCHAIN_FILE=$(CURDIR)/contrib/depends/$(target)/share/toolchain.cmake ../../.. && $(MAKE) + cd build/$(target)/release && USE_DEVICE_TREZOR_MANDATORY=1 cmake -DCMAKE_TOOLCHAIN_FILE=$(CURDIR)/contrib/depends/$(target)/share/toolchain.cmake ../../.. && $(MAKE) cmake-debug: mkdir -p $(builddir)/debug diff --git a/cmake/CheckTrezor.cmake b/cmake/CheckTrezor.cmake index 05b8ebd93..87582a713 100644 --- a/cmake/CheckTrezor.cmake +++ b/cmake/CheckTrezor.cmake @@ -75,7 +75,13 @@ if (USE_DEVICE_TREZOR) # Protobuf is required to build protobuf messages for Trezor include(FindProtobuf OPTIONAL) - FIND_PACKAGE(Protobuf CONFIG) + # PkgConfig works better with new Protobuf + find_package(PkgConfig QUIET) + pkg_check_modules(PROTOBUF protobuf) + + if (NOT Protobuf_FOUND) + FIND_PACKAGE(Protobuf CONFIG) + endif() if (NOT Protobuf_FOUND) FIND_PACKAGE(Protobuf) endif() @@ -83,11 +89,11 @@ if (USE_DEVICE_TREZOR) _trezor_protobuf_fix_vars() # Early fail for optional Trezor support - if(${Protobuf_VERSION} GREATER 21) - trezor_fatal_msg("Trezor: Unsupported Protobuf version ${Protobuf_VERSION}. Please, use Protobuf v21.") - elseif(NOT Protobuf_FOUND AND NOT Protobuf_LIBRARY AND NOT Protobuf_PROTOC_EXECUTABLE AND NOT Protobuf_INCLUDE_DIR) + if(NOT Protobuf_FOUND AND NOT Protobuf_LIBRARY AND NOT Protobuf_PROTOC_EXECUTABLE AND NOT Protobuf_INCLUDE_DIR) trezor_fatal_msg("Trezor: Could not find Protobuf") - elseif(NOT Protobuf_LIBRARY OR NOT EXISTS "${Protobuf_LIBRARY}") + elseif(${CMAKE_CXX_STANDARD} LESS 17 AND ${Protobuf_VERSION} GREATER 21) + trezor_fatal_msg("Trezor: Unsupported Protobuf version ${Protobuf_VERSION} with C++ ${CMAKE_CXX_STANDARD}. Please, use Protobuf v21.") + elseif(NOT Protobuf_LIBRARY) trezor_fatal_msg("Trezor: Protobuf library not found: ${Protobuf_LIBRARY}") unset(Protobuf_FOUND) elseif(NOT Protobuf_PROTOC_EXECUTABLE OR NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}") @@ -150,9 +156,10 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON) endif() if(USE_DEVICE_TREZOR_PROTOBUF_TEST) - # For now, Protobuf v21 is the maximum supported version as v23 requires C++17. TODO: Remove once we move to C++17 - if(${Protobuf_VERSION} GREATER 21) - trezor_fatal_msg("Trezor: Unsupported Protobuf version ${Protobuf_VERSION}. Please, use Protobuf v21.") + if(PROTOBUF_LDFLAGS) + set(PROTOBUF_TRYCOMPILE_LINKER "${PROTOBUF_LDFLAGS}") + else() + set(PROTOBUF_TRYCOMPILE_LINKER "${Protobuf_LIBRARY}") endif() try_compile(Protobuf_COMPILE_TEST_PASSED @@ -164,7 +171,7 @@ if(Protobuf_FOUND AND USE_DEVICE_TREZOR AND TREZOR_PYTHON) CMAKE_EXE_LINKER_FLAGS ${CMAKE_TRY_COMPILE_LINKER_FLAGS} "-DINCLUDE_DIRECTORIES=${Protobuf_INCLUDE_DIR};${CMAKE_BINARY_DIR}" "-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}" - LINK_LIBRARIES ${Protobuf_LIBRARY} ${CMAKE_TRY_COMPILE_LINK_LIBRARIES} + LINK_LIBRARIES "${PROTOBUF_TRYCOMPILE_LINKER}" ${CMAKE_TRY_COMPILE_LINK_LIBRARIES} OUTPUT_VARIABLE OUTPUT ) if(NOT Protobuf_COMPILE_TEST_PASSED) diff --git a/cmake/FindLibUSB.cmake b/cmake/FindLibUSB.cmake index f701b6398..647f3c656 100644 --- a/cmake/FindLibUSB.cmake +++ b/cmake/FindLibUSB.cmake @@ -119,10 +119,6 @@ if ( LibUSB_FOUND ) list(APPEND TEST_COMPILE_EXTRA_LIBRARIES ${LibUSB_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES ${TEST_COMPILE_EXTRA_LIBRARIES}) - check_library_exists ( "${LibUSB_LIBRARIES}" usb_open "" LibUSB_FOUND ) - check_library_exists ( "${LibUSB_LIBRARIES}" libusb_get_device_list "" LibUSB_VERSION_1.0 ) - check_library_exists ( "${LibUSB_LIBRARIES}" libusb_get_port_numbers "" LibUSB_VERSION_1.0.16 ) - if((STATIC AND UNIX AND NOT APPLE AND NOT FREEBSD) OR (DEPENDS AND CMAKE_SYSTEM_NAME STREQUAL "Linux") OR ANDROID) find_library(LIBUDEV_LIBRARY udev) if(LIBUDEV_LIBRARY) @@ -132,6 +128,10 @@ if ( LibUSB_FOUND ) endif() endif() + check_library_exists ( "${LibUSB_LIBRARIES}" usb_open "" LibUSB_FOUND ) + check_library_exists ( "${LibUSB_LIBRARIES}" libusb_get_device_list "" LibUSB_VERSION_1.0 ) + check_library_exists ( "${LibUSB_LIBRARIES}" libusb_get_port_numbers "" LibUSB_VERSION_1.0.16 ) + # Library 1.0.16+ compilation test. # The check_library_exists does not work well on Apple with shared libs. if (APPLE OR LibUSB_VERSION_1.0.16 OR STATIC) @@ -141,7 +141,7 @@ if ( LibUSB_FOUND ) CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${LibUSB_INCLUDE_DIRS}" "-DLINK_DIRECTORIES=${LibUSB_LIBRARIES}" - LINK_LIBRARIES ${TEST_COMPILE_EXTRA_LIBRARIES} + LINK_LIBRARIES ${LibUSB_LIBRARIES} ${TEST_COMPILE_EXTRA_LIBRARIES} OUTPUT_VARIABLE OUTPUT) unset(TEST_COMPILE_EXTRA_LIBRARIES) message(STATUS "LibUSB Compilation test: ${LibUSB_COMPILE_TEST_PASSED}") diff --git a/contrib/depends/packages/native_cctools.mk b/contrib/depends/packages/native_cctools.mk index 0324f7acd..8c1ea4c62 100644 --- a/contrib/depends/packages/native_cctools.mk +++ b/contrib/depends/packages/native_cctools.mk @@ -6,6 +6,7 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=70a7189418c2086d20c299c5d59250cf5940782c778892ccc899c66516ed240e $(package)_build_subdir=cctools $(package)_dependencies=native_clang native_libtapi +$(package)_patches=no-build-date.patch define $(package)_set_vars $(package)_config_opts=--target=$(host) --disable-lto-support --with-libtapi=$(host_prefix) @@ -14,6 +15,10 @@ $(package)_cc=$(host_prefix)/native/bin/clang $(package)_cxx=$(host_prefix)/native/bin/clang++ endef +define $(package)_preprocess_cmds + patch -p1 < $($(package)_patch_dir)/no-build-date.patch +endef + define $(package)_config_cmds $($(package)_autoconf) endef diff --git a/contrib/depends/packages/native_libtapi.mk b/contrib/depends/packages/native_libtapi.mk index 56ee087cb..c5625501a 100644 --- a/contrib/depends/packages/native_libtapi.mk +++ b/contrib/depends/packages/native_libtapi.mk @@ -6,6 +6,11 @@ $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=62e419c12d1c9fad67cc1cd523132bc00db050998337c734c15bc8d73cc02b61 $(package)_build_subdir=build $(package)_dependencies=native_clang +$(package)_patches=no_embed_git_rev.patch + +define $(package)_preprocess_cmds + patch -p1 -i $($(package)_patch_dir)/no_embed_git_rev.patch +endef define $(package)_config_cmds echo -n $(build_prefix) > INSTALLPREFIX; \ diff --git a/contrib/depends/packages/native_protobuf.mk b/contrib/depends/packages/native_protobuf.mk index 2dc11b23c..8d7649b67 100644 --- a/contrib/depends/packages/native_protobuf.mk +++ b/contrib/depends/packages/native_protobuf.mk @@ -1,4 +1,4 @@ -package=protobuf3 +package=native_protobuf $(package)_version=21.12 $(package)_version_protobuf_cpp=3.21.12 $(package)_download_path=https://github.com/protocolbuffers/protobuf/releases/download/v$($(package)_version)/ @@ -16,13 +16,13 @@ define $(package)_config_cmds endef define $(package)_build_cmds - $(MAKE) -C src + $(MAKE) -C src protoc endef define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install + $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install-binPROGRAMS install-nobase_dist_protoDATA endef define $(package)_postprocess_cmds - rm lib/libprotoc.a + rm -rf lib/ endef diff --git a/contrib/depends/packages/openssl.mk b/contrib/depends/packages/openssl.mk index a157762c7..a9734029d 100644 --- a/contrib/depends/packages/openssl.mk +++ b/contrib/depends/packages/openssl.mk @@ -4,9 +4,12 @@ $(package)_download_path=https://www.openssl.org/source $(package)_file_name=$(package)-$($(package)_version).tar.gz $(package)_sha256_hash=88525753f79d3bec27d2fa7c66aa0b92b3aa9498dafd93d7cfa4b3780cdae313 +# The bundled ranlib in Android NDK 18b inserts timestamps by default. +# To prevent reproducibility issues, we must enable [D]eterministic mode. + define $(package)_set_vars -$(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" -$(package)_config_env_android=ANDROID_NDK_ROOT="$(host_prefix)/native" PATH="$(host_prefix)/native/bin" CC=clang AR=ar RANLIB=ranlib +$(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" +$(package)_config_env_android=ANDROID_NDK_ROOT="$(host_prefix)/native" PATH="$(host_prefix)/native/bin" CC=clang AR=ar RANLIB="ranlib -D" $(package)_build_env_android=ANDROID_NDK_ROOT="$(host_prefix)/native" $(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl --libdir=$(host_prefix)/lib $(package)_config_opts+=no-capieng @@ -52,7 +55,7 @@ define $(package)_preprocess_cmds endef define $(package)_config_cmds - ./Configure $($(package)_config_opts) + ./Configure $($(package)_config_opts) ARFLAGS=$($(package)_arflags) endef define $(package)_build_cmds diff --git a/contrib/depends/packages/protobuf.mk b/contrib/depends/packages/protobuf.mk index 780357c90..9702506d0 100644 --- a/contrib/depends/packages/protobuf.mk +++ b/contrib/depends/packages/protobuf.mk @@ -21,12 +21,7 @@ define $(package)_build_cmds endef define $(package)_stage_cmds - $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install-libLTLIBRARIES install-nobase_includeHEADERS &&\ - $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA + $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install-nobase_includeHEADERS &&\ + $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA &&\ + cp src/.libs/libprotobuf.a $($(package)_staging_prefix_dir)/lib/ endef - -define $(package)_postprocess_cmds - rm lib/libprotoc.a &&\ - rm lib/*.la -endef - diff --git a/contrib/depends/packages/unbound.mk b/contrib/depends/packages/unbound.mk index d9ef0076a..254636bca 100644 --- a/contrib/depends/packages/unbound.mk +++ b/contrib/depends/packages/unbound.mk @@ -24,7 +24,7 @@ define $(package)_preprocess_cmds endef define $(package)_config_cmds - $($(package)_autoconf) ac_cv_func_getentropy=no + $($(package)_autoconf) ac_cv_func_getentropy=no AR_FLAGS=$($(package)_arflags) endef define $(package)_build_cmds diff --git a/contrib/depends/patches/native_cctools/no-build-date.patch b/contrib/depends/patches/native_cctools/no-build-date.patch new file mode 100644 index 000000000..8b7d1e1f7 --- /dev/null +++ b/contrib/depends/patches/native_cctools/no-build-date.patch @@ -0,0 +1,12 @@ +diff --git a/cctools/ld64/src/ld/Options.cpp b/cctools/ld64/src/ld/Options.cpp +index 3bb8324..033760d 100644 +--- a/cctools/ld64/src/ld/Options.cpp ++++ b/cctools/ld64/src/ld/Options.cpp +@@ -4279,7 +4279,6 @@ void Options::buildSearchPaths(int argc, const char* argv[]) + fVerbose = true; + extern const char ldVersionString[]; + fprintf(stderr, "%s", ldVersionString); +- fprintf(stderr, "BUILD " __TIME__ " " __DATE__"\n"); + fprintf(stderr, "configured to support archs: %s\n", ALL_SUPPORTED_ARCHS); + // if only -v specified, exit cleanly + if ( argc == 2 ) { diff --git a/contrib/depends/patches/native_libtapi/no_embed_git_rev.patch b/contrib/depends/patches/native_libtapi/no_embed_git_rev.patch new file mode 100644 index 000000000..b898ccb43 --- /dev/null +++ b/contrib/depends/patches/native_libtapi/no_embed_git_rev.patch @@ -0,0 +1,31 @@ +diff --git a/src/llvm/CMakeLists.txt b/src/llvm/CMakeLists.txt +index ab92717c8..4ad621ea3 100644 +--- a/src/llvm/CMakeLists.txt ++++ b/src/llvm/CMakeLists.txt +@@ -752,9 +752,10 @@ set(LLVM_SRPM_USER_BINARY_SPECFILE ${CMAKE_CURRENT_SOURCE_DIR}/llvm.spec.in + set(LLVM_SRPM_BINARY_SPECFILE ${CMAKE_CURRENT_BINARY_DIR}/llvm.spec) + set(LLVM_SRPM_DIR "${CMAKE_CURRENT_BINARY_DIR}/srpm") + +-# SVN_REVISION and GIT_COMMIT get set by the call to add_version_info_from_vcs. +-# DUMMY_VAR contains a version string which we don't care about. +-add_version_info_from_vcs(DUMMY_VAR) ++# A call to add_version_info_from_vcs() was removed, leaving SVN_REVISION ++# and GIT_COMMIT unset. Accordingly, LLVM_RPM_SPEC_REVISION is left empty. ++# This variable appears to be unused. Since it may be used in a future ++# update of native_libtapi this change serves as a precautionairy measure. + if ( SVN_REVISION ) + set(LLVM_RPM_SPEC_REVISION "r${SVN_REVISION}") + elseif ( GIT_COMMIT ) +diff --git a/src/llvm/cmake/modules/GenerateVersionFromCVS.cmake b/src/llvm/cmake/modules/GenerateVersionFromCVS.cmake +index 6b1c71983..e16326ed6 100644 +--- a/src/llvm/cmake/modules/GenerateVersionFromCVS.cmake ++++ b/src/llvm/cmake/modules/GenerateVersionFromCVS.cmake +@@ -24,7 +24,7 @@ include(VersionFromVCS) + set(ENV{TERM} "dumb") + + function(append_info name path) +- add_version_info_from_vcs(REVISION ${path}) ++ set(REVISION "git-0000000") + string(STRIP "${REVISION}" REVISION) + file(APPEND "${HEADER_FILE}.txt" + "#define ${name} \"${REVISION}\"\n") diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h index 7fcd02726..887f4aa40 100644 --- a/contrib/epee/include/string_tools.h +++ b/contrib/epee/include/string_tools.h @@ -31,6 +31,7 @@ #include "mlocker.h" #include <boost/utility/string_ref.hpp> +#include <boost/algorithm/string.hpp> #include <sstream> #include <string> #include <cstdint> @@ -69,23 +70,19 @@ namespace string_tools #ifdef _WIN32 std::string get_current_module_path(); #endif - bool set_module_name_and_folder(const std::string& path_to_process_); - bool trim_left(std::string& str); - bool trim_right(std::string& str); + void set_module_name_and_folder(const std::string& path_to_process_); + void trim_left(std::string& str); + void trim_right(std::string& str); //---------------------------------------------------------------------------- inline std::string& trim(std::string& str) { - trim_left(str); - trim_right(str); + boost::trim(str); return str; } //---------------------------------------------------------------------------- - inline std::string trim(const std::string& str_) + inline std::string trim(const std::string& str) { - std::string str = str_; - trim_left(str); - trim_right(str); - return str; + return boost::trim_copy(str); } std::string pad_string(std::string s, size_t n, char c = ' ', bool prepend = false); diff --git a/contrib/epee/src/readline_buffer.cpp b/contrib/epee/src/readline_buffer.cpp index ac68d1fdb..cefde158c 100644 --- a/contrib/epee/src/readline_buffer.cpp +++ b/contrib/epee/src/readline_buffer.cpp @@ -1,4 +1,5 @@ #include "readline_buffer.h" +#include "string_tools.h" #include <readline/readline.h> #include <readline/history.h> #include <iostream> @@ -173,7 +174,7 @@ static void handle_line(char* line) line_stat = rdln::full; the_line = line; std::string test_line = line; - boost::trim_right(test_line); + epee::string_tools::trim_right(test_line); if(!test_line.empty()) { if (!same_as_last_line(test_line)) diff --git a/contrib/epee/src/string_tools.cpp b/contrib/epee/src/string_tools.cpp index 3abb83c74..d8580c216 100644 --- a/contrib/epee/src/string_tools.cpp +++ b/contrib/epee/src/string_tools.cpp @@ -38,9 +38,12 @@ #include <cstdlib> #include <string> #include <type_traits> +#include <system_error> #include <boost/lexical_cast.hpp> +#include <boost/algorithm/string.hpp> #include <boost/algorithm/string/predicate.hpp> #include <boost/utility/string_ref.hpp> +#include <boost/filesystem.hpp> #include "misc_log_ex.h" #include "storages/parserse_base_utils.h" #include "hex.h" @@ -147,46 +150,33 @@ namespace string_tools return pname; } #endif - - bool set_module_name_and_folder(const std::string& path_to_process_) - { - std::string path_to_process = path_to_process_; + + void set_module_name_and_folder(const std::string& path_to_process_) + { + boost::filesystem::path path_to_process = path_to_process_; + #ifdef _WIN32 path_to_process = get_current_module_path(); #endif - std::string::size_type a = path_to_process.rfind( '\\' ); - if(a == std::string::npos ) - { - a = path_to_process.rfind( '/' ); - } - if ( a != std::string::npos ) - { - get_current_module_name() = path_to_process.substr(a+1, path_to_process.size()); - get_current_module_folder() = path_to_process.substr(0, a); - return true; - }else - return false; - } + get_current_module_name() = path_to_process.filename().string(); + get_current_module_folder() = path_to_process.parent_path().string(); + } //---------------------------------------------------------------------------- - bool trim_left(std::string& str) - { - for(std::string::iterator it = str.begin(); it!= str.end() && isspace(static_cast<unsigned char>(*it));) - str.erase(str.begin()); - - return true; - } - //---------------------------------------------------------------------------- - bool trim_right(std::string& str) - { + void trim_left(std::string& str) + { + boost::trim_left(str); + return; + } - for(std::string::reverse_iterator it = str.rbegin(); it!= str.rend() && isspace(static_cast<unsigned char>(*it));) - str.erase( --((it++).base())); + //---------------------------------------------------------------------------- + void trim_right(std::string& str) + { + boost::trim_right(str); + return; + } - return true; - } - //---------------------------------------------------------------------------- std::string pad_string(std::string s, size_t n, char c, bool prepend) { if (s.size() < n) @@ -199,28 +189,17 @@ namespace string_tools return s; } - std::string get_extension(const std::string& str) - { - std::string res; - std::string::size_type pos = str.rfind('.'); - if(std::string::npos == pos) - return res; - - res = str.substr(pos+1, str.size()-pos); - return res; - } + std::string get_extension(const std::string& str) + { + return boost::filesystem::path(str).extension().string(); + } + //---------------------------------------------------------------------------- - std::string cut_off_extension(const std::string& str) - { - std::string res; - std::string::size_type pos = str.rfind('.'); - if(std::string::npos == pos) - return str; + std::string cut_off_extension(const std::string& str) + { + return boost::filesystem::path(str).stem().string(); + } - res = str.substr(0, pos); - return res; - } - //---------------------------------------------------------------------------- #ifdef _WIN32 std::wstring utf8_to_utf16(const std::string& str) { diff --git a/contrib/valgrind/monero.supp b/contrib/valgrind/monero.supp index 015b05a1c..8df2cc120 100644 --- a/contrib/valgrind/monero.supp +++ b/contrib/valgrind/monero.supp @@ -26,3 +26,34 @@ fun:_ZN2el4base7Storage7getELPPEv ... } + +{ + in boost multiprecision, we don't get a pointer to the actual code causing it but if so it's only in the test itself anyway + Memcheck:Overlap + fun:__memcpy_chk + fun:_ZL6MKHASHmm + fun:_ZN26difficulty_check_hash_Test8TestBodyEv + fun:_ZN7testing8internal38HandleSehExceptionsInMethodIfSupportedINS_4TestEvEET0_PT_MS4_FS3_vEPKc + fun:_ZN7testing8internal35HandleExceptionsInMethodIfSupportedINS_4TestEvEET0_PT_MS4_FS3_vEPKc + fun:_ZN7testing4Test3RunEv + fun:_ZN7testing8TestInfo3RunEv + fun:_ZN7testing8TestCase3RunEv + fun:_ZN7testing8internal12UnitTestImpl11RunAllTestsEv + fun:_ZN7testing8internal38HandleSehExceptionsInMethodIfSupportedINS0_12UnitTestImplEbEET0_PT_MS4_FS3_vEPKc + fun:_ZN7testing8internal35HandleExceptionsInMethodIfSupportedINS0_12UnitTestImplEbEET0_PT_MS4_FS3_vEPKc + fun:_ZN7testing8UnitTest3RunEv +} + +{ + valgrind seems to be confusing memmove with memcpy + Memcheck:Overlap + fun:__memcpy_chk + fun:memmove + fun:left_shift_byte<boost::multiprecision::backends::cpp_int_backend<512, 512, (boost::multiprecision::cpp_integer_type)0, (boost::multiprecision::cpp_int_check_type)0, void> > + fun:eval_left_shift<512, 512, (boost::multiprecision::cpp_integer_type)0, (boost::multiprecision::cpp_int_check_type)0, void> + fun:eval_left_shift<512, 512, (boost::multiprecision::cpp_integer_type)0, (boost::multiprecision::cpp_int_check_type)0, void> + fun:operator<<=<int> + fun:_ZN10cryptonote14check_hash_128ERKN6crypto4hashEN5boost14multiprecision6numberINS5_8backends15cpp_int_backendILj128ELj128ELNS5_16cpp_integer_typeE0ELNS5_18cpp_int_check_typeE0EvEELNS5_26expression_template_optionE0EEE + fun:_ZN10cryptonote10check_hashERKN6crypto4hashEN5boost14multiprecision6numberINS5_8backends15cpp_int_backendILj128ELj128ELNS5_16cpp_integer_typeE0ELNS5_18cpp_int_check_typeE0EvEELNS5_26expression_template_optionE0EEE + fun:_ZN26difficulty_check_hash_Test8TestBodyEv +} diff --git a/src/common/timings.cc b/src/common/timings.cc index 612ac2cc6..aa719fa5e 100644 --- a/src/common/timings.cc +++ b/src/common/timings.cc @@ -12,10 +12,11 @@ TimingsDatabase::TimingsDatabase() { } -TimingsDatabase::TimingsDatabase(const std::string &filename): +TimingsDatabase::TimingsDatabase(const std::string &filename, const bool load_previous /*=false*/): filename(filename) { - load(); + if (load_previous) + load(); } TimingsDatabase::~TimingsDatabase() @@ -73,53 +74,96 @@ bool TimingsDatabase::load() { i.deciles.push_back(atoi(fields[idx++].c_str())); } - instances.insert(std::make_pair(name, i)); + instances.emplace_back(name, i); } fclose(f); return true; } -bool TimingsDatabase::save() +bool TimingsDatabase::save(const bool save_current_time /*=true*/) { - if (filename.empty()) + if (filename.empty() || instances.empty()) return true; - FILE *f = fopen(filename.c_str(), "w"); + FILE *f = fopen(filename.c_str(), "a"); // append if (!f) { MERROR("Failed to write to file " << filename << ": " << strerror(errno)); return false; } - for (const auto &i: instances) + + if (save_current_time) { - fprintf(f, "%s", i.first.c_str()); - fprintf(f, "\t%lu", (unsigned long)i.second.t); - fprintf(f, " %zu", i.second.npoints); - fprintf(f, " %f", i.second.min); - fprintf(f, " %f", i.second.max); - fprintf(f, " %f", i.second.mean); - fprintf(f, " %f", i.second.median); - fprintf(f, " %f", i.second.stddev); - fprintf(f, " %f", i.second.npskew); - for (uint64_t v: i.second.deciles) - fprintf(f, " %lu", (unsigned long)v); + // save current time in readable format (UTC) + std::time_t sys_time{std::time(nullptr)}; + std::tm *utc_time = std::gmtime(&sys_time); //GMT is equivalent to UTC + + // format: year-month-day : hour:minute:second + std::string current_time{}; + if (utc_time && sys_time != (std::time_t)(-1)) + { + char timeString[22]; //length = std::size("yyyy-mm-dd : hh:mm:ss") (constexpr std::size is C++17) + std::strftime(timeString, 22, "%F : %T", utc_time); + current_time += timeString; + } + else + { + current_time += "TIME_ERROR_"; + } + fputc('\n', f); // add an extra line before each 'print time' + fprintf(f, "%s", current_time.c_str()); fputc('\n', f); } + + for (const auto &i: instances) + { + fprintf(f, "%s,", i.first.c_str()); + + if (i.second.npoints > 0) + { + fprintf(f, "%lu,", (unsigned long)i.second.t); + fprintf(f, "%zu,", i.second.npoints); + fprintf(f, "%f,", i.second.min); + fprintf(f, "%f,", i.second.max); + fprintf(f, "%f,", i.second.mean); + fprintf(f, "%f,", i.second.median); + fprintf(f, "%f,", i.second.stddev); + fprintf(f, "%f,", i.second.npskew); + for (uint64_t v: i.second.deciles) + fprintf(f, "%lu,", (unsigned long)v); + + // note: only add a new line if there are points; assume that 'no points' means i.first is a message meant to be + // prepended to the next save operation + fputc('\n', f); + } + } fclose(f); + + // after saving, clear so next save does not append the same stuff over again + instances.clear(); + return true; } -std::vector<TimingsDatabase::instance> TimingsDatabase::get(const char *name) const +const TimingsDatabase::instance* TimingsDatabase::get_most_recent(const char *name) const { - std::vector<instance> ret; - auto range = instances.equal_range(name); - for (auto i = range.first; i != range.second; ++i) - ret.push_back(i->second); - std::sort(ret.begin(), ret.end(), [](const instance &e0, const instance &e1){ return e0.t < e1.t; }); - return ret; + time_t latest_time = 0; + const TimingsDatabase::instance *instance_ptr = nullptr; + + for (const auto &i: instances) + { + if (i.first != name) + continue; + if (i.second.t < latest_time) + continue; + + latest_time = i.second.t; + instance_ptr = &i.second; + } + return instance_ptr; } void TimingsDatabase::add(const char *name, const instance &i) { - instances.insert(std::make_pair(name, i)); + instances.emplace_back(name, i); } diff --git a/src/common/timings.h b/src/common/timings.h index fb905611f..6e7ff5659 100644 --- a/src/common/timings.h +++ b/src/common/timings.h @@ -2,8 +2,8 @@ #include <stdint.h> #include <string> +#include <utility> #include <vector> -#include <map> class TimingsDatabase { @@ -18,17 +18,17 @@ public: public: TimingsDatabase(); - TimingsDatabase(const std::string &filename); + TimingsDatabase(const std::string &filename, const bool load_previous = false); ~TimingsDatabase(); - std::vector<instance> get(const char *name) const; + const instance* get_most_recent(const char *name) const; void add(const char *name, const instance &data); + bool save(const bool print_current_time = true); private: bool load(); - bool save(); private: std::string filename; - std::multimap<std::string, instance> instances; + std::vector<std::pair<std::string, instance>> instances; }; diff --git a/src/crypto/CMakeLists.txt b/src/crypto/CMakeLists.txt index 9ac376780..2559c754e 100644 --- a/src/crypto/CMakeLists.txt +++ b/src/crypto/CMakeLists.txt @@ -29,6 +29,7 @@ set(crypto_sources aesb.c blake256.c + blake2b.c chacha.c crypto-ops-data.c crypto-ops.c diff --git a/src/crypto/blake2b.c b/src/crypto/blake2b.c new file mode 100644 index 000000000..7e8be7890 --- /dev/null +++ b/src/crypto/blake2b.c @@ -0,0 +1,563 @@ +/* +Copyright (c) 2018-2019, tevador <tevador@gmail.com> + +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 copyright holder 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 HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +#include "blake2b.h" + +#include "memwipe.h" + +#include <stdint.h> +#include <string.h> +#include <stdio.h> + +/// BEGIN: endian.h + +#if defined(_MSC_VER) +#define FORCE_INLINE __inline +#elif defined(__GNUC__) || defined(__clang__) +#define FORCE_INLINE __inline__ +#else +#define FORCE_INLINE +#endif + + /* Argon2 Team - Begin Code */ + /* + Not an exhaustive list, but should cover the majority of modern platforms + Additionally, the code will always be correct---this is only a performance + tweak. + */ +#if (defined(__BYTE_ORDER__) && \ + (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ + defined(__LITTLE_ENDIAN__) || defined(__ARMEL__) || defined(__MIPSEL__) || \ + defined(__AARCH64EL__) || defined(__amd64__) || defined(__i386__) || \ + defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || \ + defined(_M_ARM) +#define NATIVE_LITTLE_ENDIAN +#endif + /* Argon2 Team - End Code */ + +static FORCE_INLINE uint32_t load32(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = (const uint8_t *)src; + uint32_t w = *p++; + w |= (uint32_t)(*p++) << 8; + w |= (uint32_t)(*p++) << 16; + w |= (uint32_t)(*p++) << 24; + return w; +#endif +} + +static FORCE_INLINE uint64_t load64_native(const void *src) { + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +} + +static FORCE_INLINE uint64_t load64(const void *src) { +#if defined(NATIVE_LITTLE_ENDIAN) + return load64_native(src); +#else + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + w |= (uint64_t)(*p++) << 48; + w |= (uint64_t)(*p++) << 56; + return w; +#endif +} + +static FORCE_INLINE void store32(void *dst, uint32_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +static FORCE_INLINE void store64_native(void *dst, uint64_t w) { + memcpy(dst, &w, sizeof w); +} + +static FORCE_INLINE void store64(void *dst, uint64_t w) { +#if defined(NATIVE_LITTLE_ENDIAN) + store64_native(dst, w); +#else + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +#endif +} + +/// END: endian.h + +/// BEGIN: blake2-impl.h + +static FORCE_INLINE uint64_t load48(const void *src) { + const uint8_t *p = (const uint8_t *)src; + uint64_t w = *p++; + w |= (uint64_t)(*p++) << 8; + w |= (uint64_t)(*p++) << 16; + w |= (uint64_t)(*p++) << 24; + w |= (uint64_t)(*p++) << 32; + w |= (uint64_t)(*p++) << 40; + return w; +} + +static FORCE_INLINE void store48(void *dst, uint64_t w) { + uint8_t *p = (uint8_t *)dst; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; + w >>= 8; + *p++ = (uint8_t)w; +} + +static FORCE_INLINE uint32_t rotr32(const uint32_t w, const unsigned c) { + return (w >> c) | (w << (32 - c)); +} + +static FORCE_INLINE uint64_t rotr64(const uint64_t w, const unsigned c) { + return (w >> c) | (w << (64 - c)); +} + +/// END: blake2-impl.h + +void clear_internal_memory(void *mem, const size_t length) { + memwipe(mem, length); +} + +/// BEGIN: blake2b.c + +static const uint64_t blake2b_IV[8] = { + UINT64_C(0x6a09e667f3bcc908), UINT64_C(0xbb67ae8584caa73b), + UINT64_C(0x3c6ef372fe94f82b), UINT64_C(0xa54ff53a5f1d36f1), + UINT64_C(0x510e527fade682d1), UINT64_C(0x9b05688c2b3e6c1f), + UINT64_C(0x1f83d9abfb41bd6b), UINT64_C(0x5be0cd19137e2179) }; + +static const unsigned int blake2b_sigma[12][16] = { + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, + {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, + {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, + {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, + {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, + {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, + {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, + {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, + {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, + {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, + {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, +}; + +static FORCE_INLINE void blake2b_set_lastnode(blake2b_state *S) { + S->f[1] = (uint64_t)-1; +} + +static FORCE_INLINE void blake2b_set_lastblock(blake2b_state *S) { + if (S->last_node) { + blake2b_set_lastnode(S); + } + S->f[0] = (uint64_t)-1; +} + +static FORCE_INLINE void blake2b_increment_counter(blake2b_state *S, + uint64_t inc) { + S->t[0] += inc; + S->t[1] += (S->t[0] < inc); +} + +static FORCE_INLINE void blake2b_invalidate_state(blake2b_state *S) { + clear_internal_memory(S, sizeof(*S)); /* wipe */ + blake2b_set_lastblock(S); /* invalidate for further use */ +} + +static FORCE_INLINE void blake2b_init0(blake2b_state *S) { + memset(S, 0, sizeof(*S)); + memcpy(S->h, blake2b_IV, sizeof(S->h)); +} + +int blake2b_init_param(blake2b_state *S, const blake2b_param *P) { + const unsigned char *p = (const unsigned char *)P; + unsigned int i; + + if (NULL == P || NULL == S) { + return -1; + } + + blake2b_init0(S); + /* IV XOR Parameter Block */ + for (i = 0; i < 8; ++i) { + S->h[i] ^= load64(&p[i * sizeof(S->h[i])]); + } + S->outlen = P->digest_length; + return 0; +} + +/* Sequential blake2b initialization */ +int blake2b_init(blake2b_state *S, size_t outlen) { + blake2b_param P; + + if (S == NULL) { + return -1; + } + + if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + /* Setup Parameter Block for unkeyed BLAKE2 */ + P.digest_length = (uint8_t)outlen; + P.key_length = 0; + P.fanout = 1; + P.depth = 1; + P.leaf_length = 0; + P.node_offset = 0; + P.node_depth = 0; + P.inner_length = 0; + memset(P.reserved, 0, sizeof(P.reserved)); + memset(P.salt, 0, sizeof(P.salt)); + memset(P.personal, 0, sizeof(P.personal)); + + return blake2b_init_param(S, &P); +} + +int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, size_t keylen) { + blake2b_param P; + + if (S == NULL) { + return -1; + } + + if ((outlen == 0) || (outlen > BLAKE2B_OUTBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + if ((key == 0) || (keylen == 0) || (keylen > BLAKE2B_KEYBYTES)) { + blake2b_invalidate_state(S); + return -1; + } + + /* Setup Parameter Block for keyed BLAKE2 */ + P.digest_length = (uint8_t)outlen; + P.key_length = (uint8_t)keylen; + P.fanout = 1; + P.depth = 1; + P.leaf_length = 0; + P.node_offset = 0; + P.node_depth = 0; + P.inner_length = 0; + memset(P.reserved, 0, sizeof(P.reserved)); + memset(P.salt, 0, sizeof(P.salt)); + memset(P.personal, 0, sizeof(P.personal)); + + if (blake2b_init_param(S, &P) < 0) { + blake2b_invalidate_state(S); + return -1; + } + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset(block, 0, BLAKE2B_BLOCKBYTES); + memcpy(block, key, keylen); + blake2b_update(S, block, BLAKE2B_BLOCKBYTES); + /* Burn the key from stack */ + clear_internal_memory(block, BLAKE2B_BLOCKBYTES); + } + return 0; +} + +static void blake2b_compress(blake2b_state *S, const uint8_t *block) { + uint64_t m[16]; + uint64_t v[16]; + unsigned int i, r; + + for (i = 0; i < 16; ++i) { + m[i] = load64(block + i * sizeof(m[i])); + } + + for (i = 0; i < 8; ++i) { + v[i] = S->h[i]; + } + + v[8] = blake2b_IV[0]; + v[9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + +#define G(r, i, a, b, c, d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while ((void)0, 0) + +#define ROUND(r) \ + do { \ + G(r, 0, v[0], v[4], v[8], v[12]); \ + G(r, 1, v[1], v[5], v[9], v[13]); \ + G(r, 2, v[2], v[6], v[10], v[14]); \ + G(r, 3, v[3], v[7], v[11], v[15]); \ + G(r, 4, v[0], v[5], v[10], v[15]); \ + G(r, 5, v[1], v[6], v[11], v[12]); \ + G(r, 6, v[2], v[7], v[8], v[13]); \ + G(r, 7, v[3], v[4], v[9], v[14]); \ + } while ((void)0, 0) + + for (r = 0; r < 12; ++r) { + ROUND(r); + } + + for (i = 0; i < 8; ++i) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } + +#undef G +#undef ROUND +} + +int blake2b_update(blake2b_state *S, const void *in, size_t inlen) { + const uint8_t *pin = (const uint8_t *)in; + + if (inlen == 0) { + return 0; + } + + /* Sanity check */ + if (S == NULL || in == NULL) { + return -1; + } + + /* Is this a reused state? */ + if (S->f[0] != 0) { + return -1; + } + + if (S->buflen + inlen > BLAKE2B_BLOCKBYTES) { + /* Complete current block */ + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + memcpy(&S->buf[left], pin, fill); + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, S->buf); + S->buflen = 0; + inlen -= fill; + pin += fill; + /* Avoid buffer copies when possible */ + while (inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress(S, pin); + inlen -= BLAKE2B_BLOCKBYTES; + pin += BLAKE2B_BLOCKBYTES; + } + } + memcpy(&S->buf[S->buflen], pin, inlen); + S->buflen += (unsigned int)inlen; + return 0; +} + +int blake2b_final(blake2b_state *S, void *out, size_t outlen) { + uint8_t buffer[BLAKE2B_OUTBYTES] = { 0 }; + unsigned int i; + + /* Sanity checks */ + if (S == NULL || out == NULL || outlen < S->outlen) { + return -1; + } + + /* Is this a reused state? */ + if (S->f[0] != 0) { + return -1; + } + + blake2b_increment_counter(S, S->buflen); + blake2b_set_lastblock(S); + memset(&S->buf[S->buflen], 0, BLAKE2B_BLOCKBYTES - S->buflen); /* Padding */ + blake2b_compress(S, S->buf); + + for (i = 0; i < 8; ++i) { /* Output full hash to temp buffer */ + store64(buffer + sizeof(S->h[i]) * i, S->h[i]); + } + + memcpy(out, buffer, S->outlen); + clear_internal_memory(buffer, sizeof(buffer)); + clear_internal_memory(S->buf, sizeof(S->buf)); + clear_internal_memory(S->h, sizeof(S->h)); + return 0; +} + +int blake2b(void *out, size_t outlen, const void *in, size_t inlen, + const void *key, size_t keylen) { + blake2b_state S; + int ret = -1; + + /* Verify parameters */ + if (NULL == in && inlen > 0) { + goto fail; + } + + if (NULL == out || outlen == 0 || outlen > BLAKE2B_OUTBYTES) { + goto fail; + } + + if ((NULL == key && keylen > 0) || keylen > BLAKE2B_KEYBYTES) { + goto fail; + } + + if (keylen > 0) { + if (blake2b_init_key(&S, outlen, key, keylen) < 0) { + goto fail; + } + } + else { + if (blake2b_init(&S, outlen) < 0) { + goto fail; + } + } + + if (blake2b_update(&S, in, inlen) < 0) { + goto fail; + } + ret = blake2b_final(&S, out, outlen); + +fail: + clear_internal_memory(&S, sizeof(S)); + return ret; +} + +/* Argon2 Team - Begin Code */ +int blake2b_long(void *pout, size_t outlen, const void *in, size_t inlen) { + uint8_t *out = (uint8_t *)pout; + blake2b_state blake_state; + uint8_t outlen_bytes[sizeof(uint32_t)] = { 0 }; + int ret = -1; + + if (outlen > UINT32_MAX) { + goto fail; + } + + /* Ensure little-endian byte order! */ + store32(outlen_bytes, (uint32_t)outlen); + +#define TRY(statement) \ + do { \ + ret = statement; \ + if (ret < 0) { \ + goto fail; \ + } \ + } while ((void)0, 0) + + if (outlen <= BLAKE2B_OUTBYTES) { + TRY(blake2b_init(&blake_state, outlen)); + TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + TRY(blake2b_update(&blake_state, in, inlen)); + TRY(blake2b_final(&blake_state, out, outlen)); + } + else { + uint32_t toproduce; + uint8_t out_buffer[BLAKE2B_OUTBYTES]; + uint8_t in_buffer[BLAKE2B_OUTBYTES]; + TRY(blake2b_init(&blake_state, BLAKE2B_OUTBYTES)); + TRY(blake2b_update(&blake_state, outlen_bytes, sizeof(outlen_bytes))); + TRY(blake2b_update(&blake_state, in, inlen)); + TRY(blake2b_final(&blake_state, out_buffer, BLAKE2B_OUTBYTES)); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce = (uint32_t)outlen - BLAKE2B_OUTBYTES / 2; + + while (toproduce > BLAKE2B_OUTBYTES) { + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + TRY(blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer, + BLAKE2B_OUTBYTES, NULL, 0)); + memcpy(out, out_buffer, BLAKE2B_OUTBYTES / 2); + out += BLAKE2B_OUTBYTES / 2; + toproduce -= BLAKE2B_OUTBYTES / 2; + } + + memcpy(in_buffer, out_buffer, BLAKE2B_OUTBYTES); + TRY(blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES, NULL, + 0)); + memcpy(out, out_buffer, toproduce); + } +fail: + clear_internal_memory(&blake_state, sizeof(blake_state)); + return ret; +#undef TRY +} +/* Argon2 Team - End Code */ + +/// END: blake2b.c diff --git a/src/crypto/blake2b.h b/src/crypto/blake2b.h new file mode 100644 index 000000000..ea00f381b --- /dev/null +++ b/src/crypto/blake2b.h @@ -0,0 +1,116 @@ +/* +Copyright (c) 2018-2019, tevador <tevador@gmail.com> + +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 copyright holder 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 HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* Original code from Argon2 reference source code package used under CC0 Licence + * https://github.com/P-H-C/phc-winner-argon2 + * Copyright 2015 + * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves +*/ + +/// NOTE: implementation lifted out of randomx package + +#pragma once + +#include <stddef.h> +#include <stdint.h> +#include <limits.h> + +#if defined(__cplusplus) +extern "C" { +#endif + + enum blake2b_constant { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 + }; + +#pragma pack(push, 1) + typedef struct __blake2b_param { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint64_t node_offset; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ + } blake2b_param; +#pragma pack(pop) + + typedef struct __blake2b_state { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + unsigned buflen; + unsigned outlen; + uint8_t last_node; + } blake2b_state; + + /* Ensure param structs have not been wrongly padded */ + /* Poor man's static_assert */ + enum { + blake2_size_check_0 = 1 / !!(CHAR_BIT == 8), + blake2_size_check_2 = + 1 / !!(sizeof(blake2b_param) == sizeof(uint64_t) * CHAR_BIT) + }; + + // crypto namespace (fixes naming collisions with libsodium) +#define blake2b_init crypto_blake2b_init +#define blake2b_init_key crypto_blake2b_init_key +#define blake2b_init_param crypto_blake2b_init_param +#define blake2b_update crypto_blake2b_update +#define blake2b_final crypto_blake2b_final +#define blake2b crypto_blake2b +#define blake2b_long crypto_blake2b_long + + /* Streaming API */ + int blake2b_init(blake2b_state *S, size_t outlen); + int blake2b_init_key(blake2b_state *S, size_t outlen, const void *key, + size_t keylen); + int blake2b_init_param(blake2b_state *S, const blake2b_param *P); + int blake2b_update(blake2b_state *S, const void *in, size_t inlen); + int blake2b_final(blake2b_state *S, void *out, size_t outlen); + + /* Simple API */ + int blake2b(void *out, size_t outlen, const void *in, size_t inlen, + const void *key, size_t keylen); + + /* Argon2 Team - Begin Code */ + int blake2b_long(void *out, size_t outlen, const void *in, size_t inlen); + /* Argon2 Team - End Code */ + +#if defined(__cplusplus) +} +#endif diff --git a/src/cryptonote_basic/verification_context.h b/src/cryptonote_basic/verification_context.h index 11d54ae9f..8dcd55187 100644 --- a/src/cryptonote_basic/verification_context.h +++ b/src/cryptonote_basic/verification_context.h @@ -59,6 +59,7 @@ namespace cryptonote bool m_fee_too_low; bool m_too_few_outputs; bool m_tx_extra_too_big; + bool m_nonzero_unlock_time; }; struct block_verification_context diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 3e1704048..d610ce2a0 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -3691,18 +3691,16 @@ void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const } //------------------------------------------------------------------ -uint64_t Blockchain::get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight, uint8_t version) +uint64_t Blockchain::get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight) { - const uint64_t min_block_weight = get_min_block_weight(version); + constexpr uint64_t min_block_weight = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V5; if (median_block_weight < min_block_weight) median_block_weight = min_block_weight; uint64_t hi, lo; - if (version >= HF_VERSION_PER_BYTE_FEE) { lo = mul128(block_reward, DYNAMIC_FEE_REFERENCE_TRANSACTION_WEIGHT, &hi); div128_64(hi, lo, median_block_weight, &hi, &lo, NULL, NULL); - if (version >= HF_VERSION_2021_SCALING) { // min_fee_per_byte = round_up( 0.95 * block_reward * ref_weight / (fee_median^2) ) // note: since hardfork HF_VERSION_2021_SCALING, fee_median (a.k.a. median_block_weight) equals effective long term median @@ -3711,29 +3709,7 @@ uint64_t Blockchain::get_dynamic_base_fee(uint64_t block_reward, size_t median_b lo -= lo / 20; return lo == 0 ? 1 : lo; } - else - { - // min_fee_per_byte = 0.2 * block_reward * ref_weight / (min_penalty_free_zone * fee_median) - div128_64(hi, lo, min_block_weight, &hi, &lo, NULL, NULL); - assert(hi == 0); - lo /= 5; - return lo; - } } - - const uint64_t fee_base = version >= 5 ? DYNAMIC_FEE_PER_KB_BASE_FEE_V5 : DYNAMIC_FEE_PER_KB_BASE_FEE; - - uint64_t unscaled_fee_base = (fee_base * min_block_weight / median_block_weight); - lo = mul128(unscaled_fee_base, block_reward, &hi); - div128_64(hi, lo, DYNAMIC_FEE_PER_KB_BASE_BLOCK_REWARD, &hi, &lo, NULL, NULL); - assert(hi == 0); - - // quantize fee up to 8 decimals - uint64_t mask = get_fee_quantization_mask(); - uint64_t qlo = (lo + mask - 1) / mask * mask; - MDEBUG("lo " << print_money(lo) << ", qlo " << print_money(qlo) << ", mask " << mask); - - return qlo; } //------------------------------------------------------------------ @@ -3744,7 +3720,6 @@ bool Blockchain::check_fee(size_t tx_weight, uint64_t fee) const uint64_t median = 0; uint64_t already_generated_coins = 0; uint64_t base_reward = 0; - if (version >= HF_VERSION_DYNAMIC_FEE) { median = m_current_block_cumul_weight_limit / 2; const uint64_t blockchain_height = m_db->height(); @@ -3754,33 +3729,15 @@ bool Blockchain::check_fee(size_t tx_weight, uint64_t fee) const } uint64_t needed_fee; - if (version >= HF_VERSION_PER_BYTE_FEE) { - const bool use_long_term_median_in_fee = version >= HF_VERSION_LONG_TERM_BLOCK_WEIGHT; - uint64_t fee_per_byte = get_dynamic_base_fee(base_reward, use_long_term_median_in_fee ? std::min<uint64_t>(median, m_long_term_effective_median_block_weight) : median, version); + const uint64_t fee_per_byte = get_dynamic_base_fee(base_reward, + std::min<uint64_t>(median, m_long_term_effective_median_block_weight)); MDEBUG("Using " << print_money(fee_per_byte) << "/byte fee"); needed_fee = tx_weight * fee_per_byte; // quantize fee up to 8 decimals const uint64_t mask = get_fee_quantization_mask(); needed_fee = (needed_fee + mask - 1) / mask * mask; } - else - { - uint64_t fee_per_kb; - if (version < HF_VERSION_DYNAMIC_FEE) - { - fee_per_kb = FEE_PER_KB; - } - else - { - fee_per_kb = get_dynamic_base_fee(base_reward, median, version); - } - MDEBUG("Using " << print_money(fee_per_kb) << "/kB fee"); - - needed_fee = tx_weight / 1024; - needed_fee += (tx_weight % 1024) ? 1 : 0; - needed_fee *= fee_per_kb; - } if (fee < needed_fee - needed_fee / 50) // keep a little 2% buffer on acceptance - no integer overflow { @@ -3791,7 +3748,8 @@ bool Blockchain::check_fee(size_t tx_weight, uint64_t fee) const } //------------------------------------------------------------------ -void Blockchain::get_dynamic_base_fee_estimate_2021_scaling(uint64_t grace_blocks, uint64_t base_reward, uint64_t Mnw, uint64_t Mlw, std::vector<uint64_t> &fees) const +void Blockchain::get_dynamic_base_fee_estimate_2021_scaling(uint64_t base_reward, uint64_t Mnw, + uint64_t Mlw, std::vector<uint64_t> &fees) { // variable names and calculations as per https://github.com/ArticMine/Monero-Documents/blob/master/MoneroScaling2021-02.pdf // from (earlier than) this fork, the base fee is per byte @@ -3863,55 +3821,8 @@ void Blockchain::get_dynamic_base_fee_estimate_2021_scaling(uint64_t grace_block base_reward = BLOCK_REWARD_OVERESTIMATE; } - get_dynamic_base_fee_estimate_2021_scaling(grace_blocks, base_reward, Mnw, Mlw_penalty_free_zone_for_wallet, fees); -} - -//------------------------------------------------------------------ -uint64_t Blockchain::get_dynamic_base_fee_estimate(uint64_t grace_blocks) const -{ - const uint8_t version = get_current_hard_fork_version(); - const uint64_t db_height = m_db->height(); - - if (version < HF_VERSION_DYNAMIC_FEE) - return FEE_PER_KB; - - if (grace_blocks >= CRYPTONOTE_REWARD_BLOCKS_WINDOW) - grace_blocks = CRYPTONOTE_REWARD_BLOCKS_WINDOW - 1; - - if (version >= HF_VERSION_2021_SCALING) - { - std::vector<uint64_t> fees; - get_dynamic_base_fee_estimate_2021_scaling(grace_blocks, fees); - return fees[0]; - } - - const uint64_t min_block_weight = get_min_block_weight(version); - std::vector<uint64_t> weights; - get_last_n_blocks_weights(weights, CRYPTONOTE_REWARD_BLOCKS_WINDOW - grace_blocks); - weights.reserve(grace_blocks); - for (size_t i = 0; i < grace_blocks; ++i) - weights.push_back(min_block_weight); - - uint64_t median = epee::misc_utils::median(weights); - if(median <= min_block_weight) - median = min_block_weight; - - uint64_t already_generated_coins = db_height ? m_db->get_block_already_generated_coins(db_height - 1) : 0; - uint64_t base_reward; - if (!get_block_reward(m_current_block_cumul_weight_limit / 2, 1, already_generated_coins, base_reward, version)) - { - MERROR("Failed to determine block reward, using placeholder " << print_money(BLOCK_REWARD_OVERESTIMATE) << " as a high bound"); - base_reward = BLOCK_REWARD_OVERESTIMATE; - } - - const bool use_long_term_median_in_fee = version >= HF_VERSION_LONG_TERM_BLOCK_WEIGHT; - const uint64_t use_median_value = use_long_term_median_in_fee ? std::min<uint64_t>(median, m_long_term_effective_median_block_weight) : median; - const uint64_t fee = get_dynamic_base_fee(base_reward, use_median_value, version); - const bool per_byte = version < HF_VERSION_PER_BYTE_FEE; - MDEBUG("Estimating " << grace_blocks << "-block fee at " << print_money(fee) << "/" << (per_byte ? "byte" : "kB")); - return fee; + get_dynamic_base_fee_estimate_2021_scaling(base_reward, Mnw, Mlw_penalty_free_zone_for_wallet, fees); } - //------------------------------------------------------------------ // This function checks to see if a tx is unlocked. unlock_time is either // a block index or a unix time. diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index be2848d09..2249d8cb2 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -638,27 +638,24 @@ namespace cryptonote * * @param block_reward the current block reward * @param median_block_weight the median block weight in the past window - * @param version hard fork version for rules and constants to use * * @return the fee */ - static uint64_t get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight, uint8_t version); + static uint64_t get_dynamic_base_fee(uint64_t block_reward, size_t median_block_weight); /** - * @brief get dynamic per kB or byte fee estimate for the next few blocks + * @brief get four levels of dynamic per byte fee estimate for the next few blocks * * The dynamic fee is based on the block weight in a past window, and - * the current block reward. It is expressed by kB before v8, and - * per byte from v8. - * This function calculates an estimate for a dynamic fee which will be - * valid for the next grace_blocks - * - * @param grace_blocks number of blocks we want the fee to be valid for + * the current block reward. It is expressed per byte, and is based on + * https://github.com/ArticMine/Monero-Documents/blob/master/MoneroScaling2021-02.pdf * - * @return the fee estimate + * @param Mnw min(Msw, 50*Mlw) + * @param Mlw The median over the last 99990 and future 10 blocks of max(min(Mbw, 2*Ml), Zm, Ml/2) + * @param[out] fees fee estimate levels [Fl, Fn, Fm, Fh] */ - uint64_t get_dynamic_base_fee_estimate(uint64_t grace_blocks) const; - void get_dynamic_base_fee_estimate_2021_scaling(uint64_t grace_blocks, uint64_t base_reward, uint64_t Mnw, uint64_t Mlw, std::vector<uint64_t> &fees) const; + static void get_dynamic_base_fee_estimate_2021_scaling(uint64_t base_reward, uint64_t Mnw, + uint64_t Mlw, std::vector<uint64_t> &fees); /** * @brief get four levels of dynamic per byte fee estimate for the next few blocks @@ -670,8 +667,7 @@ namespace cryptonote * valid for the next grace_blocks * * @param grace_blocks number of blocks we want the fee to be valid for - * - * @return the fee estimates (4 of them) + * @param[out] fees fee estimate levels [Fl, Fn, Fm, Fh] */ void get_dynamic_base_fee_estimate_2021_scaling(uint64_t grace_blocks, std::vector<uint64_t> &fees) const; diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index 60b399bb5..d5bb8fee7 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -203,7 +203,7 @@ namespace cryptonote return addr.m_view_public_key; } //--------------------------------------------------------------- - bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool shuffle_outs, bool use_view_tags) + bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool shuffle_outs, bool use_view_tags) { hw::device &hwdev = sender_account_keys.get_device(); @@ -218,7 +218,7 @@ namespace cryptonote amount_keys.clear(); tx.version = rct ? 2 : 1; - tx.unlock_time = unlock_time; + tx.unlock_time = 0; tx.extra = extra; crypto::public_key txkey_pub; @@ -606,7 +606,7 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool use_view_tags) + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct, const rct::RCTConfig &rct_config, bool use_view_tags) { hw::device &hwdev = sender_account_keys.get_device(); hwdev.open_tx(tx_key); @@ -627,7 +627,7 @@ namespace cryptonote } bool shuffle_outs = true; - bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config, shuffle_outs, use_view_tags); + bool r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, tx_key, additional_tx_keys, rct, rct_config, shuffle_outs, use_view_tags); hwdev.close_tx(); return r; } catch(...) { @@ -636,14 +636,14 @@ namespace cryptonote } } //--------------------------------------------------------------- - bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time) + bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry>& sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx) { std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0}; crypto::secret_key tx_key; std::vector<crypto::secret_key> additional_tx_keys; std::vector<tx_destination_entry> destinations_copy = destinations; - return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, { rct::RangeProofBorromean, 0}); + return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, tx_key, additional_tx_keys, false, { rct::RangeProofBorromean, 0}); } //--------------------------------------------------------------- bool generate_genesis_block( diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 2ee93fd8f..8f1073766 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -118,9 +118,9 @@ namespace cryptonote //--------------------------------------------------------------- crypto::public_key get_destination_view_key_pub(const std::vector<tx_destination_entry> &destinations, const boost::optional<cryptonote::account_public_address>& change_addr); - bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time); - bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool shuffle_outs = true, bool use_view_tags = false); - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool use_view_tags = false); + bool construct_tx(const account_keys& sender_account_keys, std::vector<tx_source_entry> &sources, const std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx); + bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, const crypto::secret_key &tx_key, const std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool shuffle_outs = true, bool use_view_tags = false); + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map<crypto::public_key, subaddress_index>& subaddresses, std::vector<tx_source_entry>& sources, std::vector<tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, const std::vector<uint8_t> &extra, transaction& tx, crypto::secret_key &tx_key, std::vector<crypto::secret_key> &additional_tx_keys, bool rct = false, const rct::RCTConfig &rct_config = { rct::RangeProofBorromean, 0 }, bool use_view_tags = false); bool generate_output_ephemeral_keys(const size_t tx_version, const cryptonote::account_keys &sender_account_keys, const crypto::public_key &txkey_pub, const crypto::secret_key &tx_key, const cryptonote::tx_destination_entry &dst_entr, const boost::optional<cryptonote::account_public_address> &change_addr, const size_t output_index, const bool &need_additional_txkeys, const std::vector<crypto::secret_key> &additional_tx_keys, diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 4f0501c1d..96b229177 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -235,6 +235,15 @@ namespace cryptonote return false; } + if (!kept_by_block && tx.unlock_time) + { + LOG_PRINT_L1("transaction unlock time is not zero: " << tx.unlock_time); + tvc.m_verifivation_failed = true; + tvc.m_nonzero_unlock_time = true; + tvc.m_no_drop_offense = true; + return false; + } + // if the transaction came from a block popped from the chain, // don't check if we have its key images as spent. // TODO: Investigate why not? diff --git a/src/device_trezor/README.md b/src/device_trezor/README.md index ce08c0009..dede853ae 100644 --- a/src/device_trezor/README.md +++ b/src/device_trezor/README.md @@ -15,19 +15,29 @@ Please, refer to [monero readme](https://github.com/trezor/trezor-firmware/blob/ ## Dependencies -Trezor uses [Protobuf](https://protobuf.dev/) library. As Monero is compiled with C++14, the newest Protobuf library version cannot be compiled because it requires C++17 (through its dependency Abseil library). -This can result in a compilation failure. +Trezor uses [Protobuf](https://protobuf.dev/) library. Monero is now compiled with C++ 17 by default. +Protobuf v21 is tested, older versions are not guaranteed to work. Note that Protobuf v23+ requires C++ 17. -Protobuf v21 is the latest compatible protobuf version. +If you are getting Trezor compilation errors, it may be caused by abseil (protobuf dependency) not being compiled with C++17. +To fix this try installing protobuf from sources: -If you want to compile Monero with Trezor support, please make sure the Protobuf v21 is installed. +```shell +git clone --recursive git@github.com:protocolbuffers/protobuf.git +cd protobuf +cmake -DABSL_PROPAGATE_CXX_STD=TRUE -DCMAKE_CXX_STANDARD=17 -Dprotobuf_BUILD_SHARED_LIBS=ON -Dprotobuf_BUILD_TESTS=OFF . +cmake --build . +sudo make install +``` + +If Monero is compiled with C++14, Protobuf v21 is the latest compatible protobuf version for C++ 14. +If you want to compile Monero with Trezor support with C++14, please make sure the Protobuf v21 is installed. More about this limitation: [PR #8752](https://github.com/monero-project/monero/pull/8752), [1](https://github.com/monero-project/monero/pull/8752#discussion_r1246174755), [2](https://github.com/monero-project/monero/pull/8752#discussion_r1246480393) ### OSX -To build with installed, but not linked protobuf: +To build with installed, but not linked Protobuf v21: ```bash CMAKE_PREFIX_PATH=$(find /opt/homebrew/Cellar/protobuf@21 -maxdepth 1 -type d -name "21.*" -print -quit) \ @@ -53,7 +63,7 @@ pacman --noconfirm -U mingw-w64-x86_64-protobuf-c-1.4.1-1-any.pkg.tar.zst mingw- ### Other systems -- install protobufv21 +- install Protobuf v21 - point `CMAKE_PREFIX_PATH` environment variable to Protobuf v21 installation. ## Troubleshooting diff --git a/src/gen_multisig/gen_multisig.cpp b/src/gen_multisig/gen_multisig.cpp index 48cf818ef..fd82c66af 100644 --- a/src/gen_multisig/gen_multisig.cpp +++ b/src/gen_multisig/gen_multisig.cpp @@ -121,16 +121,15 @@ static bool generate_multisig(uint32_t threshold, uint32_t total, const std::str } // exchange keys until the wallets are done - bool ready{false}; - wallets[0]->multisig(&ready); - while (!ready) + multisig::multisig_account_status ms_status{wallets[0]->get_multisig_status()}; + while (!ms_status.is_ready) { for (size_t n = 0; n < total; ++n) { kex_msgs_intermediate[n] = wallets[n]->exchange_multisig_keys(pwd_container->password(), kex_msgs_intermediate); } - wallets[0]->multisig(&ready); + ms_status = wallets[0]->get_multisig_status(); } std::string address = wallets[0]->get_account().get_public_address_str(wallets[0]->nettype()); diff --git a/src/multisig/multisig_account.h b/src/multisig/multisig_account.h index 0d832f243..2ea8d0133 100644 --- a/src/multisig/multisig_account.h +++ b/src/multisig/multisig_account.h @@ -40,6 +40,19 @@ namespace multisig { + struct multisig_account_status + { + // is the multisig account active/initialized? + bool multisig_is_active{false}; + // has the multisig account completed the main key exchange rounds? + bool kex_is_done{false}; + // is the multisig account ready to use? + bool is_ready{false}; + // multisig is: M-of-N + std::uint32_t threshold{0}; // M + std::uint32_t total{0}; // N + }; + /** * multisig account: * diff --git a/src/multisig/multisig_tx_builder_ringct.cpp b/src/multisig/multisig_tx_builder_ringct.cpp index 8643a8af4..2653a70dd 100644 --- a/src/multisig/multisig_tx_builder_ringct.cpp +++ b/src/multisig/multisig_tx_builder_ringct.cpp @@ -820,7 +820,6 @@ tx_builder_ringct_t::~tx_builder_ringct_t() bool tx_builder_ringct_t::init( const cryptonote::account_keys& account_keys, const std::vector<std::uint8_t>& extra, - const std::uint64_t unlock_time, const std::uint32_t subaddr_account, const std::set<std::uint32_t>& subaddr_minor_indices, std::vector<cryptonote::tx_source_entry>& sources, @@ -854,7 +853,7 @@ bool tx_builder_ringct_t::init( // misc. fields unsigned_tx.version = 2; //rct = 2 - unsigned_tx.unlock_time = unlock_time; + unsigned_tx.unlock_time = 0; // sort inputs sort_sources(sources); diff --git a/src/multisig/multisig_tx_builder_ringct.h b/src/multisig/multisig_tx_builder_ringct.h index f1bd24e73..a1b72b177 100644 --- a/src/multisig/multisig_tx_builder_ringct.h +++ b/src/multisig/multisig_tx_builder_ringct.h @@ -71,7 +71,6 @@ public: bool init( const cryptonote::account_keys& account_keys, const std::vector<std::uint8_t>& extra, - const std::uint64_t unlock_time, const std::uint32_t subaddr_account, const std::set<std::uint32_t>& subaddr_minor_indices, std::vector<cryptonote::tx_source_entry>& sources, diff --git a/src/ringct/rctTypes.h b/src/ringct/rctTypes.h index 299798e17..dea95ace0 100644 --- a/src/ringct/rctTypes.h +++ b/src/ringct/rctTypes.h @@ -771,7 +771,7 @@ namespace std BLOB_SERIALIZER(rct::key); BLOB_SERIALIZER(rct::key64); BLOB_SERIALIZER(rct::ctkey); -BLOB_SERIALIZER(rct::multisig_kLRki); +BLOB_SERIALIZER_FORCED(rct::multisig_kLRki); BLOB_SERIALIZER(rct::boroSig); VARIANT_TAG(debug_archive, rct::key, "rct::key"); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 9a0b02f70..16d66e79d 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1378,6 +1378,8 @@ namespace cryptonote add_reason(reason, "too few outputs"); if ((res.tx_extra_too_big = tvc.m_tx_extra_too_big)) add_reason(reason, "tx-extra too big"); + if ((res.nonzero_unlock_time = tvc.m_nonzero_unlock_time)) + add_reason(reason, "tx unlock time is not zero"); const std::string punctuation = reason.empty() ? "" : ": "; if (tvc.m_verifivation_failed) { @@ -3019,16 +3021,10 @@ namespace cryptonote CHECK_PAYMENT(req, res, COST_PER_FEE_ESTIMATE); - const uint8_t version = m_core.get_blockchain_storage().get_current_hard_fork_version(); - if (version >= HF_VERSION_2021_SCALING) { m_core.get_blockchain_storage().get_dynamic_base_fee_estimate_2021_scaling(req.grace_blocks, res.fees); res.fee = res.fees[0]; } - else - { - res.fee = m_core.get_blockchain_storage().get_dynamic_base_fee_estimate(req.grace_blocks); - } res.quantization_mask = Blockchain::get_fee_quantization_mask(); res.status = CORE_RPC_STATUS_OK; return true; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 2a0a6201d..c634b8957 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -88,7 +88,7 @@ namespace cryptonote // advance which version they will stop working with // Don't go over 32767 for any of these #define CORE_RPC_VERSION_MAJOR 3 -#define CORE_RPC_VERSION_MINOR 13 +#define CORE_RPC_VERSION_MINOR 14 #define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor)) #define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR) @@ -640,6 +640,7 @@ namespace cryptonote bool too_few_outputs; bool sanity_check_failed; bool tx_extra_too_big; + bool nonzero_unlock_time; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_PARENT(rpc_access_response_base) @@ -655,6 +656,7 @@ namespace cryptonote KV_SERIALIZE(too_few_outputs) KV_SERIALIZE(sanity_check_failed) KV_SERIALIZE(tx_extra_too_big) + KV_SERIALIZE(nonzero_unlock_time) END_KV_SERIALIZE_MAP() }; typedef epee::misc_utils::struct_init<response_t> response; diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp index 52067bd4d..4712de134 100644 --- a/src/rpc/daemon_handler.cpp +++ b/src/rpc/daemon_handler.cpp @@ -422,6 +422,16 @@ namespace rpc if (!res.error_details.empty()) res.error_details += " and "; res.error_details += "too few outputs"; } + if (tvc.m_tx_extra_too_big) + { + if (!res.error_details.empty()) res.error_details += " and "; + res.error_details += "tx_extra too long"; + } + if (tvc.m_nonzero_unlock_time) + { + if (!res.error_details.empty()) res.error_details += " and "; + res.error_details += "non-zero unlock time"; + } if (res.error_details.empty()) { res.error_details = "an unknown issue was found with the transaction"; @@ -831,14 +841,11 @@ namespace rpc void DaemonHandler::handle(const GetFeeEstimate::Request& req, GetFeeEstimate::Response& res) { res.hard_fork_version = m_core.get_blockchain_storage().get_current_hard_fork_version(); - res.estimated_base_fee = m_core.get_blockchain_storage().get_dynamic_base_fee_estimate(req.num_grace_blocks); - if (res.hard_fork_version < HF_VERSION_PER_BYTE_FEE) - { - res.size_scale = 1024; // per KiB fee - res.fee_mask = 1; - } - else + std::vector<uint64_t> fees; + m_core.get_blockchain_storage().get_dynamic_base_fee_estimate_2021_scaling(req.num_grace_blocks, fees); + res.estimated_base_fee = fees[0]; + { res.size_scale = 1; // per byte fee res.fee_mask = Blockchain::get_fee_quantization_mask(); diff --git a/src/serialization/crypto.h b/src/serialization/crypto.h index 896d00583..2da26abe7 100644 --- a/src/serialization/crypto.h +++ b/src/serialization/crypto.h @@ -81,7 +81,7 @@ BLOB_SERIALIZER(crypto::chacha_iv); BLOB_SERIALIZER(crypto::hash); BLOB_SERIALIZER(crypto::hash8); BLOB_SERIALIZER(crypto::public_key); -BLOB_SERIALIZER(crypto::secret_key); +BLOB_SERIALIZER_FORCED(crypto::secret_key); BLOB_SERIALIZER(crypto::key_derivation); BLOB_SERIALIZER(crypto::key_image); BLOB_SERIALIZER(crypto::signature); diff --git a/src/serialization/serialization.h b/src/serialization/serialization.h index d1f97e324..33edf3f62 100644 --- a/src/serialization/serialization.h +++ b/src/serialization/serialization.h @@ -50,13 +50,16 @@ #include <boost/type_traits/integral_constant.hpp> #include <boost/mpl/bool.hpp> -/*! \struct is_blob_type +/*! \struct is_blob_type / is_blob_forced * - * \brief a descriptor for dispatching serialize + * \brief descriptors for dispatching serialize: whether to take byte-wise copy/store to type */ template <class T> struct is_blob_type { typedef boost::false_type type; }; +template <class T> +struct is_blob_forced: std::false_type {}; + /*! \fn do_serialize(Archive &ar, T &v) * * \brief main function for dispatching serialization for a given pair of archive and value types @@ -68,6 +71,8 @@ struct is_blob_type { typedef boost::false_type type; }; template <class Archive, class T> inline std::enable_if_t<is_blob_type<T>::type::value, bool> do_serialize(Archive &ar, T &v) { + static_assert(std::is_trivially_copyable<T>() || is_blob_forced<T>(), + "sanity check: types that can't be trivially copied shouldn't be using the blob serializer"); ar.serialize_blob(&v, sizeof(v)); return true; } @@ -94,6 +99,9 @@ inline bool do_serialize(Archive &ar, bool &v) /*! \macro BLOB_SERIALIZER * * \brief makes the type have a blob serializer trait defined + * + * In case your type is not a good candidate to be blob serialized, a static assertion may be thrown + * at compile-time. */ #define BLOB_SERIALIZER(T) \ template<> \ @@ -101,6 +109,20 @@ inline bool do_serialize(Archive &ar, bool &v) typedef boost::true_type type; \ } +/*! \macro BLOB_SERIALIZER_FORCED + * + * \brief makes the type have a blob serializer trait defined, even if it isn't trivially copyable + * + * Caution: do NOT use this macro for your type <T>, unless you are absolutely sure that moving raw + * bytes in/out of this type will not cause undefined behavior. Any types with managed memory + * (e.g. vector, string, etc) will segfault and/or cause memory errors if you use this macro with + * that type. + */ +#define BLOB_SERIALIZER_FORCED(T) \ + BLOB_SERIALIZER(T); \ + template<> \ + struct is_blob_forced<T>: std::true_type {}; + /*! \macro VARIANT_TAG * * \brief Adds the tag \tag to the \a Archive of \a Type diff --git a/src/serialization/tuple.h b/src/serialization/tuple.h index d9592bc96..b1ef94097 100644 --- a/src/serialization/tuple.h +++ b/src/serialization/tuple.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2023, The Monero Project +// Copyright (c) 2014-2024, The Monero Project // // All rights reserved. // @@ -29,7 +29,7 @@ // Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers #pragma once -#include <memory> +#include <tuple> #include "serialization.h" namespace serialization @@ -51,119 +51,71 @@ namespace serialization } } -template <template <bool> class Archive, class E0, class E1, class E2> -inline bool do_serialize(Archive<false>& ar, std::tuple<E0,E1,E2>& p) +template <size_t I, bool BackwardsCompat, bool W, template <bool> class Archive, typename... Ts> +bool do_serialize_tuple_nth(Archive<W>& ar, std::tuple<Ts...>& v) { - size_t cnt; - ar.begin_array(cnt); - if (!ar.good()) - return false; - if (cnt != 3) - return false; + static constexpr const size_t tuple_size = std::tuple_size<std::tuple<Ts...>>(); + static_assert(I <= tuple_size, "bad call"); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<0>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<1>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<2>(p))) - return false; - if (!ar.good()) - return false; + if constexpr (I == 0) + { + // If BackwardsCompat is true, we serialize the size of 3-tuples and 4-tuples + if constexpr (BackwardsCompat && (tuple_size == 3 || tuple_size == 4)) + { + size_t cnt = tuple_size; + ar.begin_array(cnt); + if (cnt != tuple_size) + return false; + } + else + { + ar.begin_array(); + } + } + else if constexpr (I < tuple_size) + { + ar.delimit_array(); + } - ar.end_array(); - return true; + if constexpr (I == tuple_size) + { + ar.end_array(); + return ar.good(); + } + else + { + if (!::serialization::detail::serialize_tuple_element(ar, std::get<I>(v)) + || !ar.good()) + return false; + + return do_serialize_tuple_nth<I + 1, BackwardsCompat>(ar, v); + } } -template <template <bool> class Archive, class E0, class E1, class E2> -inline bool do_serialize(Archive<true>& ar, std::tuple<E0,E1,E2>& p) +template <bool BackwardsCompat, bool W, template <bool> class Archive, typename... Ts> +bool do_serialize_tuple(Archive<W>& ar, std::tuple<Ts...>& v) { - ar.begin_array(3); - if (!ar.good()) - return false; - if(!::serialization::detail::serialize_tuple_element(ar, std::get<0>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if(!::serialization::detail::serialize_tuple_element(ar, std::get<1>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if(!::serialization::detail::serialize_tuple_element(ar, std::get<2>(p))) - return false; - if (!ar.good()) - return false; - ar.end_array(); - return true; + return do_serialize_tuple_nth<0, BackwardsCompat>(ar, v); } -template <template <bool> class Archive, class E0, class E1, class E2, class E3> -inline bool do_serialize(Archive<false>& ar, std::tuple<E0,E1,E2,E3>& p) +template <bool W, template <bool> class Archive, typename... Ts> +bool do_serialize(Archive<W>& ar, std::tuple<Ts...>& v) { - size_t cnt; - ar.begin_array(cnt); - if (!ar.good()) - return false; - if (cnt != 4) - return false; + return do_serialize_tuple<true>(ar, v); +} - if (!::serialization::detail::serialize_tuple_element(ar, std::get<0>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<1>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<2>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if (!::serialization::detail::serialize_tuple_element(ar, std::get<3>(p))) - return false; - if (!ar.good()) - return false; +#define TUPLE_COMPACT_FIELDS(v) \ + do { \ + if (!do_serialize_tuple<false>(ar, v) || !ar.good()) \ + return false; \ + } while (0); - ar.end_array(); - return true; -} +#define TUPLE_COMPACT_FIELD_N(t, v) \ + do { \ + ar.tag(t); \ + TUPLE_COMPACT_FIELDS(v); \ + } while (0); -template <template <bool> class Archive, class E0, class E1, class E2, class E3> -inline bool do_serialize(Archive<true>& ar, std::tuple<E0,E1,E2,E3>& p) -{ - ar.begin_array(4); - if (!ar.good()) - return false; - if(!::serialization::detail::serialize_tuple_element(ar, std::get<0>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if(!::serialization::detail::serialize_tuple_element(ar, std::get<1>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if(!::serialization::detail::serialize_tuple_element(ar, std::get<2>(p))) - return false; - if (!ar.good()) - return false; - ar.delimit_array(); - if(!::serialization::detail::serialize_tuple_element(ar, std::get<3>(p))) - return false; - if (!ar.good()) - return false; - ar.end_array(); - return true; -} +#define TUPLE_COMPACT_FIELD(f) TUPLE_COMPACT_FIELD_N(#f, f) +#define TUPLE_COMPACT_FIELD_F(f) TUPLE_COMPACT_FIELD_N(#f, v.f) diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 5a9d790cb..ce23728ed 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -148,11 +148,6 @@ typedef cryptonote::simple_wallet sw; } \ } while(0) -enum TransferType { - Transfer, - TransferLocked, -}; - static std::string get_human_readable_timespan(std::chrono::seconds seconds); static std::string get_human_readable_timespan(uint64_t seconds); @@ -189,8 +184,6 @@ namespace const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]"); const char* USAGE_PAYMENT_ID("payment_id"); const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [subtractfeefrom=<D0>[,<D1>,all,...]] [<payment_id>]"); - const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]"); - const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id (obsolete)>]"); const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]"); const char* USAGE_SWEEP_ACCOUNT("sweep_account <account> [index=<N1>[,<N2>,...] | index=all] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]"); const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id (obsolete)>]"); @@ -819,7 +812,6 @@ bool simple_wallet::print_seed(bool encrypted) { bool success = false; epee::wipeable_string seed; - bool ready, multisig; if (m_wallet->key_on_device()) { @@ -832,10 +824,10 @@ bool simple_wallet::print_seed(bool encrypted) return true; } - multisig = m_wallet->multisig(&ready); - if (multisig) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (ms_status.multisig_is_active) { - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("wallet is multisig but not yet finalized"); return true; @@ -844,7 +836,7 @@ bool simple_wallet::print_seed(bool encrypted) SCOPED_WALLET_UNLOCK(); - if (!multisig && !m_wallet->is_deterministic()) + if (!ms_status.multisig_is_active && !m_wallet->is_deterministic()) { fail_msg_writer() << tr("wallet is non-deterministic and has no seed"); return true; @@ -859,7 +851,7 @@ bool simple_wallet::print_seed(bool encrypted) seed_pass = pwd_container->password(); } - if (multisig) + if (ms_status.multisig_is_active) success = m_wallet->get_multisig_seed(seed, seed_pass); else if (m_wallet->is_deterministic()) success = m_wallet->get_seed(seed, seed_pass); @@ -898,7 +890,7 @@ bool simple_wallet::seed_set_language(const std::vector<std::string> &args/* = s fail_msg_writer() << tr("command not supported by HW wallet"); return true; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("wallet is multisig and has no seed"); return true; @@ -1044,7 +1036,7 @@ bool simple_wallet::prepare_multisig_main(const std::vector<std::string> &args, fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("This wallet is already multisig"); return false; @@ -1091,7 +1083,7 @@ bool simple_wallet::make_multisig_main(const std::vector<std::string> &args, boo fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("This wallet is already multisig"); return false; @@ -1136,9 +1128,7 @@ bool simple_wallet::make_multisig_main(const std::vector<std::string> &args, boo auto local_args = args; local_args.erase(local_args.begin()); std::string multisig_extra_info = m_wallet->make_multisig(orig_pwd_container->password(), local_args, threshold); - bool ready; - m_wallet->multisig(&ready); - if (!ready) + if (!m_wallet->get_multisig_status().is_ready) { success_msg_writer() << tr("Another step is needed"); success_msg_writer() << multisig_extra_info; @@ -1156,13 +1146,13 @@ bool simple_wallet::make_multisig_main(const std::vector<std::string> &args, boo return false; } - uint32_t total; - if (!m_wallet->multisig(NULL, &threshold, &total)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("Error creating multisig: new wallet is not multisig"); return false; } - success_msg_writer() << std::to_string(threshold) << "/" << total << tr(" multisig address: ") + success_msg_writer() << std::to_string(ms_status.threshold) << "/" << ms_status.total << tr(" multisig address: ") << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); return true; @@ -1188,18 +1178,18 @@ bool simple_wallet::exchange_multisig_keys_main(const std::vector<std::string> & const bool force_update_use_with_caution, const bool called_by_mms) { CHECK_MULTISIG_ENABLED(); - bool ready; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (!m_wallet->multisig(&ready)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This wallet is not multisig"); return false; } - if (ready) + if (ms_status.is_ready) { fail_msg_writer() << tr("This wallet is already finalized"); return false; @@ -1215,9 +1205,7 @@ bool simple_wallet::exchange_multisig_keys_main(const std::vector<std::string> & try { std::string multisig_extra_info = m_wallet->exchange_multisig_keys(orig_pwd_container->password(), args, force_update_use_with_caution); - bool ready; - m_wallet->multisig(&ready); - if (!ready) + if (!m_wallet->get_multisig_status().is_ready) { message_writer() << tr("Another step is needed"); message_writer() << multisig_extra_info; @@ -1228,9 +1216,8 @@ bool simple_wallet::exchange_multisig_keys_main(const std::vector<std::string> & } return true; } else { - uint32_t threshold, total; - m_wallet->multisig(NULL, &threshold, &total); - success_msg_writer() << tr("Multisig wallet has been successfully created. Current wallet type: ") << threshold << "/" << total; + const multisig::multisig_account_status ms_status_new{m_wallet->get_multisig_status()}; + success_msg_writer() << tr("Multisig wallet has been successfully created. Current wallet type: ") << ms_status_new.threshold << "/" << ms_status_new.total; success_msg_writer() << tr("Multisig address: ") << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); } } @@ -1253,18 +1240,18 @@ bool simple_wallet::export_multisig(const std::vector<std::string> &args) bool simple_wallet::export_multisig_main(const std::vector<std::string> &args, bool called_by_mms) { CHECK_MULTISIG_ENABLED(); - bool ready; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (!m_wallet->multisig(&ready)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This wallet is not multisig"); return false; } - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("This multisig wallet is not yet finalized"); return false; @@ -1320,24 +1307,24 @@ bool simple_wallet::import_multisig(const std::vector<std::string> &args) bool simple_wallet::import_multisig_main(const std::vector<std::string> &args, bool called_by_mms) { CHECK_MULTISIG_ENABLED(); - bool ready; - uint32_t threshold, total; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (!m_wallet->multisig(&ready, &threshold, &total)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This wallet is not multisig"); return false; } - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("This multisig wallet is not yet finalized"); return false; } - if (args.size() < threshold - 1) + if (args.size() + 1 < ms_status.threshold) { PRINT_USAGE(USAGE_IMPORT_MULTISIG_INFO); return false; @@ -1417,18 +1404,19 @@ bool simple_wallet::sign_multisig(const std::vector<std::string> &args) bool simple_wallet::sign_multisig_main(const std::vector<std::string> &args, bool called_by_mms) { CHECK_MULTISIG_ENABLED(); - bool ready; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()};\ + if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if(!m_wallet->multisig(&ready)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This is not a multisig wallet"); return false; } - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("This multisig wallet is not yet finalized"); return false; @@ -1502,9 +1490,7 @@ bool simple_wallet::sign_multisig_main(const std::vector<std::string> &args, boo if (txids.empty()) { - uint32_t threshold; - m_wallet->multisig(NULL, &threshold); - uint32_t signers_needed = threshold - signers - 1; + uint32_t signers_needed = ms_status.threshold - signers - 1; success_msg_writer(true) << tr("Transaction successfully signed to file ") << filename << ", " << signers_needed << " more signer(s) needed"; return true; @@ -1534,19 +1520,19 @@ bool simple_wallet::submit_multisig(const std::vector<std::string> &args) bool simple_wallet::submit_multisig_main(const std::vector<std::string> &args, bool called_by_mms) { CHECK_MULTISIG_ENABLED(); - bool ready; - uint32_t threshold; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return false; } - if (!m_wallet->multisig(&ready, &threshold)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This is not a multisig wallet"); return false; } - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("This multisig wallet is not yet finalized"); return false; @@ -1584,10 +1570,10 @@ bool simple_wallet::submit_multisig_main(const std::vector<std::string> &args, b return false; } } - if (txs.m_signers.size() < threshold) + if (txs.m_signers.size() < ms_status.threshold) { fail_msg_writer() << (boost::format(tr("Multisig transaction signed by only %u signers, needs %u more signatures")) - % txs.m_signers.size() % (threshold - txs.m_signers.size())).str(); + % txs.m_signers.size() % (ms_status.threshold - txs.m_signers.size())).str(); return false; } @@ -1616,19 +1602,19 @@ bool simple_wallet::submit_multisig_main(const std::vector<std::string> &args, b bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args) { CHECK_MULTISIG_ENABLED(); - bool ready; - uint32_t threshold; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (m_wallet->key_on_device()) { fail_msg_writer() << tr("command not supported by HW wallet"); return true; } - if (!m_wallet->multisig(&ready, &threshold)) + if (!ms_status.multisig_is_active) { fail_msg_writer() << tr("This is not a multisig wallet"); return true; } - if (!ready) + if (!ms_status.is_ready) { fail_msg_writer() << tr("This multisig wallet is not yet finalized"); return true; @@ -1654,10 +1640,10 @@ bool simple_wallet::export_raw_multisig(const std::vector<std::string> &args) fail_msg_writer() << tr("Failed to load multisig transaction from file"); return true; } - if (txs.m_signers.size() < threshold) + if (txs.m_signers.size() < ms_status.threshold) { fail_msg_writer() << (boost::format(tr("Multisig transaction signed by only %u signers, needs %u more signatures")) - % txs.m_signers.size() % (threshold - txs.m_signers.size())).str(); + % txs.m_signers.size() % (ms_status.threshold - txs.m_signers.size())).str(); return true; } @@ -3126,14 +3112,6 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::on_command, this, &simple_wallet::transfer, _1), tr(USAGE_TRANSFER), tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included). The \"subtractfeefrom=\" list allows you to choose which destinations to fund the tx fee from instead of the change output. The fee will be split across the chosen destinations proportionally equally. For example, to make 3 transfers where the fee is taken from the first and third destinations, one could do: \"transfer <addr1> 3 <addr2> 0.5 <addr3> 1 subtractfeefrom=0,2\". Let's say the tx fee is 0.1. The balance would drop by exactly 4.5 XMR including fees, and addr1 & addr3 would receive 2.925 & 0.975 XMR, respectively. Use \"subtractfeefrom=all\" to spread the fee across all destinations.")); - m_cmd_binder.set_handler("locked_transfer", - boost::bind(&simple_wallet::on_command, this, &simple_wallet::locked_transfer,_1), - tr(USAGE_LOCKED_TRANSFER), - tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included)")); - m_cmd_binder.set_handler("locked_sweep_all", - boost::bind(&simple_wallet::on_command, this, &simple_wallet::locked_sweep_all,_1), - tr(USAGE_LOCKED_SWEEP_ALL), - tr("Send all unlocked balance to an address and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" or \"index=all\" is specified, the wallet sweeps outputs received by those or all address indices, respectively. If omitted, the wallet randomly chooses an address index to be used. <priority> is the priority of the sweep. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability.")); m_cmd_binder.set_handler("sweep_unmixable", boost::bind(&simple_wallet::on_command, this, &simple_wallet::sweep_unmixable, _1), tr("Send all unmixable outputs to yourself with ring_size 1")); @@ -3870,7 +3848,7 @@ void simple_wallet::print_seed(const epee::wipeable_string &seed) { success_msg_writer(true) << "\n" << boost::format(tr("NOTE: the following %s can be used to recover access to your wallet. " "Write them down and store them somewhere safe and secure. Please do not store them in " - "your email or on file storage services outside of your immediate control.\n")) % (m_wallet->multisig() ? tr("string") : tr("25 words")); + "your email or on file storage services outside of your immediate control.\n")) % (m_wallet->get_multisig_status().multisig_is_active ? tr("string") : tr("25 words")); // don't log int space_index = 0; size_t len = seed.size(); @@ -4922,14 +4900,14 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr const epee::wipeable_string &msig_keys = m_wallet->decrypt<epee::wipeable_string>(std::string(multisig_keys.data(), multisig_keys.size()), key, true); m_wallet->generate(m_wallet_file, std::move(rc.second).password(), msig_keys, create_address_file); } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total) || !ready) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active || !ms_status.is_ready) { fail_msg_writer() << tr("failed to generate new mutlisig wallet"); return {}; } - message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % threshold % total + message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % ms_status.threshold % ms_status.total << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); } catch (const std::exception& e) @@ -4973,12 +4951,11 @@ boost::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::p m_wallet->callback(this); m_wallet->load(m_wallet_file, password); std::string prefix; - bool ready; - uint32_t threshold, total; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; if (m_wallet->watch_only()) prefix = tr("Opened watch-only wallet"); - else if (m_wallet->multisig(&ready, &threshold, &total)) - prefix = (boost::format(tr("Opened %u/%u multisig wallet%s")) % threshold % total % (ready ? "" : " (not yet finalized)")).str(); + else if (ms_status.multisig_is_active) + prefix = (boost::format(tr("Opened %u/%u multisig wallet%s")) % ms_status.threshold % ms_status.total % (ms_status.is_ready ? "" : " (not yet finalized)")).str(); else prefix = tr("Opened wallet"); message_writer(console_color_white, true) << @@ -5096,7 +5073,7 @@ bool simple_wallet::save(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::save_watch_only(const std::vector<std::string> &args/* = std::vector<std::string>()*/) { - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("wallet is multisig and cannot save a watch-only version"); return true; @@ -6297,7 +6274,7 @@ bool simple_wallet::on_command(bool (simple_wallet::*cmd)(const std::vector<std: return (this->*cmd)(args); } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::string> &args_, bool called_by_mms) +bool simple_wallet::transfer_main(const std::vector<std::string> &args_, bool called_by_mms) { // "transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]" if (!try_connect_to_daemon()) @@ -6349,7 +6326,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri return false; } - const size_t min_args = (transfer_type == TransferLocked) ? 2 : 1; + const size_t min_args = 1; if(local_args.size() < min_args) { fail_msg_writer() << tr("wrong number of arguments"); @@ -6374,26 +6351,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri } } - uint64_t locked_blocks = 0; - if (transfer_type == TransferLocked) - { - try - { - locked_blocks = boost::lexical_cast<uint64_t>(local_args.back()); - } - catch (const std::exception &e) - { - fail_msg_writer() << tr("bad locked_blocks parameter:") << " " << local_args.back(); - return false; - } - if (locked_blocks > 1000000) - { - fail_msg_writer() << tr("Locked blocks too high, max 1000000 (Ëœ4 yrs)"); - return false; - } - local_args.pop_back(); - } - // Parse subtractfeefrom destination list tools::wallet2::unique_index_container subtract_fee_from_outputs; bool subtract_fee_from_all = false; @@ -6523,28 +6480,8 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri try { // figure out what tx will be necessary - std::vector<tools::wallet2::pending_tx> ptx_vector; - uint64_t bc_height, unlock_block = 0; - std::string err; - switch (transfer_type) - { - case TransferLocked: - bc_height = get_daemon_blockchain_height(err); - if (!err.empty()) - { - fail_msg_writer() << tr("failed to get blockchain height: ") << err; - return false; - } - unlock_block = bc_height + locked_blocks; - ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs); - break; - default: - LOG_ERROR("Unknown transfer method, using default"); - /* FALLTHRU */ - case Transfer: - ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs); - break; - } + auto ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, priority, extra, + m_current_subaddress_account, subaddr_indices, subtract_fee_from_outputs); if (ptx_vector.empty()) { @@ -6654,11 +6591,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri if (dust_in_fee != 0) prompt << boost::format(tr(", of which %s is dust from change")) % print_money(dust_in_fee); if (dust_not_in_fee != 0) prompt << tr(".") << ENDL << boost::format(tr("A total of %s from dust change will be sent to dust address")) % print_money(dust_not_in_fee); - if (transfer_type == TransferLocked) - { - float days = locked_blocks / 720.0f; - prompt << boost::format(tr(".\nThis transaction (including %s change) will unlock on block %llu, in approximately %s days (assuming 2 minutes per block)")) % cryptonote::print_money(change) % ((unsigned long long)unlock_block) % days; - } if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members())) return false; @@ -6676,7 +6608,8 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri } // actually commit the transactions - if (m_wallet->multisig() && called_by_mms) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (ms_status.multisig_is_active && called_by_mms) { std::string ciphertext = m_wallet->save_multisig_tx(ptx_vector); if (!ciphertext.empty()) @@ -6685,7 +6618,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to MMS"); } } - else if (m_wallet->multisig()) + else if (ms_status.multisig_is_active) { bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx"); if (!r) @@ -6762,29 +6695,7 @@ bool simple_wallet::transfer(const std::vector<std::string> &args_) PRINT_USAGE(USAGE_TRANSFER); return true; } - transfer_main(Transfer, args_, false); - return true; -} -//---------------------------------------------------------------------------------------------------- -bool simple_wallet::locked_transfer(const std::vector<std::string> &args_) -{ - if (args_.size() < 1) - { - PRINT_USAGE(USAGE_LOCKED_TRANSFER); - return true; - } - transfer_main(TransferLocked, args_, false); - return true; -} -//---------------------------------------------------------------------------------------------------- -bool simple_wallet::locked_sweep_all(const std::vector<std::string> &args_) -{ - if (args_.size() < 1) - { - PRINT_USAGE(USAGE_LOCKED_SWEEP_ALL); - return true; - } - sweep_main(m_current_subaddress_account, 0, true, args_); + transfer_main(args_, false); return true; } //---------------------------------------------------------------------------------------------------- @@ -6839,7 +6750,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_) } // actually commit the transactions - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { CHECK_MULTISIG_ENABLED(); bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx"); @@ -6896,7 +6807,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_) return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args_) +bool simple_wallet::sweep_main(uint32_t account, uint64_t below, const std::vector<std::string> &args_) { auto print_usage = [this, account, below]() { @@ -6976,41 +6887,6 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co return true; } - uint64_t unlock_block = 0; - if (locked) { - uint64_t locked_blocks = 0; - - if (local_args.size() < 2) { - fail_msg_writer() << tr("missing lockedblocks parameter"); - return true; - } - - try - { - locked_blocks = boost::lexical_cast<uint64_t>(local_args[1]); - } - catch (const std::exception &e) - { - fail_msg_writer() << tr("bad locked_blocks parameter"); - return true; - } - if (locked_blocks > 1000000) - { - fail_msg_writer() << tr("Locked blocks too high, max 1000000 (Ëœ4 yrs)"); - return true; - } - std::string err; - uint64_t bc_height = get_daemon_blockchain_height(err); - if (!err.empty()) - { - fail_msg_writer() << tr("failed to get blockchain height: ") << err; - return true; - } - unlock_block = bc_height + locked_blocks; - - local_args.erase(local_args.begin() + 1); - } - size_t outputs = 1; if (local_args.size() > 0 && local_args[0].substr(0, 8) == "outputs=") { @@ -7085,7 +6961,7 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co try { // figure out what tx will be necessary - auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, outputs, fake_outs_count, unlock_block /* unlock_time */, priority, extra, account, subaddr_indices); + auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, outputs, fake_outs_count, priority, extra, account, subaddr_indices); if (ptx_vector.empty()) { @@ -7144,7 +7020,7 @@ bool simple_wallet::sweep_main(uint32_t account, uint64_t below, bool locked, co } // actually commit the transactions - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { CHECK_MULTISIG_ENABLED(); bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx"); @@ -7342,7 +7218,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_) try { // figure out what tx will be necessary - auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, outputs, fake_outs_count, 0 /* unlock_time */, priority, extra); + auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, outputs, fake_outs_count, priority, extra); if (ptx_vector.empty()) { @@ -7379,7 +7255,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_) } // actually commit the transactions - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { CHECK_MULTISIG_ENABLED(); bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_monero_tx"); @@ -7452,7 +7328,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_) //---------------------------------------------------------------------------------------------------- bool simple_wallet::sweep_all(const std::vector<std::string> &args_) { - sweep_main(m_current_subaddress_account, 0, false, args_); + sweep_main(m_current_subaddress_account, 0, args_); return true; } //---------------------------------------------------------------------------------------------------- @@ -7472,7 +7348,7 @@ bool simple_wallet::sweep_account(const std::vector<std::string> &args_) } local_args.erase(local_args.begin()); - sweep_main(account, 0, false, local_args); + sweep_main(account, 0, local_args); return true; } //---------------------------------------------------------------------------------------------------- @@ -7490,7 +7366,7 @@ bool simple_wallet::sweep_below(const std::vector<std::string> &args_) fail_msg_writer() << tr("invalid amount threshold"); return true; } - sweep_main(m_current_subaddress_account, below, false, std::vector<std::string>(++args_.begin(), args_.end())); + sweep_main(m_current_subaddress_account, below, std::vector<std::string>(++args_.begin(), args_.end())); return true; } //---------------------------------------------------------------------------------------------------- @@ -7727,7 +7603,7 @@ bool simple_wallet::sign_transfer(const std::vector<std::string> &args_) fail_msg_writer() << tr("command not supported by HW wallet"); return true; } - if(m_wallet->multisig()) + if(m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("This is a multisig wallet, it can only sign with sign_multisig"); return true; @@ -8260,7 +8136,7 @@ bool simple_wallet::get_reserve_proof(const std::vector<std::string> &args) return true; } - if (m_wallet->watch_only() || m_wallet->multisig()) + if (m_wallet->watch_only() || m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("The reserve proof can be generated only by a full wallet"); return true; @@ -9748,8 +9624,8 @@ bool simple_wallet::status(const std::vector<std::string> &args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::wallet_info(const std::vector<std::string> &args) { - bool ready; - uint32_t threshold, total; + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + std::string description = m_wallet->get_description(); if (description.empty()) { @@ -9761,8 +9637,8 @@ bool simple_wallet::wallet_info(const std::vector<std::string> &args) std::string type; if (m_wallet->watch_only()) type = tr("Watch only"); - else if (m_wallet->multisig(&ready, &threshold, &total)) - type = (boost::format(tr("%u/%u multisig%s")) % threshold % total % (ready ? "" : " (not yet finalized)")).str(); + else if (ms_status.multisig_is_active) + type = (boost::format(tr("%u/%u multisig%s")) % ms_status.threshold % ms_status.total % (ms_status.is_ready ? "" : " (not yet finalized)")).str(); else type = tr("Normal"); message_writer() << tr("Type: ") << type; @@ -9789,7 +9665,7 @@ bool simple_wallet::sign(const std::vector<std::string> &args) fail_msg_writer() << tr("wallet is watch-only and cannot sign"); return true; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { fail_msg_writer() << tr("This wallet is multisig and cannot sign"); return true; @@ -11018,7 +10894,7 @@ void simple_wallet::mms_sync(const std::vector<std::string> &args) void simple_wallet::mms_transfer(const std::vector<std::string> &args) { // It's too complicated to check any arguments here, just let 'transfer_main' do the whole job - transfer_main(Transfer, args, true); + transfer_main(args, true); } void simple_wallet::mms_delete(const std::vector<std::string> &args) diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 2a5d7f2b6..11b2be342 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -167,11 +167,9 @@ namespace cryptonote bool show_incoming_transfers(const std::vector<std::string> &args); bool show_payments(const std::vector<std::string> &args); bool show_blockchain_height(const std::vector<std::string> &args); - bool transfer_main(int transfer_type, const std::vector<std::string> &args, bool called_by_mms); + bool transfer_main(const std::vector<std::string> &args, bool called_by_mms); bool transfer(const std::vector<std::string> &args); - bool locked_transfer(const std::vector<std::string> &args); - bool locked_sweep_all(const std::vector<std::string> &args); - bool sweep_main(uint32_t account, uint64_t below, bool locked, const std::vector<std::string> &args); + bool sweep_main(uint32_t account, uint64_t below, const std::vector<std::string> &args); bool sweep_all(const std::vector<std::string> &args); bool sweep_account(const std::vector<std::string> &args); bool sweep_below(const std::vector<std::string> &args); diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 7f4dbbc79..58cb84947 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -38,6 +38,7 @@ #include "subaddress_account.h" #include "common_defines.h" #include "common/util.h" +#include "multisig/multisig_account.h" #include "mnemonics/electrum-words.h" #include "mnemonics/english.h" @@ -87,12 +88,13 @@ namespace { throw runtime_error("Wallet is not initialized yet"); } - bool ready; - if (!wallet->multisig(&ready)) { + const multisig::multisig_account_status ms_status{wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { throw runtime_error("Wallet is not multisig"); } - if (!ready) { + if (!ms_status.is_ready) { throw runtime_error("Multisig wallet is not finalized yet"); } } @@ -105,12 +107,13 @@ namespace { throw runtime_error("Wallet is not initialized yet"); } - bool ready; - if (!wallet->multisig(&ready)) { + const multisig::multisig_account_status ms_status{wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { throw runtime_error("Wallet is not multisig"); } - if (ready) { + if (ms_status.is_ready) { throw runtime_error("Multisig wallet is already finalized"); } } @@ -1297,7 +1300,13 @@ void WalletImpl::setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex MultisigState WalletImpl::multisig() const { MultisigState state; - state.isMultisig = m_wallet->multisig(&state.isReady, &state.threshold, &state.total); + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + state.isMultisig = ms_status.multisig_is_active; + state.kexIsDone = ms_status.kex_is_done; + state.isReady = ms_status.is_ready; + state.threshold = ms_status.threshold; + state.total = ms_status.total; return state; } @@ -1318,7 +1327,7 @@ string WalletImpl::makeMultisig(const vector<string>& info, const uint32_t thres try { clearStatus(); - if (m_wallet->multisig()) { + if (m_wallet->get_multisig_status().multisig_is_active) { throw runtime_error("Wallet is already multisig"); } @@ -1519,11 +1528,11 @@ PendingTransaction *WalletImpl::createTransactionMultDest(const std::vector<stri fake_outs_count = m_wallet->adjust_mixin(mixin_count); if (amount) { - transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, + transaction->m_pending_tx = m_wallet->create_transactions_2(dsts, fake_outs_count, adjusted_priority, extra, subaddr_account, subaddr_indices); } else { - transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count, 0 /* unlock_time */, + transaction->m_pending_tx = m_wallet->create_transactions_all(0, info.address, info.is_subaddress, 1, fake_outs_count, adjusted_priority, extra, subaddr_account, subaddr_indices); } @@ -2053,8 +2062,8 @@ std::string WalletImpl::signMultisigParticipant(const std::string &message) cons { clearStatus(); - bool ready = false; - if (!m_wallet->multisig(&ready) || !ready) { + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + if (!ms_status.multisig_is_active || !ms_status.is_ready) { m_status = Status_Error; m_errorString = tr("The wallet must be in multisig ready state"); return {}; diff --git a/src/wallet/api/wallet2_api.h b/src/wallet/api/wallet2_api.h index df86da847..53210832b 100644 --- a/src/wallet/api/wallet2_api.h +++ b/src/wallet/api/wallet2_api.h @@ -322,9 +322,10 @@ struct SubaddressAccount }; struct MultisigState { - MultisigState() : isMultisig(false), isReady(false), threshold(0), total(0) {} + MultisigState() : isMultisig(false), kexIsDone(false), isReady(false), threshold(0), total(0) {} bool isMultisig; + bool kexIsDone; bool isReady; uint32_t threshold; uint32_t total; diff --git a/src/wallet/message_store.h b/src/wallet/message_store.h index 202d77be6..c0afa2afa 100644 --- a/src/wallet/message_store.h +++ b/src/wallet/message_store.h @@ -245,18 +245,23 @@ namespace mms crypto::secret_key view_secret_key; bool multisig; bool multisig_is_ready; + bool multisig_kex_is_done; bool has_multisig_partial_key_images; uint32_t multisig_rounds_passed; size_t num_transfer_details; std::string mms_file; BEGIN_SERIALIZE_OBJECT() - VERSION_FIELD(0) + VERSION_FIELD(1) FIELD(address) VARINT_FIELD(nettype) FIELD(view_secret_key) FIELD(multisig) FIELD(multisig_is_ready) + if (version > 0) + FIELD(multisig_kex_is_done) + else + multisig_kex_is_done = multisig_is_ready; FIELD(has_multisig_partial_key_images) VARINT_FIELD(multisig_rounds_passed) VARINT_FIELD(num_transfer_details) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index a9ad67f04..709a862de 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -30,6 +30,7 @@ #include <algorithm> #include <numeric> +#include <string> #include <tuple> #include <queue> #include <boost/format.hpp> @@ -1360,6 +1361,10 @@ bool wallet2::set_daemon(std::string daemon_address, boost::optional<epee::net_u { boost::lock_guard<boost::recursive_mutex> lock(m_daemon_rpc_mutex); + if(daemon_address.empty()) { + daemon_address.append("http://localhost:" + std::to_string(get_config(m_nettype).RPC_DEFAULT_PORT)); + } + if(m_http_client->is_connected()) m_http_client->disconnect(); CHECK_AND_ASSERT_MES2(m_proxy.empty() || proxy.empty() , "It is not possible to set global proxy (--proxy) and daemon specific proxy together."); @@ -1438,14 +1443,14 @@ bool wallet2::get_seed(epee::wipeable_string& electrum_words, const epee::wipeab //---------------------------------------------------------------------------------------------------- bool wallet2::get_multisig_seed(epee::wipeable_string& seed, const epee::wipeable_string &passphrase) const { - bool ready; - uint32_t threshold, total; - if (!multisig(&ready, &threshold, &total)) + const multisig::multisig_account_status ms_status{get_multisig_status()}; + + if (!ms_status.multisig_is_active) { std::cout << "This is not a multisig wallet" << std::endl; return false; } - if (!ready) + if (!ms_status.is_ready) { std::cout << "This multisig wallet is not yet finalized" << std::endl; return false; @@ -1459,8 +1464,8 @@ bool wallet2::get_multisig_seed(epee::wipeable_string& seed, const epee::wipeabl THROW_WALLET_EXCEPTION_IF(num_expected_ms_keys != keys.m_multisig_keys.size(), error::wallet_internal_error, "Unexpected number of private multisig keys") epee::wipeable_string data; - data.append((const char*)&threshold, sizeof(uint32_t)); - data.append((const char*)&total, sizeof(uint32_t)); + data.append((const char*)&ms_status.threshold, sizeof(uint32_t)); + data.append((const char*)&ms_status.total, sizeof(uint32_t)); skey = keys.m_spend_secret_key; data.append((const char*)&skey, sizeof(skey)); pkey = keys.m_account_address.m_spend_public_key; @@ -5617,8 +5622,8 @@ std::string wallet2::exchange_multisig_keys(const epee::wipeable_string &passwor const std::vector<std::string> &kex_messages, const bool force_update_use_with_caution /*= false*/) { - bool ready{false}; - CHECK_AND_ASSERT_THROW_MES(multisig(&ready), "The wallet is not multisig"); + const multisig::multisig_account_status ms_status{get_multisig_status()}; + CHECK_AND_ASSERT_THROW_MES(ms_status.multisig_is_active, "The wallet is not multisig"); // decrypt account keys epee::misc_utils::auto_scope_leave_caller keys_reencryptor; @@ -5745,20 +5750,30 @@ std::string wallet2::get_multisig_first_kex_msg() const return multisig_account.get_next_kex_round_msg(); } //---------------------------------------------------------------------------------------------------- -bool wallet2::multisig(bool *ready, uint32_t *threshold, uint32_t *total) const +multisig::multisig_account_status wallet2::get_multisig_status() const { - if (!m_multisig) - return false; - if (threshold) - *threshold = m_multisig_threshold; - if (total) - *total = m_multisig_signers.size(); - if (ready) + multisig::multisig_account_status ret; + + if (m_multisig) { - *ready = !(get_account().get_keys().m_account_address.m_spend_public_key == rct::rct2pk(rct::identity())) && + ret.multisig_is_active = true; + ret.threshold = m_multisig_threshold; + ret.total = m_multisig_signers.size(); + ret.kex_is_done = !(get_account().get_keys().m_account_address.m_spend_public_key == rct::rct2pk(rct::identity())) && + (m_multisig_rounds_passed >= multisig::multisig_kex_rounds_required(m_multisig_signers.size(), m_multisig_threshold)); + ret.is_ready = ret.kex_is_done && (m_multisig_rounds_passed == multisig::multisig_setup_rounds_required(m_multisig_signers.size(), m_multisig_threshold)); } - return true; + else + { + ret.multisig_is_active = false; + ret.threshold = 0; + ret.total = 0; + ret.kex_is_done = false; + ret.is_ready = false; + } + + return ret; } //---------------------------------------------------------------------------------------------------- bool wallet2::has_multisig_partial_key_images() const @@ -7252,14 +7267,15 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin { tools::wallet2::tx_construction_data &sd = exported_txs.txes[n]; THROW_WALLET_EXCEPTION_IF(sd.sources.empty(), error::wallet_internal_error, "Empty sources"); + THROW_WALLET_EXCEPTION_IF(sd.unlock_time, error::nonzero_unlock_time); LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size()); signed_txes.ptx.push_back(pending_tx()); tools::wallet2::pending_tx &ptx = signed_txes.ptx.back(); rct::RCTConfig rct_config = sd.rct_config; crypto::secret_key tx_key; std::vector<crypto::secret_key> additional_tx_keys; - bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, sd.unlock_time, tx_key, additional_tx_keys, sd.use_rct, rct_config, sd.use_view_tags); - THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype); + bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sd.sources, sd.splitted_dsts, sd.change_dts.addr, sd.extra, ptx.tx, tx_key, additional_tx_keys, sd.use_rct, rct_config, sd.use_view_tags); + THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, m_nettype); // we don't test tx size, because we don't know the current limit, due to not having a blockchain, // and it's a bit pointless to fail there anyway, since it'd be a (good) guess only. We sign anyway, // and if we really go over limit, the daemon will reject when it gets submitted. Chances are it's @@ -7787,7 +7803,6 @@ bool wallet2::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector<crypto not multisig_tx_builder.init( m_account.get_keys(), ptx.construction_data.extra, - ptx.construction_data.unlock_time, ptx.construction_data.subaddr_account, ptx.construction_data.subaddr_indices, ptx.construction_data.sources, @@ -9199,7 +9214,7 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> template<typename T> void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::unordered_set<crypto::public_key> &valid_public_keys_cache, - uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx, + uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx, bool use_view_tags) { using namespace cryptonote; @@ -9310,9 +9325,9 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent crypto::secret_key tx_key; std::vector<crypto::secret_key> additional_tx_keys; LOG_PRINT_L2("constructing tx"); - bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, false, {}, use_view_tags); + bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, tx_key, additional_tx_keys, false, {}, use_view_tags); LOG_PRINT_L2("constructed tx, r="<<r); - THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype); + THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, m_nettype); THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit); std::string key_images; @@ -9345,7 +9360,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent ptx.construction_data.splitted_dsts = splitted_dsts; ptx.construction_data.selected_transfers = selected_transfers; ptx.construction_data.extra = tx.extra; - ptx.construction_data.unlock_time = unlock_time; + ptx.construction_data.unlock_time = 0; ptx.construction_data.use_rct = false; ptx.construction_data.rct_config = { rct::RangeProofBorromean, 0 }; ptx.construction_data.use_view_tags = use_view_tags; @@ -9360,7 +9375,7 @@ void wallet2::transfer_selected(const std::vector<cryptonote::tx_destination_ent void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::unordered_set<crypto::public_key> &valid_public_keys_cache, - uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config, bool use_view_tags) + uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config, bool use_view_tags) { using namespace cryptonote; // throw if attempting a transaction with no destinations @@ -9556,7 +9571,6 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry THROW_WALLET_EXCEPTION_IF( not multisig_tx_builder.init(m_account.get_keys(), extra, - unlock_time, subaddr_account, subaddr_minor_indices, sources, @@ -9576,9 +9590,9 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry } else { // make a normal tx - bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, unlock_time, tx_key, additional_tx_keys, true, rct_config, use_view_tags); + bool r = cryptonote::construct_tx_and_get_tx_key(m_account.get_keys(), m_subaddresses, sources, splitted_dsts, change_dts.addr, extra, tx, tx_key, additional_tx_keys, true, rct_config, use_view_tags); LOG_PRINT_L2("constructed tx, r="<<r); - THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, unlock_time, m_nettype); + THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, dsts, m_nettype); } THROW_WALLET_EXCEPTION_IF(upper_transaction_weight_limit <= get_transaction_weight(tx), error::tx_too_big, tx, upper_transaction_weight_limit); @@ -9700,7 +9714,7 @@ void wallet2::transfer_selected_rct(std::vector<cryptonote::tx_destination_entry ptx.construction_data.splitted_dsts = splitted_dsts; ptx.construction_data.selected_transfers = ptx.selected_transfers; ptx.construction_data.extra = tx.extra; - ptx.construction_data.unlock_time = unlock_time; + ptx.construction_data.unlock_time = 0; ptx.construction_data.use_rct = true; ptx.construction_data.rct_config = { rct::RangeProofPaddedBulletproof, @@ -9860,7 +9874,7 @@ static uint32_t get_count_above(const std::vector<wallet2::transfer_details> &tr // This system allows for sending (almost) the entire balance, since it does // not generate spurious change in all txes, thus decreasing the instantaneous // usable balance. -std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs) +std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs) { //ensure device is let in NONE mode in any case hw::device &hwdev = m_account.get_device(); @@ -10383,10 +10397,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp tx.selected_transfers.size() << " inputs"); auto tx_dsts = tx.get_adjusted_dsts(needed_fee); if (use_rct) - transfer_selected_rct(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, + transfer_selected_rct(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra, test_tx, test_ptx, rct_config, use_view_tags); else - transfer_selected(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, + transfer_selected(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); auto txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask); @@ -10422,21 +10436,21 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp else { LOG_PRINT_L2("We made a tx, adjusting fee and saving it, we need " << print_money(needed_fee) << " and we have " << print_money(test_ptx.fee)); - size_t fee_tries; - for (fee_tries = 0; fee_tries < 10 && needed_fee > test_ptx.fee; ++fee_tries) { + size_t fee_tries = 0; + do { tx_dsts = tx.get_adjusted_dsts(needed_fee); if (use_rct) - transfer_selected_rct(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, + transfer_selected_rct(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra, test_tx, test_ptx, rct_config, use_view_tags); else - transfer_selected(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, + transfer_selected(tx_dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask); LOG_PRINT_L2("Made an attempt at a final " << get_weight_string(test_ptx.tx, txBlob.size()) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " change"); - }; + } while (needed_fee > test_ptx.fee && ++fee_tries < 10); THROW_WALLET_EXCEPTION_IF(fee_tries == 10, error::wallet_internal_error, "Too many attempts to raise pending tx fee to level of needed fee"); @@ -10503,7 +10517,6 @@ skip_tx: fake_outs_count, /* CONST size_t fake_outputs_count, */ tx.outs, /* MOD std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, */ valid_public_keys_cache, - unlock_time, /* CONST uint64_t unlock_time, */ tx.needed_fee, /* CONST uint64_t fee, */ extra, /* const std::vector<uint8_t>& extra, */ test_tx, /* OUT cryptonote::transaction& tx, */ @@ -10516,7 +10529,6 @@ skip_tx: fake_outs_count, tx.outs, valid_public_keys_cache, - unlock_time, tx.needed_fee, extra, detail::digit_split_strategy, @@ -10630,7 +10642,7 @@ bool wallet2::sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, c return true; } -std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices) +std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices) { std::vector<size_t> unused_transfers_indices; std::vector<size_t> unused_dust_indices; @@ -10700,10 +10712,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below } } - return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra); + return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, priority, extra); } -std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra) +std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra) { std::vector<size_t> unused_transfers_indices; std::vector<size_t> unused_dust_indices; @@ -10721,10 +10733,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt break; } } - return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, unlock_time, priority, extra); + return create_transactions_from(address, is_subaddress, outputs, unused_transfers_indices, unused_dust_indices, fake_outs_count, priority, extra); } -std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra) +std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra) { //ensure device is let in NONE mode in any case hw::device &hwdev = m_account.get_device(); @@ -10833,10 +10845,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " << tx.selected_transfers.size() << " outputs"); if (use_rct) - transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, + transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra, test_tx, test_ptx, rct_config, use_view_tags); else - transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); auto txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask); @@ -10870,10 +10882,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton dt.amount = dt_amount + dt_residue; } if (use_rct) - transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, + transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra, test_tx, test_ptx, rct_config, use_view_tags); else - transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, unlock_time, needed_fee, extra, + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, valid_public_keys_cache, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(use_per_byte_fee, test_ptx.tx, txBlob.size(), base_fee, fee_quantization_mask); @@ -10909,10 +10921,10 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_from(const crypton cryptonote::transaction test_tx; pending_tx test_ptx; if (use_rct) { - transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, unlock_time, tx.needed_fee, extra, + transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, tx.needed_fee, extra, test_tx, test_ptx, rct_config, use_view_tags); } else { - transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, unlock_time, tx.needed_fee, extra, + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, valid_public_keys_cache, tx.needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx, use_view_tags); } auto txBlob = t_serializable_object_to_blob(test_ptx.tx); @@ -11214,7 +11226,7 @@ std::vector<wallet2::pending_tx> wallet2::create_unmixable_sweep_transactions() unmixable_transfer_outputs.push_back(n); } - return create_transactions_from(m_account_public_address, false, 1, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector<uint8_t>()); + return create_transactions_from(m_account_public_address, false, 1, unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 1 /*priority */, std::vector<uint8_t>()); } //---------------------------------------------------------------------------------------------------- void wallet2::discard_unmixable_outputs() @@ -14302,9 +14314,13 @@ void wallet2::generate_genesis(cryptonote::block& b) const { //---------------------------------------------------------------------------------------------------- mms::multisig_wallet_state wallet2::get_multisig_wallet_state() const { + const multisig::multisig_account_status ms_status{get_multisig_status()}; + mms::multisig_wallet_state state; state.nettype = m_nettype; - state.multisig = multisig(&state.multisig_is_ready); + state.multisig = ms_status.multisig_is_active; + state.multisig_is_ready = ms_status.is_ready; + state.multisig_kex_is_done = ms_status.kex_is_done; state.has_multisig_partial_key_images = has_multisig_partial_key_images(); state.multisig_rounds_passed = m_multisig_rounds_passed; state.num_transfer_details = m_transfers.size(); diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 5f884e374..5f2f0e0c4 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -57,6 +57,7 @@ #include "common/util.h" #include "crypto/chacha.h" #include "crypto/hash.h" +#include "multisig/multisig_account.h" #include "ringct/rctTypes.h" #include "ringct/rctOps.h" #include "checkpoints/checkpoints.h" @@ -991,13 +992,13 @@ private: uint64_t max_reorg_depth() const {return m_max_reorg_depth;} bool deinit(); - bool init(std::string daemon_address = "http://localhost:8080", + bool init(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login = boost::none, const std::string &proxy = "", uint64_t upper_transaction_weight_limit = 0, bool trusted_daemon = true, epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect); - bool set_daemon(std::string daemon_address = "http://localhost:8080", + bool set_daemon(std::string daemon_address, boost::optional<epee::net_utils::http::login> daemon_login = boost::none, bool trusted_daemon = true, epee::net_utils::ssl_options_t ssl_options = epee::net_utils::ssl_support_t::e_ssl_support_autodetect, const std::string &proxy = ""); @@ -1059,7 +1060,7 @@ private: cryptonote::network_type nettype() const { return m_nettype; } bool watch_only() const { return m_watch_only; } - bool multisig(bool *ready = NULL, uint32_t *threshold = NULL, uint32_t *total = NULL) const; + multisig::multisig_account_status get_multisig_status() const; bool has_multisig_partial_key_images() const; bool has_unknown_key_images() const; bool get_multisig_seed(epee::wipeable_string& seed, const epee::wipeable_string &passphrase = std::string()) const; @@ -1079,10 +1080,10 @@ private: template<typename T> void transfer_selected(const std::vector<cryptonote::tx_destination_entry>& dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::unordered_set<crypto::public_key> &valid_public_keys_cache, - uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx, const bool use_view_tags); + uint64_t fee, const std::vector<uint8_t>& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx, const bool use_view_tags); void transfer_selected_rct(std::vector<cryptonote::tx_destination_entry> dsts, const std::vector<size_t>& selected_transfers, size_t fake_outputs_count, std::vector<std::vector<tools::wallet2::get_outs_entry>> &outs, std::unordered_set<crypto::public_key> &valid_public_keys_cache, - uint64_t unlock_time, uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config, const bool use_view_tags); + uint64_t fee, const std::vector<uint8_t>& extra, cryptonote::transaction& tx, pending_tx &ptx, const rct::RCTConfig &rct_config, const bool use_view_tags); void commit_tx(pending_tx& ptx_vector); void commit_tx(std::vector<pending_tx>& ptx_vector); @@ -1104,10 +1105,10 @@ private: bool parse_unsigned_tx_from_str(const std::string &unsigned_tx_st, unsigned_tx_set &exported_txs) const; bool load_tx(const std::string &signed_filename, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set&)> accept_func = NULL); bool parse_tx_from_str(const std::string &signed_tx_st, std::vector<tools::wallet2::pending_tx> &ptx, std::function<bool(const signed_tx_set &)> accept_func); - std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose - std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices); - std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra); - std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector<uint8_t>& extra); + std::vector<wallet2::pending_tx> create_transactions_2(std::vector<cryptonote::tx_destination_entry> dsts, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices, const unique_index_container& subtract_fee_from_outputs = {}); // pass subaddr_indices by value on purpose + std::vector<wallet2::pending_tx> create_transactions_all(uint64_t below, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra, uint32_t subaddr_account, std::set<uint32_t> subaddr_indices); + std::vector<wallet2::pending_tx> create_transactions_single(const crypto::key_image &ki, const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra); + std::vector<wallet2::pending_tx> create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, const size_t outputs, std::vector<size_t> unused_transfers_indices, std::vector<size_t> unused_dust_indices, const size_t fake_outs_count, uint32_t priority, const std::vector<uint8_t>& extra); bool sanity_check(const std::vector<wallet2::pending_tx> &ptx_vector, const std::vector<cryptonote::tx_destination_entry>& dsts, const unique_index_container& subtract_fee_from_outputs = {}) const; void cold_tx_aux_import(const std::vector<pending_tx>& ptx, const std::vector<std::string>& tx_device_aux); void cold_sign_tx(const std::vector<pending_tx>& ptx_vector, signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::vector<std::string> & tx_device_aux); diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 5166f868f..2bbfc3167 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -86,6 +86,7 @@ namespace tools // zero_amount // zero_destination // subtract_fee_from_bad_index + // nonzero_unlock_time // wallet_rpc_error * // daemon_busy // no_connection_to_daemon @@ -592,20 +593,17 @@ namespace tools std::string && loc , sources_t const & sources , destinations_t const & destinations - , uint64_t unlock_time , cryptonote::network_type nettype ) : transfer_error(std::move(loc), "transaction was not constructed") , m_sources(sources) , m_destinations(destinations) - , m_unlock_time(unlock_time) , m_nettype(nettype) { } const sources_t& sources() const { return m_sources; } const destinations_t& destinations() const { return m_destinations; } - uint64_t unlock_time() const { return m_unlock_time; } std::string to_string() const { @@ -637,15 +635,12 @@ namespace tools cryptonote::print_money(dst.amount); } - ss << "\nunlock_time: " << m_unlock_time; - return ss.str(); } private: sources_t m_sources; destinations_t m_destinations; - uint64_t m_unlock_time; cryptonote::network_type m_nettype; }; //---------------------------------------------------------------------------------------------------- @@ -789,6 +784,14 @@ namespace tools } }; //---------------------------------------------------------------------------------------------------- + struct nonzero_unlock_time : public transfer_error + { + explicit nonzero_unlock_time(std::string&& loc) + : transfer_error(std::move(loc), "transaction cannot have non-zero unlock time") + { + } + }; + //---------------------------------------------------------------------------------------------------- struct wallet_rpc_error : public wallet_logic_error { const std::string& request() const { return m_request; } diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index d7aa80e0a..652f087ad 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -65,7 +65,7 @@ using namespace epee; #define CHECK_MULTISIG_ENABLED() \ do \ { \ - if (m_wallet->multisig() && !m_wallet->is_multisig_enabled()) \ + if (m_wallet->get_multisig_status().multisig_is_active && !m_wallet->is_multisig_enabled()) \ { \ er.code = WALLET_RPC_ERROR_CODE_DISABLED; \ er.message = "This wallet is multisig, and multisig is disabled. Multisig is an experimental feature and may have bugs. Things that could go wrong include: funds sent to a multisig wallet can't be spent at all, can only be spent with the participation of a malicious group member, or can be stolen by a malicious group member. You can enable it by running this once in monero-wallet-cli: set enable-multisig-experimental 1"; \ @@ -459,7 +459,7 @@ namespace tools { res.balance = req.all_accounts ? m_wallet->balance_all(req.strict) : m_wallet->balance(req.account_index, req.strict); res.unlocked_balance = req.all_accounts ? m_wallet->unlocked_balance_all(req.strict, &res.blocks_to_unlock, &res.time_to_unlock) : m_wallet->unlocked_balance(req.account_index, req.strict, &res.blocks_to_unlock, &res.time_to_unlock); - res.multisig_import_needed = m_wallet->multisig() && m_wallet->has_multisig_partial_key_images(); + res.multisig_import_needed = m_wallet->get_multisig_status().multisig_is_active && m_wallet->has_multisig_partial_key_images(); std::map<uint32_t, std::map<uint32_t, uint64_t>> balance_per_subaddress_per_account; std::map<uint32_t, std::map<uint32_t, std::pair<uint64_t, std::pair<uint64_t, uint64_t>>>> unlocked_balance_per_subaddress_per_account; if (req.all_accounts) @@ -1024,7 +1024,7 @@ namespace tools fill(spent_key_images, key_image_list); } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector)); if (multisig_txset.empty()) @@ -1079,6 +1079,12 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } + else if (req.unlock_time) + { + er.code = WALLET_RPC_ERROR_CODE_NONZERO_UNLOCK_TIME; + er.message = "Transaction cannot have non-zero unlock time"; + return false; + } CHECK_MULTISIG_ENABLED(); @@ -1092,7 +1098,7 @@ namespace tools { uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint32_t priority = m_wallet->adjust_priority(req.priority); - std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, req.subtract_fee_from_outputs); + std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, priority, extra, req.account_index, req.subaddr_indices, req.subtract_fee_from_outputs); if (ptx_vector.empty()) { @@ -1133,6 +1139,12 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } + else if (req.unlock_time) + { + er.code = WALLET_RPC_ERROR_CODE_NONZERO_UNLOCK_TIME; + er.message = "Transaction cannot have non-zero unlock time"; + return false; + } CHECK_MULTISIG_ENABLED(); @@ -1147,7 +1159,7 @@ namespace tools uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint32_t priority = m_wallet->adjust_priority(req.priority); LOG_PRINT_L2("on_transfer_split calling create_transactions_2"); - std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices); + std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_2(dsts, mixin, priority, extra, req.account_index, req.subaddr_indices); LOG_PRINT_L2("on_transfer_split called create_transactions_2"); if (ptx_vector.empty()) @@ -1569,6 +1581,12 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } + else if (req.unlock_time) + { + er.code = WALLET_RPC_ERROR_CODE_NONZERO_UNLOCK_TIME; + er.message = "Transaction cannot have non-zero unlock time"; + return false; + } CHECK_MULTISIG_ENABLED(); @@ -1604,7 +1622,7 @@ namespace tools { uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint32_t priority = m_wallet->adjust_priority(req.priority); - std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra, req.account_index, subaddr_indices); + std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_all(req.below_amount, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, priority, extra, req.account_index, subaddr_indices); return fill_response(ptx_vector, req.get_tx_keys, res.tx_key_list, res.amount_list, res.amounts_by_dest_list, res.fee_list, res.weight_list, res.multisig_txset, res.unsigned_txset, req.do_not_relay, res.tx_hash_list, req.get_tx_hex, res.tx_blob_list, req.get_tx_metadata, res.tx_metadata_list, res.spent_key_images_list, er); @@ -1629,6 +1647,12 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } + else if (req.unlock_time) + { + er.code = WALLET_RPC_ERROR_CODE_NONZERO_UNLOCK_TIME; + er.message = "Transaction cannot have non-zero unlock time"; + return false; + } if (req.outputs < 1) { @@ -1661,7 +1685,7 @@ namespace tools { uint64_t mixin = m_wallet->adjust_mixin(req.ring_size ? req.ring_size - 1 : 0); uint32_t priority = m_wallet->adjust_priority(req.priority); - std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, req.unlock_time, priority, extra); + std::vector<wallet2::pending_tx> ptx_vector = m_wallet->create_transactions_single(ki, dsts[0].addr, dsts[0].is_subaddress, req.outputs, mixin, priority, extra); if (ptx_vector.empty()) { @@ -2066,10 +2090,11 @@ namespace tools if (req.key_type.compare("mnemonic") == 0) { epee::wipeable_string seed; - bool ready; - if (m_wallet->multisig(&ready)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (ms_status.multisig_is_active) { - if (!ready) + if (!ms_status.is_ready) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is multisig, but not yet finalized"; @@ -3979,7 +4004,14 @@ namespace tools bool wallet_rpc_server::on_is_multisig(const wallet_rpc::COMMAND_RPC_IS_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_IS_MULTISIG::response& res, epee::json_rpc::error& er, const connection_context *ctx) { if (!m_wallet) return not_open(er); - res.multisig = m_wallet->multisig(&res.ready, &res.threshold, &res.total); + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + res.multisig = ms_status.multisig_is_active; + res.kex_is_done = ms_status.kex_is_done; + res.ready = ms_status.is_ready; + res.threshold = ms_status.threshold; + res.total = ms_status.total; + return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -3992,7 +4024,7 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_ALREADY_MULTISIG; er.message = "This wallet is already multisig"; @@ -4021,7 +4053,7 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - if (m_wallet->multisig()) + if (m_wallet->get_multisig_status().multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_ALREADY_MULTISIG; er.message = "This wallet is already multisig"; @@ -4059,14 +4091,15 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - if (!m_wallet->multisig(&ready)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; return false; } - if (!ready) + if (!ms_status.is_ready) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is multisig, but not yet finalized"; @@ -4100,15 +4133,15 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; return false; } - if (!ready) + if (!ms_status.is_ready) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is multisig, but not yet finalized"; @@ -4116,7 +4149,7 @@ namespace tools } CHECK_MULTISIG_ENABLED(); - if (req.info.size() < threshold - 1) + if (req.info.size() + 1 < ms_status.threshold) { er.code = WALLET_RPC_ERROR_CODE_THRESHOLD_NOT_REACHED; er.message = "Needs multisig export info from more participants"; @@ -4180,9 +4213,9 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) + multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; @@ -4190,7 +4223,7 @@ namespace tools } CHECK_MULTISIG_ENABLED(); - if (req.multisig_info.size() + 1 < total) + if (req.multisig_info.size() + 1 < ms_status.total) { er.code = WALLET_RPC_ERROR_CODE_THRESHOLD_NOT_REACHED; er.message = "Needs multisig info from more participants"; @@ -4200,8 +4233,8 @@ namespace tools try { res.multisig_info = m_wallet->exchange_multisig_keys(req.password, req.multisig_info, req.force_update_use_with_caution); - m_wallet->multisig(&ready); - if (ready) + ms_status = m_wallet->get_multisig_status(); + if (ms_status.is_ready) { res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype()); } @@ -4224,15 +4257,15 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; return false; } - if (!ready) + if (!ms_status.is_ready) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is multisig, but not yet finalized"; @@ -4294,15 +4327,15 @@ namespace tools er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) + const multisig::multisig_account_status ms_status{m_wallet->get_multisig_status()}; + + if (!ms_status.multisig_is_active) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is not multisig"; return false; } - if (!ready) + if (!ms_status.is_ready) { er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; er.message = "This wallet is multisig, but not yet finalized"; @@ -4327,7 +4360,7 @@ namespace tools return false; } - if (txs.m_signers.size() < threshold) + if (txs.m_signers.size() < ms_status.threshold) { er.code = WALLET_RPC_ERROR_CODE_THRESHOLD_NOT_REACHED; er.message = "Not enough signers signed this transaction."; diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index f9f534097..2173f5b6e 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -2323,12 +2323,14 @@ namespace wallet_rpc struct response_t { bool multisig; + bool kex_is_done; bool ready; uint32_t threshold; uint32_t total; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(multisig) + KV_SERIALIZE(kex_is_done) KV_SERIALIZE(ready) KV_SERIALIZE(threshold) KV_SERIALIZE(total) diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h index 2988f52ad..ca2de0cc6 100644 --- a/src/wallet/wallet_rpc_server_error_codes.h +++ b/src/wallet/wallet_rpc_server_error_codes.h @@ -80,3 +80,4 @@ #define WALLET_RPC_ERROR_CODE_INVALID_SIGNATURE_TYPE -47 #define WALLET_RPC_ERROR_CODE_DISABLED -48 #define WALLET_RPC_ERROR_CODE_PROXY_ALREADY_DEFINED -49 +#define WALLET_RPC_ERROR_CODE_NONZERO_UNLOCK_TIME -50 diff --git a/tests/block_weight/block_weight.cpp b/tests/block_weight/block_weight.cpp index 4b00fc63f..676d56006 100644 --- a/tests/block_weight/block_weight.cpp +++ b/tests/block_weight/block_weight.cpp @@ -138,7 +138,7 @@ static uint32_t lcg() static void test(test_t t, uint64_t blocks) { - PREFIX(10); + PREFIX(HF_VERSION_2021_SCALING); for (uint64_t h = 0; h < LONG_TERM_BLOCK_WEIGHT_WINDOW; ++h) { @@ -177,8 +177,8 @@ static void test(test_t t, uint64_t blocks) } uint64_t ltw = bc->get_next_long_term_block_weight(w); cryptonote::block b; - b.major_version = 10; - b.minor_version = 10; + b.major_version = HF_VERSION_2021_SCALING; + b.minor_version = HF_VERSION_2021_SCALING; bc->get_db().add_block(std::make_pair(std::move(b), ""), w, ltw, bc->get_db().height(), bc->get_db().height(), {}); if (!bc->update_next_cumulative_weight_limit()) diff --git a/tests/block_weight/block_weight.py b/tests/block_weight/block_weight.py index 5ec09896d..cfd0900fb 100755 --- a/tests/block_weight/block_weight.py +++ b/tests/block_weight/block_weight.py @@ -18,14 +18,20 @@ ltembw = MEDIAN_THRESHOLD weights = [MEDIAN_THRESHOLD]*MEDIAN_WINDOW_SMALL # weights of recent blocks (B), with index -1 most recent lt_weights = [MEDIAN_THRESHOLD]*MEDIAN_WINDOW_BIG # long-term weights +# see contrib/epee/include/misc_language.h, get_mid +def get_mid(a, b): + return (a//2) + (b//2) + ((a - 2*(a//2)) + (b - 2*(b//2)))//2; + # Compute the median of a list def get_median(vec): - #temp = vec + if len(vec) == 1: + return vec[0] temp = sorted(vec) + n = len(temp) // 2 if len(temp) % 2 == 1: - return temp[len(temp)//2] + return temp[n] else: - return int((temp[len(temp)//2]+temp[len(temp)//2-1])//2) + return get_mid(temp[n-1], temp[n]) def LCG(): global lcg_seed @@ -46,7 +52,7 @@ def run(t, blocks): # determine the effective weight stmedian = get_median(weights[-MEDIAN_WINDOW_SMALL:]) - embw = min(max(MEDIAN_THRESHOLD,stmedian),int(MULTIPLIER_BIG*ltembw)) + embw = min(max(ltembw,stmedian),int(MULTIPLIER_BIG*ltembw)) # drop the lowest values weights = weights[1:] @@ -64,7 +70,7 @@ def run(t, blocks): else: sys.exit(1) weights.append(max_weight) - lt_weights.append(min(max_weight,int(ltembw + int(ltembw * 2 / 5)))) + lt_weights.append(min(max(max_weight, ltembw * 10 // 17),int(ltembw + int(ltembw * 7 / 10)))) #print "H %u, r %u, BW %u, EMBW %u, LTBW %u, LTEMBW %u, ltmedian %u" % (block, r, max_weight, embw, lt_weights[-1], ltembw, ltmedian) print("H %u, BW %u, EMBW %u, LTBW %u" % (block, max_weight, embw, lt_weights[-1])) diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp index 071d2198e..fd5ab5a7f 100644 --- a/tests/core_tests/block_validation.cpp +++ b/tests/core_tests/block_validation.cpp @@ -350,7 +350,7 @@ bool gen_block_miner_tx_has_2_in::generate(std::vector<test_event_entry>& events destinations.push_back(de); transaction tmp_tx; - if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tmp_tx, 0)) + if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tmp_tx)) return false; MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); @@ -393,7 +393,7 @@ bool gen_block_miner_tx_with_txin_to_key::generate(std::vector<test_event_entry> destinations.push_back(de); transaction tmp_tx; - if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tmp_tx, 0)) + if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tmp_tx)) return false; MAKE_MINER_TX_MANUALLY(miner_tx, blk_1); diff --git a/tests/core_tests/bulletproof_plus.cpp b/tests/core_tests/bulletproof_plus.cpp index ece03dd77..742670063 100644 --- a/tests/core_tests/bulletproof_plus.cpp +++ b/tests/core_tests/bulletproof_plus.cpp @@ -136,7 +136,7 @@ bool gen_bpp_tx_validation_base::generate_with(std::vector<test_event_entry>& ev std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0}; rct_txes.resize(rct_txes.size() + 1); - bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes.back(), 0, tx_key, additional_tx_keys, true, rct_config[n]); + bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes.back(), tx_key, additional_tx_keys, true, rct_config[n]); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (post_tx && !post_tx(rct_txes.back(), n)) diff --git a/tests/core_tests/bulletproofs.cpp b/tests/core_tests/bulletproofs.cpp index f875edf74..278bf46a2 100644 --- a/tests/core_tests/bulletproofs.cpp +++ b/tests/core_tests/bulletproofs.cpp @@ -136,7 +136,7 @@ bool gen_bp_tx_validation_base::generate_with(std::vector<test_event_entry>& eve std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0}; rct_txes.resize(rct_txes.size() + 1); - bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes.back(), 0, tx_key, additional_tx_keys, true, rct_config[n]); + bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes.back(), tx_key, additional_tx_keys, true, rct_config[n]); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (post_tx && !post_tx(rct_txes.back(), n)) diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 9aa0de8e5..8b2c2a577 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -1043,7 +1043,7 @@ bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote vector<tx_destination_entry> destinations; fill_tx_sources_and_destinations(events, blk_head, from, get_address(to), amount, fee, nmix, sources, destinations, check_unlock_time, fnc_tx_in_accept); - return construct_tx_rct(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); + return construct_tx_rct(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version); } bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote::transaction& tx, const cryptonote::block& blk_head, @@ -1060,7 +1060,7 @@ bool construct_tx_to_key(const std::vector<test_event_entry>& events, cryptonote fill_tx_destinations(from, destinations, fee, sources, destinations_all, false); - return construct_tx_rct(from.get_keys(), sources, destinations_all, get_address(from), std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); + return construct_tx_rct(from.get_keys(), sources, destinations_all, get_address(from), std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version); } bool construct_tx_to_key(cryptonote::transaction& tx, @@ -1070,7 +1070,7 @@ bool construct_tx_to_key(cryptonote::transaction& tx, { vector<tx_destination_entry> destinations; fill_tx_destinations(from, get_address(to), amount, fee, sources, destinations, rct); - return construct_tx_rct(from.get_keys(), sources, destinations, get_address(from), std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); + return construct_tx_rct(from.get_keys(), sources, destinations, get_address(from), std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version); } bool construct_tx_to_key(cryptonote::transaction& tx, @@ -1081,10 +1081,10 @@ bool construct_tx_to_key(cryptonote::transaction& tx, { vector<tx_destination_entry> all_destinations; fill_tx_destinations(from, destinations, fee, sources, all_destinations, rct); - return construct_tx_rct(from.get_keys(), sources, all_destinations, get_address(from), std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); + return construct_tx_rct(from.get_keys(), sources, all_destinations, get_address(from), std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version); } -bool construct_tx_rct(const cryptonote::account_keys& sender_account_keys, std::vector<cryptonote::tx_source_entry>& sources, const std::vector<cryptonote::tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, cryptonote::transaction& tx, uint64_t unlock_time, bool rct, rct::RangeProofType range_proof_type, int bp_version) +bool construct_tx_rct(const cryptonote::account_keys& sender_account_keys, std::vector<cryptonote::tx_source_entry>& sources, const std::vector<cryptonote::tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, cryptonote::transaction& tx, bool rct, rct::RangeProofType range_proof_type, int bp_version) { std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0, 0}; @@ -1092,7 +1092,7 @@ bool construct_tx_rct(const cryptonote::account_keys& sender_account_keys, std:: std::vector<crypto::secret_key> additional_tx_keys; std::vector<tx_destination_entry> destinations_copy = destinations; rct::RCTConfig rct_config = {range_proof_type, bp_version}; - return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config); + return construct_tx_and_get_tx_key(sender_account_keys, subaddresses, sources, destinations_copy, change_addr, extra, tx, tx_key, additional_tx_keys, rct, rct_config); } transaction construct_tx_with_fee(std::vector<test_event_entry>& events, const block& blk_head, diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 41f7275d3..0a1eb232d 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -472,7 +472,7 @@ bool construct_tx_rct(const cryptonote::account_keys& sender_account_keys, std::vector<cryptonote::tx_source_entry>& sources, const std::vector<cryptonote::tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, - std::vector<uint8_t> extra, cryptonote::transaction& tx, uint64_t unlock_time, + std::vector<uint8_t> extra, cryptonote::transaction& tx, bool rct=false, rct::RangeProofType range_proof_type=rct::RangeProofBorromean, int bp_version = 0); diff --git a/tests/core_tests/double_spend.inl b/tests/core_tests/double_spend.inl index b6e3726cc..5ccf4de98 100644 --- a/tests/core_tests/double_spend.inl +++ b/tests/core_tests/double_spend.inl @@ -138,7 +138,7 @@ bool gen_double_spend_in_tx<txs_keeped_by_block>::generate(std::vector<test_even destinations.push_back(de); cryptonote::transaction tx_1; - if (!construct_tx(bob_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_1, 0)) + if (!construct_tx(bob_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_1)) return false; SET_EVENT_VISITOR_SETT(events, txs_keeped_by_block ? event_visitor_settings::set_txs_keeped_by_block : 0); diff --git a/tests/core_tests/integer_overflow.cpp b/tests/core_tests/integer_overflow.cpp index 6ffc3786b..2f48ec04a 100644 --- a/tests/core_tests/integer_overflow.cpp +++ b/tests/core_tests/integer_overflow.cpp @@ -174,7 +174,7 @@ bool gen_uint_overflow_2::generate(std::vector<test_event_entry>& events) const destinations.push_back(tx_destination_entry(sources.front().amount - MONEY_SUPPLY - MONEY_SUPPLY + 1 - TESTS_DEFAULT_FEE, bob_addr, false)); cryptonote::transaction tx_1; - if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_1, 0)) + if (!construct_tx(miner_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_1)) return false; events.push_back(tx_1); @@ -200,7 +200,7 @@ bool gen_uint_overflow_2::generate(std::vector<test_event_entry>& events) const destinations.push_back(de); cryptonote::transaction tx_2; - if (!construct_tx(bob_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_2, 0)) + if (!construct_tx(bob_account.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_2)) return false; events.push_back(tx_2); diff --git a/tests/core_tests/multisig.cpp b/tests/core_tests/multisig.cpp index ed6fd68b5..e33803325 100644 --- a/tests/core_tests/multisig.cpp +++ b/tests/core_tests/multisig.cpp @@ -310,7 +310,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry crypto::secret_key multisig_tx_key_entropy; auto sources_copy = sources; multisig::signing::tx_builder_ringct_t tx_builder; - CHECK_AND_ASSERT_MES(tx_builder.init(miner_account[creator].get_keys(), {}, 0, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, false, tx_key, additional_tx_secret_keys, multisig_tx_key_entropy, tx), false, "error: multisig::signing::tx_builder_ringct_t::init"); + CHECK_AND_ASSERT_MES(tx_builder.init(miner_account[creator].get_keys(), {}, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, false, tx_key, additional_tx_secret_keys, multisig_tx_key_entropy, tx), false, "error: multisig::signing::tx_builder_ringct_t::init"); // work out the permutation done on sources std::vector<size_t> ins_order; @@ -399,7 +399,7 @@ bool gen_multisig_tx_validation_base::generate_with(std::vector<test_event_entry } tools::apply_permutation(ins_order, k); multisig::signing::tx_builder_ringct_t signer_tx_builder; - CHECK_AND_ASSERT_MES(signer_tx_builder.init(miner_account[signer].get_keys(), {}, 0, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, true, tx_key, additional_tx_secret_keys, multisig_tx_key_entropy, tx), false, "error: multisig::signing::tx_builder_ringct_t::init"); + CHECK_AND_ASSERT_MES(signer_tx_builder.init(miner_account[signer].get_keys(), {}, 0, {0}, sources, destinations, {}, {rct::RangeProofPaddedBulletproof, 4}, true, true, tx_key, additional_tx_secret_keys, multisig_tx_key_entropy, tx), false, "error: multisig::signing::tx_builder_ringct_t::init"); MDEBUG("signing with k size " << k.size()); for (size_t n = 0; n < multisig::signing::kAlphaComponents; ++n) diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index 3f2cfbea3..9ea7a8e3b 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -122,7 +122,7 @@ bool gen_rct_tx_validation_base::generate_with_full(std::vector<test_event_entry std::vector<crypto::secret_key> additional_tx_keys; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0}; - bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes[n], 0, tx_key, additional_tx_keys, true); + bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes[n], tx_key, additional_tx_keys, true); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); events.push_back(rct_txes[n]); starting_rct_tx_hashes.push_back(get_transaction_hash(rct_txes[n])); @@ -229,7 +229,7 @@ bool gen_rct_tx_validation_base::generate_with_full(std::vector<test_event_entry std::vector<crypto::secret_key> additional_tx_keys; std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[miner_accounts[0].get_keys().m_account_address.m_spend_public_key] = {0,0}; - bool r = construct_tx_and_get_tx_key(miner_accounts[0].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), tx, 0, tx_key, additional_tx_keys, true, rct_config, use_view_tags); + bool r = construct_tx_and_get_tx_key(miner_accounts[0].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), tx, tx_key, additional_tx_keys, true, rct_config, use_view_tags); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (post_tx) diff --git a/tests/core_tests/rct2.cpp b/tests/core_tests/rct2.cpp index c8e0f6260..28e97b06d 100644 --- a/tests/core_tests/rct2.cpp +++ b/tests/core_tests/rct2.cpp @@ -136,7 +136,7 @@ bool gen_rct2_tx_validation_base::generate_with(std::vector<test_event_entry>& e std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[miner_accounts[n].get_keys().m_account_address.m_spend_public_key] = {0,0}; rct_txes.resize(rct_txes.size() + 1); - bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes.back(), 0, tx_key, additional_tx_keys, true, rct_config[n]); + bool r = construct_tx_and_get_tx_key(miner_accounts[n].get_keys(), subaddresses, sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), rct_txes.back(), tx_key, additional_tx_keys, true, rct_config[n]); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (post_tx && !post_tx(rct_txes.back(), n)) diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp index b5ecba9ae..c27e6b375 100644 --- a/tests/core_tests/transaction_tests.cpp +++ b/tests/core_tests/transaction_tests.cpp @@ -102,7 +102,7 @@ bool test_transaction_generation_and_ring_signature() destinations.push_back(td); transaction tx_rc1; - bool r = construct_tx(miner_acc2.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_rc1, 0); + bool r = construct_tx(miner_acc2.get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx_rc1); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); crypto::hash pref_hash = get_transaction_prefix_hash(tx_rc1); diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index bc8622539..a46b2a06a 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -212,7 +212,7 @@ bool gen_tx_unlock_time::generate(std::vector<test_event_entry>& events) const GENERATE_ACCOUNT(miner_account); MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); - REWIND_BLOCKS_N(events, blk_1, blk_0, miner_account, 10); + REWIND_BLOCKS_N(events, blk_1, blk_0, miner_account, 20); REWIND_BLOCKS(events, blk_1r, blk_1, miner_account); auto make_tx_with_unlock_time = [&](uint64_t unlock_time) -> transaction @@ -222,9 +222,34 @@ bool gen_tx_unlock_time::generate(std::vector<test_event_entry>& events) const std::list<transaction> txs_0; + // Let's make sure that non-zero unlock times fail with a normal relay method + SET_EVENT_VISITOR_SETT(events, 0); // set relay_method::fluff + txs_0.push_back(make_tx_with_unlock_time(0)); events.push_back(txs_0.back()); + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) - 1)); + + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(make_tx_with_unlock_time(get_block_height(blk_1r))); + + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) + 1)); + + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) + 2)); + + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(make_tx_with_unlock_time(ts_start - 1)); + + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(make_tx_with_unlock_time(time(0) + 60 * 60)); + + // We want to try adding these transactions with non-zero unlock times to the pool, but relay + // rules enforce otherwise, so we set the relay method to block + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block); // set relay_method::block + txs_0.push_back(make_tx_with_unlock_time(get_block_height(blk_1r) - 1)); events.push_back(txs_0.back()); @@ -596,6 +621,7 @@ bool gen_tx_check_input_unlock_time::generate(std::vector<test_event_entry>& eve events.push_back(txs_0.back()); }; + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block); // set relay_method::block uint64_t blk_3_height = get_block_height(blk_1r) + 2; make_tx_to_acc(0, 0); make_tx_to_acc(1, blk_3_height - 1); @@ -604,6 +630,7 @@ bool gen_tx_check_input_unlock_time::generate(std::vector<test_event_entry>& eve make_tx_to_acc(4, time(0) - 1); make_tx_to_acc(5, time(0) + 60 * 60); MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_0); + SET_EVENT_VISITOR_SETT(events, 0); // set relay_method::fluff std::list<transaction> txs_1; auto make_tx_from_acc = [&](size_t acc_idx, bool invalid) diff --git a/tests/core_tests/v2_tests.cpp b/tests/core_tests/v2_tests.cpp index f2d0121b6..9030f22ba 100644 --- a/tests/core_tests/v2_tests.cpp +++ b/tests/core_tests/v2_tests.cpp @@ -107,7 +107,7 @@ bool gen_v2_tx_validation_base::generate_with(std::vector<test_event_entry>& eve destinations.push_back(td); transaction tx; - bool r = construct_tx(miner_accounts[0].get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx, 0); + bool r = construct_tx(miner_accounts[0].get_keys(), sources, destinations, boost::none, std::vector<uint8_t>(), tx); CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); if (!valid) DO_CALLBACK(events, "mark_invalid_tx"); diff --git a/tests/core_tests/wallet_tools.cpp b/tests/core_tests/wallet_tools.cpp index ee29fdad1..c81abbbaf 100644 --- a/tests/core_tests/wallet_tools.cpp +++ b/tests/core_tests/wallet_tools.cpp @@ -271,7 +271,7 @@ bool construct_tx_to_key(cryptonote::transaction& tx, { vector<tx_destination_entry> destinations; fill_tx_destinations(sender_wallet->get_account(), get_address(to), amount, fee, sources, destinations, rct); - return construct_tx_rct(sender_wallet, sources, destinations, get_address(sender_wallet), std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); + return construct_tx_rct(sender_wallet, sources, destinations, get_address(sender_wallet), std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version); } bool construct_tx_to_key(cryptonote::transaction& tx, @@ -282,15 +282,15 @@ bool construct_tx_to_key(cryptonote::transaction& tx, { vector<tx_destination_entry> all_destinations; fill_tx_destinations(sender_wallet->get_account(), destinations, fee, sources, all_destinations, rct); - return construct_tx_rct(sender_wallet, sources, all_destinations, get_address(sender_wallet), std::vector<uint8_t>(), tx, 0, rct, range_proof_type, bp_version); + return construct_tx_rct(sender_wallet, sources, all_destinations, get_address(sender_wallet), std::vector<uint8_t>(), tx, rct, range_proof_type, bp_version); } -bool construct_tx_rct(tools::wallet2 * sender_wallet, std::vector<cryptonote::tx_source_entry>& sources, const std::vector<cryptonote::tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, cryptonote::transaction& tx, uint64_t unlock_time, bool rct, rct::RangeProofType range_proof_type, int bp_version) +bool construct_tx_rct(tools::wallet2 * sender_wallet, std::vector<cryptonote::tx_source_entry>& sources, const std::vector<cryptonote::tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, std::vector<uint8_t> extra, cryptonote::transaction& tx, bool rct, rct::RangeProofType range_proof_type, int bp_version) { subaddresses_t & subaddresses = wallet_accessor_test::get_subaddresses(sender_wallet); crypto::secret_key tx_key; std::vector<crypto::secret_key> additional_tx_keys; std::vector<tx_destination_entry> destinations_copy = destinations; rct::RCTConfig rct_config = {range_proof_type, bp_version}; - return construct_tx_and_get_tx_key(sender_wallet->get_account().get_keys(), subaddresses, sources, destinations_copy, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, rct, rct_config); + return construct_tx_and_get_tx_key(sender_wallet->get_account().get_keys(), subaddresses, sources, destinations_copy, change_addr, extra, tx, tx_key, additional_tx_keys, rct, rct_config); } diff --git a/tests/core_tests/wallet_tools.h b/tests/core_tests/wallet_tools.h index 2201e11f4..94921e56e 100644 --- a/tests/core_tests/wallet_tools.h +++ b/tests/core_tests/wallet_tools.h @@ -53,6 +53,7 @@ class wallet_accessor_test { public: static void set_account(tools::wallet2 * wallet, cryptonote::account_base& account); + static void set_password(tools::wallet2 * wallet, const epee::wipeable_string & password) { wallet->setup_keys(password); } static tools::wallet2::transfer_container & get_transfers(tools::wallet2 * wallet) { return wallet->m_transfers; } static subaddresses_t & get_subaddresses(tools::wallet2 * wallet) { return wallet->m_subaddresses; } static void process_parsed_blocks(tools::wallet2 * wallet, uint64_t start_height, const std::vector<cryptonote::block_complete_entry> &blocks, const std::vector<tools::wallet2::parsed_block> &parsed_blocks, uint64_t& blocks_added); @@ -92,5 +93,5 @@ bool construct_tx_rct(tools::wallet2 * sender_wallet, std::vector<cryptonote::tx_source_entry>& sources, const std::vector<cryptonote::tx_destination_entry>& destinations, const boost::optional<cryptonote::account_public_address>& change_addr, - std::vector<uint8_t> extra, cryptonote::transaction& tx, uint64_t unlock_time, + std::vector<uint8_t> extra, cryptonote::transaction& tx, bool rct=false, rct::RangeProofType range_proof_type=rct::RangeProofBorromean, int bp_version = 0); diff --git a/tests/functional_tests/functional_tests_rpc.py b/tests/functional_tests/functional_tests_rpc.py index 7e4d49ffa..e483352a4 100755 --- a/tests/functional_tests/functional_tests_rpc.py +++ b/tests/functional_tests/functional_tests_rpc.py @@ -12,8 +12,8 @@ import os USAGE = 'usage: functional_tests_rpc.py <python> <srcdir> <builddir> [<tests-to-run> | all]' DEFAULT_TESTS = [ 'address_book', 'bans', 'blockchain', 'cold_signing', 'daemon_info', 'get_output_distribution', - 'integrated_address', 'k_anonymity', 'mining', 'multisig', 'p2p', 'proofs', 'rpc_payment', - 'sign_message', 'transfer', 'txpool', 'uri', 'validate_address', 'wallet' + 'http_digest_auth', 'integrated_address', 'k_anonymity', 'mining', 'multisig', 'p2p', 'proofs', + 'rpc_payment', 'sign_message', 'transfer', 'txpool', 'uri', 'validate_address', 'wallet' ] try: python = sys.argv[1] @@ -41,12 +41,12 @@ except: # a main offline monerod, does most of the tests # a restricted RPC monerod setup with RPC payment # two local online monerods connected to each other -N_MONERODS = 4 +N_MONERODS = 5 # 4 wallets connected to the main offline monerod # 1 wallet connected to the first local online monerod # 1 offline wallet -N_WALLETS = 6 +N_WALLETS = 7 WALLET_DIRECTORY = builddir + "/functional-tests-directory" FUNCTIONAL_TESTS_DIRECTORY = builddir + "/tests/functional_tests" @@ -58,15 +58,17 @@ monerod_extra = [ ["--rpc-payment-address", "44SKxxLQw929wRF6BA9paQ1EWFshNnKhXM3qz6Mo3JGDE2YG3xyzVutMStEicxbQGRfrYvAAYxH6Fe8rnD56EaNwUiqhcwR", "--rpc-payment-difficulty", str(DIFFICULTY), "--rpc-payment-credits", "5000", "--offline"], ["--add-exclusive-node", "127.0.0.1:18283"], ["--add-exclusive-node", "127.0.0.1:18282"], + ["--rpc-login", "md5_lover:Z1ON0101", "--offline"], ] -wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", WALLET_DIRECTORY, "--rpc-bind-port", "wallet_port", "--disable-rpc-login", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--log-level", "1", "--allow-mismatched-daemon-version"] +wallet_base = [builddir + "/bin/monero-wallet-rpc", "--wallet-dir", WALLET_DIRECTORY, "--rpc-bind-port", "wallet_port", "--rpc-ssl", "disabled", "--daemon-ssl", "disabled", "--log-level", "1", "--allow-mismatched-daemon-version"] wallet_extra = [ - ["--daemon-port", "18180"], - ["--daemon-port", "18180"], - ["--daemon-port", "18180"], - ["--daemon-port", "18180"], - ["--daemon-port", "18182"], - ["--offline"], + ["--daemon-port", "18180", "--disable-rpc-login"], + ["--daemon-port", "18180", "--disable-rpc-login"], + ["--daemon-port", "18180", "--disable-rpc-login"], + ["--daemon-port", "18180", "--disable-rpc-login"], + ["--daemon-port", "18182", "--disable-rpc-login"], + ["--offline", "--disable-rpc-login"], + ["--daemon-port", "18184", "--daemon-login", "md5_lover:Z1ON0101", "--rpc-login", "kyle:reveille"], ] command_lines = [] diff --git a/tests/functional_tests/http_digest_auth.py b/tests/functional_tests/http_digest_auth.py new file mode 100644 index 000000000..7c22f9f30 --- /dev/null +++ b/tests/functional_tests/http_digest_auth.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 + +# Copyright (c) 2024, The Monero Project +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. 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. +# +# 3. Neither the name of the copyright holder 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +from framework.daemon import Daemon +from framework.wallet import Wallet + +import time + + +DAEMON_IDX = 4 +DAEMON_USER = "md5_lover" +DAEMON_PASS = "Z1ON0101" +WALLET_IDX = 6 +WALLET_USER = "kyle" +WALLET_PASS = "reveille" +WALLET_SEED = "velvet lymph giddy number token physics poetry unquoted nibs useful sabotage limits \ + benches lifestyle eden nitrogen anvil fewest avoid batch vials washing fences goat unquoted" + +class HttpDigestAuthTest(): + def run_test(self): + self.test_daemon_login_required() + self.test_wallet_login_required() + + self.make_daemon_conn() + self.create_wallet() + + self.mine_through_wallet() + + def test_daemon_login_required(self): + print('Attempting to connect to daemon loginless with RPC digest authentication required...') + bad_daemon = Daemon(idx = DAEMON_IDX) + try: + res = bad_daemon.get_height() + assert(False) + except: + pass + + def test_wallet_login_required(self): + print('Attempting to connect to wallet server loginless with RPC digest authentication required...') + bad_wallet = Wallet(idx = WALLET_IDX) + try: + res = bad_wallet.get_balance() + assert(False) + except: + pass + + def make_daemon_conn(self): + print('Connecting to daemon with RPC digest authentication required...') + self.daemon = Daemon(idx = DAEMON_IDX, username = DAEMON_USER, password = DAEMON_PASS) + res = self.daemon.get_height() + self.daemon.pop_blocks(res.height - 1) + self.daemon.flush_txpool() + + def create_wallet(self): + print('Connecting to wallet server with RPC digest authentication required...') + self.wallet = Wallet(idx = WALLET_IDX, username = WALLET_USER, password = WALLET_PASS) + # close the wallet if any, will throw if none is loaded + try: self.wallet.close_wallet() + except: pass + res = self.wallet.restore_deterministic_wallet(seed = WALLET_SEED) + + def mine_through_wallet(self): + print('Telling login-required daemon to start mining through login-required wallet server...') + start_height = self.daemon.get_height().height + self.wallet.start_mining(2) + + print("Waiting a few seconds for mining to occur...") + for tries in range(20): + time.sleep(1) + + stop_height = self.daemon.get_height().height + if stop_height > start_height: + break + + print('Telling login-required daemon to stop mining through login-required wallet server...') + self.wallet.stop_mining() + + num_blocks_mined = stop_height - start_height + assert num_blocks_mined > 0 + print('Mined {} blocks!'.format(num_blocks_mined)) + +if __name__ == '__main__': + HttpDigestAuthTest().run_test() diff --git a/tests/functional_tests/transactions_flow_test.cpp b/tests/functional_tests/transactions_flow_test.cpp index 8c4b27d24..a15348bca 100644 --- a/tests/functional_tests/transactions_flow_test.cpp +++ b/tests/functional_tests/transactions_flow_test.cpp @@ -85,7 +85,7 @@ bool do_send_money(tools::wallet2& w1, tools::wallet2& w2, size_t mix_in_factor, try { std::vector<tools::wallet2::pending_tx> ptx; - ptx = w1.create_transactions_2(dsts, mix_in_factor, 0, 0, std::vector<uint8_t>(), 0, {}); + ptx = w1.create_transactions_2(dsts, mix_in_factor, 0, std::vector<uint8_t>(), 0, {}); for (auto &p: ptx) w1.commit_tx(p); return true; diff --git a/tests/hash/main.cpp b/tests/hash/main.cpp index 23455f7f3..c1ad80c7c 100644 --- a/tests/hash/main.cpp +++ b/tests/hash/main.cpp @@ -43,7 +43,7 @@ #include "warnings.h" #include "crypto/hash.h" #include "crypto/variant2_int_sqrt.h" -#include "randomx/src/blake2/blake2.h" +#include "crypto/blake2b.h" #include "../io.h" using namespace std; diff --git a/tests/performance_tests/check_tx_signature.h b/tests/performance_tests/check_tx_signature.h index de979856a..2ae4a2613 100644 --- a/tests/performance_tests/check_tx_signature.h +++ b/tests/performance_tests/check_tx_signature.h @@ -72,7 +72,7 @@ public: std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[this->m_miners[this->real_source_idx].get_keys().m_account_address.m_spend_public_key] = {0,0}; rct::RCTConfig rct_config{range_proof_type, bp_version}; - if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_tx, 0, tx_key, additional_tx_keys, rct, rct_config)) + if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_tx, tx_key, additional_tx_keys, rct, rct_config)) return false; get_transaction_prefix_hash(m_tx, m_tx_prefix_hash); @@ -136,7 +136,7 @@ public: m_txes.resize(a_num_txes + (extra_outs > 0 ? 1 : 0)); for (size_t n = 0; n < a_num_txes; ++n) { - if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_txes[n], 0, tx_key, additional_tx_keys, true, {rct::RangeProofPaddedBulletproof, 2})) + if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_txes[n], tx_key, additional_tx_keys, true, {rct::RangeProofPaddedBulletproof, 2})) return false; } @@ -147,7 +147,7 @@ public: for (size_t n = 1; n < extra_outs; ++n) destinations.push_back(tx_destination_entry(1, m_alice.get_keys().m_account_address, false)); - if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_txes.back(), 0, tx_key, additional_tx_keys, true, {rct::RangeProofMultiOutputBulletproof, 2})) + if (!construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_txes.back(), tx_key, additional_tx_keys, true, {rct::RangeProofMultiOutputBulletproof, 2})) return false; } diff --git a/tests/performance_tests/construct_tx.h b/tests/performance_tests/construct_tx.h index 4b3f061c4..14a603ca5 100644 --- a/tests/performance_tests/construct_tx.h +++ b/tests/performance_tests/construct_tx.h @@ -74,7 +74,7 @@ public: std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[this->m_miners[this->real_source_idx].get_keys().m_account_address.m_spend_public_key] = {0,0}; rct::RCTConfig rct_config{range_proof_type, bp_version}; - return cryptonote::construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, m_destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_tx, 0, tx_key, additional_tx_keys, rct, rct_config); + return cryptonote::construct_tx_and_get_tx_key(this->m_miners[this->real_source_idx].get_keys(), subaddresses, this->m_sources, m_destinations, cryptonote::account_public_address{}, std::vector<uint8_t>(), m_tx, tx_key, additional_tx_keys, rct, rct_config); } private: diff --git a/tests/performance_tests/ge_frombytes_vartime.h b/tests/performance_tests/ge_frombytes_vartime.h index d543ed720..d3d717195 100644 --- a/tests/performance_tests/ge_frombytes_vartime.h +++ b/tests/performance_tests/ge_frombytes_vartime.h @@ -57,7 +57,7 @@ public: std::vector<tx_destination_entry> destinations; destinations.push_back(tx_destination_entry(1, m_alice.get_keys().m_account_address, false)); - if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, boost::none, std::vector<uint8_t>(), m_tx, 0)) + if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, boost::none, std::vector<uint8_t>(), m_tx)) return false; const cryptonote::txin_to_key& txin = boost::get<cryptonote::txin_to_key>(m_tx.vin[0]); diff --git a/tests/performance_tests/ge_tobytes.h b/tests/performance_tests/ge_tobytes.h index a3c6121b1..7adf1dcea 100644 --- a/tests/performance_tests/ge_tobytes.h +++ b/tests/performance_tests/ge_tobytes.h @@ -57,7 +57,7 @@ public: std::vector<tx_destination_entry> destinations; destinations.push_back(tx_destination_entry(1, m_alice.get_keys().m_account_address, false)); - if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, boost::none, std::vector<uint8_t>(), m_tx, 0)) + if (!construct_tx(this->m_miners[this->real_source_idx].get_keys(), this->m_sources, destinations, boost::none, std::vector<uint8_t>(), m_tx)) return false; const cryptonote::txin_to_key& txin = boost::get<cryptonote::txin_to_key>(m_tx.vin[0]); diff --git a/tests/performance_tests/performance_tests.h b/tests/performance_tests/performance_tests.h index 0f16ff8fc..68679a36c 100644 --- a/tests/performance_tests/performance_tests.h +++ b/tests/performance_tests/performance_tests.h @@ -249,7 +249,7 @@ bool run_test(const std::string &filter, ParamsT ¶ms_shuttle, const char* te double stddev = runner.get_stddev(); double npskew = runner.get_non_parametric_skew(); - std::vector<TimingsDatabase::instance> prev_instances = params.td.get(test_name); + const TimingsDatabase::instance* prev_instance = params.td.get_most_recent(test_name); params.td.add(test_name, {time(NULL), runner.get_size(), min, max, mean, med, stddev, npskew, quantiles}); std::cout << (params.verbose ? " time per call: " : " ") << time_per_call << " " << unit << "/call" << (params.verbose ? "\n" : ""); @@ -260,15 +260,14 @@ bool run_test(const std::string &filter, ParamsT ¶ms_shuttle, const char* te uint64_t p95s = quantiles[9] / scale; uint64_t stddevs = stddev / scale; std::string cmp; - if (!prev_instances.empty()) + if (prev_instance) { - const TimingsDatabase::instance &prev_instance = prev_instances.back(); - if (!runner.is_same_distribution(prev_instance.npoints, prev_instance.mean, prev_instance.stddev)) + if (!runner.is_same_distribution(prev_instance->npoints, prev_instance->mean, prev_instance->stddev)) { - double pc = fabs(100. * (prev_instance.mean - runner.get_mean()) / prev_instance.mean); - cmp = ", " + std::to_string(pc) + "% " + (mean > prev_instance.mean ? "slower" : "faster"); + double pc = fabs(100. * (prev_instance->mean - runner.get_mean()) / prev_instance->mean); + cmp = ", " + std::to_string(pc) + "% " + (mean > prev_instance->mean ? "slower" : "faster"); } - cmp += " -- " + std::to_string(prev_instance.mean); + cmp += " -- " + std::to_string(prev_instance->mean); } std::cout << " (min " << mins << " " << unit << ", 90th " << p95s << " " << unit << ", median " << meds << " " << unit << ", std dev " << stddevs << " " << unit << ")" << cmp; } diff --git a/tests/trezor/trezor_tests.cpp b/tests/trezor/trezor_tests.cpp index b21da95c0..0fcd10cef 100644 --- a/tests/trezor/trezor_tests.cpp +++ b/tests/trezor/trezor_tests.cpp @@ -2206,6 +2206,7 @@ bool gen_trezor_wallet_passphrase::generate(std::vector<test_event_entry>& event const auto wallet_path = (m_wallet_dir / "alice2").string(); const epee::wipeable_string& password = epee::wipeable_string("test-pass"); + wallet_accessor_test::set_password(m_wl_alice2.get(), password); m_wl_alice2->store_to(wallet_path, password); // Positive load diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 212f834d2..567ca8b00 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -51,7 +51,6 @@ set(unit_tests_sources epee_serialization.cpp epee_utils.cpp expect.cpp - fee.cpp json_serialization.cpp get_xtype_from_string.cpp hashchain.cpp diff --git a/tests/unit_tests/crypto.cpp b/tests/unit_tests/crypto.cpp index 88ecb5853..9f79ed60e 100644 --- a/tests/unit_tests/crypto.cpp +++ b/tests/unit_tests/crypto.cpp @@ -112,6 +112,7 @@ TEST(Crypto, tree_branch) { crypto::hash inputs[6]; crypto::hash branch[8]; + crypto::hash branch_1[8 + 1]; crypto::hash root, root2; size_t depth; uint32_t path, path2; @@ -296,12 +297,16 @@ TEST(Crypto, tree_branch) ASSERT_FALSE(crypto::is_branch_in_tree(inputs[5].data, root.data, (const char(*)[32])branch, depth, path)); ASSERT_FALSE(crypto::is_branch_in_tree(crypto::null_hash.data, root.data, (const char(*)[32])branch, depth, path)); + // a version with an extra (dummy) hash + memcpy(branch_1, branch, sizeof(branch)); + branch_1[depth] = crypto::null_hash; + ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth - 1, path)); - ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth + 1, path)); + ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch_1, depth + 1, path)); ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path ^ 1)); ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path ^ 2)); ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])branch, depth, path ^ 3)); - ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])(branch + 1), depth, path)); + ASSERT_FALSE(crypto::is_branch_in_tree(inputs[4].data, root.data, (const char(*)[32])(branch_1 + 1), depth, path)); // five, not found ASSERT_FALSE(crypto::tree_branch((const char(*)[32])inputs, 5, crypto::null_hash.data, (char(*)[32])branch, &depth, &path)); diff --git a/tests/unit_tests/fee.cpp b/tests/unit_tests/fee.cpp deleted file mode 100644 index 1df1a4f04..000000000 --- a/tests/unit_tests/fee.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright (c) 2014-2023, The Monero Project -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without modification, are -// permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this list of -// conditions and the following disclaimer. -// -// 2. 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. -// -// 3. Neither the name of the copyright holder 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF -// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Parts of this file are originally copyright (c) 2012-2013 The Cryptonote developers - -#include "gtest/gtest.h" - -#include "cryptonote_core/blockchain.h" - -using namespace cryptonote; - -namespace -{ - static uint64_t clamp_fee(uint64_t fee) - { - static uint64_t mask = 0; - if (mask == 0) - { - mask = 1; - for (size_t n = PER_KB_FEE_QUANTIZATION_DECIMALS; n < CRYPTONOTE_DISPLAY_DECIMAL_POINT; ++n) - mask *= 10; - } - return (fee + mask - 1) / mask * mask; - } - - //-------------------------------------------------------------------------------------------------------------------- - class fee : public ::testing::Test - { - }; - - // try with blocks ~ 1GB. Passing 2 GB will break on 32 bit systems - - TEST_F(fee, 10xmr) - { - // CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped - ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(2000000000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(2000000000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(2000000000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, 1, 3), 2000000000); - - // higher is inverse proportional - ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(2000000000 / 2)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(2000000000 / 10)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(2000000000 / 1000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(10000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(2000000000 / 20000)); - } - - TEST_F(fee, 1xmr) - { - // CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped - ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(200000000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(200000000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(200000000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, 1, 3), 200000000); - - // higher is inverse proportional - ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(200000000 / 2)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(200000000 / 10)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(200000000 / 1000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(1000000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(200000000 / 20000)); - } - - TEST_F(fee, dot3xmr) - { - // CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 and lower are clamped - ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, 3), clamp_fee(60000000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 2, 3), clamp_fee(60000000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 / 100, 3), clamp_fee(60000000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, 1, 3), 60000000); - - // higher is inverse proportional - ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, 3), clamp_fee(60000000 / 2)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, 3), clamp_fee(60000000 / 10)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, 3), clamp_fee(60000000 / 1000)); - ASSERT_EQ(Blockchain::get_dynamic_base_fee(300000000000, CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull, 3), clamp_fee(60000000 / 20000)); - } - - static bool is_more_or_less(double x, double y) - { - return fabs(y - x) < 0.001; - } - - static const double MAX_MULTIPLIER = 166.f; - - TEST_F(fee, double_at_full) - { - static const uint64_t block_rewards[] = { - 20000000000000ull, // 20 monero - 13000000000000ull, - 1000000000000ull, - 600000000000ull, // .6 monero, minimum reward per block at 2min - 300000000000ull, // .3 monero, minimum reward per block at 1min - }; - static const uint64_t median_block_weights[] = { - CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2, - CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 2, - CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 10, - CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 1000, - // with clamping, the formula does not hold for such large blocks and small fees - // CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V2 * 20000ull - }; - - for (uint64_t block_reward: block_rewards) - { - for (uint64_t median_block_weight: median_block_weights) - { - ASSERT_TRUE(is_more_or_less(Blockchain::get_dynamic_base_fee(block_reward, median_block_weight, 3) * (median_block_weight / 1024.) * MAX_MULTIPLIER / (double)block_reward, 1.992 * 1000 / 1024)); - } - } - } -} diff --git a/tests/unit_tests/json_serialization.cpp b/tests/unit_tests/json_serialization.cpp index aa46b68dc..9525d23ea 100644 --- a/tests/unit_tests/json_serialization.cpp +++ b/tests/unit_tests/json_serialization.cpp @@ -78,7 +78,7 @@ namespace test std::unordered_map<crypto::public_key, cryptonote::subaddress_index> subaddresses; subaddresses[from.m_account_address.m_spend_public_key] = {0,0}; - if (!cryptonote::construct_tx_and_get_tx_key(from, subaddresses, actual_sources, to, boost::none, {}, tx, 0, tx_key, extra_keys, rct, { bulletproof ? rct::RangeProofBulletproof : rct::RangeProofBorromean, bulletproof ? 2 : 0 })) + if (!cryptonote::construct_tx_and_get_tx_key(from, subaddresses, actual_sources, to, boost::none, {}, tx, tx_key, extra_keys, rct, { bulletproof ? rct::RangeProofBulletproof : rct::RangeProofBorromean, bulletproof ? 2 : 0 })) throw std::runtime_error{"transaction construction error"}; return tx; diff --git a/tests/unit_tests/multisig.cpp b/tests/unit_tests/multisig.cpp index a79b81e84..c044591c1 100644 --- a/tests/unit_tests/multisig.cpp +++ b/tests/unit_tests/multisig.cpp @@ -159,12 +159,12 @@ static void check_results(const std::vector<std::string> &intermediate_infos, for (size_t i = 0; i < wallets.size(); ++i) { EXPECT_TRUE(!intermediate_infos[i].empty()); - bool ready; - uint32_t threshold, total; - EXPECT_TRUE(wallets[i].multisig(&ready, &threshold, &total)); - EXPECT_TRUE(ready); - EXPECT_TRUE(threshold == M); - EXPECT_TRUE(total == wallets.size()); + const multisig::multisig_account_status ms_status{wallets[i].get_multisig_status()}; + EXPECT_TRUE(ms_status.multisig_is_active); + EXPECT_TRUE(ms_status.kex_is_done); + EXPECT_TRUE(ms_status.is_ready); + EXPECT_TRUE(ms_status.threshold == M); + EXPECT_TRUE(ms_status.total == wallets.size()); wallets[i].decrypt_keys(""); @@ -226,10 +226,8 @@ static void make_wallets(const unsigned int M, const unsigned int N, const bool } // wallets should not be multisig yet - for (const auto &wallet: wallets) - { - ASSERT_FALSE(wallet.multisig()); - } + for (const auto& wallet: wallets) + ASSERT_FALSE(wallet.get_multisig_status().multisig_is_active); // make wallets multisig, get second round kex messages (if appropriate) std::vector<std::string> intermediate_infos(wallets.size()); @@ -242,16 +240,15 @@ static void make_wallets(const unsigned int M, const unsigned int N, const bool ++rounds_complete; // perform kex rounds until kex is complete - bool ready; - wallets[0].multisig(&ready); - while (!ready) + multisig::multisig_account_status ms_status{wallets[0].get_multisig_status()}; + while (!ms_status.is_ready) { if (force_update) intermediate_infos = exchange_round_force_update(wallets, intermediate_infos, rounds_complete + 1); else intermediate_infos = exchange_round(wallets, intermediate_infos); - wallets[0].multisig(&ready); + ms_status = wallets[0].get_multisig_status(); ++rounds_complete; } diff --git a/tests/unit_tests/scaling_2021.cpp b/tests/unit_tests/scaling_2021.cpp index d90f0f9e6..59e036d10 100644 --- a/tests/unit_tests/scaling_2021.cpp +++ b/tests/unit_tests/scaling_2021.cpp @@ -30,68 +30,26 @@ // - https://github.com/ArticMine/Monero-Documents/blob/master/MoneroScaling2021.pdf // - https://github.com/monero-project/research-lab/issues/70 -#define IN_UNIT_TESTS - #include "gtest/gtest.h" #include "cryptonote_core/blockchain.h" -#include "cryptonote_core/tx_pool.h" -#include "cryptonote_core/cryptonote_core.h" -#include "blockchain_db/testdb.h" - -namespace -{ - -class TestDB: public cryptonote::BaseTestDB -{ -public: - TestDB() { m_open = true; } -}; - -} - -#define PREFIX_WINDOW(hf_version,window) \ - struct get_test_options { \ - const std::pair<uint8_t, uint64_t> hard_forks[3]; \ - const cryptonote::test_options test_options = { \ - hard_forks, \ - window, \ - }; \ - get_test_options(): hard_forks{std::make_pair(1, (uint64_t)0), std::make_pair((uint8_t)hf_version, (uint64_t)1), std::make_pair((uint8_t)0, (uint64_t)0)} {} \ - } opts; \ - cryptonote::BlockchainAndPool bap; \ - cryptonote::Blockchain *blockchain = &bap.blockchain; \ - cryptonote::Blockchain *bc = blockchain; \ - bool r = blockchain->init(new TestDB(), cryptonote::FAKECHAIN, true, &opts.test_options, 0, NULL); \ - ASSERT_TRUE(r) - -#define PREFIX(hf_version) PREFIX_WINDOW(hf_version, TEST_LONG_TERM_BLOCK_WEIGHT_WINDOW) TEST(fee_2021_scaling, relay_fee_cases_from_pdf) { - PREFIX_WINDOW(HF_VERSION_2021_SCALING, CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE); - - ASSERT_EQ(bc->get_dynamic_base_fee(1200000000000, 300000, HF_VERSION_2021_SCALING-1), 8000); - ASSERT_EQ(bc->get_dynamic_base_fee(1200000000000, 300000, HF_VERSION_2021_SCALING), 38000); - ASSERT_EQ(bc->get_dynamic_base_fee(1200000000000, 1425000, HF_VERSION_2021_SCALING-1), 1684 /*1680*/); - ASSERT_EQ(bc->get_dynamic_base_fee(1200000000000, 1425000, HF_VERSION_2021_SCALING), 1684 /*1680*/); - ASSERT_EQ(bc->get_dynamic_base_fee(1200000000000, 1500000, HF_VERSION_2021_SCALING-1), 1600); - ASSERT_EQ(bc->get_dynamic_base_fee(1200000000000, 1500000, HF_VERSION_2021_SCALING), 1520); - - ASSERT_EQ(bc->get_dynamic_base_fee(600000000000, 300000, HF_VERSION_2021_SCALING-1), 4000); - ASSERT_EQ(bc->get_dynamic_base_fee(600000000000, 300000, HF_VERSION_2021_SCALING), 19000); - ASSERT_EQ(bc->get_dynamic_base_fee(600000000000, 1425000, HF_VERSION_2021_SCALING-1), 842 /*840*/); - ASSERT_EQ(bc->get_dynamic_base_fee(600000000000, 1425000, HF_VERSION_2021_SCALING), 842 /*840*/); - ASSERT_EQ(bc->get_dynamic_base_fee(600000000000, 1500000, HF_VERSION_2021_SCALING-1), 800); - ASSERT_EQ(bc->get_dynamic_base_fee(600000000000, 1500000, HF_VERSION_2021_SCALING), 760); + ASSERT_EQ(cryptonote::Blockchain::get_dynamic_base_fee(1200000000000, 300000), 38000); + ASSERT_EQ(cryptonote::Blockchain::get_dynamic_base_fee(1200000000000, 1425000), 1684 /*1680*/); + ASSERT_EQ(cryptonote::Blockchain::get_dynamic_base_fee(1200000000000, 1500000), 1520); + + ASSERT_EQ(cryptonote::Blockchain::get_dynamic_base_fee(600000000000, 300000), 19000); + ASSERT_EQ(cryptonote::Blockchain::get_dynamic_base_fee(600000000000, 1425000), 842 /*840*/); + ASSERT_EQ(cryptonote::Blockchain::get_dynamic_base_fee(600000000000, 1500000), 760); } TEST(fee_2021_scaling, wallet_fee_cases_from_pdf) { - PREFIX_WINDOW(HF_VERSION_2021_SCALING, CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE); std::vector<uint64_t> fees; fees.clear(); - bc->get_dynamic_base_fee_estimate_2021_scaling(10, 600000000000, 300000, 300000, fees); + cryptonote::Blockchain::get_dynamic_base_fee_estimate_2021_scaling(600000000000, 300000, 300000, fees); ASSERT_EQ(fees.size(), 4); ASSERT_EQ(fees[0], 20000); ASSERT_EQ(fees[1], 80000); @@ -99,7 +57,7 @@ TEST(fee_2021_scaling, wallet_fee_cases_from_pdf) ASSERT_EQ(fees[3], 4000000); fees.clear(); - bc->get_dynamic_base_fee_estimate_2021_scaling(10, 600000000000, 15000000, 300000, fees); + cryptonote::Blockchain::get_dynamic_base_fee_estimate_2021_scaling(600000000000, 15000000, 300000, fees); ASSERT_EQ(fees.size(), 4); ASSERT_EQ(fees[0], 20000); ASSERT_EQ(fees[1], 80000); @@ -107,7 +65,7 @@ TEST(fee_2021_scaling, wallet_fee_cases_from_pdf) ASSERT_EQ(fees[3], 1300000); fees.clear(); - bc->get_dynamic_base_fee_estimate_2021_scaling(10, 600000000000, 1425000, 1425000, fees); + cryptonote::Blockchain::get_dynamic_base_fee_estimate_2021_scaling(600000000000, 1425000, 1425000, fees); ASSERT_EQ(fees.size(), 4); ASSERT_EQ(fees[0], 890); ASSERT_EQ(fees[1], 3600); @@ -115,7 +73,7 @@ TEST(fee_2021_scaling, wallet_fee_cases_from_pdf) ASSERT_EQ(fees[3], 850000 /* 842000 */); fees.clear(); - bc->get_dynamic_base_fee_estimate_2021_scaling(10, 600000000000, 1500000, 1500000, fees); + cryptonote::Blockchain::get_dynamic_base_fee_estimate_2021_scaling(600000000000, 1500000, 1500000, fees); ASSERT_EQ(fees.size(), 4); ASSERT_EQ(fees[0], 800); ASSERT_EQ(fees[1], 3200); @@ -123,7 +81,7 @@ TEST(fee_2021_scaling, wallet_fee_cases_from_pdf) ASSERT_EQ(fees[3], 800000); fees.clear(); - bc->get_dynamic_base_fee_estimate_2021_scaling(10, 600000000000, 75000000, 1500000, fees); + cryptonote::Blockchain::get_dynamic_base_fee_estimate_2021_scaling(600000000000, 75000000, 1500000, fees); ASSERT_EQ(fees.size(), 4); ASSERT_EQ(fees[0], 800); ASSERT_EQ(fees[1], 3200); diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index ab81acefc..2af8012ed 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -51,11 +51,21 @@ using namespace std; using namespace crypto; +static_assert(!std::is_trivially_copyable<std::vector<unsigned char>>(), + "should fail to compile when applying blob serializer"); +static_assert(!std::is_trivially_copyable<std::string>(), + "should fail to compile when applying blob serializer"); + struct Struct { int32_t a; int32_t b; char blob[8]; + + bool operator==(const Struct &other) const + { + return a == other.a && b == other.b && 0 == memcmp(blob, other.blob, sizeof(blob)); + } }; template <class Archive> @@ -1207,3 +1217,90 @@ TEST(Serialization, adl_free_function) const std::string expected = "{\"custom_fieldname\": " + std::to_string(msg.size()) + '"' + epee::string_tools::buff_to_hex_nodelimer(msg) + "\"}"; EXPECT_EQ(expected, ss.str()); } + +using Tuple3 = std::tuple<uint16_t, std::string, uint64_t>; +using Tuple4 = std::tuple<int32_t, std::string, uint64_t, Struct>; + +TEST(Serialization, tuple_3_4_backwards_compatibility) +{ + std::string serialized; + + //////////////////////////////////////// + + Tuple3 t3{1876, "Hullabaloo", 1963}; + EXPECT_TRUE(::serialization::dump_binary(t3, serialized)); + + EXPECT_EQ("0354070a48756c6c6162616c6f6fab0f", + epee::string_tools::buff_to_hex_nodelimer(serialized)); + + Tuple3 t3_recovered; + EXPECT_TRUE(::serialization::parse_binary(serialized, t3_recovered)); + EXPECT_EQ(t3, t3_recovered); + + ///////////////////////////////////////// + + Tuple4 t4{1999, "Caneck Caneck", (uint64_t)-1, {20229, 242, {1, 1, 2, 3, 5, 8, 13, 21}}}; + EXPECT_TRUE(::serialization::dump_binary(t4, serialized)); + + EXPECT_EQ("04cf0700000d43616e65636b2043616e65636bffffffffffffffffff01054f0000f20000000101020305080d15", + epee::string_tools::buff_to_hex_nodelimer(serialized)); + + Tuple4 t4_recovered; + EXPECT_TRUE(::serialization::parse_binary(serialized, t4_recovered)); + EXPECT_EQ(t4, t4_recovered); +} + +struct Tupler +{ + std::tuple<> t0; + std::tuple<int8_t> t1; + std::tuple<uint8_t, int16_t> t2; + Tuple3 t3_backcompat; + Tuple3 t3_compact; + Tuple4 t4_backcompat; + Tuple4 t4_compact; + std::tuple<uint32_t, std::string, bool, int64_t, Struct> t5; + + BEGIN_SERIALIZE_OBJECT() + FIELD(t0) + FIELD(t1) + FIELD(t2) + FIELD(t3_backcompat) + TUPLE_COMPACT_FIELD(t3_compact) + FIELD(t4_backcompat) + TUPLE_COMPACT_FIELD(t4_compact) + TUPLE_COMPACT_FIELD(t5) + END_SERIALIZE() +}; + +bool operator==(const Tupler &a, const Tupler &b) +{ + return a.t0 == b.t0 && a.t1 == b.t1 && a.t2 == b.t2 && a.t3_backcompat == b.t3_backcompat && + a.t3_compact == b.t3_compact && a.t4_backcompat == b.t4_backcompat && a.t5 == b.t5; +} + +TEST(Serialization, tuple_many_tuples) +{ + Tupler tupler{ + {}, + {69}, + {42, 420}, + {1876, "Hullabaloo", 1963}, + {1876, "Hullabaloo", 1963}, + {1999, "Caneck Caneck", (uint64_t)-1, {20229, 242, {1, 1, 2, 3, 5, 8, 13, 21}}}, + {1999, "Caneck Caneck", (uint64_t)-1, {20229, 242, {1, 1, 2, 3, 5, 8, 13, 21}}}, + {72982, "He is now rising from affluence to poverty.", false, 256, + { + 13, 37, { 1, 1, 1, 2, 3, 7, 11, 26 } + } + } + }; + + std::string serialized; + EXPECT_TRUE(::serialization::dump_binary(tupler, serialized)); + + Tupler tupler_recovered; + EXPECT_TRUE(::serialization::parse_binary(serialized, tupler_recovered)); + + EXPECT_EQ(tupler, tupler_recovered); +} diff --git a/utils/python-rpc/framework/daemon.py b/utils/python-rpc/framework/daemon.py index c7831d1ee..4ac24332d 100644 --- a/utils/python-rpc/framework/daemon.py +++ b/utils/python-rpc/framework/daemon.py @@ -33,11 +33,12 @@ from .rpc import JSONRPC class Daemon(object): - def __init__(self, protocol='http', host='127.0.0.1', port=0, idx=0, restricted_rpc = False): + def __init__(self, protocol='http', host='127.0.0.1', port=0, idx=0, restricted_rpc = False, username=None, password=None): base = 18480 if restricted_rpc else 18180 self.host = host self.port = port - self.rpc = JSONRPC('{protocol}://{host}:{port}'.format(protocol=protocol, host=host, port=port if port else base+idx)) + self.rpc = JSONRPC('{protocol}://{host}:{port}'.format(protocol=protocol, host=host, port=port if port else base+idx), + username, password) def getblocktemplate(self, address, prev_block = "", client = ""): getblocktemplate = { diff --git a/utils/python-rpc/framework/rpc.py b/utils/python-rpc/framework/rpc.py index 6d9a4b27e..567bdd78d 100644 --- a/utils/python-rpc/framework/rpc.py +++ b/utils/python-rpc/framework/rpc.py @@ -28,6 +28,7 @@ # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. import requests +from requests.auth import HTTPDigestAuth import json class Response(dict): @@ -60,14 +61,17 @@ class Response(dict): return True class JSONRPC(object): - def __init__(self, url): + def __init__(self, url, username=None, password=None): self.url = url + self.username = username + self.password = password def send_request(self, path, inputs, result_field = None): res = requests.post( self.url + path, data=json.dumps(inputs), - headers={'content-type': 'application/json'}) + headers={'content-type': 'application/json'}, + auth=HTTPDigestAuth(self.username, self.password) if self.username is not None else None) res = res.json() assert 'error' not in res, res diff --git a/utils/python-rpc/framework/wallet.py b/utils/python-rpc/framework/wallet.py index 18af4edc4..8fa3eaafd 100644 --- a/utils/python-rpc/framework/wallet.py +++ b/utils/python-rpc/framework/wallet.py @@ -33,10 +33,11 @@ from .rpc import JSONRPC class Wallet(object): - def __init__(self, protocol='http', host='127.0.0.1', port=0, idx=0): + def __init__(self, protocol='http', host='127.0.0.1', port=0, idx=0, username=None, password=None): self.host = host self.port = port - self.rpc = JSONRPC('{protocol}://{host}:{port}'.format(protocol=protocol, host=host, port=port if port else 18090+idx)) + self.rpc = JSONRPC('{protocol}://{host}:{port}'.format(protocol=protocol, host=host, + port=port if port else 18090+idx), username, password) def transfer(self, destinations, account_index = 0, subaddr_indices = [], priority = 0, ring_size = 0, unlock_time = 0, payment_id = '', get_tx_key = True, do_not_relay = False, get_tx_hex = False, get_tx_metadata = False, subtract_fee_from_outputs = []): transfer = { |