diff --git a/.gitignore b/.gitignore index 2c0183090..f7784d8cb 100644 --- a/.gitignore +++ b/.gitignore @@ -118,4 +118,7 @@ tests/data/wallet_9svHk1a.keys # Protobuf files src/cryptonote_core/protobuf/*.pb.cc -src/cryptonote_core/protobuf/*.pb.h \ No newline at end of file +src/cryptonote_core/protobuf/*.pb.h + +# QT creator files +*.user diff --git a/CMakeLists.txt b/CMakeLists.txt index 875e61355..7668357c6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,7 +205,6 @@ enable_testing() option(BUILD_DOCUMENTATION "Build the Doxygen documentation." ON) option(BUILD_TESTS "Build tests." OFF) -option(BUILD_WIN_WALLET_WRAPPER "Build wrapper DLL around wallet API" OFF) # Check whether we're on a 32-bit or 64-bit system if(CMAKE_SIZEOF_VOID_P EQUAL "8") @@ -366,6 +365,9 @@ add_definitions("-DBLOCKCHAIN_DB=${BLOCKCHAIN_DB}") if (APPLE) set(DEFAULT_STACK_TRACE OFF) set(LIBUNWIND_LIBRARIES "") +elseif (DEPENDS AND NOT LINUX) + set(DEFAULT_STACK_TRACE OFF) + set(LIBUNWIND_LIBRARIES "") elseif(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT MINGW) set(DEFAULT_STACK_TRACE ON) set(STACK_TRACE_LIB "easylogging++") # for diag output only @@ -404,6 +406,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "(SunOS|Solaris)") endif () if (APPLE AND NOT IOS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default -std=c++11") if (NOT OpenSSL_DIR) EXECUTE_PROCESS(COMMAND brew --prefix openssl OUTPUT_VARIABLE OPENSSL_ROOT_DIR @@ -478,7 +481,9 @@ if(MSVC) include_directories(SYSTEM src/platform/msc) else() include(TestCXXAcceptsFlag) - set(ARCH native CACHE STRING "CPU to build for: -march value or 'default' to not pass -march at all") + if(NOT DEPENDS) + set(ARCH native CACHE STRING "CPU to build for: -march value or 'default' to not pass -march at all") + endif() message(STATUS "Building on ${CMAKE_SYSTEM_PROCESSOR} for ${ARCH}") if(ARCH STREQUAL "default") set(ARCH_FLAG "") @@ -713,7 +718,7 @@ else() endif() if(APPLE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_HAS_TR1_TUPLE=0") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -DGTEST_HAS_TR1_TUPLE=0") endif() set(DEBUG_FLAGS "-g3") @@ -806,7 +811,11 @@ include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) if(MINGW) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wa,-mbig-obj") set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi;crypt32;bcrypt) - set(ICU_LIBRARIES ${Boost_LOCALE_LIBRARY} icuio icuin icuuc icudt icutu iconv) + if(DEPENDS) + set(ICU_LIBRARIES icuio icui18n icuuc icudata icutu iconv) + else() + set(ICU_LIBRARIES icuio icuin icuuc icudt icutu iconv) + endif() elseif(APPLE OR OPENBSD OR ANDROID) set(EXTRA_LIBRARIES "") elseif(FREEBSD) @@ -816,15 +825,21 @@ elseif(DRAGONFLY) set(EXTRA_LIBRARIES execinfo ${COMPAT}) elseif(CMAKE_SYSTEM_NAME MATCHES "(SunOS|Solaris)") set(EXTRA_LIBRARIES socket nsl resolv) -elseif(NOT MSVC) +elseif(NOT MSVC AND NOT DEPENDS) find_library(RT rt) set(EXTRA_LIBRARIES ${RT}) endif() list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS}) +if (APPLE) + if(DEPENDS) + list(APPEND EXTRA_LIBRARIES "-framework Foundation -framework IOKit") + endif() +endif() + option(USE_READLINE "Build with GNU readline support." ON) -if(USE_READLINE) +if(USE_READLINE AND NOT DEPENDS) find_package(Readline) if(READLINE_FOUND AND GNU_READLINE_FOUND) add_definitions(-DHAVE_READLINE) @@ -834,6 +849,14 @@ if(USE_READLINE) else() message(STATUS "Could not find GNU readline library so building without readline support") endif() +elseif(USE_READLINE AND DEPENDS AND NOT MINGW) + find_path(Readline_INCLUDE_PATH readline/readline.h) + find_library(Readline_LIBRARY readline) + find_library(Terminfo_LIBRARY tinfo) + set(Readline_LIBRARY "${Readline_LIBRARY};${Terminfo_LIBRARY}") + set(GNU_READLINE_LIBRARY ${Readline_LIBRARY}) + add_definitions(-DHAVE_READLINE) + set(EPEE_READLINE epee_readline) endif() if(ANDROID) @@ -904,9 +927,6 @@ option(BUILD_SAFEX_PROTOBUF_RPC "Build PROTOBUF RPC endpoints." OFF) # when ON - it will build safex-advanced-wallet-cli option(BUILD_ADVANCED_WALLET "Build Advanced CLI Wallet." OFF) -#when ON - it will build safex-wallet-rpc -option(BUILD_WALLET_RPC "Build cli rpc wallet server." OFF) - #when ON - it will build multisignature tool #not yet supported for safex option(BUILD_GEN_MULTISIG "Build multisignature tool." OFF) diff --git a/Doxyfile b/Doxyfile index 26979428c..bc331d70a 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,13 +38,13 @@ PROJECT_NAME = "Safex" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = @VERSION_STRING@ # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = +PROJECT_BRIEF = @CPACK_PACKAGE_DESCRIPTION_SUMMARY@ # With the PROJECT_LOGO tag one can specify an logo or icon that is included in # the documentation. The maximum height of the logo should not exceed 55 pixels @@ -68,7 +68,7 @@ OUTPUT_DIRECTORY = doc # performance problems for the file system. # The default value is: NO. -CREATE_SUBDIRS = NO +CREATE_SUBDIRS = YES # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII @@ -309,7 +309,7 @@ AUTOLINK_SUPPORT = YES # diagrams that involve STL classes more complete and accurate. # The default value is: NO. -BUILTIN_STL_SUPPORT = NO +BUILTIN_STL_SUPPORT = YES # If you use Microsoft's C++/CLI language, you should set this option to YES to # enable parsing support. @@ -421,7 +421,7 @@ EXTRACT_PRIVATE = YES # scope will be included in the documentation. # The default value is: NO. -EXTRACT_PACKAGE = NO +EXTRACT_PACKAGE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file will be # included in the documentation. @@ -443,7 +443,7 @@ EXTRACT_LOCAL_CLASSES = YES # included. # The default value is: NO. -EXTRACT_LOCAL_METHODS = NO +EXTRACT_LOCAL_METHODS = YES # If this flag is set to YES, the members of anonymous namespaces will be # extracted and appear in the documentation as a namespace called @@ -489,7 +489,7 @@ HIDE_IN_BODY_DOCS = NO # will be excluded. Set it to YES to include the internal documentation. # The default value is: NO. -INTERNAL_DOCS = NO +INTERNAL_DOCS = YES # If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file # names in lower-case letters. If set to YES upper-case letters are also @@ -754,7 +754,12 @@ WARN_LOGFILE = # spaces. # Note: If this tag is empty the current directory is searched. -INPUT = src +INPUT = README.md \ + contrib/ \ + external/ \ + include/ \ + tests/ \ + src/ # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -774,7 +779,9 @@ INPUT_ENCODING = UTF-8 # *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, # *.qsf, *.as and *.js. -FILE_PATTERNS = +FILE_PATTERNS = *.cpp \ + *.h \ + *.hpp # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -805,7 +812,19 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = *.pb.* \ + tinythread.* \ + fast_mutex.* \ + anyoption.* \ + stacktrace.* \ + */simpleini/* \ + ExportWrapper.* \ + WinsockWrapper.* \ + otapicli.* \ + test*.* \ + irrXML.* \ + */chaiscript/* \ + */zmq/* # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -816,7 +835,7 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = tinythread # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include @@ -903,7 +922,7 @@ USE_MDFILE_AS_MAINPAGE = # also VERBATIM_HEADERS is set to NO. # The default value is: NO. -SOURCE_BROWSER = NO +SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body of functions, # classes and enums directly into the documentation. @@ -1552,7 +1571,7 @@ EXTRA_SEARCH_MAPPINGS = # If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output. # The default value is: YES. -GENERATE_LATEX = YES +GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a # relative path is entered the value of OUTPUT_DIRECTORY will be put in front of @@ -2056,7 +2075,7 @@ HIDE_UNDOC_RELATIONS = YES # set to NO # The default value is: NO. -HAVE_DOT = $(HAVE_DOT) +HAVE_DOT = YES # The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed # to run in parallel. When set to 0 doxygen will base this on the number of diff --git a/Makefile b/Makefile index 784fd246c..4c5034562 100644 --- a/Makefile +++ b/Makefile @@ -34,6 +34,44 @@ cmake-debug: mkdir -p build/debug cd build/debug && cmake -D CMAKE_BUILD_TYPE=Debug ../.. + +libwallet-build: + mkdir -p build/libwallet + cd build/libwallet && cmake -DBUILD_SHARED_LIBS=OFF -DBUILD_GUI_DEPS=ON \ + -DBUILD_TESTS=OFF -DSTATIC=ON -DBOOST_ROOT=${PWD}/boost \ + -DSTATIC=ON \ + -DProtobuf_USE_STATIC_LIBS=OFF \ + -DBUILD_SAFEX_PROTOBUF_RPC=OFF \ + -DARCH="x86-64" -D \ + -DBUILD_64=ON -D \ + -DCMAKE_BUILD_TYPE=release \ + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true \ + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=${PWD}/deps \ + ../.. && $(MAKE) wallet_merged epee easylogging lmdb unbound VERBOSE=1 + +libwallet-build-windows: + cd contrib/depends && $(MAKE) HOST=x86_64-w64-mingw32 + mkdir -p build/libwallet-win + cd build/libwallet-win && cmake -DBUILD_SHARED_LIBS=OFF -DBUILD_GUI_DEPS=OFF \ + -DBUILD_TESTS=OFF -DSTATIC=ON -DBOOST_ROOT=${PWD}/boost \ + -DSTATIC=ON \ + -DProtobuf_USE_STATIC_LIBS=OFF \ + -DBUILD_SAFEX_PROTOBUF_RPC=OFF \ + -DARCH="x86-64" -D \ + -DBUILD_64=ON -D \ + -DCMAKE_BUILD_TYPE=release \ + -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=true \ + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY=${PWD}/deps \ + -DCMAKE_WINDOWS_EXPORT_ALL_SYMBOLS=TRUE \ + -DCMAKE_TOOLCHAIN_FILE=$(CURDIR)/contrib/depends/x86_64-w64-mingw32/share/toolchain.cmake \ + ../.. && $(MAKE) wallet_api VERBOSE=1 + +depends: + cd contrib/depends && $(MAKE) HOST=$(target) && cd ../.. && mkdir -p build/$(target)/release + cd build/$(target)/release && cmake -D STATIC=ON -D Protobuf_USE_STATIC_LIBS=ON -D BUILD_SAFEX_PROTOBUF_RPC=ON \ + -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release \ + -DCMAKE_TOOLCHAIN_FILE=$(CURDIR)/contrib/depends/$(target)/share/toolchain.cmake ../../.. && $(MAKE) + debug: cmake-debug cd build/debug && $(MAKE) @@ -44,14 +82,9 @@ debug-test: cd build/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE) && $(MAKE) ARGS="-E libwallet_api_tests" test debug-all: - mkdir -p build/debug - cd build/debug && cmake -D BUILD_TESTS=ON -D BUILD_SHARED_LIBS=OFF -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE) - -debug-all-protobuf: mkdir -p build/debug cd build/debug && cmake -D BUILD_SAFEX_PROTOBUF_RPC=ON -D BUILD_TESTS=ON -D BUILD_SHARED_LIBS=OFF -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE) - debug-static-all: mkdir -p build/debug cd build/debug && cmake -D BUILD_TESTS=ON -D STATIC=ON -D CMAKE_BUILD_TYPE=Debug ../.. && $(MAKE) @@ -77,21 +110,12 @@ release-all: release-static: mkdir -p build/release - cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_WALLET_RPC=ON ../.. && $(MAKE) - -release-static-proto: - mkdir -p build/release - cd build/release && cmake -D STATIC=ON -D Protobuf_USE_STATIC_LIBS=ON -D BUILD_SAFEX_PROTOBUF_RPC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_WALLET_RPC=ON ../.. && $(MAKE) + cd build/release && cmake -D STATIC=ON -D Protobuf_USE_STATIC_LIBS=ON -D BUILD_SAFEX_PROTOBUF_RPC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE) dist-static: mkdir -p build/dist - cd build/dist && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_WALLET_RPC=ON -D BUILD_ADVANCED_WALLET=ON ../.. && $(MAKE) + cd build/dist && cmake -D STATIC=ON -D Protobuf_USE_STATIC_LIBS=ON -D BUILD_SAFEX_PROTOBUF_RPC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_ADVANCED_WALLET=ON ../.. && $(MAKE) -dist-static-proto: - mkdir -p build/dist - cd build/dist && cmake -D STATIC=ON -D Protobuf_USE_STATIC_LIBS=ON -D BUILD_SAFEX_PROTOBUF_RPC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_WALLET_RPC=ON -D BUILD_ADVANCED_WALLET=ON ../.. && $(MAKE) - - coverage: mkdir -p build/debug @@ -124,10 +148,6 @@ release-static-freebsd-x86_64: cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="freebsd-x64" ../.. && $(MAKE) release-static-mac-x86_64: - mkdir -p build/release - cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="mac-x64" ../.. && $(MAKE) - -release-static-mac-x86_64-proto: mkdir -p build/release cd build/release && cmake -D Protobuf_USE_STATIC_LIBS=ON -D BUILD_SAFEX_PROTOBUF_RPC=ON -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="mac-x64" ../.. && $(MAKE) @@ -136,10 +156,6 @@ release-static-linux-i686: cd build/release && cmake -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release -D BUILD_TAG="linux-x86" ../.. && $(MAKE) release-static-win64: - mkdir -p build/release - cd build/release && cmake -G "MSYS Makefiles" -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=../../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 ../.. && $(MAKE) - -release-static-win64-proto: mkdir -p build/release cd build/release && cmake -G "MSYS Makefiles" -D Protobuf_USE_STATIC_LIBS=ON -D BUILD_SAFEX_PROTOBUF_RPC=ON -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=Release -D BUILD_TAG="win-x64" -D CMAKE_TOOLCHAIN_FILE=../../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 ../.. && $(MAKE) @@ -160,6 +176,8 @@ clean: read -r -p "This will destroy the build directory, continue (y/N)?: " CONTINUE; \ [ $$CONTINUE = "y" ] || [ $$CONTINUE = "Y" ] || (echo "Exiting."; exit 1;) rm -rf build +documentation: + doxygen Doxyfile tags: ctags -R --sort=1 --c++-kinds=+p --fields=+iaS --extra=+q --language-force=C++ src contrib tests/gtest diff --git a/contrib/depends/.gitignore b/contrib/depends/.gitignore new file mode 100644 index 000000000..3cb4b9ac1 --- /dev/null +++ b/contrib/depends/.gitignore @@ -0,0 +1,10 @@ +SDKs/ +work/ +built/ +sources/ +config.site +x86_64* +i686* +mips* +arm* +aarch64* diff --git a/contrib/depends/Makefile b/contrib/depends/Makefile new file mode 100644 index 000000000..28ec972e4 --- /dev/null +++ b/contrib/depends/Makefile @@ -0,0 +1,232 @@ +.NOTPARALLEL : + +SOURCES_PATH ?= $(BASEDIR)/sources +BASE_CACHE ?= $(BASEDIR)/built +SDK_PATH ?= $(BASEDIR)/SDKs +FALLBACK_DOWNLOAD_PATH ?= https://bitcoincore.org/depends-sources + +BUILD = $(shell ./config.guess) +HOST ?= $(BUILD) +PATCHES_PATH = $(BASEDIR)/patches +BASEDIR = $(CURDIR) +HASH_LENGTH:=11 +DOWNLOAD_CONNECT_TIMEOUT:=10 +DOWNLOAD_RETRIES:=3 +HOST_ID_SALT ?= salt +BUILD_ID_SALT ?= salt + +host:=$(BUILD) +ifneq ($(HOST),) +host:=$(HOST) +host_toolchain:=$(HOST)- +endif + +ifneq ($(DEBUG),) +release_type=Debug +else +release_type=Release +endif + +ifneq ($(TESTS),) +build_tests=ON +release_type=Debug +else +build_tests=OFF +endif + +base_build_dir=$(BASEDIR)/work/build +base_staging_dir=$(BASEDIR)/work/staging +base_download_dir=$(BASEDIR)/work/download +canonical_host:=$(shell ./config.sub $(HOST)) +build:=$(shell ./config.sub $(BUILD)) + +build_arch =$(firstword $(subst -, ,$(build))) +build_vendor=$(word 2,$(subst -, ,$(build))) +full_build_os:=$(subst $(build_arch)-$(build_vendor)-,,$(build)) +build_os:=$(findstring linux,$(full_build_os)) +build_os+=$(findstring darwin,$(full_build_os)) +build_os:=$(strip $(build_os)) +ifeq ($(build_os),) +build_os=$(full_build_os) +endif + +host_arch=$(firstword $(subst -, ,$(canonical_host))) +host_vendor=$(word 2,$(subst -, ,$(canonical_host))) +full_host_os:=$(subst $(host_arch)-$(host_vendor)-,,$(canonical_host)) +host_os:=$(findstring android,$(full_host_os)) +ifeq ($(host_os),) +host_os:=$(findstring linux,$(full_host_os)) +endif +host_os+=$(findstring darwin,$(full_host_os)) +host_os+=$(findstring freebsd,$(full_host_os)) +host_os+=$(findstring mingw32,$(full_host_os)) +host_os:=$(strip $(host_os)) +ifeq ($(host_os),) +host_os=$(full_host_os) +endif + +$(host_arch)_$(host_os)_prefix=$(BASEDIR)/$(host) +$(host_arch)_$(host_os)_host=$(host) +host_prefix=$($(host_arch)_$(host_os)_prefix) +build_prefix=$(host_prefix)/native +ifeq ($(host_os),mingw32) +host_cmake=Windows +endif +ifeq ($(host_os),linux) +host_cmake=Linux +endif +ifeq ($(host_os),freebsd) +host_cmake=FreeBSD +endif +ifeq ($(host_os),darwin) +host_cmake=Darwin +endif +ifeq ($(host_os),android) +host_cmake=Android +endif + +AT_$(V):= +AT_:=@ +AT:=$(AT_$(V)) + +all: install + +include hosts/$(host_os).mk +include hosts/default.mk +include builders/$(build_os).mk +include builders/default.mk +include packages/packages.mk + +build_id_string:=$(BUILD_ID_SALT) +build_id_string+=$(shell $(build_CC) --version 2>/dev/null) +build_id_string+=$(shell $(build_AR) --version 2>/dev/null) +build_id_string+=$(shell $(build_CXX) --version 2>/dev/null) +build_id_string+=$(shell $(build_RANLIB) --version 2>/dev/null) +build_id_string+=$(shell $(build_STRIP) --version 2>/dev/null) + +$(host_arch)_$(host_os)_id_string:=$(HOST_ID_SALT) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_CC) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_AR) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_CXX) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_RANLIB) --version 2>/dev/null) +$(host_arch)_$(host_os)_id_string+=$(shell $(host_STRIP) --version 2>/dev/null) + +qt_packages_$(NO_QT) = $(qt_packages) +packages += $($(host_arch)_$(host_os)_packages) $($(host_os)_packages) $(qt_packages_) +native_packages += $($(host_arch)_$(host_os)_native_packages) $($(host_os)_native_packages) + +all_packages = $(packages) $(native_packages) + +meta_depends = Makefile funcs.mk builders/default.mk hosts/default.mk hosts/$(host_os).mk builders/$(build_os).mk + +$(host_arch)_$(host_os)_native_toolchain?=$($(host_os)_native_toolchain) + +include funcs.mk + +CONF_PKGS := cmake-conf mxe-conf + +build-only-$(1)_$(3): CMAKE_RUNRESULT_FILE = $(PREFIX)/share/cmake/modules/TryRunResults.cmake +build-only-$(1)_$(3): CMAKE_TOOLCHAIN_FILE = $(PREFIX)/$(3)/share/cmake/mxe-conf.cmake +build-only-$(1)_$(3): CMAKE_TOOLCHAIN_DIR = $(PREFIX)/$(3)/share/cmake/mxe-conf.d +build-only-$(1)_$(3): CMAKE_STATIC_BOOL = $(if $(findstring shared,$(3)),OFF,ON) +build-only-$(1)_$(3): CMAKE_SHARED_BOOL = $(if $(findstring shared,$(3)),ON,OFF) + + +toolchain_path=$($($(host_arch)_$(host_os)_native_toolchain)_prefixbin) +final_build_id_long+=$(shell $(build_SHA256SUM) config.site.in) +final_build_id_long+=$(shell $(build_SHA256SUM) toolchain.cmake.in) +final_build_id+=$(shell echo -n "$(final_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH)) +$(host_prefix)/.stamp_$(final_build_id): $(native_packages) $(packages) + $(AT)rm -rf $(@D) + $(AT)mkdir -p $(@D) + $(AT)echo copying packages: $^ + $(AT)echo to: $(@D) + $(AT)cd $(@D); $(foreach package,$^, tar xf $($(package)_cached); ) + $(AT)touch $@ + +$(host_prefix)/share/config.site : config.site.in $(host_prefix)/.stamp_$(final_build_id) + $(AT)@mkdir -p $(@D) + $(AT)sed -e 's|@HOST@|$(host)|' \ + -e 's|@CC@|$(toolchain_path)$(host_CC)|' \ + -e 's|@CXX@|$(toolchain_path)$(host_CXX)|' \ + -e 's|@AR@|$(toolchain_path)$(host_AR)|' \ + -e 's|@RANLIB@|$(toolchain_path)$(host_RANLIB)|' \ + -e 's|@NM@|$(toolchain_path)$(host_NM)|' \ + -e 's|@STRIP@|$(toolchain_path)$(host_STRIP)|' \ + -e 's|@build_os@|$(build_os)|' \ + -e 's|@host_os@|$(host_os)|' \ + -e 's|@CFLAGS@|$(strip $(host_CFLAGS) $(host_$(release_type)_CFLAGS))|' \ + -e 's|@CXXFLAGS@|$(strip $(host_CXXFLAGS) $(host_$(release_type)_CXXFLAGS))|' \ + -e 's|@CPPFLAGS@|$(strip $(host_CPPFLAGS) $(host_$(release_type)_CPPFLAGS))|' \ + -e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \ + -e 's|@allow_host_packages@|$(ALLOW_HOST_PACKAGES)|' \ + -e 's|@debug@|$(DEBUG)|' \ + $< > $@ + $(AT)touch $@ + +$(host_prefix)/share/toolchain.cmake : toolchain.cmake.in $(host_prefix)/.stamp_$(final_build_id) + $(AT)@mkdir -p $(@D) + $(AT)sed -e 's|@HOST@|$(host)|' \ + -e 's|@CC@|$(toolchain_path)$(host_CC)|' \ + -e 's|@CXX@|$(toolchain_path)$(host_CXX)|' \ + -e 's|@AR@|$(toolchain_path)$(host_AR)|' \ + -e 's|@RANLIB@|$(toolchain_path)$(host_RANLIB)|' \ + -e 's|@NM@|$(toolchain_path)$(host_NM)|' \ + -e 's|@STRIP@|$(toolchain_path)$(host_STRIP)|' \ + -e 's|@build_os@|$(build_os)|' \ + -e 's|@host_os@|$(host_os)|' \ + -e 's|@CFLAGS@|$(strip $(host_CFLAGS) $(host_$(release_type)_CFLAGS))|' \ + -e 's|@CXXFLAGS@|$(strip $(host_CXXFLAGS) $(host_$(release_type)_CXXFLAGS))|' \ + -e 's|@CPPFLAGS@|$(strip $(host_CPPFLAGS) $(host_$(release_type)_CPPFLAGS))|' \ + -e 's|@LDFLAGS@|$(strip $(host_LDFLAGS) $(host_$(release_type)_LDFLAGS))|' \ + -e 's|@allow_host_packages@|$(ALLOW_HOST_PACKAGES)|' \ + -e 's|@debug@|$(DEBUG)|' \ + -e 's|@release_type@|$(release_type)|' \ + -e 's|@build_tests@|$(build_tests)|' \ + -e 's|@depends@|$(host_cmake)|' \ + -e 's|@prefix@|$($(host_arch)_$(host_os)_prefix)|'\ + -e 's|@sdk@|$(SDK_PATH)|'\ + -e 's|@arch@|$(host_arch)|'\ + $< > $@ + $(AT)touch $@ + +define check_or_remove_cached + mkdir -p $(BASE_CACHE)/$(host)/$(package) && cd $(BASE_CACHE)/$(host)/$(package); \ + $(build_SHA256SUM) -c $($(package)_cached_checksum) >/dev/null 2>/dev/null || \ + ( rm -f $($(package)_cached_checksum); \ + if test -f "$($(package)_cached)"; then echo "Checksum mismatch for $(package). Forcing rebuild.."; rm -f $($(package)_cached_checksum) $($(package)_cached); fi ) +endef + +define check_or_remove_sources + mkdir -p $($(package)_source_dir); cd $($(package)_source_dir); \ + test -f $($(package)_fetched) && ( $(build_SHA256SUM) -c $($(package)_fetched) >/dev/null 2>/dev/null || \ + ( echo "Checksum missing or mismatched for $(package) source. Forcing re-download."; \ + rm -f $($(package)_all_sources) $($(1)_fetched))) || true +endef + +check-packages: + @$(foreach package,$(all_packages),$(call check_or_remove_cached,$(package));) +check-sources: + @$(foreach package,$(all_packages),$(call check_or_remove_sources,$(package));) + +$(host_prefix)/share/config.site: check-packages +$(host_prefix)/share/toolchain.cmake: check-packages + +check-packages: check-sources + +install: check-packages $(host_prefix)/share/config.site +install: check-packages $(host_prefix)/share/toolchain.cmake + +download-one: check-sources $(all_sources) + +download-osx: + @$(MAKE) -s HOST=x86_64-apple-darwin11 download-one +download-linux: + @$(MAKE) -s HOST=x86_64-unknown-linux-gnu download-one +download-win: + @$(MAKE) -s HOST=x86_64-w64-mingw32 download-one +download: download-osx download-linux download-win + + $(foreach package,$(all_packages),$(eval $(call ext_add_stages,$(package)))) + +.PHONY: install cached download-one download-osx download-linux download-win download check-packages check-sources diff --git a/contrib/depends/README.md b/contrib/depends/README.md new file mode 100644 index 000000000..10866acbe --- /dev/null +++ b/contrib/depends/README.md @@ -0,0 +1,83 @@ +### Usage + +To build dependencies for the current arch+OS: + +```bash +make +``` + +To build for another arch/OS: + +```bash +make HOST=host-platform-triplet +``` + +For example: + +```bash +make HOST=x86_64-w64-mingw32 -j4 +``` + +A toolchain will be generated that's suitable for plugging into Monero's +cmake. In the above example, a dir named x86_64-w64-mingw32 will be +created. To use it for Monero: + +```bash +cmake -DCMAKE_TOOLCHAIN=`pwd`/contrib/depends/x86_64-w64-mingw32 +``` + +Common `host-platform-triplets` for cross compilation are: + +- `i686-w64-mingw32` for Win32 +- `x86_64-w64-mingw32` for Win64 +- `x86_64-apple-darwin11` for MacOSX +- `arm-linux-gnueabihf` for Linux ARM 32 bit +- `aarch64-linux-gnu` for Linux ARM 64 bit +- `riscv64-linux-gnu` for Linux RISCV 64 bit + +No other options are needed, the paths are automatically configured. + +Dependency Options: +The following can be set when running make: make FOO=bar + +``` +SOURCES_PATH: downloaded sources will be placed here +BASE_CACHE: built packages will be placed here +SDK_PATH: Path where sdk's can be found (used by OSX) +FALLBACK_DOWNLOAD_PATH: If a source file can't be fetched, try here before giving up +DEBUG: disable some optimizations and enable more runtime checking +HOST_ID_SALT: Optional salt to use when generating host package ids +BUILD_ID_SALT: Optional salt to use when generating build package ids +``` + +Additional targets: + +``` +download: run 'make download' to fetch all sources without building them +download-osx: run 'make download-osx' to fetch all sources needed for osx builds +download-win: run 'make download-win' to fetch all sources needed for win builds +download-linux: run 'make download-linux' to fetch all sources needed for linux builds +``` + +#Darwin (macos) builds: + +To build with the x86_64-apple-darwin11 you require the mac os developer tools in MacOSX10.11.sdk. +Download it from apple, or search for it on github. Create a new directoty called SDKs in this +directory and place the entire MacOSX10.11.sdk folder in it. The depends build will then pick it up automatically +(without requiring SDK_PATH). + + +#Mingw builds + +Building for 32/64bit mingw requires switching alternatives to a posix mode + +```bash +update-alternatives --set x86_64-w64-mingw32-g++ x86_64-w64-mingw32-g++-posix +update-alternatives --set x86_64-w64-mingw32-gcc x86_64-w64-mingw32-gcc-posix +``` + +### Other documentation + +- [description.md](description.md): General description of the depends system +- [packages.md](packages.md): Steps for adding packages + diff --git a/contrib/depends/builders/darwin.mk b/contrib/depends/builders/darwin.mk new file mode 100644 index 000000000..27f550ab0 --- /dev/null +++ b/contrib/depends/builders/darwin.mk @@ -0,0 +1,22 @@ +build_darwin_CC: = $(shell xcrun -f clang) +build_darwin_CXX: = $(shell xcrun -f clang++) +build_darwin_AR: = $(shell xcrun -f ar) +build_darwin_RANLIB: = $(shell xcrun -f ranlib) +build_darwin_STRIP: = $(shell xcrun -f strip) +build_darwin_OTOOL: = $(shell xcrun -f otool) +build_darwin_NM: = $(shell xcrun -f nm) +build_darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) +build_darwin_SHA256SUM = shasum -a 256 +build_darwin_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o + +#darwin host on darwin builder. overrides darwin host preferences. +darwin_CC=$(shell xcrun -f clang) -mmacosx-version-min=$(OSX_MIN_VERSION) +darwin_CXX:=$(shell xcrun -f clang++) -mmacosx-version-min=$(OSX_MIN_VERSION) -stdlib=libc++ +darwin_AR:=$(shell xcrun -f ar) +darwin_RANLIB:=$(shell xcrun -f ranlib) +darwin_STRIP:=$(shell xcrun -f strip) +darwin_LIBTOOL:=$(shell xcrun -f libtool) +darwin_OTOOL:=$(shell xcrun -f otool) +darwin_NM:=$(shell xcrun -f nm) +darwin_INSTALL_NAME_TOOL:=$(shell xcrun -f install_name_tool) +darwin_native_toolchain= diff --git a/contrib/depends/builders/default.mk b/contrib/depends/builders/default.mk new file mode 100644 index 000000000..c4191435d --- /dev/null +++ b/contrib/depends/builders/default.mk @@ -0,0 +1,20 @@ +default_build_CC = gcc +default_build_CXX = g++ +default_build_AR = ar +default_build_RANLIB = ranlib +default_build_STRIP = strip +default_build_NM = nm +default_build_OTOOL = otool +default_build_INSTALL_NAME_TOOL = install_name_tool + +define add_build_tool_func +build_$(build_os)_$1 ?= $$(default_build_$1) +build_$(build_arch)_$(build_os)_$1 ?= $$(build_$(build_os)_$1) +build_$1=$$(build_$(build_arch)_$(build_os)_$1) +endef +$(foreach var,CC CXX AR RANLIB NM STRIP SHA256SUM DOWNLOAD OTOOL INSTALL_NAME_TOOL,$(eval $(call add_build_tool_func,$(var)))) +define add_build_flags_func +build_$(build_arch)_$(build_os)_$1 += $(build_$(build_os)_$1) +build_$1=$$(build_$(build_arch)_$(build_os)_$1) +endef +$(foreach flags, CFLAGS CXXFLAGS ARFLAGS LDFLAGS, $(eval $(call add_build_flags_func,$(flags)))) diff --git a/contrib/depends/builders/linux.mk b/contrib/depends/builders/linux.mk new file mode 100644 index 000000000..b03f42401 --- /dev/null +++ b/contrib/depends/builders/linux.mk @@ -0,0 +1,2 @@ +build_linux_SHA256SUM = sha256sum +build_linux_DOWNLOAD = curl --location --fail --connect-timeout $(DOWNLOAD_CONNECT_TIMEOUT) --retry $(DOWNLOAD_RETRIES) -o diff --git a/contrib/depends/config.guess b/contrib/depends/config.guess new file mode 100755 index 000000000..69ed3e573 --- /dev/null +++ b/contrib/depends/config.guess @@ -0,0 +1,1466 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright 1992-2017 Free Software Foundation, Inc. + +timestamp='2017-03-05' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). +# +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. +# +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# +# Please send patches to . + + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright 1992-2017 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +case "${UNAME_SYSTEM}" in +Linux|GNU|GNU/*) + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + LIBC=gnu + + eval $set_cc_for_build + cat <<-EOF > $dummy.c + #include + #if defined(__UCLIBC__) + LIBC=uclibc + #elif defined(__dietlibc__) + LIBC=dietlibc + #else + LIBC=gnu + #endif + EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + ;; +esac + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently (or will in the future) and ABI. + case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}${abi}" + exit ;; + *:Bitrig:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE=alpha ;; + "EV4.5 (21064)") + UNAME_MACHINE=alpha ;; + "LCA4 (21066/21068)") + UNAME_MACHINE=alpha ;; + "EV5 (21164)") + UNAME_MACHINE=alphaev5 ;; + "EV5.6 (21164A)") + UNAME_MACHINE=alphaev56 ;; + "EV5.6 (21164PC)") + UNAME_MACHINE=alphapca56 ;; + "EV5.7 (21164PC)") + UNAME_MACHINE=alphapca57 ;; + "EV6 (21264)") + UNAME_MACHINE=alphaev6 ;; + "EV6.7 (21264A)") + UNAME_MACHINE=alphaev67 ;; + "EV6.8CB (21264C)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8AL (21264B)") + UNAME_MACHINE=alphaev68 ;; + "EV6.8CX (21264D)") + UNAME_MACHINE=alphaev68 ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE=alphaev69 ;; + "EV7 (21364)") + UNAME_MACHINE=alphaev7 ;; + "EV7.9 (21364A)") + UNAME_MACHINE=alphaev79 ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + exitcode=$? + trap '' 0 + exit $exitcode ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm*:riscos:*:*|arm*:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) + echo i386-pc-auroraux${UNAME_RELEASE} + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH=i386 + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH=x86_64 + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[4567]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = hppa2.0w ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH=hppa2.0w + else + HP_ARCH=hppa64 + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + UNAME_PROCESSOR=`/usr/bin/uname -p` + case ${UNAME_PROCESSOR} in + amd64) + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; + esac + echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW64*:*) + echo ${UNAME_MACHINE}-pc-mingw64 + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + *:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + authenticamd | genuineintel | EM64T) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + aarch64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + aarch64_be:Linux:*:*) + UNAME_MACHINE=aarch64_be + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arc:Linux:*:* | arceb:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + else + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + else + echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + fi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + cris:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + crisv32:Linux:*:*) + echo ${UNAME_MACHINE}-axis-linux-${LIBC} + exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + frv:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + hexagon:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + ;; + mips64el:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-${LIBC} + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; + PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; + *) echo hppa-unknown-linux-${LIBC} ;; + esac + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-${LIBC} + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-${LIBC} + exit ;; + ppc64le:Linux:*:*) + echo powerpc64le-unknown-linux-${LIBC} + exit ;; + ppcle:Linux:*:*) + echo powerpcle-unknown-linux-${LIBC} + exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux-${LIBC} + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + tile*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-${LIBC} + exit ;; + x86_64:Linux:*:*) + echo ${UNAME_MACHINE}-pc-linux-${LIBC} + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configure will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + x86_64:Haiku:*:*) + echo x86_64-unknown-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + eval $set_cc_for_build + if test "$UNAME_PROCESSOR" = unknown ; then + UNAME_PROCESSOR=powerpc + fi + if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + fi + elif test "$UNAME_PROCESSOR" = i386 ; then + # Avoid executing cc on OS X 10.9, as it ships with a stub + # that puts up a graphical alert prompting to install + # developer tools. Any system running Mac OS X 10.7 or + # later (Darwin 11 and later) is required to have a 64-bit + # processor. This is not true of the ARM version of Darwin + # that Apple uses in portable devices. + UNAME_PROCESSOR=x86_64 + fi + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = x86; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NEO-?:NONSTOP_KERNEL:*:*) + echo neo-tandem-nsk${UNAME_RELEASE} + exit ;; + NSE-*:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + NSX-?:NONSTOP_KERNEL:*:*) + echo nsx-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = 386; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; + x86_64:VMkernel:*:*) + echo ${UNAME_MACHINE}-unknown-esx + exit ;; + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs + exit ;; +esac + +cat >&2 </dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/contrib/depends/config.site.in b/contrib/depends/config.site.in new file mode 100644 index 000000000..dd91bcb2a --- /dev/null +++ b/contrib/depends/config.site.in @@ -0,0 +1,81 @@ +depends_prefix="`dirname ${ac_site_file}`/.." + +cross_compiling=maybe +host_alias=@HOST@ +ac_tool_prefix=${host_alias}- + +if test -z $with_boost; then + with_boost=$depends_prefix +fi +if test -z $with_qt_plugindir; then + with_qt_plugindir=$depends_prefix/plugins +fi +if test -z $with_qt_translationdir; then + with_qt_translationdir=$depends_prefix/translations +fi + +if test x@host_os@ = xdarwin; then + BREW=no + PORT=no +fi + +if test x@host_os@ = xmingw32; then + if test -z $with_qt_incdir; then + with_qt_incdir=$depends_prefix/include + fi + if test -z $with_qt_libdir; then + with_qt_libdir=$depends_prefix/lib + fi +fi + +PATH=$depends_prefix/native/bin:$PATH +PKG_CONFIG="`which pkg-config` --static" + +# These two need to remain exported because pkg-config does not see them +# otherwise. That means they must be unexported at the end of configure.ac to +# avoid ruining the cache. Sigh. +export PKG_CONFIG_PATH=$depends_prefix/share/pkgconfig:$depends_prefix/lib/pkgconfig +if test -z "@allow_host_packages@"; then + export PKGCONFIG_LIBDIR= +fi + +CPPFLAGS="-I$depends_prefix/include/ $CPPFLAGS" +LDFLAGS="-L$depends_prefix/lib $LDFLAGS" + +CC="@CC@" +CXX="@CXX@" +OBJC="${CC}" +CCACHE=$depends_prefix/native/bin/ccache +PYTHONPATH=$depends_prefix/native/lib/python/dist-packages:$PYTHONPATH + +if test -n "@AR@"; then + AR=@AR@ + ac_cv_path_ac_pt_AR=${AR} +fi + +if test -n "@RANLIB@"; then + RANLIB=@RANLIB@ + ac_cv_path_ac_pt_RANLIB=${RANLIB} +fi + +if test -n "@NM@"; then + NM=@NM@ + ac_cv_path_ac_pt_NM=${NM} +fi + +if test -n "@debug@"; then + enable_reduce_exports=no +fi + +if test -n "@CFLAGS@"; then + CFLAGS="@CFLAGS@ $CFLAGS" +fi +if test -n "@CXXFLAGS@"; then + CXXFLAGS="@CXXFLAGS@ $CXXFLAGS" +fi +if test -n "@CPPFLAGS@"; then + CPPFLAGS="@CPPFLAGS@ $CPPFLAGS" +fi +if test -n "@LDFLAGS@"; then + LDFLAGS="@LDFLAGS@ $LDFLAGS" +fi diff --git a/contrib/depends/config.sub b/contrib/depends/config.sub new file mode 100755 index 000000000..40ea5dfe1 --- /dev/null +++ b/contrib/depends/config.sub @@ -0,0 +1,1836 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright 1992-2017 Free Software Foundation, Inc. + +timestamp='2017-04-02' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that +# program. This Exception is an additional permission under section 7 +# of the GNU General Public License, version 3 ("GPLv3"). + + +# Please send patches to . +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# You can get the latest version of this script from: +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright 1992-2017 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ + linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + android-linux) + os=-linux-android + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray | -microblaze*) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*178) + os=-lynxos178 + ;; + -lynx*5) + os=-lynxos5 + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arceb \ + | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ + | avr | avr32 \ + | ba \ + | be32 | be64 \ + | bfin \ + | c4x | c8051 | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i860 | i960 | ia16 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nios | nios2 | nios2eb | nios2el \ + | ns16k | ns32k \ + | open8 | or1k | or1knd | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle \ + | pru \ + | pyramid \ + | riscv32 | riscv64 \ + | rl78 | rx \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu \ + | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ + | ubicom32 \ + | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ + | wasm32 \ + | we32k \ + | x86 | xc16x | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + c54x) + basic_machine=tic54x-unknown + ;; + c55x) + basic_machine=tic55x-unknown + ;; + c6x) + basic_machine=tic6x-unknown + ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; + m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + strongarm | thumb | xscale) + basic_machine=arm-unknown + ;; + xgate) + basic_machine=$basic_machine-unknown + os=-none + ;; + xscaleeb) + basic_machine=armeb-unknown + ;; + + xscaleel) + basic_machine=armel-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | aarch64-* | aarch64_be-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | ba-* \ + | be32-* | be64-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* \ + | c8051-* | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | e2k-* | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | hexagon-* \ + | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ + | ip2k-* | iq2000-* \ + | k1om-* \ + | le32-* | le64-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | microblaze-* | microblazeel-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipsr5900-* | mipsr5900el-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nds32-* | nds32le-* | nds32be-* \ + | nios-* | nios2-* | nios2eb-* | nios2el-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | open8-* \ + | or1k*-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ + | pru-* \ + | pyramid-* \ + | riscv32-* | riscv64-* \ + | rl78-* | romp-* | rs6000-* | rx-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ + | tahoe-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tile*-* \ + | tron-* \ + | ubicom32-* \ + | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ + | vax-* \ + | visium-* \ + | wasm32-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + asmjs) + basic_machine=asmjs-unknown + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c54x-*) + basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c55x-*) + basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c6x-*) + basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16 | cr16-*) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + microblaze*) + basic_machine=microblaze-xilinx + ;; + mingw64) + basic_machine=x86_64-pc + os=-mingw64 + ;; + mingw32) + basic_machine=i686-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + msys) + basic_machine=i686-pc + os=-msys + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + nacl) + basic_machine=le32-unknown + os=-nacl + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + neo-tandem) + basic_machine=neo-tandem + ;; + nse-tandem) + basic_machine=nse-tandem + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + nsx-tandem) + basic_machine=nsx-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc | ppcbe) basic_machine=powerpc-unknown + ;; + ppc-* | ppcbe-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + os=-rdos + ;; + rdos32) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + strongarm-* | thumb-*) + basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tile*) + basic_machine=$basic_machine-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + wasm32) + basic_machine=wasm32-unknown + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + xscale-* | xscalee[bl]-*) + basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -auroraux) + os=-auroraux + ;; + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ + | -sym* | -kopensolaris* | -plan9* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -linux-newlib* | -linux-musl* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -nacl*) + ;; + -ios) + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + c8051-*) + os=-elf + ;; + hexagon-*) + os=-elf + ;; + tic54x-*) + os=-coff + ;; + tic55x-*) + os=-coff + ;; + tic6x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + pru-*) + os=-elf + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/contrib/depends/description.md b/contrib/depends/description.md new file mode 100644 index 000000000..74f9ef3f2 --- /dev/null +++ b/contrib/depends/description.md @@ -0,0 +1,53 @@ +This is a system of building and caching dependencies necessary for building Bitcoin. +There are several features that make it different from most similar systems: + +### It is designed to be builder and host agnostic + +In theory, binaries for any target OS/architecture can be created, from a +builder running any OS/architecture. In practice, build-side tools must be +specified when the defaults don't fit, and packages must be amended to work +on new hosts. For now, a build architecture of x86_64 is assumed, either on +Linux or OSX. + +### No reliance on timestamps + +File presence is used to determine what needs to be built. This makes the +results distributable and easily digestable by automated builders. + +### Each build only has its specified dependencies available at build-time. + +For each build, the sysroot is wiped and the (recursive) dependencies are +installed. This makes each build deterministic, since there will never be any +unknown files available to cause side-effects. + +### Each package is cached and only rebuilt as needed. + +Before building, a unique build-id is generated for each package. This id +consists of a hash of all files used to build the package (Makefiles, packages, +etc), and as well as a hash of the same data for each recursive dependency. If +any portion of a package's build recipe changes, it will be rebuilt as well as +any other package that depends on it. If any of the main makefiles (Makefile, +funcs.mk, etc) are changed, all packages will be rebuilt. After building, the +results are cached into a tarball that can be re-used and distributed. + +### Package build results are (relatively) deterministic. + +Each package is configured and patched so that it will yield the same +build-results with each consequent build, within a reasonable set of +constraints. Some things like timestamp insertion are unavoidable, and are +beyond the scope of this system. Additionally, the toolchain itself must be +capable of deterministic results. When revisions are properly bumped, a cached +build should represent an exact single payload. + +### Sources are fetched and verified automatically + +Each package must define its source location and checksum. The build will fail +if the fetched source does not match. Sources may be pre-seeded and/or cached +as desired. + +### Self-cleaning + +Build and staging dirs are wiped after use, and any previous version of a +cached result is removed following a successful build. Automated builders +should be able to build each revision and store the results with no further +intervention. diff --git a/contrib/depends/funcs.mk b/contrib/depends/funcs.mk new file mode 100644 index 000000000..2d6b37190 --- /dev/null +++ b/contrib/depends/funcs.mk @@ -0,0 +1,262 @@ +define int_vars +#Set defaults for vars which may be overridden per-package +$(1)_cc=$($($(1)_type)_CC) +$(1)_cxx=$($($(1)_type)_CXX) +$(1)_objc=$($($(1)_type)_OBJC) +$(1)_objcxx=$($($(1)_type)_OBJCXX) +$(1)_ar=$($($(1)_type)_AR) +$(1)_ranlib=$($($(1)_type)_RANLIB) +$(1)_libtool=$($($(1)_type)_LIBTOOL) +$(1)_nm=$($($(1)_type)_NM) +$(1)_cflags=$($($(1)_type)_CFLAGS) $($($(1)_type)_$(release_type)_CFLAGS) +$(1)_cxxflags=$($($(1)_type)_CXXFLAGS) $($($(1)_type)_$(release_type)_CXXFLAGS) +$(1)_arflags=$($($(1)_type)_ARFLAGS) $($($(1)_type)_$(release_type)_ARFLAGS) +$(1)_ldflags=$($($(1)_type)_LDFLAGS) $($($(1)_type)_$(release_type)_LDFLAGS) -L$($($(1)_type)_prefix)/lib +$(1)_cppflags=$($($(1)_type)_CPPFLAGS) $($($(1)_type)_$(release_type)_CPPFLAGS) -I$($($(1)_type)_prefix)/include +$(1)_recipe_hash:= +endef + +define int_get_all_dependencies +$(sort $(foreach dep,$(2),$(2) $(call int_get_all_dependencies,$(1),$($(dep)_dependencies)))) +endef + +define fetch_file_inner + ( mkdir -p $$($(1)_download_dir) && echo Fetching $(3) from $(2) && \ + $(build_DOWNLOAD) "$$($(1)_download_dir)/$(4).temp" "$(2)/$(3)" && \ + echo "$(5) $$($(1)_download_dir)/$(4).temp" > $$($(1)_download_dir)/.$(4).hash && \ + $(build_SHA256SUM) -c $$($(1)_download_dir)/.$(4).hash && \ + mv $$($(1)_download_dir)/$(4).temp $$($(1)_source_dir)/$(4) && \ + rm -rf $$($(1)_download_dir) ) +endef + +define fetch_file + ( test -f $$($(1)_source_dir)/$(4) || \ + ( $(call fetch_file_inner,$(1),$(2),$(3),$(4),$(5)) || \ + $(call fetch_file_inner,$(1),$(FALLBACK_DOWNLOAD_PATH),$(3),$(4),$(5)))) +endef + +define int_get_build_recipe_hash +$(eval $(1)_all_file_checksums:=$(shell $(build_SHA256SUM) $(meta_depends) packages/$(1).mk $(addprefix $(PATCHES_PATH)/$(1)/,$($(1)_patches)) | cut -d" " -f1)) +$(eval $(1)_recipe_hash:=$(shell echo -n "$($(1)_all_file_checksums)" | $(build_SHA256SUM) | cut -d" " -f1)) +endef + +define int_get_build_id +$(eval $(1)_dependencies += $($(1)_$(host_arch)_$(host_os)_dependencies) $($(1)_$(host_os)_dependencies)) +$(eval $(1)_all_dependencies:=$(call int_get_all_dependencies,$(1),$($($(1)_type)_native_toolchain) $($(1)_dependencies))) +$(foreach dep,$($(1)_all_dependencies),$(eval $(1)_build_id_deps+=$(dep)-$($(dep)_version)-$($(dep)_recipe_hash))) +$(eval $(1)_build_id_long:=$(1)-$($(1)_version)-$($(1)_recipe_hash)-$(release_type) $($(1)_build_id_deps) $($($(1)_type)_id_string)) +$(eval $(1)_build_id:=$(shell echo -n "$($(1)_build_id_long)" | $(build_SHA256SUM) | cut -c-$(HASH_LENGTH))) +final_build_id_long+=$($(package)_build_id_long) + +#compute package-specific paths +$(1)_build_subdir?=. +$(1)_download_file?=$($(1)_file_name) +$(1)_source_dir:=$(SOURCES_PATH) +$(1)_source:=$$($(1)_source_dir)/$($(1)_file_name) +$(1)_staging_dir=$(base_staging_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id) +$(1)_staging_prefix_dir:=$$($(1)_staging_dir)$($($(1)_type)_prefix) +$(1)_extract_dir:=$(base_build_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id) +$(1)_download_dir:=$(base_download_dir)/$(1)-$($(1)_version) +$(1)_build_dir:=$$($(1)_extract_dir)/$$($(1)_build_subdir) +$(1)_cached_checksum:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_build_id).tar.gz.hash +$(1)_patch_dir:=$(base_build_dir)/$(host)/$(1)/$($(1)_version)-$($(1)_build_id)/.patches-$($(1)_build_id) +$(1)_prefixbin:=$($($(1)_type)_prefix)/bin/ +$(1)_cached:=$(BASE_CACHE)/$(host)/$(1)/$(1)-$($(1)_version)-$($(1)_build_id).tar.gz +$(1)_all_sources=$($(1)_file_name) $($(1)_extra_sources) + +#stamps +$(1)_fetched=$(SOURCES_PATH)/download-stamps/.stamp_fetched-$(1)-$($(1)_file_name).hash +$(1)_extracted=$$($(1)_extract_dir)/.stamp_extracted +$(1)_preprocessed=$$($(1)_extract_dir)/.stamp_preprocessed +$(1)_cleaned=$$($(1)_extract_dir)/.stamp_cleaned +$(1)_built=$$($(1)_build_dir)/.stamp_built +$(1)_configured=$$($(1)_build_dir)/.stamp_configured +$(1)_staged=$$($(1)_staging_dir)/.stamp_staged +$(1)_postprocessed=$$($(1)_staging_prefix_dir)/.stamp_postprocessed +$(1)_download_path_fixed=$(subst :,\:,$$($(1)_download_path)) + + +#default commands +$(1)_fetch_cmds ?= $(call fetch_file,$(1),$(subst \:,:,$$($(1)_download_path_fixed)),$$($(1)_download_file),$($(1)_file_name),$($(1)_sha256_hash)) +$(1)_extract_cmds ?= mkdir -p $$($(1)_extract_dir) && echo "$$($(1)_sha256_hash) $$($(1)_source)" > $$($(1)_extract_dir)/.$$($(1)_file_name).hash && $(build_SHA256SUM) -c $$($(1)_extract_dir)/.$$($(1)_file_name).hash && tar --strip-components=1 -xf $$($(1)_source) +$(1)_preprocess_cmds ?= +$(1)_build_cmds ?= +$(1)_config_cmds ?= +$(1)_stage_cmds ?= +$(1)_set_vars ?= + + +all_sources+=$$($(1)_fetched) +endef +#$(foreach dep_target,$($(1)_all_dependencies),$(eval $(1)_dependency_targets=$($(dep_target)_cached))) + + +define int_config_attach_build_config +$(eval $(call $(1)_set_vars,$(1))) +$(1)_cflags+=$($(1)_cflags_$(release_type)) +$(1)_cflags+=$($(1)_cflags_$(host_arch)) $($(1)_cflags_$(host_arch)_$(release_type)) +$(1)_cflags+=$($(1)_cflags_$(host_os)) $($(1)_cflags_$(host_os)_$(release_type)) +$(1)_cflags+=$($(1)_cflags_$(host_arch)_$(host_os)) $($(1)_cflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_cxxflags+=$($(1)_cxxflags_$(release_type)) +$(1)_cxxflags+=$($(1)_cxxflags_$(host_arch)) $($(1)_cxxflags_$(host_arch)_$(release_type)) +$(1)_cxxflags+=$($(1)_cxxflags_$(host_os)) $($(1)_cxxflags_$(host_os)_$(release_type)) +$(1)_cxxflags+=$($(1)_cxxflags_$(host_arch)_$(host_os)) $($(1)_cxxflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_arflags+=$($(1)_arflags_$(release_type)) +$(1)_arflags+=$($(1)_arflags_$(host_arch)) $($(1)_arflags_$(host_arch)_$(release_type)) +$(1)_arflags+=$($(1)_arflags_$(host_os)) $($(1)_arflags_$(host_os)_$(release_type)) +$(1)_arflags+=$($(1)_arflags_$(host_arch)_$(host_os)) $($(1)_arflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_cppflags+=$($(1)_cppflags_$(release_type)) +$(1)_cppflags+=$($(1)_cppflags_$(host_arch)) $($(1)_cppflags_$(host_arch)_$(release_type)) +$(1)_cppflags+=$($(1)_cppflags_$(host_os)) $($(1)_cppflags_$(host_os)_$(release_type)) +$(1)_cppflags+=$($(1)_cppflags_$(host_arch)_$(host_os)) $($(1)_cppflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_ldflags+=$($(1)_ldflags_$(release_type)) +$(1)_ldflags+=$($(1)_ldflags_$(host_arch)) $($(1)_ldflags_$(host_arch)_$(release_type)) +$(1)_ldflags+=$($(1)_ldflags_$(host_os)) $($(1)_ldflags_$(host_os)_$(release_type)) +$(1)_ldflags+=$($(1)_ldflags_$(host_arch)_$(host_os)) $($(1)_ldflags_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_build_opts+=$$($(1)_build_opts_$(release_type)) +$(1)_build_opts+=$$($(1)_build_opts_$(host_arch)) $$($(1)_build_opts_$(host_arch)_$(release_type)) +$(1)_build_opts+=$$($(1)_build_opts_$(host_os)) $$($(1)_build_opts_$(host_os)_$(release_type)) +$(1)_build_opts+=$$($(1)_build_opts_$(host_arch)_$(host_os)) $$($(1)_build_opts_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_config_opts+=$$($(1)_config_opts_$(release_type)) +$(1)_config_opts+=$$($(1)_config_opts_$(host_arch)) $$($(1)_config_opts_$(host_arch)_$(release_type)) +$(1)_config_opts+=$$($(1)_config_opts_$(host_os)) $$($(1)_config_opts_$(host_os)_$(release_type)) +$(1)_config_opts+=$$($(1)_config_opts_$(host_arch)_$(host_os)) $$($(1)_config_opts_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_config_env+=$$($(1)_config_env_$(release_type)) +$(1)_config_env+=$($(1)_config_env_$(host_arch)) $($(1)_config_env_$(host_arch)_$(release_type)) +$(1)_config_env+=$($(1)_config_env_$(host_os)) $($(1)_config_env_$(host_os)_$(release_type)) +$(1)_config_env+=$($(1)_config_env_$(host_arch)_$(host_os)) $($(1)_config_env_$(host_arch)_$(host_os)_$(release_type)) + +$(1)_config_env+=PKG_CONFIG_LIBDIR=$($($(1)_type)_prefix)/lib/pkgconfig +$(1)_config_env+=PKG_CONFIG_PATH=$($($(1)_type)_prefix)/share/pkgconfig +$(1)_config_env+=PATH="$(build_prefix)/bin:$(PATH)" +$(1)_build_env+=PATH="$(build_prefix)/bin:$(PATH)" +$(1)_stage_env+=PATH="$(build_prefix)/bin:$(PATH)" +$(1)_autoconf=./configure --host=$($($(1)_type)_host) --disable-dependency-tracking --prefix=$($($(1)_type)_prefix) $$($(1)_config_opts) CC="$$($(1)_cc)" CXX="$$($(1)_cxx)" + +ifneq ($($(1)_nm),) +$(1)_autoconf += NM="$$($(1)_nm)" +endif +ifneq ($($(1)_ranlib),) +$(1)_autoconf += RANLIB="$$($(1)_ranlib)" +endif +ifneq ($($(1)_ar),) +$(1)_autoconf += AR="$$($(1)_ar)" +endif +ifneq ($($(1)_arflags),) +$(1)_autoconf += ARFLAGS="$$($(1)_arflags)" +endif +ifneq ($($(1)_cflags),) +$(1)_autoconf += CFLAGS="$$($(1)_cflags)" +endif +ifneq ($($(1)_cxxflags),) +$(1)_autoconf += CXXFLAGS="$$($(1)_cxxflags)" +endif +ifneq ($($(1)_cppflags),) +$(1)_autoconf += CPPFLAGS="$$($(1)_cppflags)" +endif +ifneq ($($(1)_ldflags),) +$(1)_autoconf += LDFLAGS="$$($(1)_ldflags)" +endif +endef + +define int_add_cmds +$($(1)_fetched): + $(AT)mkdir -p $$(@D) $(SOURCES_PATH) + $(AT)rm -f $$@ + $(AT)touch $$@ + $(AT)cd $$(@D); $(call $(1)_fetch_cmds,$(1)) + $(AT)cd $($(1)_source_dir); $(foreach source,$($(1)_all_sources),$(build_SHA256SUM) $(source) >> $$(@);) + $(AT)touch $$@ +$($(1)_extracted): | $($(1)_fetched) + $(AT)echo Extracting $(1)... + $(AT)mkdir -p $$(@D) + $(AT)cd $$(@D); $(call $(1)_extract_cmds,$(1)) + $(AT)touch $$@ +$($(1)_preprocessed): | $($(1)_dependencies) $($(1)_extracted) + $(AT)echo Preprocessing $(1)... + $(AT)mkdir -p $$(@D) $($(1)_patch_dir) + $(AT)$(foreach patch,$($(1)_patches),cd $(PATCHES_PATH)/$(1); cp $(patch) $($(1)_patch_dir) ;) + $(AT)cd $$(@D); $(call $(1)_preprocess_cmds, $(1)) + $(AT)touch $$@ +$($(1)_configured): | $($(1)_preprocessed) + $(AT)echo Configuring $(1)... + $(AT)rm -rf $(host_prefix); mkdir -p $(host_prefix)/lib; cd $(host_prefix); $(foreach package,$($(1)_all_dependencies), tar xf $($(package)_cached); ) + $(AT)mkdir -p $$(@D) + $(AT)+cd $$(@D); $($(1)_config_env) $(call $(1)_config_cmds, $(1)) + $(AT)touch $$@ +$($(1)_built): | $($(1)_configured) + $(AT)echo Building $(1)... + $(AT)mkdir -p $$(@D) + $(AT)+cd $$(@D); $($(1)_build_env) $(call $(1)_build_cmds, $(1)) + $(AT)touch $$@ +$($(1)_staged): | $($(1)_built) + $(AT)echo Staging $(1)... + $(AT)mkdir -p $($(1)_staging_dir)/$(host_prefix) + $(AT)cd $($(1)_build_dir); $($(1)_stage_env) $(call $(1)_stage_cmds, $(1)) + $(AT)rm -rf $($(1)_extract_dir) + $(AT)touch $$@ +$($(1)_postprocessed): | $($(1)_staged) + $(AT)echo Postprocessing $(1)... + $(AT)cd $($(1)_staging_prefix_dir); $(call $(1)_postprocess_cmds) + $(AT)touch $$@ +$($(1)_cached): | $($(1)_dependencies) $($(1)_postprocessed) + $(AT)echo Caching $(1)... + $(AT)cd $$($(1)_staging_dir)/$(host_prefix); find . | sort | tar --no-recursion -czf $$($(1)_staging_dir)/$$(@F) -T - + $(AT)mkdir -p $$(@D) + $(AT)rm -rf $$(@D) && mkdir -p $$(@D) + $(AT)mv $$($(1)_staging_dir)/$$(@F) $$(@) + $(AT)rm -rf $($(1)_staging_dir) +$($(1)_cached_checksum): $($(1)_cached) + $(AT)cd $$(@D); $(build_SHA256SUM) $$( $$(@) + +.PHONY: $(1) +$(1): | $($(1)_cached_checksum) +.SECONDARY: $($(1)_cached) $($(1)_postprocessed) $($(1)_staged) $($(1)_built) $($(1)_configured) $($(1)_preprocessed) $($(1)_extracted) $($(1)_fetched) + +endef + +stages = fetched extracted preprocessed configured built staged postprocessed cached cached_checksum + +define ext_add_stages +$(foreach stage,$(stages), + $(1)_$(stage): $($(1)_$(stage)) + .PHONY: $(1)_$(stage)) +endef + +# These functions create the build targets for each package. They must be +# broken down into small steps so that each part is done for all packages +# before moving on to the next step. Otherwise, a package's info +# (build-id for example) would only be available to another package if it +# happened to be computed already. + +#set the type for host/build packages. +$(foreach native_package,$(native_packages),$(eval $(native_package)_type=build)) +$(foreach package,$(packages),$(eval $(package)_type=$(host_arch)_$(host_os))) + +#set overridable defaults +$(foreach package,$(all_packages),$(eval $(call int_vars,$(package)))) + +#include package files +$(foreach package,$(all_packages),$(eval include packages/$(package).mk)) + +#compute a hash of all files that comprise this package's build recipe +$(foreach package,$(all_packages),$(eval $(call int_get_build_recipe_hash,$(package)))) + +#generate a unique id for this package, incorporating its dependencies as well +$(foreach package,$(all_packages),$(eval $(call int_get_build_id,$(package)))) + +#compute final vars after reading package vars +$(foreach package,$(all_packages),$(eval $(call int_config_attach_build_config,$(package)))) + +#create build targets +$(foreach package,$(all_packages),$(eval $(call int_add_cmds,$(package)))) + +#special exception: if a toolchain package exists, all non-native packages depend on it +$(foreach package,$(packages),$(eval $($(package)_unpacked): |$($($(host_arch)_$(host_os)_native_toolchain)_cached) )) diff --git a/contrib/depends/hosts/android.mk b/contrib/depends/hosts/android.mk new file mode 100644 index 000000000..d6f8b99dd --- /dev/null +++ b/contrib/depends/hosts/android.mk @@ -0,0 +1,22 @@ +ANDROID_API=21 + +ifeq ($(host_arch),arm) +host_toolchain=arm-linux-androideabi- +endif + +android_CC=$(host_toolchain)clang +android_CXX=$(host_toolchain)clang++ +android_RANLIB=: + +android_CFLAGS=-pipe +android_CXXFLAGS=$(android_CFLAGS) +android_ARFLAGS=crsD + +android_release_CFLAGS=-O2 +android_release_CXXFLAGS=$(android_release_CFLAGS) + +android_debug_CFLAGS=-g -O0 +android_debug_CXXFLAGS=$(android_debug_CFLAGS) + +android_native_toolchain=android_ndk + diff --git a/contrib/depends/hosts/darwin.mk b/contrib/depends/hosts/darwin.mk new file mode 100644 index 000000000..7b5c8b051 --- /dev/null +++ b/contrib/depends/hosts/darwin.mk @@ -0,0 +1,18 @@ +OSX_MIN_VERSION=10.8 +OSX_SDK_VERSION=10.11 +OSX_SDK=$(SDK_PATH)/MacOSX$(OSX_SDK_VERSION).sdk +LD64_VERSION=253.9 +darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -B $(host_prefix)/native/bin +darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) -stdlib=libc++ -B $(host_prefix)/native/bin + +darwin_CFLAGS=-pipe +darwin_CXXFLAGS=$(darwin_CFLAGS) +darwin_ARFLAGS=cr + +darwin_release_CFLAGS=-O1 +darwin_release_CXXFLAGS=$(darwin_release_CFLAGS) + +darwin_debug_CFLAGS=-O1 +darwin_debug_CXXFLAGS=$(darwin_debug_CFLAGS) + +darwin_native_toolchain=native_cctools diff --git a/contrib/depends/hosts/default.mk b/contrib/depends/hosts/default.mk new file mode 100644 index 000000000..2e7f9fa23 --- /dev/null +++ b/contrib/depends/hosts/default.mk @@ -0,0 +1,26 @@ +default_host_CC = $(host_toolchain)gcc +default_host_CXX = $(host_toolchain)g++ +default_host_AR = $(host_toolchain)ar +default_host_RANLIB = $(host_toolchain)ranlib +default_host_STRIP = $(host_toolchain)strip +default_host_LIBTOOL = $(host_toolchain)libtool +default_host_INSTALL_NAME_TOOL = $(host_toolchain)install_name_tool +default_host_OTOOL = $(host_toolchain)otool +default_host_NM = $(host_toolchain)nm + +define add_host_tool_func +$(host_os)_$1?=$$(default_host_$1) +$(host_arch)_$(host_os)_$1?=$$($(host_os)_$1) +$(host_arch)_$(host_os)_$(release_type)_$1?=$$($(host_os)_$1) +host_$1=$$($(host_arch)_$(host_os)_$1) +endef + +define add_host_flags_func +$(host_arch)_$(host_os)_$1 += $($(host_os)_$1) +$(host_arch)_$(host_os)_$(release_type)_$1 += $($(host_os)_$(release_type)_$1) +host_$1 = $$($(host_arch)_$(host_os)_$1) +host_$(release_type)_$1 = $$($(host_arch)_$(host_os)_$(release_type)_$1) +endef + +$(foreach tool,CC CXX AR RANLIB STRIP NM LIBTOOL OTOOL INSTALL_NAME_TOOL,$(eval $(call add_host_tool_func,$(tool)))) +$(foreach flags,CFLAGS CXXFLAGS ARFLAGS CPPFLAGS LDFLAGS, $(eval $(call add_host_flags_func,$(flags)))) diff --git a/contrib/depends/hosts/freebsd.mk b/contrib/depends/hosts/freebsd.mk new file mode 100644 index 000000000..2e3b5933e --- /dev/null +++ b/contrib/depends/hosts/freebsd.mk @@ -0,0 +1,18 @@ +freebsd_CC=clang-8 +freebsd_CXX=clang++-8 +freebsd_AR=ar +freebsd_RANLIB=ranlib +freebsd_NM=nm + +freebsd_CFLAGS=-pipe +freebsd_CXXFLAGS=$(freebsd_CFLAGS) +freebsd_ARFLAGS=cr + +freebsd_release_CFLAGS=-O2 +freebsd_release_CXXFLAGS=$(freebsd_release_CFLAGS) + +freebsd_debug_CFLAGS=-g -O0 +freebsd_debug_CXXFLAGS=$(freebsd_debug_CFLAGS) + +freebsd_native_toolchain=freebsd_base + diff --git a/contrib/depends/hosts/linux.mk b/contrib/depends/hosts/linux.mk new file mode 100644 index 000000000..912fdb03c --- /dev/null +++ b/contrib/depends/hosts/linux.mk @@ -0,0 +1,32 @@ +linux_CFLAGS=-pipe +linux_CXXFLAGS=$(linux_CFLAGS) +linux_ARFLAGS=cr + +linux_release_CFLAGS=-O2 +linux_release_CXXFLAGS=$(linux_release_CFLAGS) + +linux_debug_CFLAGS=-O1 +linux_debug_CXXFLAGS=$(linux_debug_CFLAGS) + +linux_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC + +ifeq (86,$(findstring 86,$(build_arch))) +i686_linux_CC=gcc -m32 +i686_linux_CXX=g++ -m32 +i686_linux_AR=ar +i686_linux_RANLIB=ranlib +i686_linux_NM=nm +i686_linux_STRIP=strip + +x86_64_linux_CC=gcc -m64 +x86_64_linux_CXX=g++ -m64 +x86_64_linux_AR=ar +x86_64_linux_RANLIB=ranlib +x86_64_linux_NM=nm +x86_64_linux_STRIP=strip +else +i686_linux_CC=$(default_host_CC) -m32 +i686_linux_CXX=$(default_host_CXX) -m32 +x86_64_linux_CC=$(default_host_CC) -m64 +x86_64_linux_CXX=$(default_host_CXX) -m64 +endif diff --git a/contrib/depends/hosts/mingw32.mk b/contrib/depends/hosts/mingw32.mk new file mode 100644 index 000000000..ccc4c5082 --- /dev/null +++ b/contrib/depends/hosts/mingw32.mk @@ -0,0 +1,11 @@ +mingw32_CFLAGS=-pipe +mingw32_CXXFLAGS=$(mingw32_CFLAGS) +mingw32_ARFLAGS=cr + +mingw32_release_CFLAGS=-O2 +mingw32_release_CXXFLAGS=$(mingw32_release_CFLAGS) + +mingw32_debug_CFLAGS=-O1 +mingw32_debug_CXXFLAGS=$(mingw32_debug_CFLAGS) + +mingw32_debug_CPPFLAGS=-D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC diff --git a/contrib/depends/packages.md b/contrib/depends/packages.md new file mode 100644 index 000000000..ae5b47327 --- /dev/null +++ b/contrib/depends/packages.md @@ -0,0 +1,165 @@ +Each recipe consists of 3 main parts: defining identifiers, setting build +variables, and defining build commands. + +The package "mylib" will be used here as an example + +General tips: +- mylib_foo is written as $(package)_foo in order to make recipes more similar. + +## Identifiers +Each package is required to define at least these variables: + +``` +$(package)_version: +Version of the upstream library or program. If there is no version, a +placeholder such as 1.0 can be used. + +$(package)_download_path: +Location of the upstream source, without the file-name. Usually http or +ftp. + +$(package)_file_name: +The upstream source filename available at the download path. + +$(package)_sha256_hash: +The sha256 hash of the upstream file +``` + +These variables are optional: + +``` +$(package)_build_subdir: +cd to this dir before running configure/build/stage commands. + +$(package)_download_file: +The file-name of the upstream source if it differs from how it should be +stored locally. This can be used to avoid storing file-names with strange +characters. + +$(package)_dependencies: +Names of any other packages that this one depends on. + +$(package)_patches: +Filenames of any patches needed to build the package + +$(package)_extra_sources: +Any extra files that will be fetched via $(package)_fetch_cmds. These are +specified so that they can be fetched and verified via 'make download'. +``` + + +## Build Variables: +After defining the main identifiers, build variables may be added or customized +before running the build commands. They should be added to a function called +$(package)_set_vars. For example: + +``` +define $(package)_set_vars +... +endef +``` + +Most variables can be prefixed with the host, architecture, or both, to make +the modifications specific to that case. For example: + +``` +Universal: $(package)_cc=gcc +Linux only: $(package)_linux_cc=gcc +x86_64 only: $(package)_x86_64_cc = gcc +x86_64 linux only: $(package)_x86_64_linux_cc = gcc +``` + +These variables may be set to override or append their default values. + +``` +$(package)_cc +$(package)_cxx +$(package)_objc +$(package)_objcxx +$(package)_ar +$(package)_ranlib +$(package)_libtool +$(package)_nm +$(package)_cflags +$(package)_cxxflags +$(package)_ldflags +$(package)_cppflags +$(package)_config_env +$(package)_build_env +$(package)_stage_env +$(package)_build_opts +$(package)_config_opts +``` + +The `*_env` variables are used to add environment variables to the respective +commands. + +Many variables respect a debug/release suffix as well, in order to use them for +only the appropriate build config. For example: + +``` +$(package)_cflags_release = -O3 +$(package)_cflags_i686_debug = -g +$(package)_config_opts_release = --disable-debug +``` + +These will be used in addition to the options that do not specify +debug/release. All builds are considered to be release unless DEBUG=1 is set by +the user. Other variables may be defined as needed. + +## Build commands: + +For each build, a unique build dir and staging dir are created. For example, +`work/build/mylib/1.0-1adac830f6e` and `work/staging/mylib/1.0-1adac830f6e`. + +The following build commands are available for each recipe: + +``` +$(package)_fetch_cmds: +Runs from: build dir +Fetch the source file. If undefined, it will be fetched and verified +against its hash. + +$(package)_extract_cmds: +Runs from: build dir +Verify the source file against its hash and extract it. If undefined, the +source is assumed to be a tarball. + +$(package)_preprocess_cmds: +Runs from: build dir/$(package)_build_subdir +Preprocess the source as necessary. If undefined, does nothing. + +$(package)_config_cmds: +Runs from: build dir/$(package)_build_subdir +Configure the source. If undefined, does nothing. + +$(package)_build_cmds: +Runs from: build dir/$(package)_build_subdir +Build the source. If undefined, does nothing. + +$(package)_stage_cmds: +Runs from: build dir/$(package)_build_subdir +Stage the build results. If undefined, does nothing. +``` + +The following variables are available for each recipe: + +``` +$(1)_staging_dir: package's destination sysroot path +$(1)_staging_prefix_dir: prefix path inside of the package's staging dir +$(1)_extract_dir: path to the package's extracted sources +$(1)_build_dir: path where configure/build/stage commands will be run +$(1)_patch_dir: path where the package's patches (if any) are found +``` + +Notes on build commands: + +For packages built with autotools, `$($(package)_autoconf)` can be used in the +configure step to (usually) correctly configure automatically. Any +`$($(package)_config_opts`) will be appended. + +Most autotools projects can be properly staged using: + +```bash +$(MAKE) DESTDIR=$($(package)_staging_dir) install +``` diff --git a/contrib/depends/packages/android_ndk.mk b/contrib/depends/packages/android_ndk.mk new file mode 100644 index 000000000..9b8a5332f --- /dev/null +++ b/contrib/depends/packages/android_ndk.mk @@ -0,0 +1,22 @@ +package=android_ndk +$(package)_version=17b +$(package)_download_path=https://dl.google.com/android/repository/ +$(package)_file_name=android-ndk-r$($(package)_version)-linux-x86_64.zip +$(package)_sha256_hash=5dfbbdc2d3ba859fed90d0e978af87c71a91a5be1f6e1c40ba697503d48ccecd + +define $(package)_set_vars +$(package)_config_opts_arm=--arch arm +$(package)_config_opts_aarch64=--arch arm64 +endef + +define $(package)_extract_cmds + echo $($(package)_sha256_hash) $($(1)_source_dir)/$($(package)_file_name) | sha256sum -c &&\ + unzip -q $($(1)_source_dir)/$($(package)_file_name) +endef + +define $(package)_stage_cmds + android-ndk-r$($(package)_version)/build/tools/make_standalone_toolchain.py --api 21 \ + --install-dir $(build_prefix) --stl=libc++ $($(package)_config_opts) &&\ + mv $(build_prefix) $($(package)_staging_dir)/$(host_prefix) +endef + diff --git a/contrib/depends/packages/boost.mk b/contrib/depends/packages/boost.mk new file mode 100644 index 000000000..0d241928e --- /dev/null +++ b/contrib/depends/packages/boost.mk @@ -0,0 +1,46 @@ +package=boost +$(package)_version=1_64_0 +$(package)_download_path=https://dl.bintray.com/boostorg/release/1.64.0/source/ +$(package)_file_name=$(package)_$($(package)_version).tar.bz2 +$(package)_sha256_hash=7bcc5caace97baa948931d712ea5f37038dbb1c5d89b43ad4def4ed7cb683332 +$(package)_dependencies=libiconv +$(package)_patches=fix_aroptions.patch + +define $(package)_set_vars +$(package)_config_opts_release=variant=release +$(package)_config_opts_debug=variant=debug +$(package)_config_opts=--layout=tagged --build-type=complete --user-config=user-config.jam +$(package)_config_opts+=threading=multi link=static -sNO_BZIP2=1 -sNO_ZLIB=1 +$(package)_config_opts_linux=threadapi=pthread runtime-link=shared +$(package)_config_opts_android=threadapi=pthread runtime-link=static target-os=android +$(package)_config_opts_darwin=--toolset=darwin-4.2.1 runtime-link=shared +$(package)_config_opts_mingw32=binary-format=pe target-os=windows threadapi=win32 runtime-link=static +$(package)_config_opts_x86_64_mingw32=address-model=64 +$(package)_config_opts_i686_mingw32=address-model=32 +$(package)_config_opts_i686_linux=address-model=32 architecture=x86 +$(package)_toolset_$(host_os)=gcc +$(package)_archiver_$(host_os)=$($(package)_ar) +$(package)_toolset_darwin=darwin +$(package)_archiver_darwin=$($(package)_libtool) +$(package)_config_libraries=chrono,filesystem,program_options,system,thread,test,date_time,regex,serialization,locale +$(package)_cxxflags=-std=c++11 +$(package)_cxxflags_linux=-fPIC +$(package)_cxxflags_freebsd=-fPIC +endef + +define $(package)_preprocess_cmds + patch -p1 < $($(package)_patch_dir)/fix_aroptions.patch &&\ + echo "using $(boost_toolset_$(host_os)) : : $($(package)_cxx) : \"$($(package)_cxxflags) $($(package)_cppflags)\" \"$($(package)_ldflags)\" \"$(boost_archiver_$(host_os))\" \"$($(package)_arflags)\" \"$(host_STRIP)\" \"$(host_RANLIB)\" \"$(host_WINDRES)\" : ;" > user-config.jam +endef + +define $(package)_config_cmds + ./bootstrap.sh --without-icu --with-libraries=$(boost_config_libraries) +endef + +define $(package)_build_cmds + ./b2 -d2 -j2 -d1 --prefix=$($(package)_staging_prefix_dir) $($(package)_config_opts) stage +endef + +define $(package)_stage_cmds + ./b2 -d0 -j4 --prefix=$($(package)_staging_prefix_dir) $($(package)_config_opts) install +endef diff --git a/contrib/depends/packages/cppzmq.mk b/contrib/depends/packages/cppzmq.mk new file mode 100644 index 000000000..33178f445 --- /dev/null +++ b/contrib/depends/packages/cppzmq.mk @@ -0,0 +1,15 @@ +package=cppzmq +$(package)_version=4.4.1 +$(package)_download_path=https://github.com/zeromq/cppzmq/archive/ +$(package)_file_name=v$($(package)_version).tar.gz +$(package)_sha256_hash=117fc1ca24d98dbe1a60c072cde13be863d429134907797f8e03f654ce679385 +$(package)_dependencies=zeromq + +define $(package)_stage_cmds + mkdir $($(package)_staging_prefix_dir)/include &&\ + cp zmq.hpp $($(package)_staging_prefix_dir)/include +endef + +define $(package)_postprocess_cmds + rm -rf bin share +endef diff --git a/contrib/depends/packages/eudev.mk b/contrib/depends/packages/eudev.mk new file mode 100644 index 000000000..0e930df93 --- /dev/null +++ b/contrib/depends/packages/eudev.mk @@ -0,0 +1,29 @@ +package=eudev +$(package)_version=v3.2.6 +$(package)_download_path=https://github.com/gentoo/eudev/archive/ +$(package)_file_name=$($(package)_version).tar.gz +$(package)_sha256_hash=a96ecb8637667897b8bd4dee4c22c7c5f08b327be45186e912ce6bc768385852 + +define $(package)_set_vars + $(package)_config_opts=--disable-gudev --disable-introspection --disable-hwdb --disable-manpages --disable-shared +endef + +define $(package)_config_cmds + $($(package)_autoconf) AR_FLAGS=$($(package)_arflags) +endef + +define $(package)_build_cmd + $(MAKE) +endef + +define $(package)_preprocess_cmds + cd $($(package)_build_subdir); autoreconf -f -i +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm lib/*.la +endef diff --git a/contrib/depends/packages/expat.mk b/contrib/depends/packages/expat.mk new file mode 100644 index 000000000..ef81636a2 --- /dev/null +++ b/contrib/depends/packages/expat.mk @@ -0,0 +1,28 @@ +package=expat +$(package)_version=2.2.4 +$(package)_download_path=https://downloads.sourceforge.net/project/expat/expat/$($(package)_version) +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=03ad85db965f8ab2d27328abcf0bc5571af6ec0a414874b2066ee3fdd372019e + +define $(package)_set_vars +$(package)_config_opts=--enable-static +$(package)_config_opts=--disable-shared +$(package)_config_opts+=--prefix=$(host_prefix) +endef + +define $(package)_config_cmds + $($(package)_autoconf) $($(package)_config_opts) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm lib/*.la +endef + diff --git a/contrib/depends/packages/freebsd_base.mk b/contrib/depends/packages/freebsd_base.mk new file mode 100644 index 000000000..c6a209dcd --- /dev/null +++ b/contrib/depends/packages/freebsd_base.mk @@ -0,0 +1,23 @@ +package=freebsd_base +$(package)_version=11.3 +$(package)_download_path=https://download.freebsd.org/ftp/releases/amd64/$($(package)_version)-RELEASE/ +$(package)_download_file=base.txz +$(package)_file_name=freebsd-base-$($(package)_version).txz +$(package)_sha256_hash=4599023ac136325b86f2fddeec64c1624daa83657e40b00b2ef944c81463a4ff + +define $(package)_extract_cmds + echo $($(package)_sha256_hash) $($(1)_source_dir)/$($(package)_file_name) | sha256sum -c &&\ + tar xf $($(1)_source_dir)/$($(package)_file_name) ./lib/ ./usr/lib/ ./usr/include/ +endef + +define $(package)_build_cmds + mkdir bin &&\ + echo "exec /usr/bin/clang-8 -target x86_64-unknown-freebsd$($(package)_version) --sysroot=$(host_prefix)/native $$$$""@" > bin/clang-8 &&\ + echo "exec /usr/bin/clang++-8 -target x86_64-unknown-freebsd$($(package)_version) --sysroot=$(host_prefix)/native $$$$""@" > bin/clang++-8 &&\ + chmod 755 bin/* +endef + +define $(package)_stage_cmds + mkdir $($(package)_staging_dir)/$(host_prefix)/native &&\ + mv bin lib usr $($(package)_staging_dir)/$(host_prefix)/native +endef diff --git a/contrib/depends/packages/graphviz.mk b/contrib/depends/packages/graphviz.mk new file mode 100644 index 000000000..1c4bc1b71 --- /dev/null +++ b/contrib/depends/packages/graphviz.mk @@ -0,0 +1,30 @@ +package=graphviz +$(package)_version=2.40.1 +$(package)_download_path=www.graphviz.org/pub/graphviz/stable/SOURCES/ +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=ca5218fade0204d59947126c38439f432853543b0818d9d728c589dfe7f3a421 + +define $(package)_preprocess_cmds + ./autogen.sh +endef + +define $(package)_set_vars + $(package)_config_opts=--disable-shared --enable-multibye --without-purify --without-curses + $(package)_config_opts_release=--disable-debug-mode + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds +endef diff --git a/contrib/depends/packages/gtest.mk b/contrib/depends/packages/gtest.mk new file mode 100644 index 000000000..5df07a32e --- /dev/null +++ b/contrib/depends/packages/gtest.mk @@ -0,0 +1,38 @@ +package=gtest +$(package)_version=1.8.1 +$(package)_download_path=https://github.com/google/googletest/archive/ +$(package)_file_name=release-$($(package)_version).tar.gz +$(package)_sha256_hash=9bf1fe5182a604b4135edc1a425ae356c9ad15e9b23f9f12a02e80184c3a249c +$(package)_cxxflags=-std=c++11 +$(package)_cxxflags_linux=-fPIC + +define $(package)_config_cmds + cd googletest && \ + CC="$(host_prefix)/native/bin/$($(package)_cc)" \ + CXX="$(host_prefix)/native/bin/$($(package)_cxx)" \ + AR="$(host_prefix)/native/bin/$($(package)_ar)" \ + RANLIB="$(host_prefix)/native/bin/$($(package)_ranlib)" \ + LIBTOOL="$(host_prefix)/native/bin/$($(package)_libtool)" \ + CXXFLAGS="$($(package)_cxxflags)" \ + CCFLAGS="$($(package)_ccflags)" \ + CPPFLAGS="$($(package)_cppflags)" \ + CFLAGS="$($(package)_cflags) $($(package)_cppflags)" \ + LDLAGS="$($(package)_ldflags)" \ + cmake -DCMAKE_INSTALL_PREFIX=$(build_prefix) \ + -DTOOLCHAIN_PREFIX=$(host_toolchain) \ + -DCMAKE_AR="$(host_prefix)/native/bin/$($(package)_ar)" \ + -DCMAKE_RANLIB="$(host_prefix)/native/bin/$($(package)_ranlib)" \ + -DCMAKE_CXX_FLAGS_DEBUG=ON +endef +# -DCMAKE_TOOLCHAIN_FILE=$(HOST)/share/toolchain.cmake + +define $(package)_build_cmds + cd googletest && CC="$(host_prefix)/native/bin/$($(package)_cc)" $(MAKE) +endef + +define $(package)_stage_cmds + mkdir $($(package)_staging_prefix_dir)/lib $($(package)_staging_prefix_dir)/include &&\ + cp googletest/libgtest.a $($(package)_staging_prefix_dir)/lib/ &&\ + cp googletest/libgtest_main.a $($(package)_staging_prefix_dir)/lib/ &&\ + cp -a googletest/include/* $($(package)_staging_prefix_dir)/include/ +endef diff --git a/contrib/depends/packages/hidapi.mk b/contrib/depends/packages/hidapi.mk new file mode 100644 index 000000000..b76ef1548 --- /dev/null +++ b/contrib/depends/packages/hidapi.mk @@ -0,0 +1,35 @@ +package=hidapi +$(package)_version=0.9.0 +$(package)_download_path=https://github.com/libusb/hidapi/archive +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=630ee1834bdd5c5761ab079fd04f463a89585df8fcae51a7bfe4229b1e02a652 +$(package)_linux_dependencies=libusb eudev + +define $(package)_set_vars +$(package)_config_opts=--enable-static --disable-shared +$(package)_config_opts+=--prefix=$(host_prefix) +$(package)_config_opts_darwin+=RANLIB="$(host_prefix)/native/bin/x86_64-apple-darwin11-ranlib" AR="$(host_prefix)/native/bin/x86_64-apple-darwin11-ar" CC="$(host_prefix)/native/bin/$($(package)_cc)" +$(package)_config_opts_linux+=libudev_LIBS="-L$(host_prefix)/lib -ludev" +$(package)_config_opts_linux+=libudev_CFLAGS=-I$(host_prefix)/include +$(package)_config_opts_linux+=libusb_LIBS="-L$(host_prefix)/lib -lusb-1.0" +$(package)_config_opts_linux+=libusb_CFLAGS=-I$(host_prefix)/include/libusb-1.0 +$(package)_config_opts_linux+=--with-pic +endef + +define $(package)_config_cmds + ./bootstrap &&\ + $($(package)_autoconf) $($(package)_config_opts) AR_FLAGS=$($(package)_arflags) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm lib/*.la +endef + diff --git a/contrib/depends/packages/icu4c.mk b/contrib/depends/packages/icu4c.mk new file mode 100644 index 000000000..58ae637b0 --- /dev/null +++ b/contrib/depends/packages/icu4c.mk @@ -0,0 +1,27 @@ +package=icu4c +$(package)_version=55.2 +$(package)_download_path=https://github.com/unicode-org/icu/releases/download/release-55-2/ +$(package)_file_name=$(package)-55_2-src.tgz +$(package)_sha256_hash=eda2aa9f9c787748a2e2d310590720ca8bcc6252adf6b4cfb03b65bef9d66759 +$(package)_patches=icu-001-dont-build-static-dynamic-twice.patch + +define $(package)_set_vars + $(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -DU_USING_ICU_NAMESPACE=0 -DU_STATIC_IMPLEMENTATION -DU_COMBINED_IMPLEMENTATION -fPIC -DENABLE_STATIC=YES -DPGKDATA_MODE=static" +endef + +define $(package)_config_cmds + patch -p1 < $($(package)_patch_dir)/icu-001-dont-build-static-dynamic-twice.patch &&\ + mkdir builda &&\ + mkdir buildb &&\ + cd builda &&\ + sh ../source/runConfigureICU Linux &&\ + make &&\ + cd ../buildb &&\ + sh ../source/runConfigureICU MinGW --enable-static=yes --disable-shared --disable-layout --disable-layoutex --disable-tests --disable-samples --prefix=$(host_prefix) --with-cross-build=`pwd`/../builda &&\ + $(MAKE) $($(package)_build_opts) +endef + +define $(package)_stage_cmds + cd buildb &&\ + $(MAKE) $($(package)_build_opts) DESTDIR=$($(package)_staging_dir) install lib/* +endef diff --git a/contrib/depends/packages/ldns.mk b/contrib/depends/packages/ldns.mk new file mode 100644 index 000000000..6fbcc3466 --- /dev/null +++ b/contrib/depends/packages/ldns.mk @@ -0,0 +1,34 @@ +package=ldns +$(package)_version=1.6.17 +$(package)_download_path=https://www.nlnetlabs.nl/downloads/ldns/ +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=8b88e059452118e8949a2752a55ce59bc71fa5bc414103e17f5b6b06f9bcc8cd +$(package)_dependencies=openssl + +define $(package)_set_vars + $(package)_config_opts=--disable-shared --enable-static --with-drill + $(package)_config_opts+=--with-ssl=$(host_prefix) + $(package)_config_opts_release=--disable-debug-mode + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub . +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install-h install-lib +endef + +define $(package)_postprocess_cmds + rm lib/*.la +endef + diff --git a/contrib/depends/packages/libICE.mk b/contrib/depends/packages/libICE.mk new file mode 100644 index 000000000..a897d9aed --- /dev/null +++ b/contrib/depends/packages/libICE.mk @@ -0,0 +1,23 @@ +package=libICE +$(package)_version=1.0.9 +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=8f7032f2c1c64352b5423f6b48a8ebdc339cc63064af34d66a6c9aa79759e202 +$(package)_dependencies=xtrans xproto + +define $(package)_set_vars + $(package)_config_opts=--disable-static --disable-docs --disable-specs --without-xsltproc + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/contrib/depends/packages/libSM.mk b/contrib/depends/packages/libSM.mk new file mode 100644 index 000000000..83fcd4cdb --- /dev/null +++ b/contrib/depends/packages/libSM.mk @@ -0,0 +1,23 @@ +package=libSM +$(package)_version=1.2.2 +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/lib/ +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=0baca8c9f5d934450a70896c4ad38d06475521255ca63b717a6510fdb6e287bd +$(package)_dependencies=xtrans xproto libICE + +define $(package)_set_vars + $(package)_config_opts=--without-libuuid --without-xsltproc --disable-docs --disable-static + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/contrib/depends/packages/libiconv.mk b/contrib/depends/packages/libiconv.mk new file mode 100644 index 000000000..eac8b4331 --- /dev/null +++ b/contrib/depends/packages/libiconv.mk @@ -0,0 +1,35 @@ +package=libiconv +$(package)_version=1.15 +$(package)_download_path=https://ftp.gnu.org/gnu/libiconv +$(package)_file_name=libiconv-$($(package)_version).tar.gz +$(package)_sha256_hash=ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178 +$(package)_patches=fix-whitespace.patch + +define $(package)_set_vars + $(package)_config_opts=--disable-nls + $(package)_config_opts=--enable-static + $(package)_config_opts=--disable-shared + $(package)_config_opts_linux=--with-pic + $(package)_config_opts_freebsd=--with-pic +endef + +define $(package)_preprocess_cmds + cp -f $(BASEDIR)/config.guess $(BASEDIR)/config.sub build-aux/ &&\ + patch -p1 < $($(package)_patch_dir)/fix-whitespace.patch +endef + +define $(package)_config_cmds + $($(package)_autoconf) AR_FLAGS=$($(package)_arflags) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm lib/*.la +endef diff --git a/contrib/depends/packages/libusb.mk b/contrib/depends/packages/libusb.mk new file mode 100644 index 000000000..348c410a7 --- /dev/null +++ b/contrib/depends/packages/libusb.mk @@ -0,0 +1,39 @@ +package=libusb +$(package)_version=1.0.22 +$(package)_download_path=https://sourceforge.net/projects/libusb/files/libusb-1.0/libusb-$($(package)_version)/ +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=75aeb9d59a4fdb800d329a545c2e6799f732362193b465ea198f2aa275518157 + +define $(package)_preprocess_cmds + autoreconf -i +endef + +define $(package)_set_vars + $(package)_config_opts=--disable-shared + $(package)_config_opts_linux=--with-pic --disable-udev + $(package)_config_opts_mingw32=--disable-udev + $(package)_config_opts_darwin=--disable-udev +endef + +ifneq ($(host_os),darwin) + define $(package)_config_cmds + cp -f $(BASEDIR)/config.guess config.guess &&\ + cp -f $(BASEDIR)/config.sub config.sub &&\ + $($(package)_autoconf) AR_FLAGS=$($(package)_arflags) + endef +else + define $(package)_config_cmds + $($(package)_autoconf) AR_FLAGS=$($(package)_arflags) + endef +endif + +define $(package)_build_cmd + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds cp -f lib/libusb-1.0.a lib/libusb.a +endef diff --git a/contrib/depends/packages/native_biplist.mk b/contrib/depends/packages/native_biplist.mk new file mode 100644 index 000000000..3c6e8900f --- /dev/null +++ b/contrib/depends/packages/native_biplist.mk @@ -0,0 +1,20 @@ +package=native_biplist +$(package)_version=0.9 +$(package)_download_path=https://pypi.python.org/packages/source/b/biplist +$(package)_file_name=biplist-$($(package)_version).tar.gz +$(package)_sha256_hash=b57cadfd26e4754efdf89e9e37de87885f9b5c847b2615688ca04adfaf6ca604 +$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages +$(package)_patches=sorted_list.patch + +define $(package)_preprocess_cmds + patch -p1 < $($(package)_patch_dir)/sorted_list.patch +endef + +define $(package)_build_cmds + python setup.py build +endef + +define $(package)_stage_cmds + mkdir -p $($(package)_install_libdir) && \ + python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) +endef diff --git a/contrib/depends/packages/native_ccache.mk b/contrib/depends/packages/native_ccache.mk new file mode 100644 index 000000000..966804ce8 --- /dev/null +++ b/contrib/depends/packages/native_ccache.mk @@ -0,0 +1,25 @@ +package=native_ccache +$(package)_version=3.3.4 +$(package)_download_path=https://samba.org/ftp/ccache +$(package)_file_name=ccache-$($(package)_version).tar.bz2 +$(package)_sha256_hash=fa9d7f38367431bc86b19ad107d709ca7ecf1574fdacca01698bdf0a47cd8567 + +define $(package)_set_vars +$(package)_config_opts= +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm -rf lib include +endef diff --git a/contrib/depends/packages/native_cctools.mk b/contrib/depends/packages/native_cctools.mk new file mode 100644 index 000000000..8bf71254f --- /dev/null +++ b/contrib/depends/packages/native_cctools.mk @@ -0,0 +1,70 @@ +package=native_cctools +$(package)_version=807d6fd1be5d2224872e381870c0a75387fe05e6 +$(package)_download_path=https://github.com/theuni/cctools-port/archive +$(package)_file_name=$($(package)_version).tar.gz +$(package)_sha256_hash=a09c9ba4684670a0375e42d9d67e7f12c1f62581a27f28f7c825d6d7032ccc6a +$(package)_build_subdir=cctools +$(package)_clang_version=3.7.1 +$(package)_clang_download_path=http://llvm.org/releases/$($(package)_clang_version) +$(package)_clang_download_file=clang+llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz +$(package)_clang_file_name=clang-llvm-$($(package)_clang_version)-x86_64-linux-gnu-ubuntu-14.04.tar.xz +$(package)_clang_sha256_hash=99b28a6b48e793705228a390471991386daa33a9717cd9ca007fcdde69608fd9 +$(package)_extra_sources=$($(package)_clang_file_name) +$(package)_patches=skip_otool.patch + +define $(package)_fetch_cmds +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_clang_download_path),$($(package)_clang_download_file),$($(package)_clang_file_name),$($(package)_clang_sha256_hash)) +endef + +define $(package)_extract_cmds + mkdir -p $($(package)_extract_dir) && \ + echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_clang_sha256_hash) $($(package)_source_dir)/$($(package)_clang_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + mkdir -p toolchain/bin toolchain/lib/clang/3.5/include && \ + tar --strip-components=1 -C toolchain -xf $($(package)_source_dir)/$($(package)_clang_file_name) && \ + rm -f toolchain/lib/libc++abi.so* && \ + echo "#!/bin/sh" > toolchain/bin/$(host)-dsymutil && \ + echo "exit 0" >> toolchain/bin/$(host)-dsymutil && \ + chmod +x toolchain/bin/$(host)-dsymutil && \ + tar --strip-components=1 -xf $($(package)_source) +endef + +define $(package)_set_vars +$(package)_config_opts=--target=$(host) --disable-lto-support +$(package)_ldflags+=-Wl,-rpath=\\$$$$$$$$\$$$$$$$$ORIGIN/../lib +$(package)_cc=$($(package)_extract_dir)/toolchain/bin/clang +$(package)_cxx=$($(package)_extract_dir)/toolchain/bin/clang++ +endef + +# If clang gets updated to a version with a fix for https://reviews.llvm.org/D50559 +# then the patch that skips otool can be removed. +define $(package)_preprocess_cmds + patch -p0 < $($(package)_patch_dir)/skip_otool.patch && \ + cd $($(package)_build_subdir); ./autogen.sh && \ + sed -i.old "/define HAVE_PTHREADS/d" ld64/src/ld/InputFiles.h +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install && \ + cp $($(package)_extract_dir)/cctools/misc/install_name_tool $($(package)_staging_prefix_dir)/bin/ &&\ + cd $($(package)_extract_dir)/toolchain && \ + mkdir -p $($(package)_staging_prefix_dir)/lib/clang/$($(package)_clang_version)/include && \ + mkdir -p $($(package)_staging_prefix_dir)/bin $($(package)_staging_prefix_dir)/include && \ + cp bin/clang $($(package)_staging_prefix_dir)/bin/ &&\ + cp -P bin/clang++ $($(package)_staging_prefix_dir)/bin/ &&\ + cp lib/libLTO.so $($(package)_staging_prefix_dir)/lib/ && \ + cp -rf lib/clang/$($(package)_clang_version)/include/* $($(package)_staging_prefix_dir)/lib/clang/$($(package)_clang_version)/include/ && \ + cp bin/llvm-dsymutil $($(package)_staging_prefix_dir)/bin/$(host)-dsymutil && \ + if `test -d include/c++/`; then cp -rf include/c++/ $($(package)_staging_prefix_dir)/include/; fi && \ + if `test -d lib/c++/`; then cp -rf lib/c++/ $($(package)_staging_prefix_dir)/lib/; fi +endef diff --git a/contrib/depends/packages/native_cdrkit.mk b/contrib/depends/packages/native_cdrkit.mk new file mode 100644 index 000000000..8243458ec --- /dev/null +++ b/contrib/depends/packages/native_cdrkit.mk @@ -0,0 +1,26 @@ +package=native_cdrkit +$(package)_version=1.1.11 +$(package)_download_path=https://distro.ibiblio.org/fatdog/source/600/c +$(package)_file_name=cdrkit-$($(package)_version).tar.bz2 +$(package)_sha256_hash=b50d64c214a65b1a79afe3a964c691931a4233e2ba605d793eb85d0ac3652564 +$(package)_patches=cdrkit-deterministic.patch + +define $(package)_preprocess_cmds + patch -p1 < $($(package)_patch_dir)/cdrkit-deterministic.patch +endef + +define $(package)_config_cmds + cmake -DCMAKE_INSTALL_PREFIX=$(build_prefix) +endef + +define $(package)_build_cmds + $(MAKE) genisoimage +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) -C genisoimage install +endef + +define $(package)_postprocess_cmds + rm bin/isovfy bin/isoinfo bin/isodump bin/isodebug bin/devdump +endef diff --git a/contrib/depends/packages/native_cmake-unused.mk b/contrib/depends/packages/native_cmake-unused.mk new file mode 100644 index 000000000..c9ab75711 --- /dev/null +++ b/contrib/depends/packages/native_cmake-unused.mk @@ -0,0 +1,23 @@ +package=native_cmake +$(package)_version=3.14.0 +$(package)_version_dot=v3.14 +$(package)_download_path=https://cmake.org/files/$($(package)_version_dot)/ +$(package)_file_name=cmake-$($(package)_version).tar.gz +$(package)_sha256_hash=aa76ba67b3c2af1946701f847073f4652af5cbd9f141f221c97af99127e75502 + +define $(package)_set_vars +$(package)_config_opts= +endef + +define $(package)_config_cmds + ./bootstrap &&\ + ./configure $($(package)_config_opts) +endef + +define $(package)_build_cmd + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/contrib/depends/packages/native_ds_store.mk b/contrib/depends/packages/native_ds_store.mk new file mode 100644 index 000000000..49f5829ac --- /dev/null +++ b/contrib/depends/packages/native_ds_store.mk @@ -0,0 +1,17 @@ +package=native_ds_store +$(package)_version=1.1.0 +$(package)_download_path=https://bitbucket.org/al45tair/ds_store/get +$(package)_download_file=v$($(package)_version).tar.bz2 +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=921596764d71d1bbd3297a90ef6d286f718794d667e4f81d91d14053525d64c1 +$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages +$(package)_dependencies=native_biplist + +define $(package)_build_cmds + python setup.py build +endef + +define $(package)_stage_cmds + mkdir -p $($(package)_install_libdir) && \ + python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) +endef diff --git a/contrib/depends/packages/native_libdmg-hfsplus.mk b/contrib/depends/packages/native_libdmg-hfsplus.mk new file mode 100644 index 000000000..a4ffb6046 --- /dev/null +++ b/contrib/depends/packages/native_libdmg-hfsplus.mk @@ -0,0 +1,22 @@ +package=native_libdmg-hfsplus +$(package)_version=0.1 +$(package)_download_path=https://github.com/theuni/libdmg-hfsplus/archive +$(package)_file_name=libdmg-hfsplus-v$($(package)_version).tar.gz +$(package)_sha256_hash=6569a02eb31c2827080d7d59001869ea14484c281efab0ae7f2b86af5c3120b3 +$(package)_build_subdir=build + +define $(package)_preprocess_cmds + mkdir build +endef + +define $(package)_config_cmds + cmake -DCMAKE_INSTALL_PREFIX:PATH=$(build_prefix)/bin .. +endef + +define $(package)_build_cmds + $(MAKE) -C dmg +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) -C dmg install +endef diff --git a/contrib/depends/packages/native_mac_alias.mk b/contrib/depends/packages/native_mac_alias.mk new file mode 100644 index 000000000..85a8a402b --- /dev/null +++ b/contrib/depends/packages/native_mac_alias.mk @@ -0,0 +1,21 @@ +package=native_mac_alias +$(package)_version=1.1.0 +$(package)_download_path=https://bitbucket.org/al45tair/mac_alias/get +$(package)_download_file=v$($(package)_version).tar.bz2 +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=87ad827e66790028361e43fc754f68ed041a9bdb214cca03c853f079b04fb120 +$(package)_install_libdir=$(build_prefix)/lib/python/dist-packages +$(package)_patches=python3.patch + +define $(package)_preprocess_cmds + patch -p1 < $($(package)_patch_dir)/python3.patch +endef + +define $(package)_build_cmds + python setup.py build +endef + +define $(package)_stage_cmds + mkdir -p $($(package)_install_libdir) && \ + python setup.py install --root=$($(package)_staging_dir) --prefix=$(build_prefix) --install-lib=$($(package)_install_libdir) +endef diff --git a/contrib/depends/packages/native_protobuf.mk b/contrib/depends/packages/native_protobuf.mk new file mode 100644 index 000000000..35f648b9a --- /dev/null +++ b/contrib/depends/packages/native_protobuf.mk @@ -0,0 +1,27 @@ +package=protobuf3 +$(package)_version=3.6.1 +$(package)_download_path=https://github.com/protocolbuffers/protobuf/releases/download/v$($(package)_version)/ +$(package)_file_name=protobuf-cpp-$($(package)_version).tar.gz +$(package)_sha256_hash=b3732e471a9bb7950f090fd0457ebd2536a9ba0891b7f3785919c654fe2a2529 +$(package)_cxxflags=-std=c++11 + +define $(package)_set_vars + $(package)_config_opts=--disable-shared --prefix=$(build_prefix) + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) -C src +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install +endef + +define $(package)_postprocess_cmds + rm lib/libprotoc.a +endef diff --git a/contrib/depends/packages/ncurses.mk b/contrib/depends/packages/ncurses.mk new file mode 100644 index 000000000..d8fdf351c --- /dev/null +++ b/contrib/depends/packages/ncurses.mk @@ -0,0 +1,64 @@ +package=ncurses +$(package)_version=6.1 +$(package)_download_path=https://ftp.gnu.org/gnu/ncurses +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=aa057eeeb4a14d470101eff4597d5833dcef5965331be3528c08d99cebaa0d17 +$(package)_patches=fallback.c + +define $(package)_set_vars + $(package)_build_opts=CC="$($(package)_cc)" + $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" ARFLAGS=$($(package)_arflags) cf_cv_ar_flags="" + $(package)_config_env_darwin=RANLIB="$(host_prefix)/native/bin/x86_64-apple-darwin11-ranlib" AR="$(host_prefix)/native/bin/x86_64-apple-darwin11-ar" CC="$(host_prefix)/native/bin/$($(package)_cc)" + $(package)_config_opts=--prefix=$(host_prefix) + $(package)_config_opts+=--disable-shared + $(package)_config_opts+=--with-build-cc=gcc + $(package)_config_opts+=--without-debug + $(package)_config_opts+=--without-ada + $(package)_config_opts+=--without-cxx-binding + $(package)_config_opts+=--without-cxx + $(package)_config_opts+=--without-ticlib + $(package)_config_opts+=--without-tic + $(package)_config_opts+=--without-progs + $(package)_config_opts+=--without-tests + $(package)_config_opts+=--without-tack + $(package)_config_opts+=--without-manpages + $(package)_config_opts+=--with-termlib=tinfo + $(package)_config_opts+=--disable-tic-depends + $(package)_config_opts+=--disable-big-strings + $(package)_config_opts+=--disable-ext-colors + $(package)_config_opts+=--enable-pc-files + $(package)_config_opts+=--host=$(HOST) + $(pacakge)_config_opts+=--without-shared + $(pacakge)_config_opts+=--without-pthread + $(pacakge)_config_opts+=--disable-rpath + $(pacakge)_config_opts+=--disable-colorfgbg + $(pacakge)_config_opts+=--disable-ext-mouse + $(pacakge)_config_opts+=--disable-symlinks + $(pacakge)_config_opts+=--enable-warnings + $(pacakge)_config_opts+=--enable-assertions + $(package)_config_opts+=--with-default-terminfo-dir=/etc/_terminfo_ + $(package)_config_opts+=--with-terminfo-dirs=/etc/_terminfo_ + $(pacakge)_config_opts+=--enable-database + $(pacakge)_config_opts+=--enable-sp-funcs + $(pacakge)_config_opts+=--disable-term-driver + $(pacakge)_config_opts+=--enable-interop + $(pacakge)_config_opts+=--enable-widec + $(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC" +endef + +define $(package)_preprocess_cmds + cp $($(package)_patch_dir)/fallback.c ncurses +endef + +define $(package)_config_cmds + ./configure $($(package)_config_opts) +endef + +define $(package)_build_cmds + $(MAKE) $($(package)_build_opts) V=1 +endef + +define $(package)_stage_cmds + $(MAKE) install.libs DESTDIR=$($(package)_staging_dir) +endef + diff --git a/contrib/depends/packages/openssl.mk b/contrib/depends/packages/openssl.mk new file mode 100644 index 000000000..9d3c28465 --- /dev/null +++ b/contrib/depends/packages/openssl.mk @@ -0,0 +1,78 @@ +package=openssl +$(package)_version=1.0.2r +$(package)_download_path=https://ftp.openssl.org/source/old/1.0.2 +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=ae51d08bba8a83958e894946f15303ff894d75c2b8bbd44a852b64e3fe11d0d6 +$(package)_patches=fix_arflags.patch + +define $(package)_set_vars +$(package)_config_env=AR="$($(package)_ar)" ARFLAGS=$($(package)_arflags) RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" +$(package)_config_opts=--prefix=$(host_prefix) --openssldir=$(host_prefix)/etc/openssl +$(package)_config_opts+=no-capieng +$(package)_config_opts+=no-dso +$(package)_config_opts+=no-dtls1 +$(package)_config_opts+=no-ec_nistp_64_gcc_128 +$(package)_config_opts+=no-gost +$(package)_config_opts+=no-gmp +$(package)_config_opts+=no-heartbeats +$(package)_config_opts+=no-jpake +$(package)_config_opts+=no-krb5 +$(package)_config_opts+=no-libunbound +$(package)_config_opts+=no-md2 +$(package)_config_opts+=no-rc5 +$(package)_config_opts+=no-rdrand +$(package)_config_opts+=no-rfc3779 +$(package)_config_opts+=no-rsax +$(package)_config_opts+=no-sctp +$(package)_config_opts+=no-sha0 +$(package)_config_opts+=no-shared +$(package)_config_opts+=no-ssl-trace +$(package)_config_opts+=no-ssl2 +$(package)_config_opts+=no-ssl3 +$(package)_config_opts+=no-static_engine +$(package)_config_opts+=no-store +$(package)_config_opts+=no-unit-test +$(package)_config_opts+=no-weak-ssl-ciphers +$(package)_config_opts+=no-zlib +$(package)_config_opts+=no-zlib-dynamic +$(package)_config_opts+=$($(package)_cflags) $($(package)_cppflags) +$(package)_config_opts_linux=-fPIC -Wa,--noexecstack +$(package)_config_opts_freebsd=-fPIC -Wa,--noexecstack +$(package)_config_opts_x86_64_linux=linux-x86_64 +$(package)_config_opts_i686_linux=linux-generic32 +$(package)_config_opts_arm_linux=linux-generic32 +$(package)_config_opts_aarch64_linux=linux-generic64 +$(package)_config_opts_arm_android=--static android-armv7 no-asm +$(package)_config_opts_aarch64_android=--static android no-asm +$(package)_config_opts_riscv64_linux=linux-generic64 +$(package)_config_opts_mipsel_linux=linux-generic32 +$(package)_config_opts_mips_linux=linux-generic32 +$(package)_config_opts_powerpc_linux=linux-generic32 +$(package)_config_opts_x86_64_darwin=darwin64-x86_64-cc +$(package)_config_opts_x86_64_mingw32=mingw64 +$(package)_config_opts_i686_mingw32=mingw +$(package)_config_opts_x86_64_freebsd=BSD-x86_64 +endef + +define $(package)_preprocess_cmds + sed -i.old "/define DATE/d" util/mkbuildinf.pl && \ + sed -i.old "s|engines apps test|engines|" Makefile.org && \ + sed -i -e "s/-mandroid //" Configure && \ + patch < $($(package)_patch_dir)/fix_arflags.patch +endef + +define $(package)_config_cmds + ./Configure $($(package)_config_opts) +endef + +define $(package)_build_cmds + $(MAKE) -j1 build_libs libcrypto.pc libssl.pc openssl.pc +endef + +define $(package)_stage_cmds + $(MAKE) INSTALL_PREFIX=$($(package)_staging_dir) -j1 install_sw +endef + +define $(package)_postprocess_cmds + rm -rf share bin etc +endef diff --git a/contrib/depends/packages/packages.mk b/contrib/depends/packages/packages.mk new file mode 100644 index 000000000..531837de2 --- /dev/null +++ b/contrib/depends/packages/packages.mk @@ -0,0 +1,36 @@ +packages:=boost openssl zeromq cppzmq libiconv + +native_packages := native_ccache + +hardware_packages := hidapi protobuf libusb +hardware_native_packages := native_protobuf + +android_native_packages = android_ndk +android_packages = ncurses readline sodium + +darwin_native_packages = native_biplist native_ds_store native_mac_alias $(hardware_native_packages) +darwin_packages = sodium ncurses readline $(hardware_packages) + +# not really native... +freebsd_native_packages = freebsd_base +freebsd_packages = ncurses readline sodium + +linux_packages = eudev ncurses readline sodium $(hardware_packages) +linux_native_packages = $(hardware_native_packages) +qt_packages = qt + +ifeq ($(build_tests),ON) +packages += gtest +endif + +ifneq ($(host_arch),riscv64) +linux_packages += unwind +endif + +mingw32_packages = icu4c sodium $(hardware_packages) +mingw32_native_packages = $(hardware_native_packages) + +ifneq ($(build_os),darwin) +darwin_native_packages += native_cctools native_cdrkit native_libdmg-hfsplus +endif + diff --git a/contrib/depends/packages/protobuf.mk b/contrib/depends/packages/protobuf.mk new file mode 100644 index 000000000..ad1098975 --- /dev/null +++ b/contrib/depends/packages/protobuf.mk @@ -0,0 +1,31 @@ +package=protobuf +$(package)_version=$(native_$(package)_version) +$(package)_download_path=$(native_$(package)_download_path) +$(package)_file_name=$(native_$(package)_file_name) +$(package)_sha256_hash=$(native_$(package)_sha256_hash) +$(package)_dependencies=native_$(package) +$(package)_cxxflags=-std=c++11 + +define $(package)_set_vars + $(package)_config_opts=--disable-shared --with-protoc=$(build_prefix)/bin/protoc + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) AR_FLAGS=$($(package)_arflags) +endef + +define $(package)_build_cmds + $(MAKE) -C src libprotobuf.la +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install-libLTLIBRARIES install-nobase_includeHEADERS &&\ + $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA +endef + +define $(package)_postprocess_cmds + rm lib/libprotoc.a &&\ + rm lib/*.la +endef + diff --git a/contrib/depends/packages/qt.mk b/contrib/depends/packages/qt.mk new file mode 100644 index 000000000..98cef4631 --- /dev/null +++ b/contrib/depends/packages/qt.mk @@ -0,0 +1,148 @@ +PACKAGE=qt +$(package)_version=5.7.1 +$(package)_download_path=http://linorg.usp.br/Qt/archive/qt/5.7/5.7.1/submodules +$(package)_suffix=opensource-src-$($(package)_version).tar.gz +$(package)_file_name=qtbase-$($(package)_suffix) +$(package)_sha256_hash=95f83e532d23b3ddbde7973f380ecae1bac13230340557276f75f2e37984e410 +$(package)_build_subdir=qtbase +$(package)_qt_libs=corelib +$(package)_patches=pidlist_absolute.patch fix_qt_pkgconfig.patch qfixed-coretext.patch + +$(package)_qttranslations_file_name=qttranslations-$($(package)_suffix) +$(package)_qttranslations_sha256_hash=3a15aebd523c6d89fb97b2d3df866c94149653a26d27a00aac9b6d3020bc5a1d + +$(package)_qttools_file_name=qttools-$($(package)_suffix) +$(package)_qttools_sha256_hash=22d67de915cb8cd93e16fdd38fa006224ad9170bd217c2be1e53045a8dd02f0f + +$(package)_extra_sources = $($(package)_qttranslations_file_name) +$(package)_extra_sources += $($(package)_qttools_file_name) + +define $(package)_set_vars +$(package)_config_opts_release = -release +$(package)_config_opts_debug = -debug +$(package)_config_opts += -bindir $(build_prefix)/bin +$(package)_config_opts += -c++std c++11 +$(package)_config_opts += -confirm-license +$(package)_config_opts += -dbus-runtime +$(package)_config_opts += -no-alsa +$(package)_config_opts += -no-audio-backend +$(package)_config_opts += -no-cups +$(package)_config_opts += -no-egl +$(package)_config_opts += -no-eglfs +$(package)_config_opts += -no-feature-style-windowsmobile +$(package)_config_opts += -no-feature-style-windowsce +$(package)_config_opts += -no-freetype +$(package)_config_opts += -no-gif +$(package)_config_opts += -no-glib +$(package)_config_opts += -no-gstreamer +$(package)_config_opts += -no-icu +$(package)_config_opts += -no-iconv +$(package)_config_opts += -no-kms +$(package)_config_opts += -no-linuxfb +$(package)_config_opts += -no-libudev +$(package)_config_opts += -no-mitshm +$(package)_config_opts += -no-mtdev +$(package)_config_opts += -no-pulseaudio +$(package)_config_opts += -no-openvg +$(package)_config_opts += -no-reduce-relocations +$(package)_config_opts += -no-qml-debug +$(package)_config_opts += -no-sql-db2 +$(package)_config_opts += -no-sql-ibase +$(package)_config_opts += -no-sql-oci +$(package)_config_opts += -no-sql-tds +$(package)_config_opts += -no-sql-mysql +$(package)_config_opts += -no-sql-odbc +$(package)_config_opts += -no-sql-psql +$(package)_config_opts += -no-sql-sqlite +$(package)_config_opts += -no-sql-sqlite2 +$(package)_config_opts += -no-use-gold-linker +$(package)_config_opts += -no-xinput2 +$(package)_config_opts += -no-xrender +$(package)_config_opts += -nomake examples +$(package)_config_opts += -nomake tests +$(package)_config_opts += -opensource +$(package)_config_opts += -no-openssl +$(package)_config_opts += -optimized-qmake +$(package)_config_opts += -pch +$(package)_config_opts += -pkg-config +$(package)_config_opts += -no-libpng +$(package)_config_opts += -no-libjpeg +$(package)_config_opts += -qt-pcre +$(package)_config_opts += -no-zlib +$(package)_config_opts += -reduce-exports +$(package)_config_opts += -static +$(package)_config_opts += -silent +$(package)_config_opts += -v +$(package)_config_opts += -no-feature-printer +$(package)_config_opts += -no-feature-printdialog +$(package)_config_opts += -no-gui +$(package)_config_opts += -no-freetype +$(package)_config_opts += -no-sm +$(package)_config_opts += -no-fontconfig +$(package)_config_opts += -no-opengl +$(package)_config_opts += -no-xkb +$(package)_config_opts += -no-xcb +$(package)_config_opts += -no-xshape +$(package)_build_env = QT_RCC_TEST=1 +endef + +define $(package)_fetch_cmds +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_download_file),$($(package)_file_name),$($(package)_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_qttranslations_file_name),$($(package)_qttranslations_file_name),$($(package)_qttranslations_sha256_hash)) && \ +$(call fetch_file,$(package),$($(package)_download_path),$($(package)_qttools_file_name),$($(package)_qttools_file_name),$($(package)_qttools_sha256_hash)) +endef + +define $(package)_extract_cmds + mkdir -p $($(package)_extract_dir) && \ + echo "$($(package)_sha256_hash) $($(package)_source)" > $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_qttranslations_sha256_hash) $($(package)_source_dir)/$($(package)_qttranslations_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + echo "$($(package)_qttools_sha256_hash) $($(package)_source_dir)/$($(package)_qttools_file_name)" >> $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + $(build_SHA256SUM) -c $($(package)_extract_dir)/.$($(package)_file_name).hash && \ + mkdir qtbase && \ + tar --strip-components=1 -xf $($(package)_source) -C qtbase && \ + mkdir qttranslations && \ + tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttranslations_file_name) -C qttranslations && \ + mkdir qttools && \ + tar --strip-components=1 -xf $($(package)_source_dir)/$($(package)_qttools_file_name) -C qttools +endef + + +define $(package)_preprocess_cmds + sed -i.old "s|updateqm.commands = \$$$$\$$$$LRELEASE|updateqm.commands = $($(package)_extract_dir)/qttools/bin/lrelease|" qttranslations/translations/translations.pro && \ + sed -i.old "/updateqm.depends =/d" qttranslations/translations/translations.pro && \ + patch -p1 < $($(package)_patch_dir)/pidlist_absolute.patch && \ + patch -p1 < $($(package)_patch_dir)/fix_qt_pkgconfig.patch && \ + patch -p1 < $($(package)_patch_dir)/qfixed-coretext.patch && \ + echo "!host_build: QMAKE_CFLAGS += $($(package)_cflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ + echo "!host_build: QMAKE_CXXFLAGS += $($(package)_cxxflags) $($(package)_cppflags)" >> qtbase/mkspecs/common/gcc-base.conf && \ + echo "!host_build: QMAKE_LFLAGS += $($(package)_ldflags)" >> qtbase/mkspecs/common/gcc-base.conf +endef + +define $(package)_config_cmds + export PKG_CONFIG_SYSROOT_DIR=/ && \ + export PKG_CONFIG_LIBDIR=$(host_prefix)/lib/pkgconfig && \ + export PKG_CONFIG_PATH=$(host_prefix)/share/pkgconfig && \ + ./configure $($(package)_config_opts) && \ + echo "CONFIG += force_bootstrap" >> mkspecs/qconfig.pri && \ + $(MAKE) sub-src-clean && \ + cd ../qttranslations && ../qtbase/bin/qmake qttranslations.pro -o Makefile && \ + cd translations && ../../qtbase/bin/qmake translations.pro -o Makefile && cd ../.. &&\ + cd qttools/src/linguist/lrelease/ && ../../../../qtbase/bin/qmake lrelease.pro -o Makefile +endef + +define $(package)_build_cmds + $(MAKE) -C src $(addprefix sub-,$($(package)_qt_libs)) && \ + $(MAKE) -C ../qttools/src/linguist/lrelease && \ + $(MAKE) -C ../qttranslations +endef + +define $(package)_stage_cmds + $(MAKE) -C src INSTALL_ROOT=$($(package)_staging_dir) $(addsuffix -install_subtargets,$(addprefix sub-,$($(package)_qt_libs))) && cd .. &&\ + $(MAKE) -C qttools/src/linguist/lrelease INSTALL_ROOT=$($(package)_staging_dir) install_target && \ + $(MAKE) -C qttranslations INSTALL_ROOT=$($(package)_staging_dir) install_subtargets +endef + +define $(package)_postprocess_cmds + rm -rf native/mkspecs/ native/lib/ lib/cmake/ && \ + rm -f lib/lib*.la lib/*.prl plugins/*/*.prl +endef diff --git a/contrib/depends/packages/readline.mk b/contrib/depends/packages/readline.mk new file mode 100644 index 000000000..b6e6a451a --- /dev/null +++ b/contrib/depends/packages/readline.mk @@ -0,0 +1,32 @@ +package=readline +$(package)_version=8.0 +$(package)_download_path=https://ftp.gnu.org/gnu/readline +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=e339f51971478d369f8a053a330a190781acb9864cf4c541060f12078948e461 +$(package)_dependencies=ncurses + +define $(package)_set_vars + $(package)_build_opts=CC="$($(package)_cc)" + $(package)_config_env=AR="$($(package)_ar)" RANLIB="$($(package)_ranlib)" CC="$($(package)_cc)" LDFLAGS="-L$(host_prefix)/lib" ARFLAGS=$($(package)_arflags) + $(package)_config_env_darwin=RANLIB="$(host_prefix)/native/bin/x86_64-apple-darwin11-ranlib" AR="$(host_prefix)/native/bin/x86_64-apple-darwin11-ar" CC="$(host_prefix)/native/bin/$($(package)_cc)" + $(package)_config_opts+=--prefix=$(host_prefix) + $(package)_config_opts+=--exec-prefix=$(host_prefix) + $(package)_config_opts+=--host=$(HOST) + $(package)_config_opts+=--disable-shared --with-curses + $(package)_config_opts_release=--disable-debug-mode + $(package)_config_opts_darwin+=RANLIB="$(host_prefix)/native/bin/x86_64-apple-darwin11-ranlib" AR="$(host_prefix)/native/bin/x86_64-apple-darwin11-ar" CC="$(host_prefix)/native/bin/$($(package)_cc)" + $(package)_build_opts=CFLAGS="$($(package)_cflags) $($(package)_cppflags) -fPIC" +endef + +define $(package)_config_cmds + ./configure $($(package)_config_opts) +endef + +define $(package)_build_cmds + $(MAKE) $($(package)_build_opts) +endef + +define $(package)_stage_cmds + $(MAKE) install DESTDIR=$($(package)_staging_dir) prefix=$(host_prefix) exec-prefix=$(host_prefix) +endef + diff --git a/contrib/depends/packages/sodium.mk b/contrib/depends/packages/sodium.mk new file mode 100644 index 000000000..e2ce9b349 --- /dev/null +++ b/contrib/depends/packages/sodium.mk @@ -0,0 +1,33 @@ +package=sodium +$(package)_version=1.0.18 +$(package)_download_path=https://download.libsodium.org/libsodium/releases/ +$(package)_file_name=libsodium-$($(package)_version).tar.gz +$(package)_sha256_hash=6f504490b342a4f8a4c4a02fc9b866cbef8622d5df4e5452b46be121e46636c1 +$(package)_patches=disable-glibc-getrandom-getentropy.patch fix-whitespace.patch + +define $(package)_set_vars +$(package)_config_opts=--enable-static --disable-shared +$(package)_config_opts+=--prefix=$(host_prefix) +$(package)_config_opts_android=RANLIB=$($(package)_ranlib) AR=$($(package)_ar) CC=$($(package)_cc) +$(package)_config_opts_darwin=RANLIB="$(host_prefix)/native/bin/x86_64-apple-darwin11-ranlib" AR="$(host_prefix)/native/bin/x86_64-apple-darwin11-ar" CC="$(host_prefix)/native/bin/$($(package)_cc)" +endef + +define $(package)_config_cmds + patch -p1 < $($(package)_patch_dir)/disable-glibc-getrandom-getentropy.patch &&\ + ./autogen.sh &&\ + patch -p1 < $($(package)_patch_dir)/fix-whitespace.patch &&\ + $($(package)_autoconf) $($(package)_config_opts) AR_FLAGS=$($(package)_arflags) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm lib/*.la +endef + diff --git a/contrib/depends/packages/unbound.mk b/contrib/depends/packages/unbound.mk new file mode 100644 index 000000000..733a7f232 --- /dev/null +++ b/contrib/depends/packages/unbound.mk @@ -0,0 +1,28 @@ +package=unbound +$(package)_version=1.6.8 +$(package)_download_path=https://www.unbound.net/downloads/ +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=e3b428e33f56a45417107448418865fe08d58e0e7fea199b855515f60884dd49 +$(package)_dependencies=openssl expat ldns + +define $(package)_set_vars + $(package)_config_opts=--disable-shared --enable-static --without-pyunbound --prefix=$(host_prefix) --with-libexpat=$(host_prefix) --with-ssl=$(host_prefix) --with-libevent=no --without-pythonmodule --disable-flto --with-pthreads + $(package)_config_opts_linux=--with-pic + $(package)_config_opts_w64=--enable-static-exe --sysconfdir=/etc --prefix=$(host_prefix) --target=$(host_prefix) + $(package)_build_opts_mingw32=LDFLAGS="$($(package)_ldflags) -lpthread" +endef + +define $(package)_config_cmds + $($(package)_autoconf) $($(package)_config_opts) +endef + +define $(package)_build_cmds + $(MAKE) $($(package)_build_opts) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds +endef diff --git a/contrib/depends/packages/unwind.mk b/contrib/depends/packages/unwind.mk new file mode 100644 index 000000000..826a820c4 --- /dev/null +++ b/contrib/depends/packages/unwind.mk @@ -0,0 +1,29 @@ +package=unwind +$(package)_version=1.2 +$(package)_download_path=https://download.savannah.nongnu.org/releases/libunwind +$(package)_file_name=lib$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=1de38ffbdc88bd694d10081865871cd2bfbb02ad8ef9e1606aee18d65532b992 +$(package)_patches=fix_obj_order.patch + +define $(package)_preprocess_cmds + patch -p0 < $($(package)_patch_dir)/fix_obj_order.patch +endef + +define $(package)_config_cmds + cp -f $(BASEDIR)/config.guess config/config.guess &&\ + cp -f $(BASEDIR)/config.sub config/config.sub &&\ + $($(package)_autoconf) --disable-shared --enable-static AR_FLAGS=$($(package)_arflags) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef + +define $(package)_postprocess_cmds + rm lib/*.la +endef + diff --git a/contrib/depends/packages/xproto.mk b/contrib/depends/packages/xproto.mk new file mode 100644 index 000000000..52fe253c7 --- /dev/null +++ b/contrib/depends/packages/xproto.mk @@ -0,0 +1,21 @@ +package=xproto +$(package)_version=7.0.26 +$(package)_download_path=https://xorg.freedesktop.org/releases/individual/proto +$(package)_file_name=$(package)-$($(package)_version).tar.bz2 +$(package)_sha256_hash=636162c1759805a5a0114a369dffdeccb8af8c859ef6e1445f26a4e6e046514f + +define $(package)_set_vars +$(package)_config_opts=--disable-shared +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install +endef diff --git a/contrib/depends/packages/zeromq.mk b/contrib/depends/packages/zeromq.mk new file mode 100644 index 000000000..55941e67d --- /dev/null +++ b/contrib/depends/packages/zeromq.mk @@ -0,0 +1,38 @@ +package=zeromq +$(package)_version=4.1.7 +$(package)_download_path=https://github.com/zeromq/zeromq4-1/releases/download/v$($(package)_version)/ +$(package)_file_name=$(package)-$($(package)_version).tar.gz +$(package)_sha256_hash=31c383cfcd3be1dc8a66e448c403029e793687e70473b89c4cc0bd626e7da299 +$(package)_patches=9114d3957725acd34aa8b8d011585812f3369411.patch 9e6745c12e0b100cd38acecc16ce7db02905e27c.patch ffe62d3398d5e0191f554f61049aa7ec9fc892ae.patch + +define $(package)_set_vars + $(package)_config_opts=--without-documentation --disable-shared --without-libsodium --disable-curve + $(package)_config_opts_linux=--with-pic + $(package)_config_opts_freebsd=--with-pic + $(package)_cxxflags=-std=c++11 +endef + +define $(package)_preprocess_cmds + patch -p1 < $($(package)_patch_dir)/9114d3957725acd34aa8b8d011585812f3369411.patch && \ + patch -p1 < $($(package)_patch_dir)/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch && \ + patch -p1 < $($(package)_patch_dir)/ffe62d3398d5e0191f554f61049aa7ec9fc892ae.patch && \ + ./autogen.sh +endef + +define $(package)_config_cmds + $($(package)_autoconf) AR_FLAGS=$($(package)_arflags) +endef + +define $(package)_build_cmds + $(MAKE) libzmq.la +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) install-libLTLIBRARIES install-includeHEADERS install-pkgconfigDATA +endef + +define $(package)_postprocess_cmds + rm -rf bin share &&\ + rm lib/*.la +endef + diff --git a/contrib/depends/patches/boost/fix_aroptions.patch b/contrib/depends/patches/boost/fix_aroptions.patch new file mode 100644 index 000000000..5b2ec1006 --- /dev/null +++ b/contrib/depends/patches/boost/fix_aroptions.patch @@ -0,0 +1,28 @@ +--- boost_1_64_0/tools/build/src/tools/gcc.jam.O 2017-04-17 03:22:26.000000000 +0100 ++++ boost_1_64_0/tools/build/src/tools/gcc.jam 2019-11-15 15:46:16.957937137 +0000 +@@ -243,6 +243,8 @@ + { + ECHO notice: using gcc archiver :: $(condition) :: $(archiver[1]) ; + } ++ local arflags = [ feature.get-values : $(options) ] ; ++ toolset.flags gcc.archive .ARFLAGS $(condition) : $(arflags) ; + + # - Ranlib. + local ranlib = [ common.get-invocation-command gcc +@@ -970,6 +972,7 @@ + # logic in intel-linux, but that is hardly worth the trouble as on Linux, 'ar' + # is always available. + .AR = ar ; ++.ARFLAGS = rc ; + .RANLIB = ranlib ; + + toolset.flags gcc.archive AROPTIONS ; +@@ -1011,7 +1014,7 @@ + # + actions piecemeal archive + { +- "$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)" ++ "$(.AR)" $(AROPTIONS) $(.ARFLAGS) "$(<)" "$(>)" + "$(.RANLIB)" "$(<)" + } + diff --git a/contrib/depends/patches/cmake/cmake-1-fixes.patch b/contrib/depends/patches/cmake/cmake-1-fixes.patch new file mode 100644 index 000000000..062c06767 --- /dev/null +++ b/contrib/depends/patches/cmake/cmake-1-fixes.patch @@ -0,0 +1,67 @@ +This file is part of MXE. See LICENSE.md for licensing information. + +Contains ad hoc patches for cross building. + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tony Theodore +Date: Fri, 12 Aug 2016 02:01:20 +1000 +Subject: [PATCH 1/3] fix windres invocation options + +windres doesn't recognise various gcc flags like -mms-bitfields, +-fopenmp, -mthreads etc. (basically not `-D` or `-I`) + +diff --git a/Modules/Platform/Windows-windres.cmake b/Modules/Platform/Windows-windres.cmake +index 1111111..2222222 100644 +--- a/Modules/Platform/Windows-windres.cmake ++++ b/Modules/Platform/Windows-windres.cmake +@@ -1 +1 @@ +-set(CMAKE_RC_COMPILE_OBJECT " -O coff ") ++set(CMAKE_RC_COMPILE_OBJECT " -O coff ") + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tony Theodore +Date: Tue, 25 Jul 2017 20:34:56 +1000 +Subject: [PATCH 2/3] add option to disable -isystem + +taken from (not accepted): +https://gitlab.kitware.com/cmake/cmake/merge_requests/895 + +see also: +https://gitlab.kitware.com/cmake/cmake/issues/16291 +https://gitlab.kitware.com/cmake/cmake/issues/16919 + +diff --git a/Modules/Compiler/GNU.cmake b/Modules/Compiler/GNU.cmake +index 1111111..2222222 100644 +--- a/Modules/Compiler/GNU.cmake ++++ b/Modules/Compiler/GNU.cmake +@@ -42,7 +42,7 @@ macro(__compiler_gnu lang) + string(APPEND CMAKE_${lang}_FLAGS_RELWITHDEBINFO_INIT " -O2 -g -DNDEBUG") + set(CMAKE_${lang}_CREATE_PREPROCESSED_SOURCE " -E > ") + set(CMAKE_${lang}_CREATE_ASSEMBLY_SOURCE " -S -o ") +- if(NOT APPLE OR NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4) # work around #4462 ++ if(NOT APPLE OR NOT CMAKE_${lang}_COMPILER_VERSION VERSION_LESS 4 AND (NOT MXE_DISABLE_INCLUDE_SYSTEM_FLAG)) # work around #4462 + set(CMAKE_INCLUDE_SYSTEM_FLAG_${lang} "-isystem ") + endif() + endmacro() + +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Tony Theodore +Date: Tue, 15 Aug 2017 15:25:06 +1000 +Subject: [PATCH 3/3] add CPACK_NSIS_EXECUTABLE variable + + +diff --git a/Source/CPack/cmCPackNSISGenerator.cxx b/Source/CPack/cmCPackNSISGenerator.cxx +index 1111111..2222222 100644 +--- a/Source/CPack/cmCPackNSISGenerator.cxx ++++ b/Source/CPack/cmCPackNSISGenerator.cxx +@@ -384,7 +384,9 @@ int cmCPackNSISGenerator::InitializeInternal() + } + #endif + +- nsisPath = cmSystemTools::FindProgram("makensis", path, false); ++ this->SetOptionIfNotSet("CPACK_NSIS_EXECUTABLE", "makensis"); ++ nsisPath = cmSystemTools::FindProgram( ++ this->GetOption("CPACK_NSIS_EXECUTABLE"), path, false); + + if (nsisPath.empty()) { + cmCPackLogger( diff --git a/contrib/depends/patches/icu4c/icu-001-dont-build-static-dynamic-twice.patch b/contrib/depends/patches/icu4c/icu-001-dont-build-static-dynamic-twice.patch new file mode 100644 index 000000000..bbd4e99e7 --- /dev/null +++ b/contrib/depends/patches/icu4c/icu-001-dont-build-static-dynamic-twice.patch @@ -0,0 +1,37 @@ +Don't build object files twice + +When passed --enable-static and --enable-shared, icu will generate +both a shared and a static version of its libraries. + +However, in order to do so, it builds each and every object file +twice: once with -fPIC (for the shared library), and once without +-fPIC (for the static library). While admittedly building -fPIC for a +static library generates a slightly suboptimal code, this is what all +the autotools-based project are doing. They build each object file +once, and they use it for both the static and shared libraries. + +icu builds the object files for the shared library as .o files, and +the object files for static library as .ao files. By simply changing +the suffix of object files used for static libraries to ".o", we tell +icu to use the ones built for the shared library (i.e, with -fPIC), +and avoid the double build of icu. + +On a fast build server, this brings the target icu build from +3m41.302s down to 1m43.926s (approximate numbers: some other builds +are running on the system at the same time). + +Signed-off-by: Thomas Petazzoni + +Index: b/source/config/mh-linux +=================================================================== +--- a/source/config/mh-linux ++++ b/source/config/mh-linux +@@ -38,7 +38,7 @@ + ## Shared object suffix + SO = so + ## Non-shared intermediate object suffix +-STATIC_O = ao ++STATIC_O = o + + ## Compilation rules + %.$(STATIC_O): $(srcdir)/%.c diff --git a/contrib/depends/patches/libiconv/fix-whitespace.patch b/contrib/depends/patches/libiconv/fix-whitespace.patch new file mode 100644 index 000000000..531364b45 --- /dev/null +++ b/contrib/depends/patches/libiconv/fix-whitespace.patch @@ -0,0 +1,13 @@ +diff --git a/preload/configure b/preload/configure +index aab5c77..e20b8f0 100755 +--- a/preload/configure ++++ b/preload/configure +@@ -588,7 +588,7 @@ MAKEFLAGS= + PACKAGE_NAME='libiconv' + PACKAGE_TARNAME='libiconv' + PACKAGE_VERSION='0' +-PACKAGE_STRING='libiconv 0' ++PACKAGE_STRING='libiconv0' + PACKAGE_BUGREPORT='' + PACKAGE_URL='' + diff --git a/contrib/depends/patches/native_biplist/sorted_list.patch b/contrib/depends/patches/native_biplist/sorted_list.patch new file mode 100644 index 000000000..89abdb1b7 --- /dev/null +++ b/contrib/depends/patches/native_biplist/sorted_list.patch @@ -0,0 +1,29 @@ +--- a/biplist/__init__.py 2014-10-26 19:03:11.000000000 +0000 ++++ b/biplist/__init__.py 2016-07-19 19:30:17.663521999 +0000 +@@ -541,7 +541,7 @@ + return HashableWrapper(n) + elif isinstance(root, dict): + n = {} +- for key, value in iteritems(root): ++ for key, value in sorted(iteritems(root)): + n[self.wrapRoot(key)] = self.wrapRoot(value) + return HashableWrapper(n) + elif isinstance(root, list): +@@ -616,7 +616,7 @@ + elif isinstance(obj, dict): + size = proc_size(len(obj)) + self.incrementByteCount('dictBytes', incr=1+size) +- for key, value in iteritems(obj): ++ for key, value in sorted(iteritems(obj)): + check_key(key) + self.computeOffsets(key, asReference=True) + self.computeOffsets(value, asReference=True) +@@ -714,7 +714,7 @@ + keys = [] + values = [] + objectsToWrite = [] +- for key, value in iteritems(obj): ++ for key, value in sorted(iteritems(obj)): + keys.append(key) + values.append(value) + for key in keys: diff --git a/contrib/depends/patches/native_cctools/skip_otool.patch b/contrib/depends/patches/native_cctools/skip_otool.patch new file mode 100644 index 000000000..30c4ee524 --- /dev/null +++ b/contrib/depends/patches/native_cctools/skip_otool.patch @@ -0,0 +1,12 @@ +--- cctools/Makefile.am.O 2016-06-09 15:06:16.000000000 +0100 ++++ cctools/Makefile.am 2019-11-18 08:59:20.078663220 +0000 +@@ -1,7 +1,7 @@ + if ISDARWIN +-SUBDIRS=libstuff ar as misc otool ld64 $(LD_CLASSIC) ++SUBDIRS=libstuff ar as misc ld64 $(LD_CLASSIC) + else +-SUBDIRS=libstuff ar as misc libobjc2 otool ld64 $(LD_CLASSIC) ++SUBDIRS=libstuff ar as misc ld64 $(LD_CLASSIC) + endif + + ACLOCAL_AMFLAGS = -I m4 diff --git a/contrib/depends/patches/native_cdrkit/cdrkit-deterministic.patch b/contrib/depends/patches/native_cdrkit/cdrkit-deterministic.patch new file mode 100644 index 000000000..8ab0993dc --- /dev/null +++ b/contrib/depends/patches/native_cdrkit/cdrkit-deterministic.patch @@ -0,0 +1,86 @@ +--- cdrkit-1.1.11.old/genisoimage/tree.c 2008-10-21 19:57:47.000000000 -0400 ++++ cdrkit-1.1.11/genisoimage/tree.c 2013-12-06 00:23:18.489622668 -0500 +@@ -1139,8 +1139,9 @@ + scan_directory_tree(struct directory *this_dir, char *path, + struct directory_entry *de) + { +- DIR *current_dir; ++ int current_file; + char whole_path[PATH_MAX]; ++ struct dirent **d_list; + struct dirent *d_entry; + struct directory *parent; + int dflag; +@@ -1164,7 +1165,8 @@ + this_dir->dir_flags |= DIR_WAS_SCANNED; + + errno = 0; /* Paranoia */ +- current_dir = opendir(path); ++ //current_dir = opendir(path); ++ current_file = scandir(path, &d_list, NULL, alphasort); + d_entry = NULL; + + /* +@@ -1173,12 +1175,12 @@ + */ + old_path = path; + +- if (current_dir) { ++ if (current_file >= 0) { + errno = 0; +- d_entry = readdir(current_dir); ++ d_entry = d_list[0]; + } + +- if (!current_dir || !d_entry) { ++ if (current_file < 0 || !d_entry) { + int ret = 1; + + #ifdef USE_LIBSCHILY +@@ -1191,8 +1193,8 @@ + de->isorec.flags[0] &= ~ISO_DIRECTORY; + ret = 0; + } +- if (current_dir) +- closedir(current_dir); ++ if(d_list) ++ free(d_list); + return (ret); + } + #ifdef ABORT_DEEP_ISO_ONLY +@@ -1208,7 +1210,7 @@ + errmsgno(EX_BAD, "use Rock Ridge extensions via -R or -r,\n"); + errmsgno(EX_BAD, "or allow deep ISO9660 directory nesting via -D.\n"); + } +- closedir(current_dir); ++ free(d_list); + return (1); + } + #endif +@@ -1250,13 +1252,13 @@ + * The first time through, skip this, since we already asked + * for the first entry when we opened the directory. + */ +- if (dflag) +- d_entry = readdir(current_dir); ++ if (dflag && current_file >= 0) ++ d_entry = d_list[current_file]; + dflag++; + +- if (!d_entry) ++ if (current_file < 0) + break; +- ++ current_file--; + /* OK, got a valid entry */ + + /* If we do not want all files, then pitch the backups. */ +@@ -1348,7 +1350,7 @@ + insert_file_entry(this_dir, whole_path, d_entry->d_name); + #endif /* APPLE_HYB */ + } +- closedir(current_dir); ++ free(d_list); + + #ifdef APPLE_HYB + /* diff --git a/contrib/depends/patches/native_mac_alias/python3.patch b/contrib/depends/patches/native_mac_alias/python3.patch new file mode 100644 index 000000000..1a32340be --- /dev/null +++ b/contrib/depends/patches/native_mac_alias/python3.patch @@ -0,0 +1,72 @@ +diff -dur a/mac_alias/alias.py b/mac_alias/alias.py +--- a/mac_alias/alias.py 2015-10-19 12:12:48.000000000 +0200 ++++ b/mac_alias/alias.py 2016-04-03 12:13:12.037159417 +0200 +@@ -243,10 +243,10 @@ + alias = Alias() + alias.appinfo = appinfo + +- alias.volume = VolumeInfo (volname.replace('/',':'), ++ alias.volume = VolumeInfo (volname.decode().replace('/',':'), + voldate, fstype, disktype, + volattrs, volfsid) +- alias.target = TargetInfo (kind, filename.replace('/',':'), ++ alias.target = TargetInfo (kind, filename.decode().replace('/',':'), + folder_cnid, cnid, + crdate, creator_code, type_code) + alias.target.levels_from = levels_from +@@ -261,9 +261,9 @@ + b.read(1) + + if tag == TAG_CARBON_FOLDER_NAME: +- alias.target.folder_name = value.replace('/',':') ++ alias.target.folder_name = value.decode().replace('/',':') + elif tag == TAG_CNID_PATH: +- alias.target.cnid_path = struct.unpack(b'>%uI' % (length // 4), ++ alias.target.cnid_path = struct.unpack('>%uI' % (length // 4), + value) + elif tag == TAG_CARBON_PATH: + alias.target.carbon_path = value +@@ -298,9 +298,9 @@ + alias.target.creation_date \ + = mac_epoch + datetime.timedelta(seconds=seconds) + elif tag == TAG_POSIX_PATH: +- alias.target.posix_path = value ++ alias.target.posix_path = value.decode() + elif tag == TAG_POSIX_PATH_TO_MOUNTPOINT: +- alias.volume.posix_path = value ++ alias.volume.posix_path = value.decode() + elif tag == TAG_RECURSIVE_ALIAS_OF_DISK_IMAGE: + alias.volume.disk_image_alias = Alias.from_bytes(value) + elif tag == TAG_USER_HOME_LENGTH_PREFIX: +@@ -422,13 +422,13 @@ + # (so doing so is ridiculous, and nothing could rely on it). + b.write(struct.pack(b'>h28pI2shI64pII4s4shhI2s10s', + self.target.kind, +- carbon_volname, voldate, ++ carbon_volname, int(voldate), + self.volume.fs_type, + self.volume.disk_type, + self.target.folder_cnid, + carbon_filename, + self.target.cnid, +- crdate, ++ int(crdate), + self.target.creator_code, + self.target.type_code, + self.target.levels_from, +@@ -449,12 +449,12 @@ + + b.write(struct.pack(b'>hhQhhQ', + TAG_HIGH_RES_VOLUME_CREATION_DATE, +- 8, long(voldate * 65536), ++ 8, int(voldate * 65536), + TAG_HIGH_RES_CREATION_DATE, +- 8, long(crdate * 65536))) ++ 8, int(crdate * 65536))) + + if self.target.cnid_path: +- cnid_path = struct.pack(b'>%uI' % len(self.target.cnid_path), ++ cnid_path = struct.pack('>%uI' % len(self.target.cnid_path), + *self.target.cnid_path) + b.write(struct.pack(b'>hh', TAG_CNID_PATH, + len(cnid_path))) diff --git a/contrib/depends/patches/ncurses/fallback.c b/contrib/depends/patches/ncurses/fallback.c new file mode 100644 index 000000000..fab108c37 --- /dev/null +++ b/contrib/depends/patches/ncurses/fallback.c @@ -0,0 +1,6621 @@ +/* This file was generated by tinfo/MKfallback.sh */ + +/* + * DO NOT EDIT THIS FILE BY HAND! + */ + +#include + +#include + +/* fallback entries for: linux rxvt vt100 xterm xterm-256color screen screen.linux screen.rxvt screen.xterm-new screen.xterm-256color */ +/* linux */ + +static char linux_alias_data[] = "linux|linux console"; + +static char linux_s_bel [] = "\007"; +static char linux_s_cr [] = "\015"; +static char linux_s_csr [] = "\033[%i%p1%d;%p2%dr"; +static char linux_s_tbc [] = "\033[3g"; +static char linux_s_clear [] = "\033[H\033[J"; +static char linux_s_el [] = "\033[K"; +static char linux_s_ed [] = "\033[J"; +static char linux_s_hpa [] = "\033[%i%p1%dG"; +static char linux_s_cup [] = "\033[%i%p1%d;%p2%dH"; +static char linux_s_cud1 [] = "\012"; +static char linux_s_home [] = "\033[H"; +static char linux_s_civis [] = "\033[?25l\033[?1c"; +static char linux_s_cub1 [] = "\010"; +static char linux_s_cnorm [] = "\033[?25h\033[?0c"; +static char linux_s_cuf1 [] = "\033[C"; +static char linux_s_cuu1 [] = "\033[A"; +static char linux_s_cvvis [] = "\033[?25h\033[?8c"; +static char linux_s_dch1 [] = "\033[P"; +static char linux_s_dl1 [] = "\033[M"; +static char linux_s_smacs [] = "\016"; +static char linux_s_blink [] = "\033[5m"; +static char linux_s_bold [] = "\033[1m"; +static char linux_s_dim [] = "\033[2m"; +static char linux_s_smir [] = "\033[4h"; +static char linux_s_rev [] = "\033[7m"; +static char linux_s_smso [] = "\033[7m"; +static char linux_s_smul [] = "\033[4m"; +static char linux_s_ech [] = "\033[%p1%dX"; +static char linux_s_rmacs [] = "\017"; +static char linux_s_sgr0 [] = "\033[m\017"; +static char linux_s_rmir [] = "\033[4l"; +static char linux_s_rmso [] = "\033[27m"; +static char linux_s_rmul [] = "\033[24m"; +static char linux_s_flash [] = "\033[?5h$<200/>\033[?5l"; +static char linux_s_ich1 [] = "\033[@"; +static char linux_s_il1 [] = "\033[L"; +static char linux_s_kbs [] = "\177"; +static char linux_s_kdch1 [] = "\033[3~"; +static char linux_s_kcud1 [] = "\033[B"; +static char linux_s_kf1 [] = "\033[[A"; +static char linux_s_kf10 [] = "\033[21~"; +static char linux_s_kf2 [] = "\033[[B"; +static char linux_s_kf3 [] = "\033[[C"; +static char linux_s_kf4 [] = "\033[[D"; +static char linux_s_kf5 [] = "\033[[E"; +static char linux_s_kf6 [] = "\033[17~"; +static char linux_s_kf7 [] = "\033[18~"; +static char linux_s_kf8 [] = "\033[19~"; +static char linux_s_kf9 [] = "\033[20~"; +static char linux_s_khome [] = "\033[1~"; +static char linux_s_kich1 [] = "\033[2~"; +static char linux_s_kcub1 [] = "\033[D"; +static char linux_s_knp [] = "\033[6~"; +static char linux_s_kpp [] = "\033[5~"; +static char linux_s_kcuf1 [] = "\033[C"; +static char linux_s_kcuu1 [] = "\033[A"; +static char linux_s_nel [] = "\015\012"; +static char linux_s_dch [] = "\033[%p1%dP"; +static char linux_s_dl [] = "\033[%p1%dM"; +static char linux_s_cud [] = "\033[%p1%dB"; +static char linux_s_ich [] = "\033[%p1%d@"; +static char linux_s_il [] = "\033[%p1%dL"; +static char linux_s_cub [] = "\033[%p1%dD"; +static char linux_s_cuf [] = "\033[%p1%dC"; +static char linux_s_cuu [] = "\033[%p1%dA"; +static char linux_s_rs1 [] = "\033c\033]R"; +static char linux_s_rc [] = "\0338"; +static char linux_s_vpa [] = "\033[%i%p1%dd"; +static char linux_s_sc [] = "\0337"; +static char linux_s_ind [] = "\012"; +static char linux_s_ri [] = "\033M"; +static char linux_s_sgr [] = "\033[0;10%?%p1%t;7%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p5%t;2%;%?%p6%t;1%;m%?%p9%t\016%e\017%;"; +static char linux_s_hts [] = "\033H"; +static char linux_s_ht [] = "\011"; +static char linux_s_kb2 [] = "\033[G"; +static char linux_s_acsc [] = "++,,--..00__``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}c~~"; +static char linux_s_kcbt [] = "\033[Z"; +static char linux_s_smam [] = "\033[?7h"; +static char linux_s_rmam [] = "\033[?7l"; +static char linux_s_enacs [] = "\033)0"; +static char linux_s_kend [] = "\033[4~"; +static char linux_s_kspd [] = "\032"; +static char linux_s_kf11 [] = "\033[23~"; +static char linux_s_kf12 [] = "\033[24~"; +static char linux_s_kf13 [] = "\033[25~"; +static char linux_s_kf14 [] = "\033[26~"; +static char linux_s_kf15 [] = "\033[28~"; +static char linux_s_kf16 [] = "\033[29~"; +static char linux_s_kf17 [] = "\033[31~"; +static char linux_s_kf18 [] = "\033[32~"; +static char linux_s_kf19 [] = "\033[33~"; +static char linux_s_kf20 [] = "\033[34~"; +static char linux_s_el1 [] = "\033[1K"; +static char linux_s_u6 [] = "\033[%i%d;%dR"; +static char linux_s_u7 [] = "\033[6n"; +static char linux_s_u8 [] = "\033[?6c"; +static char linux_s_u9 [] = "\033[c"; +static char linux_s_op [] = "\033[39;49m"; +static char linux_s_oc [] = "\033]R"; +static char linux_s_initc [] = "\033]P%p1%x%p2%{255}%*%{1000}%/%02x%p3%{255}%*%{1000}%/%02x%p4%{255}%*%{1000}%/%02x"; +static char linux_s_kmous [] = "\033[M"; +static char linux_s_setaf [] = "\033[3%p1%dm"; +static char linux_s_setab [] = "\033[4%p1%dm"; +static char linux_s_smpch [] = "\033[11m"; +static char linux_s_rmpch [] = "\033[10m"; + +static char linux_bool_data[] = { + /* 0: bw */ FALSE, + /* 1: am */ TRUE, + /* 2: xsb */ FALSE, + /* 3: xhp */ FALSE, + /* 4: xenl */ TRUE, + /* 5: eo */ TRUE, + /* 6: gn */ FALSE, + /* 7: hc */ FALSE, + /* 8: km */ FALSE, + /* 9: hs */ FALSE, + /* 10: in */ FALSE, + /* 11: da */ FALSE, + /* 12: db */ FALSE, + /* 13: mir */ TRUE, + /* 14: msgr */ TRUE, + /* 15: os */ FALSE, + /* 16: eslok */ FALSE, + /* 17: xt */ FALSE, + /* 18: hz */ FALSE, + /* 19: ul */ FALSE, + /* 20: xon */ TRUE, + /* 21: nxon */ FALSE, + /* 22: mc5i */ FALSE, + /* 23: chts */ FALSE, + /* 24: nrrmc */ FALSE, + /* 25: npc */ FALSE, + /* 26: ndscr */ FALSE, + /* 27: ccc */ TRUE, + /* 28: bce */ TRUE, + /* 29: hls */ FALSE, + /* 30: xhpa */ FALSE, + /* 31: crxm */ FALSE, + /* 32: daisy */ FALSE, + /* 33: xvpa */ FALSE, + /* 34: sam */ FALSE, + /* 35: cpix */ FALSE, + /* 36: lpix */ FALSE, + /* 37: OTbs */ FALSE, + /* 38: OTns */ FALSE, + /* 39: OTnc */ FALSE, + /* 40: OTMT */ FALSE, + /* 41: OTNL */ FALSE, + /* 42: OTpt */ FALSE, + /* 43: OTxr */ FALSE, +}; +static NCURSES_INT2 linux_number_data[] = { + /* 0: cols */ ABSENT_NUMERIC, + /* 1: it */ 8, + /* 2: lines */ ABSENT_NUMERIC, + /* 3: lm */ ABSENT_NUMERIC, + /* 4: xmc */ ABSENT_NUMERIC, + /* 5: pb */ ABSENT_NUMERIC, + /* 6: vt */ ABSENT_NUMERIC, + /* 7: wsl */ ABSENT_NUMERIC, + /* 8: nlab */ ABSENT_NUMERIC, + /* 9: lh */ ABSENT_NUMERIC, + /* 10: lw */ ABSENT_NUMERIC, + /* 11: ma */ ABSENT_NUMERIC, + /* 12: wnum */ ABSENT_NUMERIC, + /* 13: colors */ 8, + /* 14: pairs */ 64, + /* 15: ncv */ 18, + /* 16: bufsz */ ABSENT_NUMERIC, + /* 17: spinv */ ABSENT_NUMERIC, + /* 18: spinh */ ABSENT_NUMERIC, + /* 19: maddr */ ABSENT_NUMERIC, + /* 20: mjump */ ABSENT_NUMERIC, + /* 21: mcs */ ABSENT_NUMERIC, + /* 22: mls */ ABSENT_NUMERIC, + /* 23: npins */ ABSENT_NUMERIC, + /* 24: orc */ ABSENT_NUMERIC, + /* 25: orl */ ABSENT_NUMERIC, + /* 26: orhi */ ABSENT_NUMERIC, + /* 27: orvi */ ABSENT_NUMERIC, + /* 28: cps */ ABSENT_NUMERIC, + /* 29: widcs */ ABSENT_NUMERIC, + /* 30: btns */ ABSENT_NUMERIC, + /* 31: bitwin */ ABSENT_NUMERIC, + /* 32: bitype */ ABSENT_NUMERIC, + /* 33: OTug */ ABSENT_NUMERIC, + /* 34: OTdC */ ABSENT_NUMERIC, + /* 35: OTdN */ ABSENT_NUMERIC, + /* 36: OTdB */ ABSENT_NUMERIC, + /* 37: OTdT */ ABSENT_NUMERIC, + /* 38: OTkn */ ABSENT_NUMERIC, +}; +static char * linux_string_data[] = { + /* 0: cbt */ ABSENT_STRING, + /* 1: bel */ linux_s_bel, + /* 2: cr */ linux_s_cr, + /* 3: csr */ linux_s_csr, + /* 4: tbc */ linux_s_tbc, + /* 5: clear */ linux_s_clear, + /* 6: el */ linux_s_el, + /* 7: ed */ linux_s_ed, + /* 8: hpa */ linux_s_hpa, + /* 9: cmdch */ ABSENT_STRING, + /* 10: cup */ linux_s_cup, + /* 11: cud1 */ linux_s_cud1, + /* 12: home */ linux_s_home, + /* 13: civis */ linux_s_civis, + /* 14: cub1 */ linux_s_cub1, + /* 15: mrcup */ ABSENT_STRING, + /* 16: cnorm */ linux_s_cnorm, + /* 17: cuf1 */ linux_s_cuf1, + /* 18: ll */ ABSENT_STRING, + /* 19: cuu1 */ linux_s_cuu1, + /* 20: cvvis */ linux_s_cvvis, + /* 21: dch1 */ linux_s_dch1, + /* 22: dl1 */ linux_s_dl1, + /* 23: dsl */ ABSENT_STRING, + /* 24: hd */ ABSENT_STRING, + /* 25: smacs */ linux_s_smacs, + /* 26: blink */ linux_s_blink, + /* 27: bold */ linux_s_bold, + /* 28: smcup */ ABSENT_STRING, + /* 29: smdc */ ABSENT_STRING, + /* 30: dim */ linux_s_dim, + /* 31: smir */ linux_s_smir, + /* 32: invis */ ABSENT_STRING, + /* 33: prot */ ABSENT_STRING, + /* 34: rev */ linux_s_rev, + /* 35: smso */ linux_s_smso, + /* 36: smul */ linux_s_smul, + /* 37: ech */ linux_s_ech, + /* 38: rmacs */ linux_s_rmacs, + /* 39: sgr0 */ linux_s_sgr0, + /* 40: rmcup */ ABSENT_STRING, + /* 41: rmdc */ ABSENT_STRING, + /* 42: rmir */ linux_s_rmir, + /* 43: rmso */ linux_s_rmso, + /* 44: rmul */ linux_s_rmul, + /* 45: flash */ linux_s_flash, + /* 46: ff */ ABSENT_STRING, + /* 47: fsl */ ABSENT_STRING, + /* 48: is1 */ ABSENT_STRING, + /* 49: is2 */ ABSENT_STRING, + /* 50: is3 */ ABSENT_STRING, + /* 51: if */ ABSENT_STRING, + /* 52: ich1 */ linux_s_ich1, + /* 53: il1 */ linux_s_il1, + /* 54: ip */ ABSENT_STRING, + /* 55: kbs */ linux_s_kbs, + /* 56: ktbc */ ABSENT_STRING, + /* 57: kclr */ ABSENT_STRING, + /* 58: kctab */ ABSENT_STRING, + /* 59: kdch1 */ linux_s_kdch1, + /* 60: kdl1 */ ABSENT_STRING, + /* 61: kcud1 */ linux_s_kcud1, + /* 62: krmir */ ABSENT_STRING, + /* 63: kel */ ABSENT_STRING, + /* 64: ked */ ABSENT_STRING, + /* 65: kf0 */ ABSENT_STRING, + /* 66: kf1 */ linux_s_kf1, + /* 67: kf10 */ linux_s_kf10, + /* 68: kf2 */ linux_s_kf2, + /* 69: kf3 */ linux_s_kf3, + /* 70: kf4 */ linux_s_kf4, + /* 71: kf5 */ linux_s_kf5, + /* 72: kf6 */ linux_s_kf6, + /* 73: kf7 */ linux_s_kf7, + /* 74: kf8 */ linux_s_kf8, + /* 75: kf9 */ linux_s_kf9, + /* 76: khome */ linux_s_khome, + /* 77: kich1 */ linux_s_kich1, + /* 78: kil1 */ ABSENT_STRING, + /* 79: kcub1 */ linux_s_kcub1, + /* 80: kll */ ABSENT_STRING, + /* 81: knp */ linux_s_knp, + /* 82: kpp */ linux_s_kpp, + /* 83: kcuf1 */ linux_s_kcuf1, + /* 84: kind */ ABSENT_STRING, + /* 85: kri */ ABSENT_STRING, + /* 86: khts */ ABSENT_STRING, + /* 87: kcuu1 */ linux_s_kcuu1, + /* 88: rmkx */ ABSENT_STRING, + /* 89: smkx */ ABSENT_STRING, + /* 90: lf0 */ ABSENT_STRING, + /* 91: lf1 */ ABSENT_STRING, + /* 92: lf10 */ ABSENT_STRING, + /* 93: lf2 */ ABSENT_STRING, + /* 94: lf3 */ ABSENT_STRING, + /* 95: lf4 */ ABSENT_STRING, + /* 96: lf5 */ ABSENT_STRING, + /* 97: lf6 */ ABSENT_STRING, + /* 98: lf7 */ ABSENT_STRING, + /* 99: lf8 */ ABSENT_STRING, + /* 100: lf9 */ ABSENT_STRING, + /* 101: rmm */ ABSENT_STRING, + /* 102: smm */ ABSENT_STRING, + /* 103: nel */ linux_s_nel, + /* 104: pad */ ABSENT_STRING, + /* 105: dch */ linux_s_dch, + /* 106: dl */ linux_s_dl, + /* 107: cud */ linux_s_cud, + /* 108: ich */ linux_s_ich, + /* 109: indn */ ABSENT_STRING, + /* 110: il */ linux_s_il, + /* 111: cub */ linux_s_cub, + /* 112: cuf */ linux_s_cuf, + /* 113: rin */ ABSENT_STRING, + /* 114: cuu */ linux_s_cuu, + /* 115: pfkey */ ABSENT_STRING, + /* 116: pfloc */ ABSENT_STRING, + /* 117: pfx */ ABSENT_STRING, + /* 118: mc0 */ ABSENT_STRING, + /* 119: mc4 */ ABSENT_STRING, + /* 120: mc5 */ ABSENT_STRING, + /* 121: rep */ ABSENT_STRING, + /* 122: rs1 */ linux_s_rs1, + /* 123: rs2 */ ABSENT_STRING, + /* 124: rs3 */ ABSENT_STRING, + /* 125: rf */ ABSENT_STRING, + /* 126: rc */ linux_s_rc, + /* 127: vpa */ linux_s_vpa, + /* 128: sc */ linux_s_sc, + /* 129: ind */ linux_s_ind, + /* 130: ri */ linux_s_ri, + /* 131: sgr */ linux_s_sgr, + /* 132: hts */ linux_s_hts, + /* 133: wind */ ABSENT_STRING, + /* 134: ht */ linux_s_ht, + /* 135: tsl */ ABSENT_STRING, + /* 136: uc */ ABSENT_STRING, + /* 137: hu */ ABSENT_STRING, + /* 138: iprog */ ABSENT_STRING, + /* 139: ka1 */ ABSENT_STRING, + /* 140: ka3 */ ABSENT_STRING, + /* 141: kb2 */ linux_s_kb2, + /* 142: kc1 */ ABSENT_STRING, + /* 143: kc3 */ ABSENT_STRING, + /* 144: mc5p */ ABSENT_STRING, + /* 145: rmp */ ABSENT_STRING, + /* 146: acsc */ linux_s_acsc, + /* 147: pln */ ABSENT_STRING, + /* 148: kcbt */ linux_s_kcbt, + /* 149: smxon */ ABSENT_STRING, + /* 150: rmxon */ ABSENT_STRING, + /* 151: smam */ linux_s_smam, + /* 152: rmam */ linux_s_rmam, + /* 153: xonc */ ABSENT_STRING, + /* 154: xoffc */ ABSENT_STRING, + /* 155: enacs */ linux_s_enacs, + /* 156: smln */ ABSENT_STRING, + /* 157: rmln */ ABSENT_STRING, + /* 158: kbeg */ ABSENT_STRING, + /* 159: kcan */ ABSENT_STRING, + /* 160: kclo */ ABSENT_STRING, + /* 161: kcmd */ ABSENT_STRING, + /* 162: kcpy */ ABSENT_STRING, + /* 163: kcrt */ ABSENT_STRING, + /* 164: kend */ linux_s_kend, + /* 165: kent */ ABSENT_STRING, + /* 166: kext */ ABSENT_STRING, + /* 167: kfnd */ ABSENT_STRING, + /* 168: khlp */ ABSENT_STRING, + /* 169: kmrk */ ABSENT_STRING, + /* 170: kmsg */ ABSENT_STRING, + /* 171: kmov */ ABSENT_STRING, + /* 172: knxt */ ABSENT_STRING, + /* 173: kopn */ ABSENT_STRING, + /* 174: kopt */ ABSENT_STRING, + /* 175: kprv */ ABSENT_STRING, + /* 176: kprt */ ABSENT_STRING, + /* 177: krdo */ ABSENT_STRING, + /* 178: kref */ ABSENT_STRING, + /* 179: krfr */ ABSENT_STRING, + /* 180: krpl */ ABSENT_STRING, + /* 181: krst */ ABSENT_STRING, + /* 182: kres */ ABSENT_STRING, + /* 183: ksav */ ABSENT_STRING, + /* 184: kspd */ linux_s_kspd, + /* 185: kund */ ABSENT_STRING, + /* 186: kBEG */ ABSENT_STRING, + /* 187: kCAN */ ABSENT_STRING, + /* 188: kCMD */ ABSENT_STRING, + /* 189: kCPY */ ABSENT_STRING, + /* 190: kCRT */ ABSENT_STRING, + /* 191: kDC */ ABSENT_STRING, + /* 192: kDL */ ABSENT_STRING, + /* 193: kslt */ ABSENT_STRING, + /* 194: kEND */ ABSENT_STRING, + /* 195: kEOL */ ABSENT_STRING, + /* 196: kEXT */ ABSENT_STRING, + /* 197: kFND */ ABSENT_STRING, + /* 198: kHLP */ ABSENT_STRING, + /* 199: kHOM */ ABSENT_STRING, + /* 200: kIC */ ABSENT_STRING, + /* 201: kLFT */ ABSENT_STRING, + /* 202: kMSG */ ABSENT_STRING, + /* 203: kMOV */ ABSENT_STRING, + /* 204: kNXT */ ABSENT_STRING, + /* 205: kOPT */ ABSENT_STRING, + /* 206: kPRV */ ABSENT_STRING, + /* 207: kPRT */ ABSENT_STRING, + /* 208: kRDO */ ABSENT_STRING, + /* 209: kRPL */ ABSENT_STRING, + /* 210: kRIT */ ABSENT_STRING, + /* 211: kRES */ ABSENT_STRING, + /* 212: kSAV */ ABSENT_STRING, + /* 213: kSPD */ ABSENT_STRING, + /* 214: kUND */ ABSENT_STRING, + /* 215: rfi */ ABSENT_STRING, + /* 216: kf11 */ linux_s_kf11, + /* 217: kf12 */ linux_s_kf12, + /* 218: kf13 */ linux_s_kf13, + /* 219: kf14 */ linux_s_kf14, + /* 220: kf15 */ linux_s_kf15, + /* 221: kf16 */ linux_s_kf16, + /* 222: kf17 */ linux_s_kf17, + /* 223: kf18 */ linux_s_kf18, + /* 224: kf19 */ linux_s_kf19, + /* 225: kf20 */ linux_s_kf20, + /* 226: kf21 */ ABSENT_STRING, + /* 227: kf22 */ ABSENT_STRING, + /* 228: kf23 */ ABSENT_STRING, + /* 229: kf24 */ ABSENT_STRING, + /* 230: kf25 */ ABSENT_STRING, + /* 231: kf26 */ ABSENT_STRING, + /* 232: kf27 */ ABSENT_STRING, + /* 233: kf28 */ ABSENT_STRING, + /* 234: kf29 */ ABSENT_STRING, + /* 235: kf30 */ ABSENT_STRING, + /* 236: kf31 */ ABSENT_STRING, + /* 237: kf32 */ ABSENT_STRING, + /* 238: kf33 */ ABSENT_STRING, + /* 239: kf34 */ ABSENT_STRING, + /* 240: kf35 */ ABSENT_STRING, + /* 241: kf36 */ ABSENT_STRING, + /* 242: kf37 */ ABSENT_STRING, + /* 243: kf38 */ ABSENT_STRING, + /* 244: kf39 */ ABSENT_STRING, + /* 245: kf40 */ ABSENT_STRING, + /* 246: kf41 */ ABSENT_STRING, + /* 247: kf42 */ ABSENT_STRING, + /* 248: kf43 */ ABSENT_STRING, + /* 249: kf44 */ ABSENT_STRING, + /* 250: kf45 */ ABSENT_STRING, + /* 251: kf46 */ ABSENT_STRING, + /* 252: kf47 */ ABSENT_STRING, + /* 253: kf48 */ ABSENT_STRING, + /* 254: kf49 */ ABSENT_STRING, + /* 255: kf50 */ ABSENT_STRING, + /* 256: kf51 */ ABSENT_STRING, + /* 257: kf52 */ ABSENT_STRING, + /* 258: kf53 */ ABSENT_STRING, + /* 259: kf54 */ ABSENT_STRING, + /* 260: kf55 */ ABSENT_STRING, + /* 261: kf56 */ ABSENT_STRING, + /* 262: kf57 */ ABSENT_STRING, + /* 263: kf58 */ ABSENT_STRING, + /* 264: kf59 */ ABSENT_STRING, + /* 265: kf60 */ ABSENT_STRING, + /* 266: kf61 */ ABSENT_STRING, + /* 267: kf62 */ ABSENT_STRING, + /* 268: kf63 */ ABSENT_STRING, + /* 269: el1 */ linux_s_el1, + /* 270: mgc */ ABSENT_STRING, + /* 271: smgl */ ABSENT_STRING, + /* 272: smgr */ ABSENT_STRING, + /* 273: fln */ ABSENT_STRING, + /* 274: sclk */ ABSENT_STRING, + /* 275: dclk */ ABSENT_STRING, + /* 276: rmclk */ ABSENT_STRING, + /* 277: cwin */ ABSENT_STRING, + /* 278: wingo */ ABSENT_STRING, + /* 279: hup */ ABSENT_STRING, + /* 280: dial */ ABSENT_STRING, + /* 281: qdial */ ABSENT_STRING, + /* 282: tone */ ABSENT_STRING, + /* 283: pulse */ ABSENT_STRING, + /* 284: hook */ ABSENT_STRING, + /* 285: pause */ ABSENT_STRING, + /* 286: wait */ ABSENT_STRING, + /* 287: u0 */ ABSENT_STRING, + /* 288: u1 */ ABSENT_STRING, + /* 289: u2 */ ABSENT_STRING, + /* 290: u3 */ ABSENT_STRING, + /* 291: u4 */ ABSENT_STRING, + /* 292: u5 */ ABSENT_STRING, + /* 293: u6 */ linux_s_u6, + /* 294: u7 */ linux_s_u7, + /* 295: u8 */ linux_s_u8, + /* 296: u9 */ linux_s_u9, + /* 297: op */ linux_s_op, + /* 298: oc */ linux_s_oc, + /* 299: initc */ linux_s_initc, + /* 300: initp */ ABSENT_STRING, + /* 301: scp */ ABSENT_STRING, + /* 302: setf */ ABSENT_STRING, + /* 303: setb */ ABSENT_STRING, + /* 304: cpi */ ABSENT_STRING, + /* 305: lpi */ ABSENT_STRING, + /* 306: chr */ ABSENT_STRING, + /* 307: cvr */ ABSENT_STRING, + /* 308: defc */ ABSENT_STRING, + /* 309: swidm */ ABSENT_STRING, + /* 310: sdrfq */ ABSENT_STRING, + /* 311: sitm */ ABSENT_STRING, + /* 312: slm */ ABSENT_STRING, + /* 313: smicm */ ABSENT_STRING, + /* 314: snlq */ ABSENT_STRING, + /* 315: snrmq */ ABSENT_STRING, + /* 316: sshm */ ABSENT_STRING, + /* 317: ssubm */ ABSENT_STRING, + /* 318: ssupm */ ABSENT_STRING, + /* 319: sum */ ABSENT_STRING, + /* 320: rwidm */ ABSENT_STRING, + /* 321: ritm */ ABSENT_STRING, + /* 322: rlm */ ABSENT_STRING, + /* 323: rmicm */ ABSENT_STRING, + /* 324: rshm */ ABSENT_STRING, + /* 325: rsubm */ ABSENT_STRING, + /* 326: rsupm */ ABSENT_STRING, + /* 327: rum */ ABSENT_STRING, + /* 328: mhpa */ ABSENT_STRING, + /* 329: mcud1 */ ABSENT_STRING, + /* 330: mcub1 */ ABSENT_STRING, + /* 331: mcuf1 */ ABSENT_STRING, + /* 332: mvpa */ ABSENT_STRING, + /* 333: mcuu1 */ ABSENT_STRING, + /* 334: porder */ ABSENT_STRING, + /* 335: mcud */ ABSENT_STRING, + /* 336: mcub */ ABSENT_STRING, + /* 337: mcuf */ ABSENT_STRING, + /* 338: mcuu */ ABSENT_STRING, + /* 339: scs */ ABSENT_STRING, + /* 340: smgb */ ABSENT_STRING, + /* 341: smgbp */ ABSENT_STRING, + /* 342: smglp */ ABSENT_STRING, + /* 343: smgrp */ ABSENT_STRING, + /* 344: smgt */ ABSENT_STRING, + /* 345: smgtp */ ABSENT_STRING, + /* 346: sbim */ ABSENT_STRING, + /* 347: scsd */ ABSENT_STRING, + /* 348: rbim */ ABSENT_STRING, + /* 349: rcsd */ ABSENT_STRING, + /* 350: subcs */ ABSENT_STRING, + /* 351: supcs */ ABSENT_STRING, + /* 352: docr */ ABSENT_STRING, + /* 353: zerom */ ABSENT_STRING, + /* 354: csnm */ ABSENT_STRING, + /* 355: kmous */ linux_s_kmous, + /* 356: minfo */ ABSENT_STRING, + /* 357: reqmp */ ABSENT_STRING, + /* 358: getm */ ABSENT_STRING, + /* 359: setaf */ linux_s_setaf, + /* 360: setab */ linux_s_setab, + /* 361: pfxl */ ABSENT_STRING, + /* 362: devt */ ABSENT_STRING, + /* 363: csin */ ABSENT_STRING, + /* 364: s0ds */ ABSENT_STRING, + /* 365: s1ds */ ABSENT_STRING, + /* 366: s2ds */ ABSENT_STRING, + /* 367: s3ds */ ABSENT_STRING, + /* 368: smglr */ ABSENT_STRING, + /* 369: smgtb */ ABSENT_STRING, + /* 370: birep */ ABSENT_STRING, + /* 371: binel */ ABSENT_STRING, + /* 372: bicr */ ABSENT_STRING, + /* 373: colornm */ ABSENT_STRING, + /* 374: defbi */ ABSENT_STRING, + /* 375: endbi */ ABSENT_STRING, + /* 376: setcolor */ ABSENT_STRING, + /* 377: slines */ ABSENT_STRING, + /* 378: dispc */ ABSENT_STRING, + /* 379: smpch */ linux_s_smpch, + /* 380: rmpch */ linux_s_rmpch, + /* 381: smsc */ ABSENT_STRING, + /* 382: rmsc */ ABSENT_STRING, + /* 383: pctrm */ ABSENT_STRING, + /* 384: scesc */ ABSENT_STRING, + /* 385: scesa */ ABSENT_STRING, + /* 386: ehhlm */ ABSENT_STRING, + /* 387: elhlm */ ABSENT_STRING, + /* 388: elohlm */ ABSENT_STRING, + /* 389: erhlm */ ABSENT_STRING, + /* 390: ethlm */ ABSENT_STRING, + /* 391: evhlm */ ABSENT_STRING, + /* 392: sgr1 */ ABSENT_STRING, + /* 393: slength */ ABSENT_STRING, + /* 394: OTi2 */ ABSENT_STRING, + /* 395: OTrs */ ABSENT_STRING, + /* 396: OTnl */ ABSENT_STRING, + /* 397: OTbc */ ABSENT_STRING, + /* 398: OTko */ ABSENT_STRING, + /* 399: OTma */ ABSENT_STRING, + /* 400: OTG2 */ ABSENT_STRING, + /* 401: OTG3 */ ABSENT_STRING, + /* 402: OTG1 */ ABSENT_STRING, + /* 403: OTG4 */ ABSENT_STRING, + /* 404: OTGR */ ABSENT_STRING, + /* 405: OTGL */ ABSENT_STRING, + /* 406: OTGU */ ABSENT_STRING, + /* 407: OTGD */ ABSENT_STRING, + /* 408: OTGH */ ABSENT_STRING, + /* 409: OTGV */ ABSENT_STRING, + /* 410: OTGC */ ABSENT_STRING, + /* 411: meml */ ABSENT_STRING, + /* 412: memu */ ABSENT_STRING, + /* 413: box1 */ ABSENT_STRING, +}; +/* rxvt */ + +static char rxvt_alias_data[] = "rxvt|rxvt terminal emulator (X Window System)"; + +static char rxvt_s_bel [] = "\007"; +static char rxvt_s_cr [] = "\015"; +static char rxvt_s_csr [] = "\033[%i%p1%d;%p2%dr"; +static char rxvt_s_tbc [] = "\033[3g"; +static char rxvt_s_clear [] = "\033[H\033[2J"; +static char rxvt_s_el [] = "\033[K"; +static char rxvt_s_ed [] = "\033[J"; +static char rxvt_s_hpa [] = "\033[%i%p1%dG"; +static char rxvt_s_cup [] = "\033[%i%p1%d;%p2%dH"; +static char rxvt_s_cud1 [] = "\012"; +static char rxvt_s_home [] = "\033[H"; +static char rxvt_s_civis [] = "\033[?25l"; +static char rxvt_s_cub1 [] = "\010"; +static char rxvt_s_cnorm [] = "\033[?25h"; +static char rxvt_s_cuf1 [] = "\033[C"; +static char rxvt_s_cuu1 [] = "\033[A"; +static char rxvt_s_dl1 [] = "\033[M"; +static char rxvt_s_smacs [] = "\016"; +static char rxvt_s_blink [] = "\033[5m"; +static char rxvt_s_bold [] = "\033[1m"; +static char rxvt_s_smcup [] = "\0337\033[?47h"; +static char rxvt_s_smir [] = "\033[4h"; +static char rxvt_s_rev [] = "\033[7m"; +static char rxvt_s_smso [] = "\033[7m"; +static char rxvt_s_smul [] = "\033[4m"; +static char rxvt_s_rmacs [] = "\017"; +static char rxvt_s_sgr0 [] = "\033[m\017"; +static char rxvt_s_rmcup [] = "\033[2J\033[?47l\0338"; +static char rxvt_s_rmir [] = "\033[4l"; +static char rxvt_s_rmso [] = "\033[27m"; +static char rxvt_s_rmul [] = "\033[24m"; +static char rxvt_s_flash [] = "\033[?5h$<100/>\033[?5l"; +static char rxvt_s_is1 [] = "\033[?47l\033=\033[?1l"; +static char rxvt_s_is2 [] = "\033[r\033[m\033[2J\033[H\033[?7h\033[?1;3;4;6l\033[4l"; +static char rxvt_s_ich1 [] = "\033[@"; +static char rxvt_s_il1 [] = "\033[L"; +static char rxvt_s_kbs [] = "\010"; +static char rxvt_s_kdch1 [] = "\033[3~"; +static char rxvt_s_kcud1 [] = "\033[B"; +static char rxvt_s_kel [] = "\033[8^"; +static char rxvt_s_kf0 [] = "\033[21~"; +static char rxvt_s_kf1 [] = "\033[11~"; +static char rxvt_s_kf10 [] = "\033[21~"; +static char rxvt_s_kf2 [] = "\033[12~"; +static char rxvt_s_kf3 [] = "\033[13~"; +static char rxvt_s_kf4 [] = "\033[14~"; +static char rxvt_s_kf5 [] = "\033[15~"; +static char rxvt_s_kf6 [] = "\033[17~"; +static char rxvt_s_kf7 [] = "\033[18~"; +static char rxvt_s_kf8 [] = "\033[19~"; +static char rxvt_s_kf9 [] = "\033[20~"; +static char rxvt_s_khome [] = "\033[7~"; +static char rxvt_s_kich1 [] = "\033[2~"; +static char rxvt_s_kcub1 [] = "\033[D"; +static char rxvt_s_knp [] = "\033[6~"; +static char rxvt_s_kpp [] = "\033[5~"; +static char rxvt_s_kcuf1 [] = "\033[C"; +static char rxvt_s_kind [] = "\033[a"; +static char rxvt_s_kri [] = "\033[b"; +static char rxvt_s_kcuu1 [] = "\033[A"; +static char rxvt_s_rmkx [] = "\033>"; +static char rxvt_s_smkx [] = "\033="; +static char rxvt_s_dl [] = "\033[%p1%dM"; +static char rxvt_s_cud [] = "\033[%p1%dB"; +static char rxvt_s_ich [] = "\033[%p1%d@"; +static char rxvt_s_il [] = "\033[%p1%dL"; +static char rxvt_s_cub [] = "\033[%p1%dD"; +static char rxvt_s_cuf [] = "\033[%p1%dC"; +static char rxvt_s_cuu [] = "\033[%p1%dA"; +static char rxvt_s_rs1 [] = "\033>\033[1;3;4;5;6l\033[?7h\033[m\033[r\033[2J\033[H"; +static char rxvt_s_rs2 [] = "\033[r\033[m\033[2J\033[H\033[?7h\033[?1;3;4;6l\033[4l\033>\033[?1000l\033[?25h"; +static char rxvt_s_rc [] = "\0338"; +static char rxvt_s_vpa [] = "\033[%i%p1%dd"; +static char rxvt_s_sc [] = "\0337"; +static char rxvt_s_ind [] = "\012"; +static char rxvt_s_ri [] = "\033M"; +static char rxvt_s_sgr [] = "\033[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;m%?%p9%t\016%e\017%;"; +static char rxvt_s_hts [] = "\033H"; +static char rxvt_s_ht [] = "\011"; +static char rxvt_s_ka1 [] = "\033Ow"; +static char rxvt_s_ka3 [] = "\033Oy"; +static char rxvt_s_kb2 [] = "\033Ou"; +static char rxvt_s_kc1 [] = "\033Oq"; +static char rxvt_s_kc3 [] = "\033Os"; +static char rxvt_s_acsc [] = "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"; +static char rxvt_s_kcbt [] = "\033[Z"; +static char rxvt_s_enacs [] = "\033(B\033)0"; +static char rxvt_s_kend [] = "\033[8~"; +static char rxvt_s_kent [] = "\033OM"; +static char rxvt_s_kfnd [] = "\033[1~"; +static char rxvt_s_kDC [] = "\033[3$"; +static char rxvt_s_kslt [] = "\033[4~"; +static char rxvt_s_kEND [] = "\033[8$"; +static char rxvt_s_kHOM [] = "\033[7$"; +static char rxvt_s_kIC [] = "\033[2$"; +static char rxvt_s_kLFT [] = "\033[d"; +static char rxvt_s_kNXT [] = "\033[6$"; +static char rxvt_s_kPRV [] = "\033[5$"; +static char rxvt_s_kRIT [] = "\033[c"; +static char rxvt_s_kf11 [] = "\033[23~"; +static char rxvt_s_kf12 [] = "\033[24~"; +static char rxvt_s_kf13 [] = "\033[25~"; +static char rxvt_s_kf14 [] = "\033[26~"; +static char rxvt_s_kf15 [] = "\033[28~"; +static char rxvt_s_kf16 [] = "\033[29~"; +static char rxvt_s_kf17 [] = "\033[31~"; +static char rxvt_s_kf18 [] = "\033[32~"; +static char rxvt_s_kf19 [] = "\033[33~"; +static char rxvt_s_kf20 [] = "\033[34~"; +static char rxvt_s_kf21 [] = "\033[23$"; +static char rxvt_s_kf22 [] = "\033[24$"; +static char rxvt_s_kf23 [] = "\033[11^"; +static char rxvt_s_kf24 [] = "\033[12^"; +static char rxvt_s_kf25 [] = "\033[13^"; +static char rxvt_s_kf26 [] = "\033[14^"; +static char rxvt_s_kf27 [] = "\033[15^"; +static char rxvt_s_kf28 [] = "\033[17^"; +static char rxvt_s_kf29 [] = "\033[18^"; +static char rxvt_s_kf30 [] = "\033[19^"; +static char rxvt_s_kf31 [] = "\033[20^"; +static char rxvt_s_kf32 [] = "\033[21^"; +static char rxvt_s_kf33 [] = "\033[23^"; +static char rxvt_s_kf34 [] = "\033[24^"; +static char rxvt_s_kf35 [] = "\033[25^"; +static char rxvt_s_kf36 [] = "\033[26^"; +static char rxvt_s_kf37 [] = "\033[28^"; +static char rxvt_s_kf38 [] = "\033[29^"; +static char rxvt_s_kf39 [] = "\033[31^"; +static char rxvt_s_kf40 [] = "\033[32^"; +static char rxvt_s_kf41 [] = "\033[33^"; +static char rxvt_s_kf42 [] = "\033[34^"; +static char rxvt_s_kf43 [] = "\033[23@"; +static char rxvt_s_kf44 [] = "\033[24@"; +static char rxvt_s_el1 [] = "\033[1K"; +static char rxvt_s_u6 [] = "\033[%i%d;%dR"; +static char rxvt_s_u7 [] = "\033[6n"; +static char rxvt_s_u8 [] = "\033[?1;2c"; +static char rxvt_s_u9 [] = "\033[c"; +static char rxvt_s_op [] = "\033[39;49m"; +static char rxvt_s_kmous [] = "\033[M"; +static char rxvt_s_setaf [] = "\033[3%p1%dm"; +static char rxvt_s_setab [] = "\033[4%p1%dm"; +static char rxvt_s_s0ds [] = "\033(B"; +static char rxvt_s_s1ds [] = "\033(0"; + +static char rxvt_bool_data[] = { + /* 0: bw */ FALSE, + /* 1: am */ TRUE, + /* 2: xsb */ FALSE, + /* 3: xhp */ FALSE, + /* 4: xenl */ TRUE, + /* 5: eo */ TRUE, + /* 6: gn */ FALSE, + /* 7: hc */ FALSE, + /* 8: km */ FALSE, + /* 9: hs */ FALSE, + /* 10: in */ FALSE, + /* 11: da */ FALSE, + /* 12: db */ FALSE, + /* 13: mir */ TRUE, + /* 14: msgr */ TRUE, + /* 15: os */ FALSE, + /* 16: eslok */ FALSE, + /* 17: xt */ FALSE, + /* 18: hz */ FALSE, + /* 19: ul */ FALSE, + /* 20: xon */ TRUE, + /* 21: nxon */ FALSE, + /* 22: mc5i */ FALSE, + /* 23: chts */ FALSE, + /* 24: nrrmc */ FALSE, + /* 25: npc */ FALSE, + /* 26: ndscr */ FALSE, + /* 27: ccc */ FALSE, + /* 28: bce */ TRUE, + /* 29: hls */ FALSE, + /* 30: xhpa */ FALSE, + /* 31: crxm */ FALSE, + /* 32: daisy */ FALSE, + /* 33: xvpa */ FALSE, + /* 34: sam */ FALSE, + /* 35: cpix */ FALSE, + /* 36: lpix */ FALSE, + /* 37: OTbs */ TRUE, + /* 38: OTns */ FALSE, + /* 39: OTnc */ FALSE, + /* 40: OTMT */ FALSE, + /* 41: OTNL */ FALSE, + /* 42: OTpt */ FALSE, + /* 43: OTxr */ FALSE, +}; +static NCURSES_INT2 rxvt_number_data[] = { + /* 0: cols */ 80, + /* 1: it */ 8, + /* 2: lines */ 24, + /* 3: lm */ ABSENT_NUMERIC, + /* 4: xmc */ ABSENT_NUMERIC, + /* 5: pb */ ABSENT_NUMERIC, + /* 6: vt */ ABSENT_NUMERIC, + /* 7: wsl */ ABSENT_NUMERIC, + /* 8: nlab */ ABSENT_NUMERIC, + /* 9: lh */ ABSENT_NUMERIC, + /* 10: lw */ ABSENT_NUMERIC, + /* 11: ma */ ABSENT_NUMERIC, + /* 12: wnum */ ABSENT_NUMERIC, + /* 13: colors */ 8, + /* 14: pairs */ 64, + /* 15: ncv */ CANCELLED_NUMERIC, + /* 16: bufsz */ ABSENT_NUMERIC, + /* 17: spinv */ ABSENT_NUMERIC, + /* 18: spinh */ ABSENT_NUMERIC, + /* 19: maddr */ ABSENT_NUMERIC, + /* 20: mjump */ ABSENT_NUMERIC, + /* 21: mcs */ ABSENT_NUMERIC, + /* 22: mls */ ABSENT_NUMERIC, + /* 23: npins */ ABSENT_NUMERIC, + /* 24: orc */ ABSENT_NUMERIC, + /* 25: orl */ ABSENT_NUMERIC, + /* 26: orhi */ ABSENT_NUMERIC, + /* 27: orvi */ ABSENT_NUMERIC, + /* 28: cps */ ABSENT_NUMERIC, + /* 29: widcs */ ABSENT_NUMERIC, + /* 30: btns */ ABSENT_NUMERIC, + /* 31: bitwin */ ABSENT_NUMERIC, + /* 32: bitype */ ABSENT_NUMERIC, + /* 33: OTug */ ABSENT_NUMERIC, + /* 34: OTdC */ ABSENT_NUMERIC, + /* 35: OTdN */ ABSENT_NUMERIC, + /* 36: OTdB */ ABSENT_NUMERIC, + /* 37: OTdT */ ABSENT_NUMERIC, + /* 38: OTkn */ ABSENT_NUMERIC, +}; +static char * rxvt_string_data[] = { + /* 0: cbt */ ABSENT_STRING, + /* 1: bel */ rxvt_s_bel, + /* 2: cr */ rxvt_s_cr, + /* 3: csr */ rxvt_s_csr, + /* 4: tbc */ rxvt_s_tbc, + /* 5: clear */ rxvt_s_clear, + /* 6: el */ rxvt_s_el, + /* 7: ed */ rxvt_s_ed, + /* 8: hpa */ rxvt_s_hpa, + /* 9: cmdch */ ABSENT_STRING, + /* 10: cup */ rxvt_s_cup, + /* 11: cud1 */ rxvt_s_cud1, + /* 12: home */ rxvt_s_home, + /* 13: civis */ rxvt_s_civis, + /* 14: cub1 */ rxvt_s_cub1, + /* 15: mrcup */ ABSENT_STRING, + /* 16: cnorm */ rxvt_s_cnorm, + /* 17: cuf1 */ rxvt_s_cuf1, + /* 18: ll */ ABSENT_STRING, + /* 19: cuu1 */ rxvt_s_cuu1, + /* 20: cvvis */ ABSENT_STRING, + /* 21: dch1 */ ABSENT_STRING, + /* 22: dl1 */ rxvt_s_dl1, + /* 23: dsl */ ABSENT_STRING, + /* 24: hd */ ABSENT_STRING, + /* 25: smacs */ rxvt_s_smacs, + /* 26: blink */ rxvt_s_blink, + /* 27: bold */ rxvt_s_bold, + /* 28: smcup */ rxvt_s_smcup, + /* 29: smdc */ ABSENT_STRING, + /* 30: dim */ ABSENT_STRING, + /* 31: smir */ rxvt_s_smir, + /* 32: invis */ ABSENT_STRING, + /* 33: prot */ ABSENT_STRING, + /* 34: rev */ rxvt_s_rev, + /* 35: smso */ rxvt_s_smso, + /* 36: smul */ rxvt_s_smul, + /* 37: ech */ ABSENT_STRING, + /* 38: rmacs */ rxvt_s_rmacs, + /* 39: sgr0 */ rxvt_s_sgr0, + /* 40: rmcup */ rxvt_s_rmcup, + /* 41: rmdc */ ABSENT_STRING, + /* 42: rmir */ rxvt_s_rmir, + /* 43: rmso */ rxvt_s_rmso, + /* 44: rmul */ rxvt_s_rmul, + /* 45: flash */ rxvt_s_flash, + /* 46: ff */ ABSENT_STRING, + /* 47: fsl */ ABSENT_STRING, + /* 48: is1 */ rxvt_s_is1, + /* 49: is2 */ rxvt_s_is2, + /* 50: is3 */ ABSENT_STRING, + /* 51: if */ ABSENT_STRING, + /* 52: ich1 */ rxvt_s_ich1, + /* 53: il1 */ rxvt_s_il1, + /* 54: ip */ ABSENT_STRING, + /* 55: kbs */ rxvt_s_kbs, + /* 56: ktbc */ ABSENT_STRING, + /* 57: kclr */ ABSENT_STRING, + /* 58: kctab */ ABSENT_STRING, + /* 59: kdch1 */ rxvt_s_kdch1, + /* 60: kdl1 */ ABSENT_STRING, + /* 61: kcud1 */ rxvt_s_kcud1, + /* 62: krmir */ ABSENT_STRING, + /* 63: kel */ rxvt_s_kel, + /* 64: ked */ ABSENT_STRING, + /* 65: kf0 */ rxvt_s_kf0, + /* 66: kf1 */ rxvt_s_kf1, + /* 67: kf10 */ rxvt_s_kf10, + /* 68: kf2 */ rxvt_s_kf2, + /* 69: kf3 */ rxvt_s_kf3, + /* 70: kf4 */ rxvt_s_kf4, + /* 71: kf5 */ rxvt_s_kf5, + /* 72: kf6 */ rxvt_s_kf6, + /* 73: kf7 */ rxvt_s_kf7, + /* 74: kf8 */ rxvt_s_kf8, + /* 75: kf9 */ rxvt_s_kf9, + /* 76: khome */ rxvt_s_khome, + /* 77: kich1 */ rxvt_s_kich1, + /* 78: kil1 */ ABSENT_STRING, + /* 79: kcub1 */ rxvt_s_kcub1, + /* 80: kll */ ABSENT_STRING, + /* 81: knp */ rxvt_s_knp, + /* 82: kpp */ rxvt_s_kpp, + /* 83: kcuf1 */ rxvt_s_kcuf1, + /* 84: kind */ rxvt_s_kind, + /* 85: kri */ rxvt_s_kri, + /* 86: khts */ ABSENT_STRING, + /* 87: kcuu1 */ rxvt_s_kcuu1, + /* 88: rmkx */ rxvt_s_rmkx, + /* 89: smkx */ rxvt_s_smkx, + /* 90: lf0 */ ABSENT_STRING, + /* 91: lf1 */ ABSENT_STRING, + /* 92: lf10 */ ABSENT_STRING, + /* 93: lf2 */ ABSENT_STRING, + /* 94: lf3 */ ABSENT_STRING, + /* 95: lf4 */ ABSENT_STRING, + /* 96: lf5 */ ABSENT_STRING, + /* 97: lf6 */ ABSENT_STRING, + /* 98: lf7 */ ABSENT_STRING, + /* 99: lf8 */ ABSENT_STRING, + /* 100: lf9 */ ABSENT_STRING, + /* 101: rmm */ ABSENT_STRING, + /* 102: smm */ ABSENT_STRING, + /* 103: nel */ ABSENT_STRING, + /* 104: pad */ ABSENT_STRING, + /* 105: dch */ ABSENT_STRING, + /* 106: dl */ rxvt_s_dl, + /* 107: cud */ rxvt_s_cud, + /* 108: ich */ rxvt_s_ich, + /* 109: indn */ ABSENT_STRING, + /* 110: il */ rxvt_s_il, + /* 111: cub */ rxvt_s_cub, + /* 112: cuf */ rxvt_s_cuf, + /* 113: rin */ ABSENT_STRING, + /* 114: cuu */ rxvt_s_cuu, + /* 115: pfkey */ ABSENT_STRING, + /* 116: pfloc */ ABSENT_STRING, + /* 117: pfx */ ABSENT_STRING, + /* 118: mc0 */ ABSENT_STRING, + /* 119: mc4 */ ABSENT_STRING, + /* 120: mc5 */ ABSENT_STRING, + /* 121: rep */ ABSENT_STRING, + /* 122: rs1 */ rxvt_s_rs1, + /* 123: rs2 */ rxvt_s_rs2, + /* 124: rs3 */ ABSENT_STRING, + /* 125: rf */ ABSENT_STRING, + /* 126: rc */ rxvt_s_rc, + /* 127: vpa */ rxvt_s_vpa, + /* 128: sc */ rxvt_s_sc, + /* 129: ind */ rxvt_s_ind, + /* 130: ri */ rxvt_s_ri, + /* 131: sgr */ rxvt_s_sgr, + /* 132: hts */ rxvt_s_hts, + /* 133: wind */ ABSENT_STRING, + /* 134: ht */ rxvt_s_ht, + /* 135: tsl */ ABSENT_STRING, + /* 136: uc */ ABSENT_STRING, + /* 137: hu */ ABSENT_STRING, + /* 138: iprog */ ABSENT_STRING, + /* 139: ka1 */ rxvt_s_ka1, + /* 140: ka3 */ rxvt_s_ka3, + /* 141: kb2 */ rxvt_s_kb2, + /* 142: kc1 */ rxvt_s_kc1, + /* 143: kc3 */ rxvt_s_kc3, + /* 144: mc5p */ ABSENT_STRING, + /* 145: rmp */ ABSENT_STRING, + /* 146: acsc */ rxvt_s_acsc, + /* 147: pln */ ABSENT_STRING, + /* 148: kcbt */ rxvt_s_kcbt, + /* 149: smxon */ ABSENT_STRING, + /* 150: rmxon */ ABSENT_STRING, + /* 151: smam */ ABSENT_STRING, + /* 152: rmam */ ABSENT_STRING, + /* 153: xonc */ ABSENT_STRING, + /* 154: xoffc */ ABSENT_STRING, + /* 155: enacs */ rxvt_s_enacs, + /* 156: smln */ ABSENT_STRING, + /* 157: rmln */ ABSENT_STRING, + /* 158: kbeg */ ABSENT_STRING, + /* 159: kcan */ ABSENT_STRING, + /* 160: kclo */ ABSENT_STRING, + /* 161: kcmd */ ABSENT_STRING, + /* 162: kcpy */ ABSENT_STRING, + /* 163: kcrt */ ABSENT_STRING, + /* 164: kend */ rxvt_s_kend, + /* 165: kent */ rxvt_s_kent, + /* 166: kext */ ABSENT_STRING, + /* 167: kfnd */ rxvt_s_kfnd, + /* 168: khlp */ ABSENT_STRING, + /* 169: kmrk */ ABSENT_STRING, + /* 170: kmsg */ ABSENT_STRING, + /* 171: kmov */ ABSENT_STRING, + /* 172: knxt */ ABSENT_STRING, + /* 173: kopn */ ABSENT_STRING, + /* 174: kopt */ ABSENT_STRING, + /* 175: kprv */ ABSENT_STRING, + /* 176: kprt */ ABSENT_STRING, + /* 177: krdo */ ABSENT_STRING, + /* 178: kref */ ABSENT_STRING, + /* 179: krfr */ ABSENT_STRING, + /* 180: krpl */ ABSENT_STRING, + /* 181: krst */ ABSENT_STRING, + /* 182: kres */ ABSENT_STRING, + /* 183: ksav */ ABSENT_STRING, + /* 184: kspd */ ABSENT_STRING, + /* 185: kund */ ABSENT_STRING, + /* 186: kBEG */ ABSENT_STRING, + /* 187: kCAN */ ABSENT_STRING, + /* 188: kCMD */ ABSENT_STRING, + /* 189: kCPY */ ABSENT_STRING, + /* 190: kCRT */ ABSENT_STRING, + /* 191: kDC */ rxvt_s_kDC, + /* 192: kDL */ ABSENT_STRING, + /* 193: kslt */ rxvt_s_kslt, + /* 194: kEND */ rxvt_s_kEND, + /* 195: kEOL */ ABSENT_STRING, + /* 196: kEXT */ ABSENT_STRING, + /* 197: kFND */ ABSENT_STRING, + /* 198: kHLP */ ABSENT_STRING, + /* 199: kHOM */ rxvt_s_kHOM, + /* 200: kIC */ rxvt_s_kIC, + /* 201: kLFT */ rxvt_s_kLFT, + /* 202: kMSG */ ABSENT_STRING, + /* 203: kMOV */ ABSENT_STRING, + /* 204: kNXT */ rxvt_s_kNXT, + /* 205: kOPT */ ABSENT_STRING, + /* 206: kPRV */ rxvt_s_kPRV, + /* 207: kPRT */ ABSENT_STRING, + /* 208: kRDO */ ABSENT_STRING, + /* 209: kRPL */ ABSENT_STRING, + /* 210: kRIT */ rxvt_s_kRIT, + /* 211: kRES */ ABSENT_STRING, + /* 212: kSAV */ ABSENT_STRING, + /* 213: kSPD */ ABSENT_STRING, + /* 214: kUND */ ABSENT_STRING, + /* 215: rfi */ ABSENT_STRING, + /* 216: kf11 */ rxvt_s_kf11, + /* 217: kf12 */ rxvt_s_kf12, + /* 218: kf13 */ rxvt_s_kf13, + /* 219: kf14 */ rxvt_s_kf14, + /* 220: kf15 */ rxvt_s_kf15, + /* 221: kf16 */ rxvt_s_kf16, + /* 222: kf17 */ rxvt_s_kf17, + /* 223: kf18 */ rxvt_s_kf18, + /* 224: kf19 */ rxvt_s_kf19, + /* 225: kf20 */ rxvt_s_kf20, + /* 226: kf21 */ rxvt_s_kf21, + /* 227: kf22 */ rxvt_s_kf22, + /* 228: kf23 */ rxvt_s_kf23, + /* 229: kf24 */ rxvt_s_kf24, + /* 230: kf25 */ rxvt_s_kf25, + /* 231: kf26 */ rxvt_s_kf26, + /* 232: kf27 */ rxvt_s_kf27, + /* 233: kf28 */ rxvt_s_kf28, + /* 234: kf29 */ rxvt_s_kf29, + /* 235: kf30 */ rxvt_s_kf30, + /* 236: kf31 */ rxvt_s_kf31, + /* 237: kf32 */ rxvt_s_kf32, + /* 238: kf33 */ rxvt_s_kf33, + /* 239: kf34 */ rxvt_s_kf34, + /* 240: kf35 */ rxvt_s_kf35, + /* 241: kf36 */ rxvt_s_kf36, + /* 242: kf37 */ rxvt_s_kf37, + /* 243: kf38 */ rxvt_s_kf38, + /* 244: kf39 */ rxvt_s_kf39, + /* 245: kf40 */ rxvt_s_kf40, + /* 246: kf41 */ rxvt_s_kf41, + /* 247: kf42 */ rxvt_s_kf42, + /* 248: kf43 */ rxvt_s_kf43, + /* 249: kf44 */ rxvt_s_kf44, + /* 250: kf45 */ ABSENT_STRING, + /* 251: kf46 */ ABSENT_STRING, + /* 252: kf47 */ ABSENT_STRING, + /* 253: kf48 */ ABSENT_STRING, + /* 254: kf49 */ ABSENT_STRING, + /* 255: kf50 */ ABSENT_STRING, + /* 256: kf51 */ ABSENT_STRING, + /* 257: kf52 */ ABSENT_STRING, + /* 258: kf53 */ ABSENT_STRING, + /* 259: kf54 */ ABSENT_STRING, + /* 260: kf55 */ ABSENT_STRING, + /* 261: kf56 */ ABSENT_STRING, + /* 262: kf57 */ ABSENT_STRING, + /* 263: kf58 */ ABSENT_STRING, + /* 264: kf59 */ ABSENT_STRING, + /* 265: kf60 */ ABSENT_STRING, + /* 266: kf61 */ ABSENT_STRING, + /* 267: kf62 */ ABSENT_STRING, + /* 268: kf63 */ ABSENT_STRING, + /* 269: el1 */ rxvt_s_el1, + /* 270: mgc */ ABSENT_STRING, + /* 271: smgl */ ABSENT_STRING, + /* 272: smgr */ ABSENT_STRING, + /* 273: fln */ ABSENT_STRING, + /* 274: sclk */ ABSENT_STRING, + /* 275: dclk */ ABSENT_STRING, + /* 276: rmclk */ ABSENT_STRING, + /* 277: cwin */ ABSENT_STRING, + /* 278: wingo */ ABSENT_STRING, + /* 279: hup */ ABSENT_STRING, + /* 280: dial */ ABSENT_STRING, + /* 281: qdial */ ABSENT_STRING, + /* 282: tone */ ABSENT_STRING, + /* 283: pulse */ ABSENT_STRING, + /* 284: hook */ ABSENT_STRING, + /* 285: pause */ ABSENT_STRING, + /* 286: wait */ ABSENT_STRING, + /* 287: u0 */ ABSENT_STRING, + /* 288: u1 */ ABSENT_STRING, + /* 289: u2 */ ABSENT_STRING, + /* 290: u3 */ ABSENT_STRING, + /* 291: u4 */ ABSENT_STRING, + /* 292: u5 */ ABSENT_STRING, + /* 293: u6 */ rxvt_s_u6, + /* 294: u7 */ rxvt_s_u7, + /* 295: u8 */ rxvt_s_u8, + /* 296: u9 */ rxvt_s_u9, + /* 297: op */ rxvt_s_op, + /* 298: oc */ ABSENT_STRING, + /* 299: initc */ ABSENT_STRING, + /* 300: initp */ ABSENT_STRING, + /* 301: scp */ ABSENT_STRING, + /* 302: setf */ ABSENT_STRING, + /* 303: setb */ ABSENT_STRING, + /* 304: cpi */ ABSENT_STRING, + /* 305: lpi */ ABSENT_STRING, + /* 306: chr */ ABSENT_STRING, + /* 307: cvr */ ABSENT_STRING, + /* 308: defc */ ABSENT_STRING, + /* 309: swidm */ ABSENT_STRING, + /* 310: sdrfq */ ABSENT_STRING, + /* 311: sitm */ ABSENT_STRING, + /* 312: slm */ ABSENT_STRING, + /* 313: smicm */ ABSENT_STRING, + /* 314: snlq */ ABSENT_STRING, + /* 315: snrmq */ ABSENT_STRING, + /* 316: sshm */ ABSENT_STRING, + /* 317: ssubm */ ABSENT_STRING, + /* 318: ssupm */ ABSENT_STRING, + /* 319: sum */ ABSENT_STRING, + /* 320: rwidm */ ABSENT_STRING, + /* 321: ritm */ ABSENT_STRING, + /* 322: rlm */ ABSENT_STRING, + /* 323: rmicm */ ABSENT_STRING, + /* 324: rshm */ ABSENT_STRING, + /* 325: rsubm */ ABSENT_STRING, + /* 326: rsupm */ ABSENT_STRING, + /* 327: rum */ ABSENT_STRING, + /* 328: mhpa */ ABSENT_STRING, + /* 329: mcud1 */ ABSENT_STRING, + /* 330: mcub1 */ ABSENT_STRING, + /* 331: mcuf1 */ ABSENT_STRING, + /* 332: mvpa */ ABSENT_STRING, + /* 333: mcuu1 */ ABSENT_STRING, + /* 334: porder */ ABSENT_STRING, + /* 335: mcud */ ABSENT_STRING, + /* 336: mcub */ ABSENT_STRING, + /* 337: mcuf */ ABSENT_STRING, + /* 338: mcuu */ ABSENT_STRING, + /* 339: scs */ ABSENT_STRING, + /* 340: smgb */ ABSENT_STRING, + /* 341: smgbp */ ABSENT_STRING, + /* 342: smglp */ ABSENT_STRING, + /* 343: smgrp */ ABSENT_STRING, + /* 344: smgt */ ABSENT_STRING, + /* 345: smgtp */ ABSENT_STRING, + /* 346: sbim */ ABSENT_STRING, + /* 347: scsd */ ABSENT_STRING, + /* 348: rbim */ ABSENT_STRING, + /* 349: rcsd */ ABSENT_STRING, + /* 350: subcs */ ABSENT_STRING, + /* 351: supcs */ ABSENT_STRING, + /* 352: docr */ ABSENT_STRING, + /* 353: zerom */ ABSENT_STRING, + /* 354: csnm */ ABSENT_STRING, + /* 355: kmous */ rxvt_s_kmous, + /* 356: minfo */ ABSENT_STRING, + /* 357: reqmp */ ABSENT_STRING, + /* 358: getm */ ABSENT_STRING, + /* 359: setaf */ rxvt_s_setaf, + /* 360: setab */ rxvt_s_setab, + /* 361: pfxl */ ABSENT_STRING, + /* 362: devt */ ABSENT_STRING, + /* 363: csin */ ABSENT_STRING, + /* 364: s0ds */ rxvt_s_s0ds, + /* 365: s1ds */ rxvt_s_s1ds, + /* 366: s2ds */ ABSENT_STRING, + /* 367: s3ds */ ABSENT_STRING, + /* 368: smglr */ ABSENT_STRING, + /* 369: smgtb */ ABSENT_STRING, + /* 370: birep */ ABSENT_STRING, + /* 371: binel */ ABSENT_STRING, + /* 372: bicr */ ABSENT_STRING, + /* 373: colornm */ ABSENT_STRING, + /* 374: defbi */ ABSENT_STRING, + /* 375: endbi */ ABSENT_STRING, + /* 376: setcolor */ ABSENT_STRING, + /* 377: slines */ ABSENT_STRING, + /* 378: dispc */ ABSENT_STRING, + /* 379: smpch */ ABSENT_STRING, + /* 380: rmpch */ ABSENT_STRING, + /* 381: smsc */ ABSENT_STRING, + /* 382: rmsc */ ABSENT_STRING, + /* 383: pctrm */ ABSENT_STRING, + /* 384: scesc */ ABSENT_STRING, + /* 385: scesa */ ABSENT_STRING, + /* 386: ehhlm */ ABSENT_STRING, + /* 387: elhlm */ ABSENT_STRING, + /* 388: elohlm */ ABSENT_STRING, + /* 389: erhlm */ ABSENT_STRING, + /* 390: ethlm */ ABSENT_STRING, + /* 391: evhlm */ ABSENT_STRING, + /* 392: sgr1 */ ABSENT_STRING, + /* 393: slength */ ABSENT_STRING, + /* 394: OTi2 */ ABSENT_STRING, + /* 395: OTrs */ ABSENT_STRING, + /* 396: OTnl */ ABSENT_STRING, + /* 397: OTbc */ ABSENT_STRING, + /* 398: OTko */ ABSENT_STRING, + /* 399: OTma */ ABSENT_STRING, + /* 400: OTG2 */ ABSENT_STRING, + /* 401: OTG3 */ ABSENT_STRING, + /* 402: OTG1 */ ABSENT_STRING, + /* 403: OTG4 */ ABSENT_STRING, + /* 404: OTGR */ ABSENT_STRING, + /* 405: OTGL */ ABSENT_STRING, + /* 406: OTGU */ ABSENT_STRING, + /* 407: OTGD */ ABSENT_STRING, + /* 408: OTGH */ ABSENT_STRING, + /* 409: OTGV */ ABSENT_STRING, + /* 410: OTGC */ ABSENT_STRING, + /* 411: meml */ ABSENT_STRING, + /* 412: memu */ ABSENT_STRING, + /* 413: box1 */ ABSENT_STRING, +}; +/* vt100 */ + +static char vt100_alias_data[] = "vt100|vt100-am|dec vt100 (w/advanced video)"; + +static char vt100_s_bel [] = "\007"; +static char vt100_s_cr [] = "\015"; +static char vt100_s_csr [] = "\033[%i%p1%d;%p2%dr"; +static char vt100_s_tbc [] = "\033[3g"; +static char vt100_s_clear [] = "\033[H\033[J$<50>"; +static char vt100_s_el [] = "\033[K$<3>"; +static char vt100_s_ed [] = "\033[J$<50>"; +static char vt100_s_cup [] = "\033[%i%p1%d;%p2%dH$<5>"; +static char vt100_s_cud1 [] = "\012"; +static char vt100_s_home [] = "\033[H"; +static char vt100_s_cub1 [] = "\010"; +static char vt100_s_cuf1 [] = "\033[C$<2>"; +static char vt100_s_cuu1 [] = "\033[A$<2>"; +static char vt100_s_smacs [] = "\016"; +static char vt100_s_blink [] = "\033[5m$<2>"; +static char vt100_s_bold [] = "\033[1m$<2>"; +static char vt100_s_rev [] = "\033[7m$<2>"; +static char vt100_s_smso [] = "\033[7m$<2>"; +static char vt100_s_smul [] = "\033[4m$<2>"; +static char vt100_s_rmacs [] = "\017"; +static char vt100_s_sgr0 [] = "\033[m\017$<2>"; +static char vt100_s_rmso [] = "\033[m$<2>"; +static char vt100_s_rmul [] = "\033[m$<2>"; +static char vt100_s_kbs [] = "\010"; +static char vt100_s_kcud1 [] = "\033OB"; +static char vt100_s_kf0 [] = "\033Oy"; +static char vt100_s_kf1 [] = "\033OP"; +static char vt100_s_kf10 [] = "\033Ox"; +static char vt100_s_kf2 [] = "\033OQ"; +static char vt100_s_kf3 [] = "\033OR"; +static char vt100_s_kf4 [] = "\033OS"; +static char vt100_s_kf5 [] = "\033Ot"; +static char vt100_s_kf6 [] = "\033Ou"; +static char vt100_s_kf7 [] = "\033Ov"; +static char vt100_s_kf8 [] = "\033Ol"; +static char vt100_s_kf9 [] = "\033Ow"; +static char vt100_s_kcub1 [] = "\033OD"; +static char vt100_s_kcuf1 [] = "\033OC"; +static char vt100_s_kcuu1 [] = "\033OA"; +static char vt100_s_rmkx [] = "\033[?1l\033>"; +static char vt100_s_smkx [] = "\033[?1h\033="; +static char vt100_s_lf1 [] = "pf1"; +static char vt100_s_lf2 [] = "pf2"; +static char vt100_s_lf3 [] = "pf3"; +static char vt100_s_lf4 [] = "pf4"; +static char vt100_s_cud [] = "\033[%p1%dB"; +static char vt100_s_cub [] = "\033[%p1%dD"; +static char vt100_s_cuf [] = "\033[%p1%dC"; +static char vt100_s_cuu [] = "\033[%p1%dA"; +static char vt100_s_mc0 [] = "\033[0i"; +static char vt100_s_mc4 [] = "\033[4i"; +static char vt100_s_mc5 [] = "\033[5i"; +static char vt100_s_rs2 [] = "\033<\033>\033[?3;4;5l\033[?7;8h\033[r"; +static char vt100_s_rc [] = "\0338"; +static char vt100_s_sc [] = "\0337"; +static char vt100_s_ind [] = "\012"; +static char vt100_s_ri [] = "\033M$<5>"; +static char vt100_s_sgr [] = "\033[0%?%p1%p6%|%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;m%?%p9%t\016%e\017%;$<2>"; +static char vt100_s_hts [] = "\033H"; +static char vt100_s_ht [] = "\011"; +static char vt100_s_ka1 [] = "\033Oq"; +static char vt100_s_ka3 [] = "\033Os"; +static char vt100_s_kb2 [] = "\033Or"; +static char vt100_s_kc1 [] = "\033Op"; +static char vt100_s_kc3 [] = "\033On"; +static char vt100_s_acsc [] = "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"; +static char vt100_s_smam [] = "\033[?7h"; +static char vt100_s_rmam [] = "\033[?7l"; +static char vt100_s_enacs [] = "\033(B\033)0"; +static char vt100_s_kent [] = "\033OM"; +static char vt100_s_el1 [] = "\033[1K$<3>"; + +static char vt100_bool_data[] = { + /* 0: bw */ FALSE, + /* 1: am */ TRUE, + /* 2: xsb */ FALSE, + /* 3: xhp */ FALSE, + /* 4: xenl */ TRUE, + /* 5: eo */ FALSE, + /* 6: gn */ FALSE, + /* 7: hc */ FALSE, + /* 8: km */ FALSE, + /* 9: hs */ FALSE, + /* 10: in */ FALSE, + /* 11: da */ FALSE, + /* 12: db */ FALSE, + /* 13: mir */ FALSE, + /* 14: msgr */ TRUE, + /* 15: os */ FALSE, + /* 16: eslok */ FALSE, + /* 17: xt */ FALSE, + /* 18: hz */ FALSE, + /* 19: ul */ FALSE, + /* 20: xon */ TRUE, + /* 21: nxon */ FALSE, + /* 22: mc5i */ TRUE, + /* 23: chts */ FALSE, + /* 24: nrrmc */ FALSE, + /* 25: npc */ FALSE, + /* 26: ndscr */ FALSE, + /* 27: ccc */ FALSE, + /* 28: bce */ FALSE, + /* 29: hls */ FALSE, + /* 30: xhpa */ FALSE, + /* 31: crxm */ FALSE, + /* 32: daisy */ FALSE, + /* 33: xvpa */ FALSE, + /* 34: sam */ FALSE, + /* 35: cpix */ FALSE, + /* 36: lpix */ FALSE, + /* 37: OTbs */ TRUE, + /* 38: OTns */ FALSE, + /* 39: OTnc */ FALSE, + /* 40: OTMT */ FALSE, + /* 41: OTNL */ FALSE, + /* 42: OTpt */ FALSE, + /* 43: OTxr */ FALSE, +}; +static NCURSES_INT2 vt100_number_data[] = { + /* 0: cols */ 80, + /* 1: it */ 8, + /* 2: lines */ 24, + /* 3: lm */ ABSENT_NUMERIC, + /* 4: xmc */ ABSENT_NUMERIC, + /* 5: pb */ ABSENT_NUMERIC, + /* 6: vt */ 3, + /* 7: wsl */ ABSENT_NUMERIC, + /* 8: nlab */ ABSENT_NUMERIC, + /* 9: lh */ ABSENT_NUMERIC, + /* 10: lw */ ABSENT_NUMERIC, + /* 11: ma */ ABSENT_NUMERIC, + /* 12: wnum */ ABSENT_NUMERIC, + /* 13: colors */ ABSENT_NUMERIC, + /* 14: pairs */ ABSENT_NUMERIC, + /* 15: ncv */ ABSENT_NUMERIC, + /* 16: bufsz */ ABSENT_NUMERIC, + /* 17: spinv */ ABSENT_NUMERIC, + /* 18: spinh */ ABSENT_NUMERIC, + /* 19: maddr */ ABSENT_NUMERIC, + /* 20: mjump */ ABSENT_NUMERIC, + /* 21: mcs */ ABSENT_NUMERIC, + /* 22: mls */ ABSENT_NUMERIC, + /* 23: npins */ ABSENT_NUMERIC, + /* 24: orc */ ABSENT_NUMERIC, + /* 25: orl */ ABSENT_NUMERIC, + /* 26: orhi */ ABSENT_NUMERIC, + /* 27: orvi */ ABSENT_NUMERIC, + /* 28: cps */ ABSENT_NUMERIC, + /* 29: widcs */ ABSENT_NUMERIC, + /* 30: btns */ ABSENT_NUMERIC, + /* 31: bitwin */ ABSENT_NUMERIC, + /* 32: bitype */ ABSENT_NUMERIC, + /* 33: OTug */ ABSENT_NUMERIC, + /* 34: OTdC */ ABSENT_NUMERIC, + /* 35: OTdN */ ABSENT_NUMERIC, + /* 36: OTdB */ ABSENT_NUMERIC, + /* 37: OTdT */ ABSENT_NUMERIC, + /* 38: OTkn */ ABSENT_NUMERIC, +}; +static char * vt100_string_data[] = { + /* 0: cbt */ ABSENT_STRING, + /* 1: bel */ vt100_s_bel, + /* 2: cr */ vt100_s_cr, + /* 3: csr */ vt100_s_csr, + /* 4: tbc */ vt100_s_tbc, + /* 5: clear */ vt100_s_clear, + /* 6: el */ vt100_s_el, + /* 7: ed */ vt100_s_ed, + /* 8: hpa */ ABSENT_STRING, + /* 9: cmdch */ ABSENT_STRING, + /* 10: cup */ vt100_s_cup, + /* 11: cud1 */ vt100_s_cud1, + /* 12: home */ vt100_s_home, + /* 13: civis */ ABSENT_STRING, + /* 14: cub1 */ vt100_s_cub1, + /* 15: mrcup */ ABSENT_STRING, + /* 16: cnorm */ ABSENT_STRING, + /* 17: cuf1 */ vt100_s_cuf1, + /* 18: ll */ ABSENT_STRING, + /* 19: cuu1 */ vt100_s_cuu1, + /* 20: cvvis */ ABSENT_STRING, + /* 21: dch1 */ ABSENT_STRING, + /* 22: dl1 */ ABSENT_STRING, + /* 23: dsl */ ABSENT_STRING, + /* 24: hd */ ABSENT_STRING, + /* 25: smacs */ vt100_s_smacs, + /* 26: blink */ vt100_s_blink, + /* 27: bold */ vt100_s_bold, + /* 28: smcup */ ABSENT_STRING, + /* 29: smdc */ ABSENT_STRING, + /* 30: dim */ ABSENT_STRING, + /* 31: smir */ ABSENT_STRING, + /* 32: invis */ ABSENT_STRING, + /* 33: prot */ ABSENT_STRING, + /* 34: rev */ vt100_s_rev, + /* 35: smso */ vt100_s_smso, + /* 36: smul */ vt100_s_smul, + /* 37: ech */ ABSENT_STRING, + /* 38: rmacs */ vt100_s_rmacs, + /* 39: sgr0 */ vt100_s_sgr0, + /* 40: rmcup */ ABSENT_STRING, + /* 41: rmdc */ ABSENT_STRING, + /* 42: rmir */ ABSENT_STRING, + /* 43: rmso */ vt100_s_rmso, + /* 44: rmul */ vt100_s_rmul, + /* 45: flash */ ABSENT_STRING, + /* 46: ff */ ABSENT_STRING, + /* 47: fsl */ ABSENT_STRING, + /* 48: is1 */ ABSENT_STRING, + /* 49: is2 */ ABSENT_STRING, + /* 50: is3 */ ABSENT_STRING, + /* 51: if */ ABSENT_STRING, + /* 52: ich1 */ ABSENT_STRING, + /* 53: il1 */ ABSENT_STRING, + /* 54: ip */ ABSENT_STRING, + /* 55: kbs */ vt100_s_kbs, + /* 56: ktbc */ ABSENT_STRING, + /* 57: kclr */ ABSENT_STRING, + /* 58: kctab */ ABSENT_STRING, + /* 59: kdch1 */ ABSENT_STRING, + /* 60: kdl1 */ ABSENT_STRING, + /* 61: kcud1 */ vt100_s_kcud1, + /* 62: krmir */ ABSENT_STRING, + /* 63: kel */ ABSENT_STRING, + /* 64: ked */ ABSENT_STRING, + /* 65: kf0 */ vt100_s_kf0, + /* 66: kf1 */ vt100_s_kf1, + /* 67: kf10 */ vt100_s_kf10, + /* 68: kf2 */ vt100_s_kf2, + /* 69: kf3 */ vt100_s_kf3, + /* 70: kf4 */ vt100_s_kf4, + /* 71: kf5 */ vt100_s_kf5, + /* 72: kf6 */ vt100_s_kf6, + /* 73: kf7 */ vt100_s_kf7, + /* 74: kf8 */ vt100_s_kf8, + /* 75: kf9 */ vt100_s_kf9, + /* 76: khome */ ABSENT_STRING, + /* 77: kich1 */ ABSENT_STRING, + /* 78: kil1 */ ABSENT_STRING, + /* 79: kcub1 */ vt100_s_kcub1, + /* 80: kll */ ABSENT_STRING, + /* 81: knp */ ABSENT_STRING, + /* 82: kpp */ ABSENT_STRING, + /* 83: kcuf1 */ vt100_s_kcuf1, + /* 84: kind */ ABSENT_STRING, + /* 85: kri */ ABSENT_STRING, + /* 86: khts */ ABSENT_STRING, + /* 87: kcuu1 */ vt100_s_kcuu1, + /* 88: rmkx */ vt100_s_rmkx, + /* 89: smkx */ vt100_s_smkx, + /* 90: lf0 */ ABSENT_STRING, + /* 91: lf1 */ vt100_s_lf1, + /* 92: lf10 */ ABSENT_STRING, + /* 93: lf2 */ vt100_s_lf2, + /* 94: lf3 */ vt100_s_lf3, + /* 95: lf4 */ vt100_s_lf4, + /* 96: lf5 */ ABSENT_STRING, + /* 97: lf6 */ ABSENT_STRING, + /* 98: lf7 */ ABSENT_STRING, + /* 99: lf8 */ ABSENT_STRING, + /* 100: lf9 */ ABSENT_STRING, + /* 101: rmm */ ABSENT_STRING, + /* 102: smm */ ABSENT_STRING, + /* 103: nel */ ABSENT_STRING, + /* 104: pad */ ABSENT_STRING, + /* 105: dch */ ABSENT_STRING, + /* 106: dl */ ABSENT_STRING, + /* 107: cud */ vt100_s_cud, + /* 108: ich */ ABSENT_STRING, + /* 109: indn */ ABSENT_STRING, + /* 110: il */ ABSENT_STRING, + /* 111: cub */ vt100_s_cub, + /* 112: cuf */ vt100_s_cuf, + /* 113: rin */ ABSENT_STRING, + /* 114: cuu */ vt100_s_cuu, + /* 115: pfkey */ ABSENT_STRING, + /* 116: pfloc */ ABSENT_STRING, + /* 117: pfx */ ABSENT_STRING, + /* 118: mc0 */ vt100_s_mc0, + /* 119: mc4 */ vt100_s_mc4, + /* 120: mc5 */ vt100_s_mc5, + /* 121: rep */ ABSENT_STRING, + /* 122: rs1 */ ABSENT_STRING, + /* 123: rs2 */ vt100_s_rs2, + /* 124: rs3 */ ABSENT_STRING, + /* 125: rf */ ABSENT_STRING, + /* 126: rc */ vt100_s_rc, + /* 127: vpa */ ABSENT_STRING, + /* 128: sc */ vt100_s_sc, + /* 129: ind */ vt100_s_ind, + /* 130: ri */ vt100_s_ri, + /* 131: sgr */ vt100_s_sgr, + /* 132: hts */ vt100_s_hts, + /* 133: wind */ ABSENT_STRING, + /* 134: ht */ vt100_s_ht, + /* 135: tsl */ ABSENT_STRING, + /* 136: uc */ ABSENT_STRING, + /* 137: hu */ ABSENT_STRING, + /* 138: iprog */ ABSENT_STRING, + /* 139: ka1 */ vt100_s_ka1, + /* 140: ka3 */ vt100_s_ka3, + /* 141: kb2 */ vt100_s_kb2, + /* 142: kc1 */ vt100_s_kc1, + /* 143: kc3 */ vt100_s_kc3, + /* 144: mc5p */ ABSENT_STRING, + /* 145: rmp */ ABSENT_STRING, + /* 146: acsc */ vt100_s_acsc, + /* 147: pln */ ABSENT_STRING, + /* 148: kcbt */ ABSENT_STRING, + /* 149: smxon */ ABSENT_STRING, + /* 150: rmxon */ ABSENT_STRING, + /* 151: smam */ vt100_s_smam, + /* 152: rmam */ vt100_s_rmam, + /* 153: xonc */ ABSENT_STRING, + /* 154: xoffc */ ABSENT_STRING, + /* 155: enacs */ vt100_s_enacs, + /* 156: smln */ ABSENT_STRING, + /* 157: rmln */ ABSENT_STRING, + /* 158: kbeg */ ABSENT_STRING, + /* 159: kcan */ ABSENT_STRING, + /* 160: kclo */ ABSENT_STRING, + /* 161: kcmd */ ABSENT_STRING, + /* 162: kcpy */ ABSENT_STRING, + /* 163: kcrt */ ABSENT_STRING, + /* 164: kend */ ABSENT_STRING, + /* 165: kent */ vt100_s_kent, + /* 166: kext */ ABSENT_STRING, + /* 167: kfnd */ ABSENT_STRING, + /* 168: khlp */ ABSENT_STRING, + /* 169: kmrk */ ABSENT_STRING, + /* 170: kmsg */ ABSENT_STRING, + /* 171: kmov */ ABSENT_STRING, + /* 172: knxt */ ABSENT_STRING, + /* 173: kopn */ ABSENT_STRING, + /* 174: kopt */ ABSENT_STRING, + /* 175: kprv */ ABSENT_STRING, + /* 176: kprt */ ABSENT_STRING, + /* 177: krdo */ ABSENT_STRING, + /* 178: kref */ ABSENT_STRING, + /* 179: krfr */ ABSENT_STRING, + /* 180: krpl */ ABSENT_STRING, + /* 181: krst */ ABSENT_STRING, + /* 182: kres */ ABSENT_STRING, + /* 183: ksav */ ABSENT_STRING, + /* 184: kspd */ ABSENT_STRING, + /* 185: kund */ ABSENT_STRING, + /* 186: kBEG */ ABSENT_STRING, + /* 187: kCAN */ ABSENT_STRING, + /* 188: kCMD */ ABSENT_STRING, + /* 189: kCPY */ ABSENT_STRING, + /* 190: kCRT */ ABSENT_STRING, + /* 191: kDC */ ABSENT_STRING, + /* 192: kDL */ ABSENT_STRING, + /* 193: kslt */ ABSENT_STRING, + /* 194: kEND */ ABSENT_STRING, + /* 195: kEOL */ ABSENT_STRING, + /* 196: kEXT */ ABSENT_STRING, + /* 197: kFND */ ABSENT_STRING, + /* 198: kHLP */ ABSENT_STRING, + /* 199: kHOM */ ABSENT_STRING, + /* 200: kIC */ ABSENT_STRING, + /* 201: kLFT */ ABSENT_STRING, + /* 202: kMSG */ ABSENT_STRING, + /* 203: kMOV */ ABSENT_STRING, + /* 204: kNXT */ ABSENT_STRING, + /* 205: kOPT */ ABSENT_STRING, + /* 206: kPRV */ ABSENT_STRING, + /* 207: kPRT */ ABSENT_STRING, + /* 208: kRDO */ ABSENT_STRING, + /* 209: kRPL */ ABSENT_STRING, + /* 210: kRIT */ ABSENT_STRING, + /* 211: kRES */ ABSENT_STRING, + /* 212: kSAV */ ABSENT_STRING, + /* 213: kSPD */ ABSENT_STRING, + /* 214: kUND */ ABSENT_STRING, + /* 215: rfi */ ABSENT_STRING, + /* 216: kf11 */ ABSENT_STRING, + /* 217: kf12 */ ABSENT_STRING, + /* 218: kf13 */ ABSENT_STRING, + /* 219: kf14 */ ABSENT_STRING, + /* 220: kf15 */ ABSENT_STRING, + /* 221: kf16 */ ABSENT_STRING, + /* 222: kf17 */ ABSENT_STRING, + /* 223: kf18 */ ABSENT_STRING, + /* 224: kf19 */ ABSENT_STRING, + /* 225: kf20 */ ABSENT_STRING, + /* 226: kf21 */ ABSENT_STRING, + /* 227: kf22 */ ABSENT_STRING, + /* 228: kf23 */ ABSENT_STRING, + /* 229: kf24 */ ABSENT_STRING, + /* 230: kf25 */ ABSENT_STRING, + /* 231: kf26 */ ABSENT_STRING, + /* 232: kf27 */ ABSENT_STRING, + /* 233: kf28 */ ABSENT_STRING, + /* 234: kf29 */ ABSENT_STRING, + /* 235: kf30 */ ABSENT_STRING, + /* 236: kf31 */ ABSENT_STRING, + /* 237: kf32 */ ABSENT_STRING, + /* 238: kf33 */ ABSENT_STRING, + /* 239: kf34 */ ABSENT_STRING, + /* 240: kf35 */ ABSENT_STRING, + /* 241: kf36 */ ABSENT_STRING, + /* 242: kf37 */ ABSENT_STRING, + /* 243: kf38 */ ABSENT_STRING, + /* 244: kf39 */ ABSENT_STRING, + /* 245: kf40 */ ABSENT_STRING, + /* 246: kf41 */ ABSENT_STRING, + /* 247: kf42 */ ABSENT_STRING, + /* 248: kf43 */ ABSENT_STRING, + /* 249: kf44 */ ABSENT_STRING, + /* 250: kf45 */ ABSENT_STRING, + /* 251: kf46 */ ABSENT_STRING, + /* 252: kf47 */ ABSENT_STRING, + /* 253: kf48 */ ABSENT_STRING, + /* 254: kf49 */ ABSENT_STRING, + /* 255: kf50 */ ABSENT_STRING, + /* 256: kf51 */ ABSENT_STRING, + /* 257: kf52 */ ABSENT_STRING, + /* 258: kf53 */ ABSENT_STRING, + /* 259: kf54 */ ABSENT_STRING, + /* 260: kf55 */ ABSENT_STRING, + /* 261: kf56 */ ABSENT_STRING, + /* 262: kf57 */ ABSENT_STRING, + /* 263: kf58 */ ABSENT_STRING, + /* 264: kf59 */ ABSENT_STRING, + /* 265: kf60 */ ABSENT_STRING, + /* 266: kf61 */ ABSENT_STRING, + /* 267: kf62 */ ABSENT_STRING, + /* 268: kf63 */ ABSENT_STRING, + /* 269: el1 */ vt100_s_el1, + /* 270: mgc */ ABSENT_STRING, + /* 271: smgl */ ABSENT_STRING, + /* 272: smgr */ ABSENT_STRING, + /* 273: fln */ ABSENT_STRING, + /* 274: sclk */ ABSENT_STRING, + /* 275: dclk */ ABSENT_STRING, + /* 276: rmclk */ ABSENT_STRING, + /* 277: cwin */ ABSENT_STRING, + /* 278: wingo */ ABSENT_STRING, + /* 279: hup */ ABSENT_STRING, + /* 280: dial */ ABSENT_STRING, + /* 281: qdial */ ABSENT_STRING, + /* 282: tone */ ABSENT_STRING, + /* 283: pulse */ ABSENT_STRING, + /* 284: hook */ ABSENT_STRING, + /* 285: pause */ ABSENT_STRING, + /* 286: wait */ ABSENT_STRING, + /* 287: u0 */ ABSENT_STRING, + /* 288: u1 */ ABSENT_STRING, + /* 289: u2 */ ABSENT_STRING, + /* 290: u3 */ ABSENT_STRING, + /* 291: u4 */ ABSENT_STRING, + /* 292: u5 */ ABSENT_STRING, + /* 293: u6 */ ABSENT_STRING, + /* 294: u7 */ ABSENT_STRING, + /* 295: u8 */ ABSENT_STRING, + /* 296: u9 */ ABSENT_STRING, + /* 297: op */ ABSENT_STRING, + /* 298: oc */ ABSENT_STRING, + /* 299: initc */ ABSENT_STRING, + /* 300: initp */ ABSENT_STRING, + /* 301: scp */ ABSENT_STRING, + /* 302: setf */ ABSENT_STRING, + /* 303: setb */ ABSENT_STRING, + /* 304: cpi */ ABSENT_STRING, + /* 305: lpi */ ABSENT_STRING, + /* 306: chr */ ABSENT_STRING, + /* 307: cvr */ ABSENT_STRING, + /* 308: defc */ ABSENT_STRING, + /* 309: swidm */ ABSENT_STRING, + /* 310: sdrfq */ ABSENT_STRING, + /* 311: sitm */ ABSENT_STRING, + /* 312: slm */ ABSENT_STRING, + /* 313: smicm */ ABSENT_STRING, + /* 314: snlq */ ABSENT_STRING, + /* 315: snrmq */ ABSENT_STRING, + /* 316: sshm */ ABSENT_STRING, + /* 317: ssubm */ ABSENT_STRING, + /* 318: ssupm */ ABSENT_STRING, + /* 319: sum */ ABSENT_STRING, + /* 320: rwidm */ ABSENT_STRING, + /* 321: ritm */ ABSENT_STRING, + /* 322: rlm */ ABSENT_STRING, + /* 323: rmicm */ ABSENT_STRING, + /* 324: rshm */ ABSENT_STRING, + /* 325: rsubm */ ABSENT_STRING, + /* 326: rsupm */ ABSENT_STRING, + /* 327: rum */ ABSENT_STRING, + /* 328: mhpa */ ABSENT_STRING, + /* 329: mcud1 */ ABSENT_STRING, + /* 330: mcub1 */ ABSENT_STRING, + /* 331: mcuf1 */ ABSENT_STRING, + /* 332: mvpa */ ABSENT_STRING, + /* 333: mcuu1 */ ABSENT_STRING, + /* 334: porder */ ABSENT_STRING, + /* 335: mcud */ ABSENT_STRING, + /* 336: mcub */ ABSENT_STRING, + /* 337: mcuf */ ABSENT_STRING, + /* 338: mcuu */ ABSENT_STRING, + /* 339: scs */ ABSENT_STRING, + /* 340: smgb */ ABSENT_STRING, + /* 341: smgbp */ ABSENT_STRING, + /* 342: smglp */ ABSENT_STRING, + /* 343: smgrp */ ABSENT_STRING, + /* 344: smgt */ ABSENT_STRING, + /* 345: smgtp */ ABSENT_STRING, + /* 346: sbim */ ABSENT_STRING, + /* 347: scsd */ ABSENT_STRING, + /* 348: rbim */ ABSENT_STRING, + /* 349: rcsd */ ABSENT_STRING, + /* 350: subcs */ ABSENT_STRING, + /* 351: supcs */ ABSENT_STRING, + /* 352: docr */ ABSENT_STRING, + /* 353: zerom */ ABSENT_STRING, + /* 354: csnm */ ABSENT_STRING, + /* 355: kmous */ ABSENT_STRING, + /* 356: minfo */ ABSENT_STRING, + /* 357: reqmp */ ABSENT_STRING, + /* 358: getm */ ABSENT_STRING, + /* 359: setaf */ ABSENT_STRING, + /* 360: setab */ ABSENT_STRING, + /* 361: pfxl */ ABSENT_STRING, + /* 362: devt */ ABSENT_STRING, + /* 363: csin */ ABSENT_STRING, + /* 364: s0ds */ ABSENT_STRING, + /* 365: s1ds */ ABSENT_STRING, + /* 366: s2ds */ ABSENT_STRING, + /* 367: s3ds */ ABSENT_STRING, + /* 368: smglr */ ABSENT_STRING, + /* 369: smgtb */ ABSENT_STRING, + /* 370: birep */ ABSENT_STRING, + /* 371: binel */ ABSENT_STRING, + /* 372: bicr */ ABSENT_STRING, + /* 373: colornm */ ABSENT_STRING, + /* 374: defbi */ ABSENT_STRING, + /* 375: endbi */ ABSENT_STRING, + /* 376: setcolor */ ABSENT_STRING, + /* 377: slines */ ABSENT_STRING, + /* 378: dispc */ ABSENT_STRING, + /* 379: smpch */ ABSENT_STRING, + /* 380: rmpch */ ABSENT_STRING, + /* 381: smsc */ ABSENT_STRING, + /* 382: rmsc */ ABSENT_STRING, + /* 383: pctrm */ ABSENT_STRING, + /* 384: scesc */ ABSENT_STRING, + /* 385: scesa */ ABSENT_STRING, + /* 386: ehhlm */ ABSENT_STRING, + /* 387: elhlm */ ABSENT_STRING, + /* 388: elohlm */ ABSENT_STRING, + /* 389: erhlm */ ABSENT_STRING, + /* 390: ethlm */ ABSENT_STRING, + /* 391: evhlm */ ABSENT_STRING, + /* 392: sgr1 */ ABSENT_STRING, + /* 393: slength */ ABSENT_STRING, + /* 394: OTi2 */ ABSENT_STRING, + /* 395: OTrs */ ABSENT_STRING, + /* 396: OTnl */ ABSENT_STRING, + /* 397: OTbc */ ABSENT_STRING, + /* 398: OTko */ ABSENT_STRING, + /* 399: OTma */ ABSENT_STRING, + /* 400: OTG2 */ ABSENT_STRING, + /* 401: OTG3 */ ABSENT_STRING, + /* 402: OTG1 */ ABSENT_STRING, + /* 403: OTG4 */ ABSENT_STRING, + /* 404: OTGR */ ABSENT_STRING, + /* 405: OTGL */ ABSENT_STRING, + /* 406: OTGU */ ABSENT_STRING, + /* 407: OTGD */ ABSENT_STRING, + /* 408: OTGH */ ABSENT_STRING, + /* 409: OTGV */ ABSENT_STRING, + /* 410: OTGC */ ABSENT_STRING, + /* 411: meml */ ABSENT_STRING, + /* 412: memu */ ABSENT_STRING, + /* 413: box1 */ ABSENT_STRING, +}; +/* xterm */ + +static char xterm_alias_data[] = "xterm|xterm terminal emulator (X Window System)"; + +static char xterm_s_cbt [] = "\033[Z"; +static char xterm_s_bel [] = "\007"; +static char xterm_s_cr [] = "\015"; +static char xterm_s_csr [] = "\033[%i%p1%d;%p2%dr"; +static char xterm_s_tbc [] = "\033[3g"; +static char xterm_s_clear [] = "\033[H\033[2J"; +static char xterm_s_el [] = "\033[K"; +static char xterm_s_ed [] = "\033[J"; +static char xterm_s_hpa [] = "\033[%i%p1%dG"; +static char xterm_s_cup [] = "\033[%i%p1%d;%p2%dH"; +static char xterm_s_cud1 [] = "\012"; +static char xterm_s_home [] = "\033[H"; +static char xterm_s_civis [] = "\033[?25l"; +static char xterm_s_cub1 [] = "\010"; +static char xterm_s_cnorm [] = "\033[?12l\033[?25h"; +static char xterm_s_cuf1 [] = "\033[C"; +static char xterm_s_cuu1 [] = "\033[A"; +static char xterm_s_cvvis [] = "\033[?12;25h"; +static char xterm_s_dch1 [] = "\033[P"; +static char xterm_s_dl1 [] = "\033[M"; +static char xterm_s_smacs [] = "\033(0"; +static char xterm_s_blink [] = "\033[5m"; +static char xterm_s_bold [] = "\033[1m"; +static char xterm_s_smcup [] = "\033[?1049h\033[22;0;0t"; +static char xterm_s_dim [] = "\033[2m"; +static char xterm_s_smir [] = "\033[4h"; +static char xterm_s_invis [] = "\033[8m"; +static char xterm_s_rev [] = "\033[7m"; +static char xterm_s_smso [] = "\033[7m"; +static char xterm_s_smul [] = "\033[4m"; +static char xterm_s_ech [] = "\033[%p1%dX"; +static char xterm_s_rmacs [] = "\033(B"; +static char xterm_s_sgr0 [] = "\033(B\033[m"; +static char xterm_s_rmcup [] = "\033[?1049l\033[23;0;0t"; +static char xterm_s_rmir [] = "\033[4l"; +static char xterm_s_rmso [] = "\033[27m"; +static char xterm_s_rmul [] = "\033[24m"; +static char xterm_s_flash [] = "\033[?5h$<100/>\033[?5l"; +static char xterm_s_is2 [] = "\033[!p\033[?3;4l\033[4l\033>"; +static char xterm_s_il1 [] = "\033[L"; +static char xterm_s_kbs [] = "\010"; +static char xterm_s_kdch1 [] = "\033[3~"; +static char xterm_s_kcud1 [] = "\033OB"; +static char xterm_s_kf1 [] = "\033OP"; +static char xterm_s_kf10 [] = "\033[21~"; +static char xterm_s_kf2 [] = "\033OQ"; +static char xterm_s_kf3 [] = "\033OR"; +static char xterm_s_kf4 [] = "\033OS"; +static char xterm_s_kf5 [] = "\033[15~"; +static char xterm_s_kf6 [] = "\033[17~"; +static char xterm_s_kf7 [] = "\033[18~"; +static char xterm_s_kf8 [] = "\033[19~"; +static char xterm_s_kf9 [] = "\033[20~"; +static char xterm_s_khome [] = "\033OH"; +static char xterm_s_kich1 [] = "\033[2~"; +static char xterm_s_kcub1 [] = "\033OD"; +static char xterm_s_knp [] = "\033[6~"; +static char xterm_s_kpp [] = "\033[5~"; +static char xterm_s_kcuf1 [] = "\033OC"; +static char xterm_s_kind [] = "\033[1;2B"; +static char xterm_s_kri [] = "\033[1;2A"; +static char xterm_s_kcuu1 [] = "\033OA"; +static char xterm_s_rmkx [] = "\033[?1l\033>"; +static char xterm_s_smkx [] = "\033[?1h\033="; +static char xterm_s_rmm [] = "\033[?1034l"; +static char xterm_s_smm [] = "\033[?1034h"; +static char xterm_s_dch [] = "\033[%p1%dP"; +static char xterm_s_dl [] = "\033[%p1%dM"; +static char xterm_s_cud [] = "\033[%p1%dB"; +static char xterm_s_ich [] = "\033[%p1%d@"; +static char xterm_s_indn [] = "\033[%p1%dS"; +static char xterm_s_il [] = "\033[%p1%dL"; +static char xterm_s_cub [] = "\033[%p1%dD"; +static char xterm_s_cuf [] = "\033[%p1%dC"; +static char xterm_s_rin [] = "\033[%p1%dT"; +static char xterm_s_cuu [] = "\033[%p1%dA"; +static char xterm_s_mc0 [] = "\033[i"; +static char xterm_s_mc4 [] = "\033[4i"; +static char xterm_s_mc5 [] = "\033[5i"; +static char xterm_s_rep [] = "%p1%c\033[%p2%{1}%-%db"; +static char xterm_s_rs1 [] = "\033c"; +static char xterm_s_rs2 [] = "\033[!p\033[?3;4l\033[4l\033>"; +static char xterm_s_rc [] = "\0338"; +static char xterm_s_vpa [] = "\033[%i%p1%dd"; +static char xterm_s_sc [] = "\0337"; +static char xterm_s_ind [] = "\012"; +static char xterm_s_ri [] = "\033M"; +static char xterm_s_sgr [] = "%?%p9%t\033(0%e\033(B%;\033[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m"; +static char xterm_s_hts [] = "\033H"; +static char xterm_s_ht [] = "\011"; +static char xterm_s_kb2 [] = "\033OE"; +static char xterm_s_acsc [] = "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"; +static char xterm_s_kcbt [] = "\033[Z"; +static char xterm_s_smam [] = "\033[?7h"; +static char xterm_s_rmam [] = "\033[?7l"; +static char xterm_s_kend [] = "\033OF"; +static char xterm_s_kent [] = "\033OM"; +static char xterm_s_kDC [] = "\033[3;2~"; +static char xterm_s_kEND [] = "\033[1;2F"; +static char xterm_s_kHOM [] = "\033[1;2H"; +static char xterm_s_kIC [] = "\033[2;2~"; +static char xterm_s_kLFT [] = "\033[1;2D"; +static char xterm_s_kNXT [] = "\033[6;2~"; +static char xterm_s_kPRV [] = "\033[5;2~"; +static char xterm_s_kRIT [] = "\033[1;2C"; +static char xterm_s_kf11 [] = "\033[23~"; +static char xterm_s_kf12 [] = "\033[24~"; +static char xterm_s_kf13 [] = "\033[1;2P"; +static char xterm_s_kf14 [] = "\033[1;2Q"; +static char xterm_s_kf15 [] = "\033[1;2R"; +static char xterm_s_kf16 [] = "\033[1;2S"; +static char xterm_s_kf17 [] = "\033[15;2~"; +static char xterm_s_kf18 [] = "\033[17;2~"; +static char xterm_s_kf19 [] = "\033[18;2~"; +static char xterm_s_kf20 [] = "\033[19;2~"; +static char xterm_s_kf21 [] = "\033[20;2~"; +static char xterm_s_kf22 [] = "\033[21;2~"; +static char xterm_s_kf23 [] = "\033[23;2~"; +static char xterm_s_kf24 [] = "\033[24;2~"; +static char xterm_s_kf25 [] = "\033[1;5P"; +static char xterm_s_kf26 [] = "\033[1;5Q"; +static char xterm_s_kf27 [] = "\033[1;5R"; +static char xterm_s_kf28 [] = "\033[1;5S"; +static char xterm_s_kf29 [] = "\033[15;5~"; +static char xterm_s_kf30 [] = "\033[17;5~"; +static char xterm_s_kf31 [] = "\033[18;5~"; +static char xterm_s_kf32 [] = "\033[19;5~"; +static char xterm_s_kf33 [] = "\033[20;5~"; +static char xterm_s_kf34 [] = "\033[21;5~"; +static char xterm_s_kf35 [] = "\033[23;5~"; +static char xterm_s_kf36 [] = "\033[24;5~"; +static char xterm_s_kf37 [] = "\033[1;6P"; +static char xterm_s_kf38 [] = "\033[1;6Q"; +static char xterm_s_kf39 [] = "\033[1;6R"; +static char xterm_s_kf40 [] = "\033[1;6S"; +static char xterm_s_kf41 [] = "\033[15;6~"; +static char xterm_s_kf42 [] = "\033[17;6~"; +static char xterm_s_kf43 [] = "\033[18;6~"; +static char xterm_s_kf44 [] = "\033[19;6~"; +static char xterm_s_kf45 [] = "\033[20;6~"; +static char xterm_s_kf46 [] = "\033[21;6~"; +static char xterm_s_kf47 [] = "\033[23;6~"; +static char xterm_s_kf48 [] = "\033[24;6~"; +static char xterm_s_kf49 [] = "\033[1;3P"; +static char xterm_s_kf50 [] = "\033[1;3Q"; +static char xterm_s_kf51 [] = "\033[1;3R"; +static char xterm_s_kf52 [] = "\033[1;3S"; +static char xterm_s_kf53 [] = "\033[15;3~"; +static char xterm_s_kf54 [] = "\033[17;3~"; +static char xterm_s_kf55 [] = "\033[18;3~"; +static char xterm_s_kf56 [] = "\033[19;3~"; +static char xterm_s_kf57 [] = "\033[20;3~"; +static char xterm_s_kf58 [] = "\033[21;3~"; +static char xterm_s_kf59 [] = "\033[23;3~"; +static char xterm_s_kf60 [] = "\033[24;3~"; +static char xterm_s_kf61 [] = "\033[1;4P"; +static char xterm_s_kf62 [] = "\033[1;4Q"; +static char xterm_s_kf63 [] = "\033[1;4R"; +static char xterm_s_el1 [] = "\033[1K"; +static char xterm_s_u6 [] = "\033[%i%d;%dR"; +static char xterm_s_u7 [] = "\033[6n"; +static char xterm_s_u8 [] = "\033[?%[;0123456789]c"; +static char xterm_s_u9 [] = "\033[c"; +static char xterm_s_op [] = "\033[39;49m"; +static char xterm_s_setf [] = "\033[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m"; +static char xterm_s_setb [] = "\033[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m"; +static char xterm_s_sitm [] = "\033[3m"; +static char xterm_s_ritm [] = "\033[23m"; +static char xterm_s_kmous [] = "\033[<"; +static char xterm_s_setaf [] = "\033[3%p1%dm"; +static char xterm_s_setab [] = "\033[4%p1%dm"; +static char xterm_s_meml [] = "\033l"; +static char xterm_s_memu [] = "\033m"; + +static char xterm_bool_data[] = { + /* 0: bw */ FALSE, + /* 1: am */ TRUE, + /* 2: xsb */ FALSE, + /* 3: xhp */ FALSE, + /* 4: xenl */ TRUE, + /* 5: eo */ FALSE, + /* 6: gn */ FALSE, + /* 7: hc */ FALSE, + /* 8: km */ TRUE, + /* 9: hs */ FALSE, + /* 10: in */ FALSE, + /* 11: da */ FALSE, + /* 12: db */ FALSE, + /* 13: mir */ TRUE, + /* 14: msgr */ TRUE, + /* 15: os */ FALSE, + /* 16: eslok */ FALSE, + /* 17: xt */ FALSE, + /* 18: hz */ FALSE, + /* 19: ul */ FALSE, + /* 20: xon */ FALSE, + /* 21: nxon */ FALSE, + /* 22: mc5i */ TRUE, + /* 23: chts */ FALSE, + /* 24: nrrmc */ FALSE, + /* 25: npc */ TRUE, + /* 26: ndscr */ FALSE, + /* 27: ccc */ FALSE, + /* 28: bce */ TRUE, + /* 29: hls */ FALSE, + /* 30: xhpa */ FALSE, + /* 31: crxm */ FALSE, + /* 32: daisy */ FALSE, + /* 33: xvpa */ FALSE, + /* 34: sam */ FALSE, + /* 35: cpix */ FALSE, + /* 36: lpix */ FALSE, + /* 37: OTbs */ TRUE, + /* 38: OTns */ FALSE, + /* 39: OTnc */ FALSE, + /* 40: OTMT */ FALSE, + /* 41: OTNL */ FALSE, + /* 42: OTpt */ FALSE, + /* 43: OTxr */ FALSE, +}; +static NCURSES_INT2 xterm_number_data[] = { + /* 0: cols */ 80, + /* 1: it */ 8, + /* 2: lines */ 24, + /* 3: lm */ ABSENT_NUMERIC, + /* 4: xmc */ ABSENT_NUMERIC, + /* 5: pb */ ABSENT_NUMERIC, + /* 6: vt */ ABSENT_NUMERIC, + /* 7: wsl */ ABSENT_NUMERIC, + /* 8: nlab */ ABSENT_NUMERIC, + /* 9: lh */ ABSENT_NUMERIC, + /* 10: lw */ ABSENT_NUMERIC, + /* 11: ma */ ABSENT_NUMERIC, + /* 12: wnum */ ABSENT_NUMERIC, + /* 13: colors */ 8, + /* 14: pairs */ 64, + /* 15: ncv */ ABSENT_NUMERIC, + /* 16: bufsz */ ABSENT_NUMERIC, + /* 17: spinv */ ABSENT_NUMERIC, + /* 18: spinh */ ABSENT_NUMERIC, + /* 19: maddr */ ABSENT_NUMERIC, + /* 20: mjump */ ABSENT_NUMERIC, + /* 21: mcs */ ABSENT_NUMERIC, + /* 22: mls */ ABSENT_NUMERIC, + /* 23: npins */ ABSENT_NUMERIC, + /* 24: orc */ ABSENT_NUMERIC, + /* 25: orl */ ABSENT_NUMERIC, + /* 26: orhi */ ABSENT_NUMERIC, + /* 27: orvi */ ABSENT_NUMERIC, + /* 28: cps */ ABSENT_NUMERIC, + /* 29: widcs */ ABSENT_NUMERIC, + /* 30: btns */ ABSENT_NUMERIC, + /* 31: bitwin */ ABSENT_NUMERIC, + /* 32: bitype */ ABSENT_NUMERIC, + /* 33: OTug */ ABSENT_NUMERIC, + /* 34: OTdC */ ABSENT_NUMERIC, + /* 35: OTdN */ ABSENT_NUMERIC, + /* 36: OTdB */ ABSENT_NUMERIC, + /* 37: OTdT */ ABSENT_NUMERIC, + /* 38: OTkn */ ABSENT_NUMERIC, +}; +static char * xterm_string_data[] = { + /* 0: cbt */ xterm_s_cbt, + /* 1: bel */ xterm_s_bel, + /* 2: cr */ xterm_s_cr, + /* 3: csr */ xterm_s_csr, + /* 4: tbc */ xterm_s_tbc, + /* 5: clear */ xterm_s_clear, + /* 6: el */ xterm_s_el, + /* 7: ed */ xterm_s_ed, + /* 8: hpa */ xterm_s_hpa, + /* 9: cmdch */ ABSENT_STRING, + /* 10: cup */ xterm_s_cup, + /* 11: cud1 */ xterm_s_cud1, + /* 12: home */ xterm_s_home, + /* 13: civis */ xterm_s_civis, + /* 14: cub1 */ xterm_s_cub1, + /* 15: mrcup */ ABSENT_STRING, + /* 16: cnorm */ xterm_s_cnorm, + /* 17: cuf1 */ xterm_s_cuf1, + /* 18: ll */ ABSENT_STRING, + /* 19: cuu1 */ xterm_s_cuu1, + /* 20: cvvis */ xterm_s_cvvis, + /* 21: dch1 */ xterm_s_dch1, + /* 22: dl1 */ xterm_s_dl1, + /* 23: dsl */ ABSENT_STRING, + /* 24: hd */ ABSENT_STRING, + /* 25: smacs */ xterm_s_smacs, + /* 26: blink */ xterm_s_blink, + /* 27: bold */ xterm_s_bold, + /* 28: smcup */ xterm_s_smcup, + /* 29: smdc */ ABSENT_STRING, + /* 30: dim */ xterm_s_dim, + /* 31: smir */ xterm_s_smir, + /* 32: invis */ xterm_s_invis, + /* 33: prot */ ABSENT_STRING, + /* 34: rev */ xterm_s_rev, + /* 35: smso */ xterm_s_smso, + /* 36: smul */ xterm_s_smul, + /* 37: ech */ xterm_s_ech, + /* 38: rmacs */ xterm_s_rmacs, + /* 39: sgr0 */ xterm_s_sgr0, + /* 40: rmcup */ xterm_s_rmcup, + /* 41: rmdc */ ABSENT_STRING, + /* 42: rmir */ xterm_s_rmir, + /* 43: rmso */ xterm_s_rmso, + /* 44: rmul */ xterm_s_rmul, + /* 45: flash */ xterm_s_flash, + /* 46: ff */ ABSENT_STRING, + /* 47: fsl */ ABSENT_STRING, + /* 48: is1 */ ABSENT_STRING, + /* 49: is2 */ xterm_s_is2, + /* 50: is3 */ ABSENT_STRING, + /* 51: if */ ABSENT_STRING, + /* 52: ich1 */ ABSENT_STRING, + /* 53: il1 */ xterm_s_il1, + /* 54: ip */ ABSENT_STRING, + /* 55: kbs */ xterm_s_kbs, + /* 56: ktbc */ ABSENT_STRING, + /* 57: kclr */ ABSENT_STRING, + /* 58: kctab */ ABSENT_STRING, + /* 59: kdch1 */ xterm_s_kdch1, + /* 60: kdl1 */ ABSENT_STRING, + /* 61: kcud1 */ xterm_s_kcud1, + /* 62: krmir */ ABSENT_STRING, + /* 63: kel */ ABSENT_STRING, + /* 64: ked */ ABSENT_STRING, + /* 65: kf0 */ ABSENT_STRING, + /* 66: kf1 */ xterm_s_kf1, + /* 67: kf10 */ xterm_s_kf10, + /* 68: kf2 */ xterm_s_kf2, + /* 69: kf3 */ xterm_s_kf3, + /* 70: kf4 */ xterm_s_kf4, + /* 71: kf5 */ xterm_s_kf5, + /* 72: kf6 */ xterm_s_kf6, + /* 73: kf7 */ xterm_s_kf7, + /* 74: kf8 */ xterm_s_kf8, + /* 75: kf9 */ xterm_s_kf9, + /* 76: khome */ xterm_s_khome, + /* 77: kich1 */ xterm_s_kich1, + /* 78: kil1 */ ABSENT_STRING, + /* 79: kcub1 */ xterm_s_kcub1, + /* 80: kll */ ABSENT_STRING, + /* 81: knp */ xterm_s_knp, + /* 82: kpp */ xterm_s_kpp, + /* 83: kcuf1 */ xterm_s_kcuf1, + /* 84: kind */ xterm_s_kind, + /* 85: kri */ xterm_s_kri, + /* 86: khts */ ABSENT_STRING, + /* 87: kcuu1 */ xterm_s_kcuu1, + /* 88: rmkx */ xterm_s_rmkx, + /* 89: smkx */ xterm_s_smkx, + /* 90: lf0 */ ABSENT_STRING, + /* 91: lf1 */ ABSENT_STRING, + /* 92: lf10 */ ABSENT_STRING, + /* 93: lf2 */ ABSENT_STRING, + /* 94: lf3 */ ABSENT_STRING, + /* 95: lf4 */ ABSENT_STRING, + /* 96: lf5 */ ABSENT_STRING, + /* 97: lf6 */ ABSENT_STRING, + /* 98: lf7 */ ABSENT_STRING, + /* 99: lf8 */ ABSENT_STRING, + /* 100: lf9 */ ABSENT_STRING, + /* 101: rmm */ xterm_s_rmm, + /* 102: smm */ xterm_s_smm, + /* 103: nel */ ABSENT_STRING, + /* 104: pad */ ABSENT_STRING, + /* 105: dch */ xterm_s_dch, + /* 106: dl */ xterm_s_dl, + /* 107: cud */ xterm_s_cud, + /* 108: ich */ xterm_s_ich, + /* 109: indn */ xterm_s_indn, + /* 110: il */ xterm_s_il, + /* 111: cub */ xterm_s_cub, + /* 112: cuf */ xterm_s_cuf, + /* 113: rin */ xterm_s_rin, + /* 114: cuu */ xterm_s_cuu, + /* 115: pfkey */ ABSENT_STRING, + /* 116: pfloc */ ABSENT_STRING, + /* 117: pfx */ ABSENT_STRING, + /* 118: mc0 */ xterm_s_mc0, + /* 119: mc4 */ xterm_s_mc4, + /* 120: mc5 */ xterm_s_mc5, + /* 121: rep */ xterm_s_rep, + /* 122: rs1 */ xterm_s_rs1, + /* 123: rs2 */ xterm_s_rs2, + /* 124: rs3 */ ABSENT_STRING, + /* 125: rf */ ABSENT_STRING, + /* 126: rc */ xterm_s_rc, + /* 127: vpa */ xterm_s_vpa, + /* 128: sc */ xterm_s_sc, + /* 129: ind */ xterm_s_ind, + /* 130: ri */ xterm_s_ri, + /* 131: sgr */ xterm_s_sgr, + /* 132: hts */ xterm_s_hts, + /* 133: wind */ ABSENT_STRING, + /* 134: ht */ xterm_s_ht, + /* 135: tsl */ ABSENT_STRING, + /* 136: uc */ ABSENT_STRING, + /* 137: hu */ ABSENT_STRING, + /* 138: iprog */ ABSENT_STRING, + /* 139: ka1 */ ABSENT_STRING, + /* 140: ka3 */ ABSENT_STRING, + /* 141: kb2 */ xterm_s_kb2, + /* 142: kc1 */ ABSENT_STRING, + /* 143: kc3 */ ABSENT_STRING, + /* 144: mc5p */ ABSENT_STRING, + /* 145: rmp */ ABSENT_STRING, + /* 146: acsc */ xterm_s_acsc, + /* 147: pln */ ABSENT_STRING, + /* 148: kcbt */ xterm_s_kcbt, + /* 149: smxon */ ABSENT_STRING, + /* 150: rmxon */ ABSENT_STRING, + /* 151: smam */ xterm_s_smam, + /* 152: rmam */ xterm_s_rmam, + /* 153: xonc */ ABSENT_STRING, + /* 154: xoffc */ ABSENT_STRING, + /* 155: enacs */ ABSENT_STRING, + /* 156: smln */ ABSENT_STRING, + /* 157: rmln */ ABSENT_STRING, + /* 158: kbeg */ ABSENT_STRING, + /* 159: kcan */ ABSENT_STRING, + /* 160: kclo */ ABSENT_STRING, + /* 161: kcmd */ ABSENT_STRING, + /* 162: kcpy */ ABSENT_STRING, + /* 163: kcrt */ ABSENT_STRING, + /* 164: kend */ xterm_s_kend, + /* 165: kent */ xterm_s_kent, + /* 166: kext */ ABSENT_STRING, + /* 167: kfnd */ ABSENT_STRING, + /* 168: khlp */ ABSENT_STRING, + /* 169: kmrk */ ABSENT_STRING, + /* 170: kmsg */ ABSENT_STRING, + /* 171: kmov */ ABSENT_STRING, + /* 172: knxt */ ABSENT_STRING, + /* 173: kopn */ ABSENT_STRING, + /* 174: kopt */ ABSENT_STRING, + /* 175: kprv */ ABSENT_STRING, + /* 176: kprt */ ABSENT_STRING, + /* 177: krdo */ ABSENT_STRING, + /* 178: kref */ ABSENT_STRING, + /* 179: krfr */ ABSENT_STRING, + /* 180: krpl */ ABSENT_STRING, + /* 181: krst */ ABSENT_STRING, + /* 182: kres */ ABSENT_STRING, + /* 183: ksav */ ABSENT_STRING, + /* 184: kspd */ ABSENT_STRING, + /* 185: kund */ ABSENT_STRING, + /* 186: kBEG */ ABSENT_STRING, + /* 187: kCAN */ ABSENT_STRING, + /* 188: kCMD */ ABSENT_STRING, + /* 189: kCPY */ ABSENT_STRING, + /* 190: kCRT */ ABSENT_STRING, + /* 191: kDC */ xterm_s_kDC, + /* 192: kDL */ ABSENT_STRING, + /* 193: kslt */ ABSENT_STRING, + /* 194: kEND */ xterm_s_kEND, + /* 195: kEOL */ ABSENT_STRING, + /* 196: kEXT */ ABSENT_STRING, + /* 197: kFND */ ABSENT_STRING, + /* 198: kHLP */ ABSENT_STRING, + /* 199: kHOM */ xterm_s_kHOM, + /* 200: kIC */ xterm_s_kIC, + /* 201: kLFT */ xterm_s_kLFT, + /* 202: kMSG */ ABSENT_STRING, + /* 203: kMOV */ ABSENT_STRING, + /* 204: kNXT */ xterm_s_kNXT, + /* 205: kOPT */ ABSENT_STRING, + /* 206: kPRV */ xterm_s_kPRV, + /* 207: kPRT */ ABSENT_STRING, + /* 208: kRDO */ ABSENT_STRING, + /* 209: kRPL */ ABSENT_STRING, + /* 210: kRIT */ xterm_s_kRIT, + /* 211: kRES */ ABSENT_STRING, + /* 212: kSAV */ ABSENT_STRING, + /* 213: kSPD */ ABSENT_STRING, + /* 214: kUND */ ABSENT_STRING, + /* 215: rfi */ ABSENT_STRING, + /* 216: kf11 */ xterm_s_kf11, + /* 217: kf12 */ xterm_s_kf12, + /* 218: kf13 */ xterm_s_kf13, + /* 219: kf14 */ xterm_s_kf14, + /* 220: kf15 */ xterm_s_kf15, + /* 221: kf16 */ xterm_s_kf16, + /* 222: kf17 */ xterm_s_kf17, + /* 223: kf18 */ xterm_s_kf18, + /* 224: kf19 */ xterm_s_kf19, + /* 225: kf20 */ xterm_s_kf20, + /* 226: kf21 */ xterm_s_kf21, + /* 227: kf22 */ xterm_s_kf22, + /* 228: kf23 */ xterm_s_kf23, + /* 229: kf24 */ xterm_s_kf24, + /* 230: kf25 */ xterm_s_kf25, + /* 231: kf26 */ xterm_s_kf26, + /* 232: kf27 */ xterm_s_kf27, + /* 233: kf28 */ xterm_s_kf28, + /* 234: kf29 */ xterm_s_kf29, + /* 235: kf30 */ xterm_s_kf30, + /* 236: kf31 */ xterm_s_kf31, + /* 237: kf32 */ xterm_s_kf32, + /* 238: kf33 */ xterm_s_kf33, + /* 239: kf34 */ xterm_s_kf34, + /* 240: kf35 */ xterm_s_kf35, + /* 241: kf36 */ xterm_s_kf36, + /* 242: kf37 */ xterm_s_kf37, + /* 243: kf38 */ xterm_s_kf38, + /* 244: kf39 */ xterm_s_kf39, + /* 245: kf40 */ xterm_s_kf40, + /* 246: kf41 */ xterm_s_kf41, + /* 247: kf42 */ xterm_s_kf42, + /* 248: kf43 */ xterm_s_kf43, + /* 249: kf44 */ xterm_s_kf44, + /* 250: kf45 */ xterm_s_kf45, + /* 251: kf46 */ xterm_s_kf46, + /* 252: kf47 */ xterm_s_kf47, + /* 253: kf48 */ xterm_s_kf48, + /* 254: kf49 */ xterm_s_kf49, + /* 255: kf50 */ xterm_s_kf50, + /* 256: kf51 */ xterm_s_kf51, + /* 257: kf52 */ xterm_s_kf52, + /* 258: kf53 */ xterm_s_kf53, + /* 259: kf54 */ xterm_s_kf54, + /* 260: kf55 */ xterm_s_kf55, + /* 261: kf56 */ xterm_s_kf56, + /* 262: kf57 */ xterm_s_kf57, + /* 263: kf58 */ xterm_s_kf58, + /* 264: kf59 */ xterm_s_kf59, + /* 265: kf60 */ xterm_s_kf60, + /* 266: kf61 */ xterm_s_kf61, + /* 267: kf62 */ xterm_s_kf62, + /* 268: kf63 */ xterm_s_kf63, + /* 269: el1 */ xterm_s_el1, + /* 270: mgc */ ABSENT_STRING, + /* 271: smgl */ ABSENT_STRING, + /* 272: smgr */ ABSENT_STRING, + /* 273: fln */ ABSENT_STRING, + /* 274: sclk */ ABSENT_STRING, + /* 275: dclk */ ABSENT_STRING, + /* 276: rmclk */ ABSENT_STRING, + /* 277: cwin */ ABSENT_STRING, + /* 278: wingo */ ABSENT_STRING, + /* 279: hup */ ABSENT_STRING, + /* 280: dial */ ABSENT_STRING, + /* 281: qdial */ ABSENT_STRING, + /* 282: tone */ ABSENT_STRING, + /* 283: pulse */ ABSENT_STRING, + /* 284: hook */ ABSENT_STRING, + /* 285: pause */ ABSENT_STRING, + /* 286: wait */ ABSENT_STRING, + /* 287: u0 */ ABSENT_STRING, + /* 288: u1 */ ABSENT_STRING, + /* 289: u2 */ ABSENT_STRING, + /* 290: u3 */ ABSENT_STRING, + /* 291: u4 */ ABSENT_STRING, + /* 292: u5 */ ABSENT_STRING, + /* 293: u6 */ xterm_s_u6, + /* 294: u7 */ xterm_s_u7, + /* 295: u8 */ xterm_s_u8, + /* 296: u9 */ xterm_s_u9, + /* 297: op */ xterm_s_op, + /* 298: oc */ ABSENT_STRING, + /* 299: initc */ ABSENT_STRING, + /* 300: initp */ ABSENT_STRING, + /* 301: scp */ ABSENT_STRING, + /* 302: setf */ xterm_s_setf, + /* 303: setb */ xterm_s_setb, + /* 304: cpi */ ABSENT_STRING, + /* 305: lpi */ ABSENT_STRING, + /* 306: chr */ ABSENT_STRING, + /* 307: cvr */ ABSENT_STRING, + /* 308: defc */ ABSENT_STRING, + /* 309: swidm */ ABSENT_STRING, + /* 310: sdrfq */ ABSENT_STRING, + /* 311: sitm */ xterm_s_sitm, + /* 312: slm */ ABSENT_STRING, + /* 313: smicm */ ABSENT_STRING, + /* 314: snlq */ ABSENT_STRING, + /* 315: snrmq */ ABSENT_STRING, + /* 316: sshm */ ABSENT_STRING, + /* 317: ssubm */ ABSENT_STRING, + /* 318: ssupm */ ABSENT_STRING, + /* 319: sum */ ABSENT_STRING, + /* 320: rwidm */ ABSENT_STRING, + /* 321: ritm */ xterm_s_ritm, + /* 322: rlm */ ABSENT_STRING, + /* 323: rmicm */ ABSENT_STRING, + /* 324: rshm */ ABSENT_STRING, + /* 325: rsubm */ ABSENT_STRING, + /* 326: rsupm */ ABSENT_STRING, + /* 327: rum */ ABSENT_STRING, + /* 328: mhpa */ ABSENT_STRING, + /* 329: mcud1 */ ABSENT_STRING, + /* 330: mcub1 */ ABSENT_STRING, + /* 331: mcuf1 */ ABSENT_STRING, + /* 332: mvpa */ ABSENT_STRING, + /* 333: mcuu1 */ ABSENT_STRING, + /* 334: porder */ ABSENT_STRING, + /* 335: mcud */ ABSENT_STRING, + /* 336: mcub */ ABSENT_STRING, + /* 337: mcuf */ ABSENT_STRING, + /* 338: mcuu */ ABSENT_STRING, + /* 339: scs */ ABSENT_STRING, + /* 340: smgb */ ABSENT_STRING, + /* 341: smgbp */ ABSENT_STRING, + /* 342: smglp */ ABSENT_STRING, + /* 343: smgrp */ ABSENT_STRING, + /* 344: smgt */ ABSENT_STRING, + /* 345: smgtp */ ABSENT_STRING, + /* 346: sbim */ ABSENT_STRING, + /* 347: scsd */ ABSENT_STRING, + /* 348: rbim */ ABSENT_STRING, + /* 349: rcsd */ ABSENT_STRING, + /* 350: subcs */ ABSENT_STRING, + /* 351: supcs */ ABSENT_STRING, + /* 352: docr */ ABSENT_STRING, + /* 353: zerom */ ABSENT_STRING, + /* 354: csnm */ ABSENT_STRING, + /* 355: kmous */ xterm_s_kmous, + /* 356: minfo */ ABSENT_STRING, + /* 357: reqmp */ ABSENT_STRING, + /* 358: getm */ ABSENT_STRING, + /* 359: setaf */ xterm_s_setaf, + /* 360: setab */ xterm_s_setab, + /* 361: pfxl */ ABSENT_STRING, + /* 362: devt */ ABSENT_STRING, + /* 363: csin */ ABSENT_STRING, + /* 364: s0ds */ ABSENT_STRING, + /* 365: s1ds */ ABSENT_STRING, + /* 366: s2ds */ ABSENT_STRING, + /* 367: s3ds */ ABSENT_STRING, + /* 368: smglr */ ABSENT_STRING, + /* 369: smgtb */ ABSENT_STRING, + /* 370: birep */ ABSENT_STRING, + /* 371: binel */ ABSENT_STRING, + /* 372: bicr */ ABSENT_STRING, + /* 373: colornm */ ABSENT_STRING, + /* 374: defbi */ ABSENT_STRING, + /* 375: endbi */ ABSENT_STRING, + /* 376: setcolor */ ABSENT_STRING, + /* 377: slines */ ABSENT_STRING, + /* 378: dispc */ ABSENT_STRING, + /* 379: smpch */ ABSENT_STRING, + /* 380: rmpch */ ABSENT_STRING, + /* 381: smsc */ ABSENT_STRING, + /* 382: rmsc */ ABSENT_STRING, + /* 383: pctrm */ ABSENT_STRING, + /* 384: scesc */ ABSENT_STRING, + /* 385: scesa */ ABSENT_STRING, + /* 386: ehhlm */ ABSENT_STRING, + /* 387: elhlm */ ABSENT_STRING, + /* 388: elohlm */ ABSENT_STRING, + /* 389: erhlm */ ABSENT_STRING, + /* 390: ethlm */ ABSENT_STRING, + /* 391: evhlm */ ABSENT_STRING, + /* 392: sgr1 */ ABSENT_STRING, + /* 393: slength */ ABSENT_STRING, + /* 394: OTi2 */ ABSENT_STRING, + /* 395: OTrs */ ABSENT_STRING, + /* 396: OTnl */ ABSENT_STRING, + /* 397: OTbc */ ABSENT_STRING, + /* 398: OTko */ ABSENT_STRING, + /* 399: OTma */ ABSENT_STRING, + /* 400: OTG2 */ ABSENT_STRING, + /* 401: OTG3 */ ABSENT_STRING, + /* 402: OTG1 */ ABSENT_STRING, + /* 403: OTG4 */ ABSENT_STRING, + /* 404: OTGR */ ABSENT_STRING, + /* 405: OTGL */ ABSENT_STRING, + /* 406: OTGU */ ABSENT_STRING, + /* 407: OTGD */ ABSENT_STRING, + /* 408: OTGH */ ABSENT_STRING, + /* 409: OTGV */ ABSENT_STRING, + /* 410: OTGC */ ABSENT_STRING, + /* 411: meml */ xterm_s_meml, + /* 412: memu */ xterm_s_memu, + /* 413: box1 */ ABSENT_STRING, +}; +/* xterm-256color */ + +static char xterm_256color_alias_data[] = "xterm-256color|xterm with 256 colors"; + +static char xterm_256color_s_cbt[] = "\033[Z"; +static char xterm_256color_s_bel[] = "\007"; +static char xterm_256color_s_cr [] = "\015"; +static char xterm_256color_s_csr[] = "\033[%i%p1%d;%p2%dr"; +static char xterm_256color_s_tbc[] = "\033[3g"; +static char xterm_256color_s_clear[] = "\033[H\033[2J"; +static char xterm_256color_s_el [] = "\033[K"; +static char xterm_256color_s_ed [] = "\033[J"; +static char xterm_256color_s_hpa[] = "\033[%i%p1%dG"; +static char xterm_256color_s_cup[] = "\033[%i%p1%d;%p2%dH"; +static char xterm_256color_s_cud1[] = "\012"; +static char xterm_256color_s_home[] = "\033[H"; +static char xterm_256color_s_civis[] = "\033[?25l"; +static char xterm_256color_s_cub1[] = "\010"; +static char xterm_256color_s_cnorm[] = "\033[?12l\033[?25h"; +static char xterm_256color_s_cuf1[] = "\033[C"; +static char xterm_256color_s_cuu1[] = "\033[A"; +static char xterm_256color_s_cvvis[] = "\033[?12;25h"; +static char xterm_256color_s_dch1[] = "\033[P"; +static char xterm_256color_s_dl1[] = "\033[M"; +static char xterm_256color_s_smacs[] = "\033(0"; +static char xterm_256color_s_blink[] = "\033[5m"; +static char xterm_256color_s_bold[] = "\033[1m"; +static char xterm_256color_s_smcup[] = "\033[?1049h\033[22;0;0t"; +static char xterm_256color_s_dim[] = "\033[2m"; +static char xterm_256color_s_smir[] = "\033[4h"; +static char xterm_256color_s_invis[] = "\033[8m"; +static char xterm_256color_s_rev[] = "\033[7m"; +static char xterm_256color_s_smso[] = "\033[7m"; +static char xterm_256color_s_smul[] = "\033[4m"; +static char xterm_256color_s_ech[] = "\033[%p1%dX"; +static char xterm_256color_s_rmacs[] = "\033(B"; +static char xterm_256color_s_sgr0[] = "\033(B\033[m"; +static char xterm_256color_s_rmcup[] = "\033[?1049l\033[23;0;0t"; +static char xterm_256color_s_rmir[] = "\033[4l"; +static char xterm_256color_s_rmso[] = "\033[27m"; +static char xterm_256color_s_rmul[] = "\033[24m"; +static char xterm_256color_s_flash[] = "\033[?5h$<100/>\033[?5l"; +static char xterm_256color_s_is2[] = "\033[!p\033[?3;4l\033[4l\033>"; +static char xterm_256color_s_il1[] = "\033[L"; +static char xterm_256color_s_kbs[] = "\010"; +static char xterm_256color_s_kdch1[] = "\033[3~"; +static char xterm_256color_s_kcud1[] = "\033OB"; +static char xterm_256color_s_kf1[] = "\033OP"; +static char xterm_256color_s_kf10[] = "\033[21~"; +static char xterm_256color_s_kf2[] = "\033OQ"; +static char xterm_256color_s_kf3[] = "\033OR"; +static char xterm_256color_s_kf4[] = "\033OS"; +static char xterm_256color_s_kf5[] = "\033[15~"; +static char xterm_256color_s_kf6[] = "\033[17~"; +static char xterm_256color_s_kf7[] = "\033[18~"; +static char xterm_256color_s_kf8[] = "\033[19~"; +static char xterm_256color_s_kf9[] = "\033[20~"; +static char xterm_256color_s_khome[] = "\033OH"; +static char xterm_256color_s_kich1[] = "\033[2~"; +static char xterm_256color_s_kcub1[] = "\033OD"; +static char xterm_256color_s_knp[] = "\033[6~"; +static char xterm_256color_s_kpp[] = "\033[5~"; +static char xterm_256color_s_kcuf1[] = "\033OC"; +static char xterm_256color_s_kind[] = "\033[1;2B"; +static char xterm_256color_s_kri[] = "\033[1;2A"; +static char xterm_256color_s_kcuu1[] = "\033OA"; +static char xterm_256color_s_rmkx[] = "\033[?1l\033>"; +static char xterm_256color_s_smkx[] = "\033[?1h\033="; +static char xterm_256color_s_rmm[] = "\033[?1034l"; +static char xterm_256color_s_smm[] = "\033[?1034h"; +static char xterm_256color_s_dch[] = "\033[%p1%dP"; +static char xterm_256color_s_dl [] = "\033[%p1%dM"; +static char xterm_256color_s_cud[] = "\033[%p1%dB"; +static char xterm_256color_s_ich[] = "\033[%p1%d@"; +static char xterm_256color_s_indn[] = "\033[%p1%dS"; +static char xterm_256color_s_il [] = "\033[%p1%dL"; +static char xterm_256color_s_cub[] = "\033[%p1%dD"; +static char xterm_256color_s_cuf[] = "\033[%p1%dC"; +static char xterm_256color_s_rin[] = "\033[%p1%dT"; +static char xterm_256color_s_cuu[] = "\033[%p1%dA"; +static char xterm_256color_s_mc0[] = "\033[i"; +static char xterm_256color_s_mc4[] = "\033[4i"; +static char xterm_256color_s_mc5[] = "\033[5i"; +static char xterm_256color_s_rep[] = "%p1%c\033[%p2%{1}%-%db"; +static char xterm_256color_s_rs1[] = "\033c\033]104\007"; +static char xterm_256color_s_rs2[] = "\033[!p\033[?3;4l\033[4l\033>"; +static char xterm_256color_s_rc [] = "\0338"; +static char xterm_256color_s_vpa[] = "\033[%i%p1%dd"; +static char xterm_256color_s_sc [] = "\0337"; +static char xterm_256color_s_ind[] = "\012"; +static char xterm_256color_s_ri [] = "\033M"; +static char xterm_256color_s_sgr[] = "%?%p9%t\033(0%e\033(B%;\033[0%?%p6%t;1%;%?%p5%t;2%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m"; +static char xterm_256color_s_hts[] = "\033H"; +static char xterm_256color_s_ht [] = "\011"; +static char xterm_256color_s_kb2[] = "\033OE"; +static char xterm_256color_s_acsc[] = "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"; +static char xterm_256color_s_kcbt[] = "\033[Z"; +static char xterm_256color_s_smam[] = "\033[?7h"; +static char xterm_256color_s_rmam[] = "\033[?7l"; +static char xterm_256color_s_kend[] = "\033OF"; +static char xterm_256color_s_kent[] = "\033OM"; +static char xterm_256color_s_kDC[] = "\033[3;2~"; +static char xterm_256color_s_kEND[] = "\033[1;2F"; +static char xterm_256color_s_kHOM[] = "\033[1;2H"; +static char xterm_256color_s_kIC[] = "\033[2;2~"; +static char xterm_256color_s_kLFT[] = "\033[1;2D"; +static char xterm_256color_s_kNXT[] = "\033[6;2~"; +static char xterm_256color_s_kPRV[] = "\033[5;2~"; +static char xterm_256color_s_kRIT[] = "\033[1;2C"; +static char xterm_256color_s_kf11[] = "\033[23~"; +static char xterm_256color_s_kf12[] = "\033[24~"; +static char xterm_256color_s_kf13[] = "\033[1;2P"; +static char xterm_256color_s_kf14[] = "\033[1;2Q"; +static char xterm_256color_s_kf15[] = "\033[1;2R"; +static char xterm_256color_s_kf16[] = "\033[1;2S"; +static char xterm_256color_s_kf17[] = "\033[15;2~"; +static char xterm_256color_s_kf18[] = "\033[17;2~"; +static char xterm_256color_s_kf19[] = "\033[18;2~"; +static char xterm_256color_s_kf20[] = "\033[19;2~"; +static char xterm_256color_s_kf21[] = "\033[20;2~"; +static char xterm_256color_s_kf22[] = "\033[21;2~"; +static char xterm_256color_s_kf23[] = "\033[23;2~"; +static char xterm_256color_s_kf24[] = "\033[24;2~"; +static char xterm_256color_s_kf25[] = "\033[1;5P"; +static char xterm_256color_s_kf26[] = "\033[1;5Q"; +static char xterm_256color_s_kf27[] = "\033[1;5R"; +static char xterm_256color_s_kf28[] = "\033[1;5S"; +static char xterm_256color_s_kf29[] = "\033[15;5~"; +static char xterm_256color_s_kf30[] = "\033[17;5~"; +static char xterm_256color_s_kf31[] = "\033[18;5~"; +static char xterm_256color_s_kf32[] = "\033[19;5~"; +static char xterm_256color_s_kf33[] = "\033[20;5~"; +static char xterm_256color_s_kf34[] = "\033[21;5~"; +static char xterm_256color_s_kf35[] = "\033[23;5~"; +static char xterm_256color_s_kf36[] = "\033[24;5~"; +static char xterm_256color_s_kf37[] = "\033[1;6P"; +static char xterm_256color_s_kf38[] = "\033[1;6Q"; +static char xterm_256color_s_kf39[] = "\033[1;6R"; +static char xterm_256color_s_kf40[] = "\033[1;6S"; +static char xterm_256color_s_kf41[] = "\033[15;6~"; +static char xterm_256color_s_kf42[] = "\033[17;6~"; +static char xterm_256color_s_kf43[] = "\033[18;6~"; +static char xterm_256color_s_kf44[] = "\033[19;6~"; +static char xterm_256color_s_kf45[] = "\033[20;6~"; +static char xterm_256color_s_kf46[] = "\033[21;6~"; +static char xterm_256color_s_kf47[] = "\033[23;6~"; +static char xterm_256color_s_kf48[] = "\033[24;6~"; +static char xterm_256color_s_kf49[] = "\033[1;3P"; +static char xterm_256color_s_kf50[] = "\033[1;3Q"; +static char xterm_256color_s_kf51[] = "\033[1;3R"; +static char xterm_256color_s_kf52[] = "\033[1;3S"; +static char xterm_256color_s_kf53[] = "\033[15;3~"; +static char xterm_256color_s_kf54[] = "\033[17;3~"; +static char xterm_256color_s_kf55[] = "\033[18;3~"; +static char xterm_256color_s_kf56[] = "\033[19;3~"; +static char xterm_256color_s_kf57[] = "\033[20;3~"; +static char xterm_256color_s_kf58[] = "\033[21;3~"; +static char xterm_256color_s_kf59[] = "\033[23;3~"; +static char xterm_256color_s_kf60[] = "\033[24;3~"; +static char xterm_256color_s_kf61[] = "\033[1;4P"; +static char xterm_256color_s_kf62[] = "\033[1;4Q"; +static char xterm_256color_s_kf63[] = "\033[1;4R"; +static char xterm_256color_s_el1[] = "\033[1K"; +static char xterm_256color_s_u6 [] = "\033[%i%d;%dR"; +static char xterm_256color_s_u7 [] = "\033[6n"; +static char xterm_256color_s_u8 [] = "\033[?%[;0123456789]c"; +static char xterm_256color_s_u9 [] = "\033[c"; +static char xterm_256color_s_op [] = "\033[39;49m"; +static char xterm_256color_s_oc [] = "\033]104\007"; +static char xterm_256color_s_initc[] = "\033]4;%p1%d;rgb:%p2%{255}%*%{1000}%/%2.2X/%p3%{255}%*%{1000}%/%2.2X/%p4%{255}%*%{1000}%/%2.2X\033\134"; +static char xterm_256color_s_sitm[] = "\033[3m"; +static char xterm_256color_s_ritm[] = "\033[23m"; +static char xterm_256color_s_kmous[] = "\033[<"; +static char xterm_256color_s_setaf[] = "\033[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m"; +static char xterm_256color_s_setab[] = "\033[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m"; +static char xterm_256color_s_meml[] = "\033l"; +static char xterm_256color_s_memu[] = "\033m"; + +static char xterm_256color_bool_data[] = { + /* 0: bw */ FALSE, + /* 1: am */ TRUE, + /* 2: xsb */ FALSE, + /* 3: xhp */ FALSE, + /* 4: xenl */ TRUE, + /* 5: eo */ FALSE, + /* 6: gn */ FALSE, + /* 7: hc */ FALSE, + /* 8: km */ TRUE, + /* 9: hs */ FALSE, + /* 10: in */ FALSE, + /* 11: da */ FALSE, + /* 12: db */ FALSE, + /* 13: mir */ TRUE, + /* 14: msgr */ TRUE, + /* 15: os */ FALSE, + /* 16: eslok */ FALSE, + /* 17: xt */ FALSE, + /* 18: hz */ FALSE, + /* 19: ul */ FALSE, + /* 20: xon */ FALSE, + /* 21: nxon */ FALSE, + /* 22: mc5i */ TRUE, + /* 23: chts */ FALSE, + /* 24: nrrmc */ FALSE, + /* 25: npc */ TRUE, + /* 26: ndscr */ FALSE, + /* 27: ccc */ TRUE, + /* 28: bce */ TRUE, + /* 29: hls */ FALSE, + /* 30: xhpa */ FALSE, + /* 31: crxm */ FALSE, + /* 32: daisy */ FALSE, + /* 33: xvpa */ FALSE, + /* 34: sam */ FALSE, + /* 35: cpix */ FALSE, + /* 36: lpix */ FALSE, + /* 37: OTbs */ TRUE, + /* 38: OTns */ FALSE, + /* 39: OTnc */ FALSE, + /* 40: OTMT */ FALSE, + /* 41: OTNL */ FALSE, + /* 42: OTpt */ FALSE, + /* 43: OTxr */ FALSE, +}; +static NCURSES_INT2 xterm_256color_number_data[] = { + /* 0: cols */ 80, + /* 1: it */ 8, + /* 2: lines */ 24, + /* 3: lm */ ABSENT_NUMERIC, + /* 4: xmc */ ABSENT_NUMERIC, + /* 5: pb */ ABSENT_NUMERIC, + /* 6: vt */ ABSENT_NUMERIC, + /* 7: wsl */ ABSENT_NUMERIC, + /* 8: nlab */ ABSENT_NUMERIC, + /* 9: lh */ ABSENT_NUMERIC, + /* 10: lw */ ABSENT_NUMERIC, + /* 11: ma */ ABSENT_NUMERIC, + /* 12: wnum */ ABSENT_NUMERIC, + /* 13: colors */ 256, + /* 14: pairs */ 32767, + /* 15: ncv */ ABSENT_NUMERIC, + /* 16: bufsz */ ABSENT_NUMERIC, + /* 17: spinv */ ABSENT_NUMERIC, + /* 18: spinh */ ABSENT_NUMERIC, + /* 19: maddr */ ABSENT_NUMERIC, + /* 20: mjump */ ABSENT_NUMERIC, + /* 21: mcs */ ABSENT_NUMERIC, + /* 22: mls */ ABSENT_NUMERIC, + /* 23: npins */ ABSENT_NUMERIC, + /* 24: orc */ ABSENT_NUMERIC, + /* 25: orl */ ABSENT_NUMERIC, + /* 26: orhi */ ABSENT_NUMERIC, + /* 27: orvi */ ABSENT_NUMERIC, + /* 28: cps */ ABSENT_NUMERIC, + /* 29: widcs */ ABSENT_NUMERIC, + /* 30: btns */ ABSENT_NUMERIC, + /* 31: bitwin */ ABSENT_NUMERIC, + /* 32: bitype */ ABSENT_NUMERIC, + /* 33: OTug */ ABSENT_NUMERIC, + /* 34: OTdC */ ABSENT_NUMERIC, + /* 35: OTdN */ ABSENT_NUMERIC, + /* 36: OTdB */ ABSENT_NUMERIC, + /* 37: OTdT */ ABSENT_NUMERIC, + /* 38: OTkn */ ABSENT_NUMERIC, +}; +static char * xterm_256color_string_data[] = { + /* 0: cbt */ xterm_256color_s_cbt, + /* 1: bel */ xterm_256color_s_bel, + /* 2: cr */ xterm_256color_s_cr, + /* 3: csr */ xterm_256color_s_csr, + /* 4: tbc */ xterm_256color_s_tbc, + /* 5: clear */ xterm_256color_s_clear, + /* 6: el */ xterm_256color_s_el, + /* 7: ed */ xterm_256color_s_ed, + /* 8: hpa */ xterm_256color_s_hpa, + /* 9: cmdch */ ABSENT_STRING, + /* 10: cup */ xterm_256color_s_cup, + /* 11: cud1 */ xterm_256color_s_cud1, + /* 12: home */ xterm_256color_s_home, + /* 13: civis */ xterm_256color_s_civis, + /* 14: cub1 */ xterm_256color_s_cub1, + /* 15: mrcup */ ABSENT_STRING, + /* 16: cnorm */ xterm_256color_s_cnorm, + /* 17: cuf1 */ xterm_256color_s_cuf1, + /* 18: ll */ ABSENT_STRING, + /* 19: cuu1 */ xterm_256color_s_cuu1, + /* 20: cvvis */ xterm_256color_s_cvvis, + /* 21: dch1 */ xterm_256color_s_dch1, + /* 22: dl1 */ xterm_256color_s_dl1, + /* 23: dsl */ ABSENT_STRING, + /* 24: hd */ ABSENT_STRING, + /* 25: smacs */ xterm_256color_s_smacs, + /* 26: blink */ xterm_256color_s_blink, + /* 27: bold */ xterm_256color_s_bold, + /* 28: smcup */ xterm_256color_s_smcup, + /* 29: smdc */ ABSENT_STRING, + /* 30: dim */ xterm_256color_s_dim, + /* 31: smir */ xterm_256color_s_smir, + /* 32: invis */ xterm_256color_s_invis, + /* 33: prot */ ABSENT_STRING, + /* 34: rev */ xterm_256color_s_rev, + /* 35: smso */ xterm_256color_s_smso, + /* 36: smul */ xterm_256color_s_smul, + /* 37: ech */ xterm_256color_s_ech, + /* 38: rmacs */ xterm_256color_s_rmacs, + /* 39: sgr0 */ xterm_256color_s_sgr0, + /* 40: rmcup */ xterm_256color_s_rmcup, + /* 41: rmdc */ ABSENT_STRING, + /* 42: rmir */ xterm_256color_s_rmir, + /* 43: rmso */ xterm_256color_s_rmso, + /* 44: rmul */ xterm_256color_s_rmul, + /* 45: flash */ xterm_256color_s_flash, + /* 46: ff */ ABSENT_STRING, + /* 47: fsl */ ABSENT_STRING, + /* 48: is1 */ ABSENT_STRING, + /* 49: is2 */ xterm_256color_s_is2, + /* 50: is3 */ ABSENT_STRING, + /* 51: if */ ABSENT_STRING, + /* 52: ich1 */ ABSENT_STRING, + /* 53: il1 */ xterm_256color_s_il1, + /* 54: ip */ ABSENT_STRING, + /* 55: kbs */ xterm_256color_s_kbs, + /* 56: ktbc */ ABSENT_STRING, + /* 57: kclr */ ABSENT_STRING, + /* 58: kctab */ ABSENT_STRING, + /* 59: kdch1 */ xterm_256color_s_kdch1, + /* 60: kdl1 */ ABSENT_STRING, + /* 61: kcud1 */ xterm_256color_s_kcud1, + /* 62: krmir */ ABSENT_STRING, + /* 63: kel */ ABSENT_STRING, + /* 64: ked */ ABSENT_STRING, + /* 65: kf0 */ ABSENT_STRING, + /* 66: kf1 */ xterm_256color_s_kf1, + /* 67: kf10 */ xterm_256color_s_kf10, + /* 68: kf2 */ xterm_256color_s_kf2, + /* 69: kf3 */ xterm_256color_s_kf3, + /* 70: kf4 */ xterm_256color_s_kf4, + /* 71: kf5 */ xterm_256color_s_kf5, + /* 72: kf6 */ xterm_256color_s_kf6, + /* 73: kf7 */ xterm_256color_s_kf7, + /* 74: kf8 */ xterm_256color_s_kf8, + /* 75: kf9 */ xterm_256color_s_kf9, + /* 76: khome */ xterm_256color_s_khome, + /* 77: kich1 */ xterm_256color_s_kich1, + /* 78: kil1 */ ABSENT_STRING, + /* 79: kcub1 */ xterm_256color_s_kcub1, + /* 80: kll */ ABSENT_STRING, + /* 81: knp */ xterm_256color_s_knp, + /* 82: kpp */ xterm_256color_s_kpp, + /* 83: kcuf1 */ xterm_256color_s_kcuf1, + /* 84: kind */ xterm_256color_s_kind, + /* 85: kri */ xterm_256color_s_kri, + /* 86: khts */ ABSENT_STRING, + /* 87: kcuu1 */ xterm_256color_s_kcuu1, + /* 88: rmkx */ xterm_256color_s_rmkx, + /* 89: smkx */ xterm_256color_s_smkx, + /* 90: lf0 */ ABSENT_STRING, + /* 91: lf1 */ ABSENT_STRING, + /* 92: lf10 */ ABSENT_STRING, + /* 93: lf2 */ ABSENT_STRING, + /* 94: lf3 */ ABSENT_STRING, + /* 95: lf4 */ ABSENT_STRING, + /* 96: lf5 */ ABSENT_STRING, + /* 97: lf6 */ ABSENT_STRING, + /* 98: lf7 */ ABSENT_STRING, + /* 99: lf8 */ ABSENT_STRING, + /* 100: lf9 */ ABSENT_STRING, + /* 101: rmm */ xterm_256color_s_rmm, + /* 102: smm */ xterm_256color_s_smm, + /* 103: nel */ ABSENT_STRING, + /* 104: pad */ ABSENT_STRING, + /* 105: dch */ xterm_256color_s_dch, + /* 106: dl */ xterm_256color_s_dl, + /* 107: cud */ xterm_256color_s_cud, + /* 108: ich */ xterm_256color_s_ich, + /* 109: indn */ xterm_256color_s_indn, + /* 110: il */ xterm_256color_s_il, + /* 111: cub */ xterm_256color_s_cub, + /* 112: cuf */ xterm_256color_s_cuf, + /* 113: rin */ xterm_256color_s_rin, + /* 114: cuu */ xterm_256color_s_cuu, + /* 115: pfkey */ ABSENT_STRING, + /* 116: pfloc */ ABSENT_STRING, + /* 117: pfx */ ABSENT_STRING, + /* 118: mc0 */ xterm_256color_s_mc0, + /* 119: mc4 */ xterm_256color_s_mc4, + /* 120: mc5 */ xterm_256color_s_mc5, + /* 121: rep */ xterm_256color_s_rep, + /* 122: rs1 */ xterm_256color_s_rs1, + /* 123: rs2 */ xterm_256color_s_rs2, + /* 124: rs3 */ ABSENT_STRING, + /* 125: rf */ ABSENT_STRING, + /* 126: rc */ xterm_256color_s_rc, + /* 127: vpa */ xterm_256color_s_vpa, + /* 128: sc */ xterm_256color_s_sc, + /* 129: ind */ xterm_256color_s_ind, + /* 130: ri */ xterm_256color_s_ri, + /* 131: sgr */ xterm_256color_s_sgr, + /* 132: hts */ xterm_256color_s_hts, + /* 133: wind */ ABSENT_STRING, + /* 134: ht */ xterm_256color_s_ht, + /* 135: tsl */ ABSENT_STRING, + /* 136: uc */ ABSENT_STRING, + /* 137: hu */ ABSENT_STRING, + /* 138: iprog */ ABSENT_STRING, + /* 139: ka1 */ ABSENT_STRING, + /* 140: ka3 */ ABSENT_STRING, + /* 141: kb2 */ xterm_256color_s_kb2, + /* 142: kc1 */ ABSENT_STRING, + /* 143: kc3 */ ABSENT_STRING, + /* 144: mc5p */ ABSENT_STRING, + /* 145: rmp */ ABSENT_STRING, + /* 146: acsc */ xterm_256color_s_acsc, + /* 147: pln */ ABSENT_STRING, + /* 148: kcbt */ xterm_256color_s_kcbt, + /* 149: smxon */ ABSENT_STRING, + /* 150: rmxon */ ABSENT_STRING, + /* 151: smam */ xterm_256color_s_smam, + /* 152: rmam */ xterm_256color_s_rmam, + /* 153: xonc */ ABSENT_STRING, + /* 154: xoffc */ ABSENT_STRING, + /* 155: enacs */ ABSENT_STRING, + /* 156: smln */ ABSENT_STRING, + /* 157: rmln */ ABSENT_STRING, + /* 158: kbeg */ ABSENT_STRING, + /* 159: kcan */ ABSENT_STRING, + /* 160: kclo */ ABSENT_STRING, + /* 161: kcmd */ ABSENT_STRING, + /* 162: kcpy */ ABSENT_STRING, + /* 163: kcrt */ ABSENT_STRING, + /* 164: kend */ xterm_256color_s_kend, + /* 165: kent */ xterm_256color_s_kent, + /* 166: kext */ ABSENT_STRING, + /* 167: kfnd */ ABSENT_STRING, + /* 168: khlp */ ABSENT_STRING, + /* 169: kmrk */ ABSENT_STRING, + /* 170: kmsg */ ABSENT_STRING, + /* 171: kmov */ ABSENT_STRING, + /* 172: knxt */ ABSENT_STRING, + /* 173: kopn */ ABSENT_STRING, + /* 174: kopt */ ABSENT_STRING, + /* 175: kprv */ ABSENT_STRING, + /* 176: kprt */ ABSENT_STRING, + /* 177: krdo */ ABSENT_STRING, + /* 178: kref */ ABSENT_STRING, + /* 179: krfr */ ABSENT_STRING, + /* 180: krpl */ ABSENT_STRING, + /* 181: krst */ ABSENT_STRING, + /* 182: kres */ ABSENT_STRING, + /* 183: ksav */ ABSENT_STRING, + /* 184: kspd */ ABSENT_STRING, + /* 185: kund */ ABSENT_STRING, + /* 186: kBEG */ ABSENT_STRING, + /* 187: kCAN */ ABSENT_STRING, + /* 188: kCMD */ ABSENT_STRING, + /* 189: kCPY */ ABSENT_STRING, + /* 190: kCRT */ ABSENT_STRING, + /* 191: kDC */ xterm_256color_s_kDC, + /* 192: kDL */ ABSENT_STRING, + /* 193: kslt */ ABSENT_STRING, + /* 194: kEND */ xterm_256color_s_kEND, + /* 195: kEOL */ ABSENT_STRING, + /* 196: kEXT */ ABSENT_STRING, + /* 197: kFND */ ABSENT_STRING, + /* 198: kHLP */ ABSENT_STRING, + /* 199: kHOM */ xterm_256color_s_kHOM, + /* 200: kIC */ xterm_256color_s_kIC, + /* 201: kLFT */ xterm_256color_s_kLFT, + /* 202: kMSG */ ABSENT_STRING, + /* 203: kMOV */ ABSENT_STRING, + /* 204: kNXT */ xterm_256color_s_kNXT, + /* 205: kOPT */ ABSENT_STRING, + /* 206: kPRV */ xterm_256color_s_kPRV, + /* 207: kPRT */ ABSENT_STRING, + /* 208: kRDO */ ABSENT_STRING, + /* 209: kRPL */ ABSENT_STRING, + /* 210: kRIT */ xterm_256color_s_kRIT, + /* 211: kRES */ ABSENT_STRING, + /* 212: kSAV */ ABSENT_STRING, + /* 213: kSPD */ ABSENT_STRING, + /* 214: kUND */ ABSENT_STRING, + /* 215: rfi */ ABSENT_STRING, + /* 216: kf11 */ xterm_256color_s_kf11, + /* 217: kf12 */ xterm_256color_s_kf12, + /* 218: kf13 */ xterm_256color_s_kf13, + /* 219: kf14 */ xterm_256color_s_kf14, + /* 220: kf15 */ xterm_256color_s_kf15, + /* 221: kf16 */ xterm_256color_s_kf16, + /* 222: kf17 */ xterm_256color_s_kf17, + /* 223: kf18 */ xterm_256color_s_kf18, + /* 224: kf19 */ xterm_256color_s_kf19, + /* 225: kf20 */ xterm_256color_s_kf20, + /* 226: kf21 */ xterm_256color_s_kf21, + /* 227: kf22 */ xterm_256color_s_kf22, + /* 228: kf23 */ xterm_256color_s_kf23, + /* 229: kf24 */ xterm_256color_s_kf24, + /* 230: kf25 */ xterm_256color_s_kf25, + /* 231: kf26 */ xterm_256color_s_kf26, + /* 232: kf27 */ xterm_256color_s_kf27, + /* 233: kf28 */ xterm_256color_s_kf28, + /* 234: kf29 */ xterm_256color_s_kf29, + /* 235: kf30 */ xterm_256color_s_kf30, + /* 236: kf31 */ xterm_256color_s_kf31, + /* 237: kf32 */ xterm_256color_s_kf32, + /* 238: kf33 */ xterm_256color_s_kf33, + /* 239: kf34 */ xterm_256color_s_kf34, + /* 240: kf35 */ xterm_256color_s_kf35, + /* 241: kf36 */ xterm_256color_s_kf36, + /* 242: kf37 */ xterm_256color_s_kf37, + /* 243: kf38 */ xterm_256color_s_kf38, + /* 244: kf39 */ xterm_256color_s_kf39, + /* 245: kf40 */ xterm_256color_s_kf40, + /* 246: kf41 */ xterm_256color_s_kf41, + /* 247: kf42 */ xterm_256color_s_kf42, + /* 248: kf43 */ xterm_256color_s_kf43, + /* 249: kf44 */ xterm_256color_s_kf44, + /* 250: kf45 */ xterm_256color_s_kf45, + /* 251: kf46 */ xterm_256color_s_kf46, + /* 252: kf47 */ xterm_256color_s_kf47, + /* 253: kf48 */ xterm_256color_s_kf48, + /* 254: kf49 */ xterm_256color_s_kf49, + /* 255: kf50 */ xterm_256color_s_kf50, + /* 256: kf51 */ xterm_256color_s_kf51, + /* 257: kf52 */ xterm_256color_s_kf52, + /* 258: kf53 */ xterm_256color_s_kf53, + /* 259: kf54 */ xterm_256color_s_kf54, + /* 260: kf55 */ xterm_256color_s_kf55, + /* 261: kf56 */ xterm_256color_s_kf56, + /* 262: kf57 */ xterm_256color_s_kf57, + /* 263: kf58 */ xterm_256color_s_kf58, + /* 264: kf59 */ xterm_256color_s_kf59, + /* 265: kf60 */ xterm_256color_s_kf60, + /* 266: kf61 */ xterm_256color_s_kf61, + /* 267: kf62 */ xterm_256color_s_kf62, + /* 268: kf63 */ xterm_256color_s_kf63, + /* 269: el1 */ xterm_256color_s_el1, + /* 270: mgc */ ABSENT_STRING, + /* 271: smgl */ ABSENT_STRING, + /* 272: smgr */ ABSENT_STRING, + /* 273: fln */ ABSENT_STRING, + /* 274: sclk */ ABSENT_STRING, + /* 275: dclk */ ABSENT_STRING, + /* 276: rmclk */ ABSENT_STRING, + /* 277: cwin */ ABSENT_STRING, + /* 278: wingo */ ABSENT_STRING, + /* 279: hup */ ABSENT_STRING, + /* 280: dial */ ABSENT_STRING, + /* 281: qdial */ ABSENT_STRING, + /* 282: tone */ ABSENT_STRING, + /* 283: pulse */ ABSENT_STRING, + /* 284: hook */ ABSENT_STRING, + /* 285: pause */ ABSENT_STRING, + /* 286: wait */ ABSENT_STRING, + /* 287: u0 */ ABSENT_STRING, + /* 288: u1 */ ABSENT_STRING, + /* 289: u2 */ ABSENT_STRING, + /* 290: u3 */ ABSENT_STRING, + /* 291: u4 */ ABSENT_STRING, + /* 292: u5 */ ABSENT_STRING, + /* 293: u6 */ xterm_256color_s_u6, + /* 294: u7 */ xterm_256color_s_u7, + /* 295: u8 */ xterm_256color_s_u8, + /* 296: u9 */ xterm_256color_s_u9, + /* 297: op */ xterm_256color_s_op, + /* 298: oc */ xterm_256color_s_oc, + /* 299: initc */ xterm_256color_s_initc, + /* 300: initp */ ABSENT_STRING, + /* 301: scp */ ABSENT_STRING, + /* 302: setf */ ABSENT_STRING, + /* 303: setb */ ABSENT_STRING, + /* 304: cpi */ ABSENT_STRING, + /* 305: lpi */ ABSENT_STRING, + /* 306: chr */ ABSENT_STRING, + /* 307: cvr */ ABSENT_STRING, + /* 308: defc */ ABSENT_STRING, + /* 309: swidm */ ABSENT_STRING, + /* 310: sdrfq */ ABSENT_STRING, + /* 311: sitm */ xterm_256color_s_sitm, + /* 312: slm */ ABSENT_STRING, + /* 313: smicm */ ABSENT_STRING, + /* 314: snlq */ ABSENT_STRING, + /* 315: snrmq */ ABSENT_STRING, + /* 316: sshm */ ABSENT_STRING, + /* 317: ssubm */ ABSENT_STRING, + /* 318: ssupm */ ABSENT_STRING, + /* 319: sum */ ABSENT_STRING, + /* 320: rwidm */ ABSENT_STRING, + /* 321: ritm */ xterm_256color_s_ritm, + /* 322: rlm */ ABSENT_STRING, + /* 323: rmicm */ ABSENT_STRING, + /* 324: rshm */ ABSENT_STRING, + /* 325: rsubm */ ABSENT_STRING, + /* 326: rsupm */ ABSENT_STRING, + /* 327: rum */ ABSENT_STRING, + /* 328: mhpa */ ABSENT_STRING, + /* 329: mcud1 */ ABSENT_STRING, + /* 330: mcub1 */ ABSENT_STRING, + /* 331: mcuf1 */ ABSENT_STRING, + /* 332: mvpa */ ABSENT_STRING, + /* 333: mcuu1 */ ABSENT_STRING, + /* 334: porder */ ABSENT_STRING, + /* 335: mcud */ ABSENT_STRING, + /* 336: mcub */ ABSENT_STRING, + /* 337: mcuf */ ABSENT_STRING, + /* 338: mcuu */ ABSENT_STRING, + /* 339: scs */ ABSENT_STRING, + /* 340: smgb */ ABSENT_STRING, + /* 341: smgbp */ ABSENT_STRING, + /* 342: smglp */ ABSENT_STRING, + /* 343: smgrp */ ABSENT_STRING, + /* 344: smgt */ ABSENT_STRING, + /* 345: smgtp */ ABSENT_STRING, + /* 346: sbim */ ABSENT_STRING, + /* 347: scsd */ ABSENT_STRING, + /* 348: rbim */ ABSENT_STRING, + /* 349: rcsd */ ABSENT_STRING, + /* 350: subcs */ ABSENT_STRING, + /* 351: supcs */ ABSENT_STRING, + /* 352: docr */ ABSENT_STRING, + /* 353: zerom */ ABSENT_STRING, + /* 354: csnm */ ABSENT_STRING, + /* 355: kmous */ xterm_256color_s_kmous, + /* 356: minfo */ ABSENT_STRING, + /* 357: reqmp */ ABSENT_STRING, + /* 358: getm */ ABSENT_STRING, + /* 359: setaf */ xterm_256color_s_setaf, + /* 360: setab */ xterm_256color_s_setab, + /* 361: pfxl */ ABSENT_STRING, + /* 362: devt */ ABSENT_STRING, + /* 363: csin */ ABSENT_STRING, + /* 364: s0ds */ ABSENT_STRING, + /* 365: s1ds */ ABSENT_STRING, + /* 366: s2ds */ ABSENT_STRING, + /* 367: s3ds */ ABSENT_STRING, + /* 368: smglr */ ABSENT_STRING, + /* 369: smgtb */ ABSENT_STRING, + /* 370: birep */ ABSENT_STRING, + /* 371: binel */ ABSENT_STRING, + /* 372: bicr */ ABSENT_STRING, + /* 373: colornm */ ABSENT_STRING, + /* 374: defbi */ ABSENT_STRING, + /* 375: endbi */ ABSENT_STRING, + /* 376: setcolor */ ABSENT_STRING, + /* 377: slines */ ABSENT_STRING, + /* 378: dispc */ ABSENT_STRING, + /* 379: smpch */ ABSENT_STRING, + /* 380: rmpch */ ABSENT_STRING, + /* 381: smsc */ ABSENT_STRING, + /* 382: rmsc */ ABSENT_STRING, + /* 383: pctrm */ ABSENT_STRING, + /* 384: scesc */ ABSENT_STRING, + /* 385: scesa */ ABSENT_STRING, + /* 386: ehhlm */ ABSENT_STRING, + /* 387: elhlm */ ABSENT_STRING, + /* 388: elohlm */ ABSENT_STRING, + /* 389: erhlm */ ABSENT_STRING, + /* 390: ethlm */ ABSENT_STRING, + /* 391: evhlm */ ABSENT_STRING, + /* 392: sgr1 */ ABSENT_STRING, + /* 393: slength */ ABSENT_STRING, + /* 394: OTi2 */ ABSENT_STRING, + /* 395: OTrs */ ABSENT_STRING, + /* 396: OTnl */ ABSENT_STRING, + /* 397: OTbc */ ABSENT_STRING, + /* 398: OTko */ ABSENT_STRING, + /* 399: OTma */ ABSENT_STRING, + /* 400: OTG2 */ ABSENT_STRING, + /* 401: OTG3 */ ABSENT_STRING, + /* 402: OTG1 */ ABSENT_STRING, + /* 403: OTG4 */ ABSENT_STRING, + /* 404: OTGR */ ABSENT_STRING, + /* 405: OTGL */ ABSENT_STRING, + /* 406: OTGU */ ABSENT_STRING, + /* 407: OTGD */ ABSENT_STRING, + /* 408: OTGH */ ABSENT_STRING, + /* 409: OTGV */ ABSENT_STRING, + /* 410: OTGC */ ABSENT_STRING, + /* 411: meml */ xterm_256color_s_meml, + /* 412: memu */ xterm_256color_s_memu, + /* 413: box1 */ ABSENT_STRING, +}; +/* screen */ + +static char screen_alias_data[] = "screen|VT 100/ANSI X3.64 virtual terminal"; + +static char screen_s_cbt [] = "\033[Z"; +static char screen_s_bel [] = "\007"; +static char screen_s_cr [] = "\015"; +static char screen_s_csr [] = "\033[%i%p1%d;%p2%dr"; +static char screen_s_tbc [] = "\033[3g"; +static char screen_s_clear [] = "\033[H\033[J"; +static char screen_s_el [] = "\033[K"; +static char screen_s_ed [] = "\033[J"; +static char screen_s_hpa [] = "\033[%i%p1%dG"; +static char screen_s_cup [] = "\033[%i%p1%d;%p2%dH"; +static char screen_s_cud1 [] = "\012"; +static char screen_s_home [] = "\033[H"; +static char screen_s_civis [] = "\033[?25l"; +static char screen_s_cub1 [] = "\010"; +static char screen_s_cnorm [] = "\033[34h\033[?25h"; +static char screen_s_cuf1 [] = "\033[C"; +static char screen_s_cuu1 [] = "\033M"; +static char screen_s_cvvis [] = "\033[34l"; +static char screen_s_dch1 [] = "\033[P"; +static char screen_s_dl1 [] = "\033[M"; +static char screen_s_smacs [] = "\016"; +static char screen_s_blink [] = "\033[5m"; +static char screen_s_bold [] = "\033[1m"; +static char screen_s_smcup [] = "\033[?1049h"; +static char screen_s_dim [] = "\033[2m"; +static char screen_s_smir [] = "\033[4h"; +static char screen_s_rev [] = "\033[7m"; +static char screen_s_smso [] = "\033[3m"; +static char screen_s_smul [] = "\033[4m"; +static char screen_s_rmacs [] = "\017"; +static char screen_s_sgr0 [] = "\033[m\017"; +static char screen_s_rmcup [] = "\033[?1049l"; +static char screen_s_rmir [] = "\033[4l"; +static char screen_s_rmso [] = "\033[23m"; +static char screen_s_rmul [] = "\033[24m"; +static char screen_s_flash [] = "\033g"; +static char screen_s_is2 [] = "\033)0"; +static char screen_s_il1 [] = "\033[L"; +static char screen_s_kbs [] = "\010"; +static char screen_s_kdch1 [] = "\033[3~"; +static char screen_s_kcud1 [] = "\033OB"; +static char screen_s_kf1 [] = "\033OP"; +static char screen_s_kf10 [] = "\033[21~"; +static char screen_s_kf2 [] = "\033OQ"; +static char screen_s_kf3 [] = "\033OR"; +static char screen_s_kf4 [] = "\033OS"; +static char screen_s_kf5 [] = "\033[15~"; +static char screen_s_kf6 [] = "\033[17~"; +static char screen_s_kf7 [] = "\033[18~"; +static char screen_s_kf8 [] = "\033[19~"; +static char screen_s_kf9 [] = "\033[20~"; +static char screen_s_khome [] = "\033[1~"; +static char screen_s_kich1 [] = "\033[2~"; +static char screen_s_kcub1 [] = "\033OD"; +static char screen_s_knp [] = "\033[6~"; +static char screen_s_kpp [] = "\033[5~"; +static char screen_s_kcuf1 [] = "\033OC"; +static char screen_s_kcuu1 [] = "\033OA"; +static char screen_s_rmkx [] = "\033[?1l\033>"; +static char screen_s_smkx [] = "\033[?1h\033="; +static char screen_s_nel [] = "\033E"; +static char screen_s_dch [] = "\033[%p1%dP"; +static char screen_s_dl [] = "\033[%p1%dM"; +static char screen_s_cud [] = "\033[%p1%dB"; +static char screen_s_ich [] = "\033[%p1%d@"; +static char screen_s_indn [] = "\033[%p1%dS"; +static char screen_s_il [] = "\033[%p1%dL"; +static char screen_s_cub [] = "\033[%p1%dD"; +static char screen_s_cuf [] = "\033[%p1%dC"; +static char screen_s_cuu [] = "\033[%p1%dA"; +static char screen_s_rs2 [] = "\033c\033[?1000l\033[?25h"; +static char screen_s_rc [] = "\0338"; +static char screen_s_vpa [] = "\033[%i%p1%dd"; +static char screen_s_sc [] = "\0337"; +static char screen_s_ind [] = "\012"; +static char screen_s_ri [] = "\033M"; +static char screen_s_sgr [] = "\033[0%?%p6%t;1%;%?%p1%t;3%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p5%t;2%;m%?%p9%t\016%e\017%;"; +static char screen_s_hts [] = "\033H"; +static char screen_s_ht [] = "\011"; +static char screen_s_acsc [] = "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"; +static char screen_s_kcbt [] = "\033[Z"; +static char screen_s_enacs [] = "\033(B\033)0"; +static char screen_s_kend [] = "\033[4~"; +static char screen_s_kf11 [] = "\033[23~"; +static char screen_s_kf12 [] = "\033[24~"; +static char screen_s_el1 [] = "\033[1K"; +static char screen_s_op [] = "\033[39;49m"; +static char screen_s_kmous [] = "\033[M"; +static char screen_s_setaf [] = "\033[3%p1%dm"; +static char screen_s_setab [] = "\033[4%p1%dm"; + +static char screen_bool_data[] = { + /* 0: bw */ FALSE, + /* 1: am */ TRUE, + /* 2: xsb */ FALSE, + /* 3: xhp */ FALSE, + /* 4: xenl */ TRUE, + /* 5: eo */ FALSE, + /* 6: gn */ FALSE, + /* 7: hc */ FALSE, + /* 8: km */ TRUE, + /* 9: hs */ FALSE, + /* 10: in */ FALSE, + /* 11: da */ FALSE, + /* 12: db */ FALSE, + /* 13: mir */ TRUE, + /* 14: msgr */ TRUE, + /* 15: os */ FALSE, + /* 16: eslok */ FALSE, + /* 17: xt */ FALSE, + /* 18: hz */ FALSE, + /* 19: ul */ FALSE, + /* 20: xon */ FALSE, + /* 21: nxon */ FALSE, + /* 22: mc5i */ FALSE, + /* 23: chts */ FALSE, + /* 24: nrrmc */ FALSE, + /* 25: npc */ FALSE, + /* 26: ndscr */ FALSE, + /* 27: ccc */ FALSE, + /* 28: bce */ FALSE, + /* 29: hls */ FALSE, + /* 30: xhpa */ FALSE, + /* 31: crxm */ FALSE, + /* 32: daisy */ FALSE, + /* 33: xvpa */ FALSE, + /* 34: sam */ FALSE, + /* 35: cpix */ FALSE, + /* 36: lpix */ FALSE, + /* 37: OTbs */ TRUE, + /* 38: OTns */ FALSE, + /* 39: OTnc */ FALSE, + /* 40: OTMT */ FALSE, + /* 41: OTNL */ FALSE, + /* 42: OTpt */ TRUE, + /* 43: OTxr */ FALSE, +}; +static NCURSES_INT2 screen_number_data[] = { + /* 0: cols */ 80, + /* 1: it */ 8, + /* 2: lines */ 24, + /* 3: lm */ ABSENT_NUMERIC, + /* 4: xmc */ ABSENT_NUMERIC, + /* 5: pb */ ABSENT_NUMERIC, + /* 6: vt */ ABSENT_NUMERIC, + /* 7: wsl */ ABSENT_NUMERIC, + /* 8: nlab */ ABSENT_NUMERIC, + /* 9: lh */ ABSENT_NUMERIC, + /* 10: lw */ ABSENT_NUMERIC, + /* 11: ma */ ABSENT_NUMERIC, + /* 12: wnum */ ABSENT_NUMERIC, + /* 13: colors */ 8, + /* 14: pairs */ 64, + /* 15: ncv */ CANCELLED_NUMERIC, + /* 16: bufsz */ ABSENT_NUMERIC, + /* 17: spinv */ ABSENT_NUMERIC, + /* 18: spinh */ ABSENT_NUMERIC, + /* 19: maddr */ ABSENT_NUMERIC, + /* 20: mjump */ ABSENT_NUMERIC, + /* 21: mcs */ ABSENT_NUMERIC, + /* 22: mls */ ABSENT_NUMERIC, + /* 23: npins */ ABSENT_NUMERIC, + /* 24: orc */ ABSENT_NUMERIC, + /* 25: orl */ ABSENT_NUMERIC, + /* 26: orhi */ ABSENT_NUMERIC, + /* 27: orvi */ ABSENT_NUMERIC, + /* 28: cps */ ABSENT_NUMERIC, + /* 29: widcs */ ABSENT_NUMERIC, + /* 30: btns */ ABSENT_NUMERIC, + /* 31: bitwin */ ABSENT_NUMERIC, + /* 32: bitype */ ABSENT_NUMERIC, + /* 33: OTug */ ABSENT_NUMERIC, + /* 34: OTdC */ ABSENT_NUMERIC, + /* 35: OTdN */ ABSENT_NUMERIC, + /* 36: OTdB */ ABSENT_NUMERIC, + /* 37: OTdT */ ABSENT_NUMERIC, + /* 38: OTkn */ ABSENT_NUMERIC, +}; +static char * screen_string_data[] = { + /* 0: cbt */ screen_s_cbt, + /* 1: bel */ screen_s_bel, + /* 2: cr */ screen_s_cr, + /* 3: csr */ screen_s_csr, + /* 4: tbc */ screen_s_tbc, + /* 5: clear */ screen_s_clear, + /* 6: el */ screen_s_el, + /* 7: ed */ screen_s_ed, + /* 8: hpa */ screen_s_hpa, + /* 9: cmdch */ ABSENT_STRING, + /* 10: cup */ screen_s_cup, + /* 11: cud1 */ screen_s_cud1, + /* 12: home */ screen_s_home, + /* 13: civis */ screen_s_civis, + /* 14: cub1 */ screen_s_cub1, + /* 15: mrcup */ ABSENT_STRING, + /* 16: cnorm */ screen_s_cnorm, + /* 17: cuf1 */ screen_s_cuf1, + /* 18: ll */ ABSENT_STRING, + /* 19: cuu1 */ screen_s_cuu1, + /* 20: cvvis */ screen_s_cvvis, + /* 21: dch1 */ screen_s_dch1, + /* 22: dl1 */ screen_s_dl1, + /* 23: dsl */ ABSENT_STRING, + /* 24: hd */ ABSENT_STRING, + /* 25: smacs */ screen_s_smacs, + /* 26: blink */ screen_s_blink, + /* 27: bold */ screen_s_bold, + /* 28: smcup */ screen_s_smcup, + /* 29: smdc */ ABSENT_STRING, + /* 30: dim */ screen_s_dim, + /* 31: smir */ screen_s_smir, + /* 32: invis */ ABSENT_STRING, + /* 33: prot */ ABSENT_STRING, + /* 34: rev */ screen_s_rev, + /* 35: smso */ screen_s_smso, + /* 36: smul */ screen_s_smul, + /* 37: ech */ ABSENT_STRING, + /* 38: rmacs */ screen_s_rmacs, + /* 39: sgr0 */ screen_s_sgr0, + /* 40: rmcup */ screen_s_rmcup, + /* 41: rmdc */ ABSENT_STRING, + /* 42: rmir */ screen_s_rmir, + /* 43: rmso */ screen_s_rmso, + /* 44: rmul */ screen_s_rmul, + /* 45: flash */ screen_s_flash, + /* 46: ff */ ABSENT_STRING, + /* 47: fsl */ ABSENT_STRING, + /* 48: is1 */ ABSENT_STRING, + /* 49: is2 */ screen_s_is2, + /* 50: is3 */ ABSENT_STRING, + /* 51: if */ ABSENT_STRING, + /* 52: ich1 */ ABSENT_STRING, + /* 53: il1 */ screen_s_il1, + /* 54: ip */ ABSENT_STRING, + /* 55: kbs */ screen_s_kbs, + /* 56: ktbc */ ABSENT_STRING, + /* 57: kclr */ ABSENT_STRING, + /* 58: kctab */ ABSENT_STRING, + /* 59: kdch1 */ screen_s_kdch1, + /* 60: kdl1 */ ABSENT_STRING, + /* 61: kcud1 */ screen_s_kcud1, + /* 62: krmir */ ABSENT_STRING, + /* 63: kel */ ABSENT_STRING, + /* 64: ked */ ABSENT_STRING, + /* 65: kf0 */ ABSENT_STRING, + /* 66: kf1 */ screen_s_kf1, + /* 67: kf10 */ screen_s_kf10, + /* 68: kf2 */ screen_s_kf2, + /* 69: kf3 */ screen_s_kf3, + /* 70: kf4 */ screen_s_kf4, + /* 71: kf5 */ screen_s_kf5, + /* 72: kf6 */ screen_s_kf6, + /* 73: kf7 */ screen_s_kf7, + /* 74: kf8 */ screen_s_kf8, + /* 75: kf9 */ screen_s_kf9, + /* 76: khome */ screen_s_khome, + /* 77: kich1 */ screen_s_kich1, + /* 78: kil1 */ ABSENT_STRING, + /* 79: kcub1 */ screen_s_kcub1, + /* 80: kll */ ABSENT_STRING, + /* 81: knp */ screen_s_knp, + /* 82: kpp */ screen_s_kpp, + /* 83: kcuf1 */ screen_s_kcuf1, + /* 84: kind */ ABSENT_STRING, + /* 85: kri */ ABSENT_STRING, + /* 86: khts */ ABSENT_STRING, + /* 87: kcuu1 */ screen_s_kcuu1, + /* 88: rmkx */ screen_s_rmkx, + /* 89: smkx */ screen_s_smkx, + /* 90: lf0 */ ABSENT_STRING, + /* 91: lf1 */ ABSENT_STRING, + /* 92: lf10 */ ABSENT_STRING, + /* 93: lf2 */ ABSENT_STRING, + /* 94: lf3 */ ABSENT_STRING, + /* 95: lf4 */ ABSENT_STRING, + /* 96: lf5 */ ABSENT_STRING, + /* 97: lf6 */ ABSENT_STRING, + /* 98: lf7 */ ABSENT_STRING, + /* 99: lf8 */ ABSENT_STRING, + /* 100: lf9 */ ABSENT_STRING, + /* 101: rmm */ ABSENT_STRING, + /* 102: smm */ ABSENT_STRING, + /* 103: nel */ screen_s_nel, + /* 104: pad */ ABSENT_STRING, + /* 105: dch */ screen_s_dch, + /* 106: dl */ screen_s_dl, + /* 107: cud */ screen_s_cud, + /* 108: ich */ screen_s_ich, + /* 109: indn */ screen_s_indn, + /* 110: il */ screen_s_il, + /* 111: cub */ screen_s_cub, + /* 112: cuf */ screen_s_cuf, + /* 113: rin */ ABSENT_STRING, + /* 114: cuu */ screen_s_cuu, + /* 115: pfkey */ ABSENT_STRING, + /* 116: pfloc */ ABSENT_STRING, + /* 117: pfx */ ABSENT_STRING, + /* 118: mc0 */ ABSENT_STRING, + /* 119: mc4 */ ABSENT_STRING, + /* 120: mc5 */ ABSENT_STRING, + /* 121: rep */ ABSENT_STRING, + /* 122: rs1 */ ABSENT_STRING, + /* 123: rs2 */ screen_s_rs2, + /* 124: rs3 */ ABSENT_STRING, + /* 125: rf */ ABSENT_STRING, + /* 126: rc */ screen_s_rc, + /* 127: vpa */ screen_s_vpa, + /* 128: sc */ screen_s_sc, + /* 129: ind */ screen_s_ind, + /* 130: ri */ screen_s_ri, + /* 131: sgr */ screen_s_sgr, + /* 132: hts */ screen_s_hts, + /* 133: wind */ ABSENT_STRING, + /* 134: ht */ screen_s_ht, + /* 135: tsl */ ABSENT_STRING, + /* 136: uc */ ABSENT_STRING, + /* 137: hu */ ABSENT_STRING, + /* 138: iprog */ ABSENT_STRING, + /* 139: ka1 */ ABSENT_STRING, + /* 140: ka3 */ ABSENT_STRING, + /* 141: kb2 */ ABSENT_STRING, + /* 142: kc1 */ ABSENT_STRING, + /* 143: kc3 */ ABSENT_STRING, + /* 144: mc5p */ ABSENT_STRING, + /* 145: rmp */ ABSENT_STRING, + /* 146: acsc */ screen_s_acsc, + /* 147: pln */ ABSENT_STRING, + /* 148: kcbt */ screen_s_kcbt, + /* 149: smxon */ ABSENT_STRING, + /* 150: rmxon */ ABSENT_STRING, + /* 151: smam */ ABSENT_STRING, + /* 152: rmam */ ABSENT_STRING, + /* 153: xonc */ ABSENT_STRING, + /* 154: xoffc */ ABSENT_STRING, + /* 155: enacs */ screen_s_enacs, + /* 156: smln */ ABSENT_STRING, + /* 157: rmln */ ABSENT_STRING, + /* 158: kbeg */ ABSENT_STRING, + /* 159: kcan */ ABSENT_STRING, + /* 160: kclo */ ABSENT_STRING, + /* 161: kcmd */ ABSENT_STRING, + /* 162: kcpy */ ABSENT_STRING, + /* 163: kcrt */ ABSENT_STRING, + /* 164: kend */ screen_s_kend, + /* 165: kent */ ABSENT_STRING, + /* 166: kext */ ABSENT_STRING, + /* 167: kfnd */ ABSENT_STRING, + /* 168: khlp */ ABSENT_STRING, + /* 169: kmrk */ ABSENT_STRING, + /* 170: kmsg */ ABSENT_STRING, + /* 171: kmov */ ABSENT_STRING, + /* 172: knxt */ ABSENT_STRING, + /* 173: kopn */ ABSENT_STRING, + /* 174: kopt */ ABSENT_STRING, + /* 175: kprv */ ABSENT_STRING, + /* 176: kprt */ ABSENT_STRING, + /* 177: krdo */ ABSENT_STRING, + /* 178: kref */ ABSENT_STRING, + /* 179: krfr */ ABSENT_STRING, + /* 180: krpl */ ABSENT_STRING, + /* 181: krst */ ABSENT_STRING, + /* 182: kres */ ABSENT_STRING, + /* 183: ksav */ ABSENT_STRING, + /* 184: kspd */ ABSENT_STRING, + /* 185: kund */ ABSENT_STRING, + /* 186: kBEG */ ABSENT_STRING, + /* 187: kCAN */ ABSENT_STRING, + /* 188: kCMD */ ABSENT_STRING, + /* 189: kCPY */ ABSENT_STRING, + /* 190: kCRT */ ABSENT_STRING, + /* 191: kDC */ ABSENT_STRING, + /* 192: kDL */ ABSENT_STRING, + /* 193: kslt */ ABSENT_STRING, + /* 194: kEND */ ABSENT_STRING, + /* 195: kEOL */ ABSENT_STRING, + /* 196: kEXT */ ABSENT_STRING, + /* 197: kFND */ ABSENT_STRING, + /* 198: kHLP */ ABSENT_STRING, + /* 199: kHOM */ ABSENT_STRING, + /* 200: kIC */ ABSENT_STRING, + /* 201: kLFT */ ABSENT_STRING, + /* 202: kMSG */ ABSENT_STRING, + /* 203: kMOV */ ABSENT_STRING, + /* 204: kNXT */ ABSENT_STRING, + /* 205: kOPT */ ABSENT_STRING, + /* 206: kPRV */ ABSENT_STRING, + /* 207: kPRT */ ABSENT_STRING, + /* 208: kRDO */ ABSENT_STRING, + /* 209: kRPL */ ABSENT_STRING, + /* 210: kRIT */ ABSENT_STRING, + /* 211: kRES */ ABSENT_STRING, + /* 212: kSAV */ ABSENT_STRING, + /* 213: kSPD */ ABSENT_STRING, + /* 214: kUND */ ABSENT_STRING, + /* 215: rfi */ ABSENT_STRING, + /* 216: kf11 */ screen_s_kf11, + /* 217: kf12 */ screen_s_kf12, + /* 218: kf13 */ ABSENT_STRING, + /* 219: kf14 */ ABSENT_STRING, + /* 220: kf15 */ ABSENT_STRING, + /* 221: kf16 */ ABSENT_STRING, + /* 222: kf17 */ ABSENT_STRING, + /* 223: kf18 */ ABSENT_STRING, + /* 224: kf19 */ ABSENT_STRING, + /* 225: kf20 */ ABSENT_STRING, + /* 226: kf21 */ ABSENT_STRING, + /* 227: kf22 */ ABSENT_STRING, + /* 228: kf23 */ ABSENT_STRING, + /* 229: kf24 */ ABSENT_STRING, + /* 230: kf25 */ ABSENT_STRING, + /* 231: kf26 */ ABSENT_STRING, + /* 232: kf27 */ ABSENT_STRING, + /* 233: kf28 */ ABSENT_STRING, + /* 234: kf29 */ ABSENT_STRING, + /* 235: kf30 */ ABSENT_STRING, + /* 236: kf31 */ ABSENT_STRING, + /* 237: kf32 */ ABSENT_STRING, + /* 238: kf33 */ ABSENT_STRING, + /* 239: kf34 */ ABSENT_STRING, + /* 240: kf35 */ ABSENT_STRING, + /* 241: kf36 */ ABSENT_STRING, + /* 242: kf37 */ ABSENT_STRING, + /* 243: kf38 */ ABSENT_STRING, + /* 244: kf39 */ ABSENT_STRING, + /* 245: kf40 */ ABSENT_STRING, + /* 246: kf41 */ ABSENT_STRING, + /* 247: kf42 */ ABSENT_STRING, + /* 248: kf43 */ ABSENT_STRING, + /* 249: kf44 */ ABSENT_STRING, + /* 250: kf45 */ ABSENT_STRING, + /* 251: kf46 */ ABSENT_STRING, + /* 252: kf47 */ ABSENT_STRING, + /* 253: kf48 */ ABSENT_STRING, + /* 254: kf49 */ ABSENT_STRING, + /* 255: kf50 */ ABSENT_STRING, + /* 256: kf51 */ ABSENT_STRING, + /* 257: kf52 */ ABSENT_STRING, + /* 258: kf53 */ ABSENT_STRING, + /* 259: kf54 */ ABSENT_STRING, + /* 260: kf55 */ ABSENT_STRING, + /* 261: kf56 */ ABSENT_STRING, + /* 262: kf57 */ ABSENT_STRING, + /* 263: kf58 */ ABSENT_STRING, + /* 264: kf59 */ ABSENT_STRING, + /* 265: kf60 */ ABSENT_STRING, + /* 266: kf61 */ ABSENT_STRING, + /* 267: kf62 */ ABSENT_STRING, + /* 268: kf63 */ ABSENT_STRING, + /* 269: el1 */ screen_s_el1, + /* 270: mgc */ ABSENT_STRING, + /* 271: smgl */ ABSENT_STRING, + /* 272: smgr */ ABSENT_STRING, + /* 273: fln */ ABSENT_STRING, + /* 274: sclk */ ABSENT_STRING, + /* 275: dclk */ ABSENT_STRING, + /* 276: rmclk */ ABSENT_STRING, + /* 277: cwin */ ABSENT_STRING, + /* 278: wingo */ ABSENT_STRING, + /* 279: hup */ ABSENT_STRING, + /* 280: dial */ ABSENT_STRING, + /* 281: qdial */ ABSENT_STRING, + /* 282: tone */ ABSENT_STRING, + /* 283: pulse */ ABSENT_STRING, + /* 284: hook */ ABSENT_STRING, + /* 285: pause */ ABSENT_STRING, + /* 286: wait */ ABSENT_STRING, + /* 287: u0 */ ABSENT_STRING, + /* 288: u1 */ ABSENT_STRING, + /* 289: u2 */ ABSENT_STRING, + /* 290: u3 */ ABSENT_STRING, + /* 291: u4 */ ABSENT_STRING, + /* 292: u5 */ ABSENT_STRING, + /* 293: u6 */ ABSENT_STRING, + /* 294: u7 */ ABSENT_STRING, + /* 295: u8 */ ABSENT_STRING, + /* 296: u9 */ ABSENT_STRING, + /* 297: op */ screen_s_op, + /* 298: oc */ ABSENT_STRING, + /* 299: initc */ ABSENT_STRING, + /* 300: initp */ ABSENT_STRING, + /* 301: scp */ ABSENT_STRING, + /* 302: setf */ ABSENT_STRING, + /* 303: setb */ ABSENT_STRING, + /* 304: cpi */ ABSENT_STRING, + /* 305: lpi */ ABSENT_STRING, + /* 306: chr */ ABSENT_STRING, + /* 307: cvr */ ABSENT_STRING, + /* 308: defc */ ABSENT_STRING, + /* 309: swidm */ ABSENT_STRING, + /* 310: sdrfq */ ABSENT_STRING, + /* 311: sitm */ ABSENT_STRING, + /* 312: slm */ ABSENT_STRING, + /* 313: smicm */ ABSENT_STRING, + /* 314: snlq */ ABSENT_STRING, + /* 315: snrmq */ ABSENT_STRING, + /* 316: sshm */ ABSENT_STRING, + /* 317: ssubm */ ABSENT_STRING, + /* 318: ssupm */ ABSENT_STRING, + /* 319: sum */ ABSENT_STRING, + /* 320: rwidm */ ABSENT_STRING, + /* 321: ritm */ ABSENT_STRING, + /* 322: rlm */ ABSENT_STRING, + /* 323: rmicm */ ABSENT_STRING, + /* 324: rshm */ ABSENT_STRING, + /* 325: rsubm */ ABSENT_STRING, + /* 326: rsupm */ ABSENT_STRING, + /* 327: rum */ ABSENT_STRING, + /* 328: mhpa */ ABSENT_STRING, + /* 329: mcud1 */ ABSENT_STRING, + /* 330: mcub1 */ ABSENT_STRING, + /* 331: mcuf1 */ ABSENT_STRING, + /* 332: mvpa */ ABSENT_STRING, + /* 333: mcuu1 */ ABSENT_STRING, + /* 334: porder */ ABSENT_STRING, + /* 335: mcud */ ABSENT_STRING, + /* 336: mcub */ ABSENT_STRING, + /* 337: mcuf */ ABSENT_STRING, + /* 338: mcuu */ ABSENT_STRING, + /* 339: scs */ ABSENT_STRING, + /* 340: smgb */ ABSENT_STRING, + /* 341: smgbp */ ABSENT_STRING, + /* 342: smglp */ ABSENT_STRING, + /* 343: smgrp */ ABSENT_STRING, + /* 344: smgt */ ABSENT_STRING, + /* 345: smgtp */ ABSENT_STRING, + /* 346: sbim */ ABSENT_STRING, + /* 347: scsd */ ABSENT_STRING, + /* 348: rbim */ ABSENT_STRING, + /* 349: rcsd */ ABSENT_STRING, + /* 350: subcs */ ABSENT_STRING, + /* 351: supcs */ ABSENT_STRING, + /* 352: docr */ ABSENT_STRING, + /* 353: zerom */ ABSENT_STRING, + /* 354: csnm */ ABSENT_STRING, + /* 355: kmous */ screen_s_kmous, + /* 356: minfo */ ABSENT_STRING, + /* 357: reqmp */ ABSENT_STRING, + /* 358: getm */ ABSENT_STRING, + /* 359: setaf */ screen_s_setaf, + /* 360: setab */ screen_s_setab, + /* 361: pfxl */ ABSENT_STRING, + /* 362: devt */ ABSENT_STRING, + /* 363: csin */ ABSENT_STRING, + /* 364: s0ds */ ABSENT_STRING, + /* 365: s1ds */ ABSENT_STRING, + /* 366: s2ds */ ABSENT_STRING, + /* 367: s3ds */ ABSENT_STRING, + /* 368: smglr */ ABSENT_STRING, + /* 369: smgtb */ ABSENT_STRING, + /* 370: birep */ ABSENT_STRING, + /* 371: binel */ ABSENT_STRING, + /* 372: bicr */ ABSENT_STRING, + /* 373: colornm */ ABSENT_STRING, + /* 374: defbi */ ABSENT_STRING, + /* 375: endbi */ ABSENT_STRING, + /* 376: setcolor */ ABSENT_STRING, + /* 377: slines */ ABSENT_STRING, + /* 378: dispc */ ABSENT_STRING, + /* 379: smpch */ ABSENT_STRING, + /* 380: rmpch */ ABSENT_STRING, + /* 381: smsc */ ABSENT_STRING, + /* 382: rmsc */ ABSENT_STRING, + /* 383: pctrm */ ABSENT_STRING, + /* 384: scesc */ ABSENT_STRING, + /* 385: scesa */ ABSENT_STRING, + /* 386: ehhlm */ ABSENT_STRING, + /* 387: elhlm */ ABSENT_STRING, + /* 388: elohlm */ ABSENT_STRING, + /* 389: erhlm */ ABSENT_STRING, + /* 390: ethlm */ ABSENT_STRING, + /* 391: evhlm */ ABSENT_STRING, + /* 392: sgr1 */ ABSENT_STRING, + /* 393: slength */ ABSENT_STRING, + /* 394: OTi2 */ ABSENT_STRING, + /* 395: OTrs */ ABSENT_STRING, + /* 396: OTnl */ ABSENT_STRING, + /* 397: OTbc */ ABSENT_STRING, + /* 398: OTko */ ABSENT_STRING, + /* 399: OTma */ ABSENT_STRING, + /* 400: OTG2 */ ABSENT_STRING, + /* 401: OTG3 */ ABSENT_STRING, + /* 402: OTG1 */ ABSENT_STRING, + /* 403: OTG4 */ ABSENT_STRING, + /* 404: OTGR */ ABSENT_STRING, + /* 405: OTGL */ ABSENT_STRING, + /* 406: OTGU */ ABSENT_STRING, + /* 407: OTGD */ ABSENT_STRING, + /* 408: OTGH */ ABSENT_STRING, + /* 409: OTGV */ ABSENT_STRING, + /* 410: OTGC */ ABSENT_STRING, + /* 411: meml */ ABSENT_STRING, + /* 412: memu */ ABSENT_STRING, + /* 413: box1 */ ABSENT_STRING, +}; +/* screen.linux */ + +static char screen_linux_alias_data[] = "screen.linux|screen in linux console"; + +static char screen_linux_s_cbt [] = "\033[Z"; +static char screen_linux_s_bel [] = "\007"; +static char screen_linux_s_cr [] = "\015"; +static char screen_linux_s_csr [] = "\033[%i%p1%d;%p2%dr"; +static char screen_linux_s_tbc [] = "\033[3g"; +static char screen_linux_s_clear[] = "\033[H\033[J"; +static char screen_linux_s_el [] = "\033[K"; +static char screen_linux_s_ed [] = "\033[J"; +static char screen_linux_s_hpa [] = "\033[%i%p1%dG"; +static char screen_linux_s_cup [] = "\033[%i%p1%d;%p2%dH"; +static char screen_linux_s_cud1 [] = "\012"; +static char screen_linux_s_home [] = "\033[H"; +static char screen_linux_s_civis[] = "\033[?25l"; +static char screen_linux_s_cub1 [] = "\010"; +static char screen_linux_s_cnorm[] = "\033[34h\033[?25h"; +static char screen_linux_s_cuf1 [] = "\033[C"; +static char screen_linux_s_cuu1 [] = "\033M"; +static char screen_linux_s_cvvis[] = "\033[34l"; +static char screen_linux_s_dch1 [] = "\033[P"; +static char screen_linux_s_dl1 [] = "\033[M"; +static char screen_linux_s_smacs[] = "\016"; +static char screen_linux_s_blink[] = "\033[5m"; +static char screen_linux_s_bold [] = "\033[1m"; +static char screen_linux_s_smcup[] = "\033[?1049h"; +static char screen_linux_s_dim [] = "\033[2m"; +static char screen_linux_s_smir [] = "\033[4h"; +static char screen_linux_s_rev [] = "\033[7m"; +static char screen_linux_s_smso [] = "\033[3m"; +static char screen_linux_s_smul [] = "\033[4m"; +static char screen_linux_s_rmacs[] = "\017"; +static char screen_linux_s_sgr0 [] = "\033[m\017"; +static char screen_linux_s_rmcup[] = "\033[?1049l"; +static char screen_linux_s_rmir [] = "\033[4l"; +static char screen_linux_s_rmso [] = "\033[23m"; +static char screen_linux_s_rmul [] = "\033[24m"; +static char screen_linux_s_flash[] = "\033g"; +static char screen_linux_s_is2 [] = "\033)0"; +static char screen_linux_s_il1 [] = "\033[L"; +static char screen_linux_s_kbs [] = "\177"; +static char screen_linux_s_kdch1[] = "\033[3~"; +static char screen_linux_s_kcud1[] = "\033OB"; +static char screen_linux_s_kf1 [] = "\033OP"; +static char screen_linux_s_kf10 [] = "\033[21~"; +static char screen_linux_s_kf2 [] = "\033OQ"; +static char screen_linux_s_kf3 [] = "\033OR"; +static char screen_linux_s_kf4 [] = "\033OS"; +static char screen_linux_s_kf5 [] = "\033[15~"; +static char screen_linux_s_kf6 [] = "\033[17~"; +static char screen_linux_s_kf7 [] = "\033[18~"; +static char screen_linux_s_kf8 [] = "\033[19~"; +static char screen_linux_s_kf9 [] = "\033[20~"; +static char screen_linux_s_khome[] = "\033[1~"; +static char screen_linux_s_kich1[] = "\033[2~"; +static char screen_linux_s_kcub1[] = "\033OD"; +static char screen_linux_s_knp [] = "\033[6~"; +static char screen_linux_s_kpp [] = "\033[5~"; +static char screen_linux_s_kcuf1[] = "\033OC"; +static char screen_linux_s_kcuu1[] = "\033OA"; +static char screen_linux_s_rmkx [] = "\033[?1l\033>"; +static char screen_linux_s_smkx [] = "\033[?1h\033="; +static char screen_linux_s_nel [] = "\033E"; +static char screen_linux_s_dch [] = "\033[%p1%dP"; +static char screen_linux_s_dl [] = "\033[%p1%dM"; +static char screen_linux_s_cud [] = "\033[%p1%dB"; +static char screen_linux_s_ich [] = "\033[%p1%d@"; +static char screen_linux_s_indn [] = "\033[%p1%dS"; +static char screen_linux_s_il [] = "\033[%p1%dL"; +static char screen_linux_s_cub [] = "\033[%p1%dD"; +static char screen_linux_s_cuf [] = "\033[%p1%dC"; +static char screen_linux_s_cuu [] = "\033[%p1%dA"; +static char screen_linux_s_rs2 [] = "\033c\033[?1000l\033[?25h"; +static char screen_linux_s_rc [] = "\0338"; +static char screen_linux_s_vpa [] = "\033[%i%p1%dd"; +static char screen_linux_s_sc [] = "\0337"; +static char screen_linux_s_ind [] = "\012"; +static char screen_linux_s_ri [] = "\033M"; +static char screen_linux_s_sgr [] = "\033[0%?%p6%t;1%;%?%p1%t;3%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p5%t;2%;m%?%p9%t\016%e\017%;"; +static char screen_linux_s_hts [] = "\033H"; +static char screen_linux_s_ht [] = "\011"; +static char screen_linux_s_acsc [] = "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"; +static char screen_linux_s_enacs[] = "\033(B\033)0"; +static char screen_linux_s_kend [] = "\033[4~"; +static char screen_linux_s_kf11 [] = "\033[23~"; +static char screen_linux_s_kf12 [] = "\033[24~"; +static char screen_linux_s_el1 [] = "\033[1K"; +static char screen_linux_s_op [] = "\033[39;49m"; +static char screen_linux_s_kmous[] = "\033[M"; +static char screen_linux_s_setaf[] = "\033[3%p1%dm"; +static char screen_linux_s_setab[] = "\033[4%p1%dm"; + +static char screen_linux_bool_data[] = { + /* 0: bw */ TRUE, + /* 1: am */ TRUE, + /* 2: xsb */ FALSE, + /* 3: xhp */ FALSE, + /* 4: xenl */ TRUE, + /* 5: eo */ FALSE, + /* 6: gn */ FALSE, + /* 7: hc */ FALSE, + /* 8: km */ TRUE, + /* 9: hs */ FALSE, + /* 10: in */ FALSE, + /* 11: da */ FALSE, + /* 12: db */ FALSE, + /* 13: mir */ TRUE, + /* 14: msgr */ TRUE, + /* 15: os */ FALSE, + /* 16: eslok */ FALSE, + /* 17: xt */ FALSE, + /* 18: hz */ FALSE, + /* 19: ul */ FALSE, + /* 20: xon */ FALSE, + /* 21: nxon */ FALSE, + /* 22: mc5i */ FALSE, + /* 23: chts */ FALSE, + /* 24: nrrmc */ FALSE, + /* 25: npc */ FALSE, + /* 26: ndscr */ FALSE, + /* 27: ccc */ FALSE, + /* 28: bce */ FALSE, + /* 29: hls */ FALSE, + /* 30: xhpa */ FALSE, + /* 31: crxm */ FALSE, + /* 32: daisy */ FALSE, + /* 33: xvpa */ FALSE, + /* 34: sam */ FALSE, + /* 35: cpix */ FALSE, + /* 36: lpix */ FALSE, + /* 37: OTbs */ TRUE, + /* 38: OTns */ FALSE, + /* 39: OTnc */ FALSE, + /* 40: OTMT */ FALSE, + /* 41: OTNL */ FALSE, + /* 42: OTpt */ TRUE, + /* 43: OTxr */ FALSE, +}; +static NCURSES_INT2 screen_linux_number_data[] = { + /* 0: cols */ 80, + /* 1: it */ 8, + /* 2: lines */ 24, + /* 3: lm */ ABSENT_NUMERIC, + /* 4: xmc */ ABSENT_NUMERIC, + /* 5: pb */ ABSENT_NUMERIC, + /* 6: vt */ ABSENT_NUMERIC, + /* 7: wsl */ ABSENT_NUMERIC, + /* 8: nlab */ ABSENT_NUMERIC, + /* 9: lh */ ABSENT_NUMERIC, + /* 10: lw */ ABSENT_NUMERIC, + /* 11: ma */ ABSENT_NUMERIC, + /* 12: wnum */ ABSENT_NUMERIC, + /* 13: colors */ 8, + /* 14: pairs */ 64, + /* 15: ncv */ ABSENT_NUMERIC, + /* 16: bufsz */ ABSENT_NUMERIC, + /* 17: spinv */ ABSENT_NUMERIC, + /* 18: spinh */ ABSENT_NUMERIC, + /* 19: maddr */ ABSENT_NUMERIC, + /* 20: mjump */ ABSENT_NUMERIC, + /* 21: mcs */ ABSENT_NUMERIC, + /* 22: mls */ ABSENT_NUMERIC, + /* 23: npins */ ABSENT_NUMERIC, + /* 24: orc */ ABSENT_NUMERIC, + /* 25: orl */ ABSENT_NUMERIC, + /* 26: orhi */ ABSENT_NUMERIC, + /* 27: orvi */ ABSENT_NUMERIC, + /* 28: cps */ ABSENT_NUMERIC, + /* 29: widcs */ ABSENT_NUMERIC, + /* 30: btns */ ABSENT_NUMERIC, + /* 31: bitwin */ ABSENT_NUMERIC, + /* 32: bitype */ ABSENT_NUMERIC, + /* 33: OTug */ ABSENT_NUMERIC, + /* 34: OTdC */ ABSENT_NUMERIC, + /* 35: OTdN */ ABSENT_NUMERIC, + /* 36: OTdB */ ABSENT_NUMERIC, + /* 37: OTdT */ ABSENT_NUMERIC, + /* 38: OTkn */ ABSENT_NUMERIC, +}; +static char * screen_linux_string_data[] = { + /* 0: cbt */ screen_linux_s_cbt, + /* 1: bel */ screen_linux_s_bel, + /* 2: cr */ screen_linux_s_cr, + /* 3: csr */ screen_linux_s_csr, + /* 4: tbc */ screen_linux_s_tbc, + /* 5: clear */ screen_linux_s_clear, + /* 6: el */ screen_linux_s_el, + /* 7: ed */ screen_linux_s_ed, + /* 8: hpa */ screen_linux_s_hpa, + /* 9: cmdch */ ABSENT_STRING, + /* 10: cup */ screen_linux_s_cup, + /* 11: cud1 */ screen_linux_s_cud1, + /* 12: home */ screen_linux_s_home, + /* 13: civis */ screen_linux_s_civis, + /* 14: cub1 */ screen_linux_s_cub1, + /* 15: mrcup */ ABSENT_STRING, + /* 16: cnorm */ screen_linux_s_cnorm, + /* 17: cuf1 */ screen_linux_s_cuf1, + /* 18: ll */ ABSENT_STRING, + /* 19: cuu1 */ screen_linux_s_cuu1, + /* 20: cvvis */ screen_linux_s_cvvis, + /* 21: dch1 */ screen_linux_s_dch1, + /* 22: dl1 */ screen_linux_s_dl1, + /* 23: dsl */ ABSENT_STRING, + /* 24: hd */ ABSENT_STRING, + /* 25: smacs */ screen_linux_s_smacs, + /* 26: blink */ screen_linux_s_blink, + /* 27: bold */ screen_linux_s_bold, + /* 28: smcup */ screen_linux_s_smcup, + /* 29: smdc */ ABSENT_STRING, + /* 30: dim */ screen_linux_s_dim, + /* 31: smir */ screen_linux_s_smir, + /* 32: invis */ ABSENT_STRING, + /* 33: prot */ ABSENT_STRING, + /* 34: rev */ screen_linux_s_rev, + /* 35: smso */ screen_linux_s_smso, + /* 36: smul */ screen_linux_s_smul, + /* 37: ech */ ABSENT_STRING, + /* 38: rmacs */ screen_linux_s_rmacs, + /* 39: sgr0 */ screen_linux_s_sgr0, + /* 40: rmcup */ screen_linux_s_rmcup, + /* 41: rmdc */ ABSENT_STRING, + /* 42: rmir */ screen_linux_s_rmir, + /* 43: rmso */ screen_linux_s_rmso, + /* 44: rmul */ screen_linux_s_rmul, + /* 45: flash */ screen_linux_s_flash, + /* 46: ff */ ABSENT_STRING, + /* 47: fsl */ ABSENT_STRING, + /* 48: is1 */ ABSENT_STRING, + /* 49: is2 */ screen_linux_s_is2, + /* 50: is3 */ ABSENT_STRING, + /* 51: if */ ABSENT_STRING, + /* 52: ich1 */ ABSENT_STRING, + /* 53: il1 */ screen_linux_s_il1, + /* 54: ip */ ABSENT_STRING, + /* 55: kbs */ screen_linux_s_kbs, + /* 56: ktbc */ ABSENT_STRING, + /* 57: kclr */ ABSENT_STRING, + /* 58: kctab */ ABSENT_STRING, + /* 59: kdch1 */ screen_linux_s_kdch1, + /* 60: kdl1 */ ABSENT_STRING, + /* 61: kcud1 */ screen_linux_s_kcud1, + /* 62: krmir */ ABSENT_STRING, + /* 63: kel */ ABSENT_STRING, + /* 64: ked */ ABSENT_STRING, + /* 65: kf0 */ ABSENT_STRING, + /* 66: kf1 */ screen_linux_s_kf1, + /* 67: kf10 */ screen_linux_s_kf10, + /* 68: kf2 */ screen_linux_s_kf2, + /* 69: kf3 */ screen_linux_s_kf3, + /* 70: kf4 */ screen_linux_s_kf4, + /* 71: kf5 */ screen_linux_s_kf5, + /* 72: kf6 */ screen_linux_s_kf6, + /* 73: kf7 */ screen_linux_s_kf7, + /* 74: kf8 */ screen_linux_s_kf8, + /* 75: kf9 */ screen_linux_s_kf9, + /* 76: khome */ screen_linux_s_khome, + /* 77: kich1 */ screen_linux_s_kich1, + /* 78: kil1 */ ABSENT_STRING, + /* 79: kcub1 */ screen_linux_s_kcub1, + /* 80: kll */ ABSENT_STRING, + /* 81: knp */ screen_linux_s_knp, + /* 82: kpp */ screen_linux_s_kpp, + /* 83: kcuf1 */ screen_linux_s_kcuf1, + /* 84: kind */ ABSENT_STRING, + /* 85: kri */ ABSENT_STRING, + /* 86: khts */ ABSENT_STRING, + /* 87: kcuu1 */ screen_linux_s_kcuu1, + /* 88: rmkx */ screen_linux_s_rmkx, + /* 89: smkx */ screen_linux_s_smkx, + /* 90: lf0 */ ABSENT_STRING, + /* 91: lf1 */ ABSENT_STRING, + /* 92: lf10 */ ABSENT_STRING, + /* 93: lf2 */ ABSENT_STRING, + /* 94: lf3 */ ABSENT_STRING, + /* 95: lf4 */ ABSENT_STRING, + /* 96: lf5 */ ABSENT_STRING, + /* 97: lf6 */ ABSENT_STRING, + /* 98: lf7 */ ABSENT_STRING, + /* 99: lf8 */ ABSENT_STRING, + /* 100: lf9 */ ABSENT_STRING, + /* 101: rmm */ ABSENT_STRING, + /* 102: smm */ ABSENT_STRING, + /* 103: nel */ screen_linux_s_nel, + /* 104: pad */ ABSENT_STRING, + /* 105: dch */ screen_linux_s_dch, + /* 106: dl */ screen_linux_s_dl, + /* 107: cud */ screen_linux_s_cud, + /* 108: ich */ screen_linux_s_ich, + /* 109: indn */ screen_linux_s_indn, + /* 110: il */ screen_linux_s_il, + /* 111: cub */ screen_linux_s_cub, + /* 112: cuf */ screen_linux_s_cuf, + /* 113: rin */ ABSENT_STRING, + /* 114: cuu */ screen_linux_s_cuu, + /* 115: pfkey */ ABSENT_STRING, + /* 116: pfloc */ ABSENT_STRING, + /* 117: pfx */ ABSENT_STRING, + /* 118: mc0 */ ABSENT_STRING, + /* 119: mc4 */ ABSENT_STRING, + /* 120: mc5 */ ABSENT_STRING, + /* 121: rep */ ABSENT_STRING, + /* 122: rs1 */ ABSENT_STRING, + /* 123: rs2 */ screen_linux_s_rs2, + /* 124: rs3 */ ABSENT_STRING, + /* 125: rf */ ABSENT_STRING, + /* 126: rc */ screen_linux_s_rc, + /* 127: vpa */ screen_linux_s_vpa, + /* 128: sc */ screen_linux_s_sc, + /* 129: ind */ screen_linux_s_ind, + /* 130: ri */ screen_linux_s_ri, + /* 131: sgr */ screen_linux_s_sgr, + /* 132: hts */ screen_linux_s_hts, + /* 133: wind */ ABSENT_STRING, + /* 134: ht */ screen_linux_s_ht, + /* 135: tsl */ ABSENT_STRING, + /* 136: uc */ ABSENT_STRING, + /* 137: hu */ ABSENT_STRING, + /* 138: iprog */ ABSENT_STRING, + /* 139: ka1 */ ABSENT_STRING, + /* 140: ka3 */ ABSENT_STRING, + /* 141: kb2 */ ABSENT_STRING, + /* 142: kc1 */ ABSENT_STRING, + /* 143: kc3 */ ABSENT_STRING, + /* 144: mc5p */ ABSENT_STRING, + /* 145: rmp */ ABSENT_STRING, + /* 146: acsc */ screen_linux_s_acsc, + /* 147: pln */ ABSENT_STRING, + /* 148: kcbt */ CANCELLED_STRING, + /* 149: smxon */ ABSENT_STRING, + /* 150: rmxon */ ABSENT_STRING, + /* 151: smam */ ABSENT_STRING, + /* 152: rmam */ ABSENT_STRING, + /* 153: xonc */ ABSENT_STRING, + /* 154: xoffc */ ABSENT_STRING, + /* 155: enacs */ screen_linux_s_enacs, + /* 156: smln */ ABSENT_STRING, + /* 157: rmln */ ABSENT_STRING, + /* 158: kbeg */ ABSENT_STRING, + /* 159: kcan */ ABSENT_STRING, + /* 160: kclo */ ABSENT_STRING, + /* 161: kcmd */ ABSENT_STRING, + /* 162: kcpy */ ABSENT_STRING, + /* 163: kcrt */ ABSENT_STRING, + /* 164: kend */ screen_linux_s_kend, + /* 165: kent */ ABSENT_STRING, + /* 166: kext */ ABSENT_STRING, + /* 167: kfnd */ ABSENT_STRING, + /* 168: khlp */ ABSENT_STRING, + /* 169: kmrk */ ABSENT_STRING, + /* 170: kmsg */ ABSENT_STRING, + /* 171: kmov */ ABSENT_STRING, + /* 172: knxt */ ABSENT_STRING, + /* 173: kopn */ ABSENT_STRING, + /* 174: kopt */ ABSENT_STRING, + /* 175: kprv */ ABSENT_STRING, + /* 176: kprt */ ABSENT_STRING, + /* 177: krdo */ ABSENT_STRING, + /* 178: kref */ ABSENT_STRING, + /* 179: krfr */ ABSENT_STRING, + /* 180: krpl */ ABSENT_STRING, + /* 181: krst */ ABSENT_STRING, + /* 182: kres */ ABSENT_STRING, + /* 183: ksav */ ABSENT_STRING, + /* 184: kspd */ ABSENT_STRING, + /* 185: kund */ ABSENT_STRING, + /* 186: kBEG */ ABSENT_STRING, + /* 187: kCAN */ ABSENT_STRING, + /* 188: kCMD */ ABSENT_STRING, + /* 189: kCPY */ ABSENT_STRING, + /* 190: kCRT */ ABSENT_STRING, + /* 191: kDC */ ABSENT_STRING, + /* 192: kDL */ ABSENT_STRING, + /* 193: kslt */ ABSENT_STRING, + /* 194: kEND */ ABSENT_STRING, + /* 195: kEOL */ ABSENT_STRING, + /* 196: kEXT */ ABSENT_STRING, + /* 197: kFND */ ABSENT_STRING, + /* 198: kHLP */ ABSENT_STRING, + /* 199: kHOM */ ABSENT_STRING, + /* 200: kIC */ ABSENT_STRING, + /* 201: kLFT */ ABSENT_STRING, + /* 202: kMSG */ ABSENT_STRING, + /* 203: kMOV */ ABSENT_STRING, + /* 204: kNXT */ ABSENT_STRING, + /* 205: kOPT */ ABSENT_STRING, + /* 206: kPRV */ ABSENT_STRING, + /* 207: kPRT */ ABSENT_STRING, + /* 208: kRDO */ ABSENT_STRING, + /* 209: kRPL */ ABSENT_STRING, + /* 210: kRIT */ ABSENT_STRING, + /* 211: kRES */ ABSENT_STRING, + /* 212: kSAV */ ABSENT_STRING, + /* 213: kSPD */ ABSENT_STRING, + /* 214: kUND */ ABSENT_STRING, + /* 215: rfi */ ABSENT_STRING, + /* 216: kf11 */ screen_linux_s_kf11, + /* 217: kf12 */ screen_linux_s_kf12, + /* 218: kf13 */ ABSENT_STRING, + /* 219: kf14 */ ABSENT_STRING, + /* 220: kf15 */ ABSENT_STRING, + /* 221: kf16 */ ABSENT_STRING, + /* 222: kf17 */ ABSENT_STRING, + /* 223: kf18 */ ABSENT_STRING, + /* 224: kf19 */ ABSENT_STRING, + /* 225: kf20 */ ABSENT_STRING, + /* 226: kf21 */ ABSENT_STRING, + /* 227: kf22 */ ABSENT_STRING, + /* 228: kf23 */ ABSENT_STRING, + /* 229: kf24 */ ABSENT_STRING, + /* 230: kf25 */ ABSENT_STRING, + /* 231: kf26 */ ABSENT_STRING, + /* 232: kf27 */ ABSENT_STRING, + /* 233: kf28 */ ABSENT_STRING, + /* 234: kf29 */ ABSENT_STRING, + /* 235: kf30 */ ABSENT_STRING, + /* 236: kf31 */ ABSENT_STRING, + /* 237: kf32 */ ABSENT_STRING, + /* 238: kf33 */ ABSENT_STRING, + /* 239: kf34 */ ABSENT_STRING, + /* 240: kf35 */ ABSENT_STRING, + /* 241: kf36 */ ABSENT_STRING, + /* 242: kf37 */ ABSENT_STRING, + /* 243: kf38 */ ABSENT_STRING, + /* 244: kf39 */ ABSENT_STRING, + /* 245: kf40 */ ABSENT_STRING, + /* 246: kf41 */ ABSENT_STRING, + /* 247: kf42 */ ABSENT_STRING, + /* 248: kf43 */ ABSENT_STRING, + /* 249: kf44 */ ABSENT_STRING, + /* 250: kf45 */ ABSENT_STRING, + /* 251: kf46 */ ABSENT_STRING, + /* 252: kf47 */ ABSENT_STRING, + /* 253: kf48 */ ABSENT_STRING, + /* 254: kf49 */ ABSENT_STRING, + /* 255: kf50 */ ABSENT_STRING, + /* 256: kf51 */ ABSENT_STRING, + /* 257: kf52 */ ABSENT_STRING, + /* 258: kf53 */ ABSENT_STRING, + /* 259: kf54 */ ABSENT_STRING, + /* 260: kf55 */ ABSENT_STRING, + /* 261: kf56 */ ABSENT_STRING, + /* 262: kf57 */ ABSENT_STRING, + /* 263: kf58 */ ABSENT_STRING, + /* 264: kf59 */ ABSENT_STRING, + /* 265: kf60 */ ABSENT_STRING, + /* 266: kf61 */ ABSENT_STRING, + /* 267: kf62 */ ABSENT_STRING, + /* 268: kf63 */ ABSENT_STRING, + /* 269: el1 */ screen_linux_s_el1, + /* 270: mgc */ ABSENT_STRING, + /* 271: smgl */ ABSENT_STRING, + /* 272: smgr */ ABSENT_STRING, + /* 273: fln */ ABSENT_STRING, + /* 274: sclk */ ABSENT_STRING, + /* 275: dclk */ ABSENT_STRING, + /* 276: rmclk */ ABSENT_STRING, + /* 277: cwin */ ABSENT_STRING, + /* 278: wingo */ ABSENT_STRING, + /* 279: hup */ ABSENT_STRING, + /* 280: dial */ ABSENT_STRING, + /* 281: qdial */ ABSENT_STRING, + /* 282: tone */ ABSENT_STRING, + /* 283: pulse */ ABSENT_STRING, + /* 284: hook */ ABSENT_STRING, + /* 285: pause */ ABSENT_STRING, + /* 286: wait */ ABSENT_STRING, + /* 287: u0 */ ABSENT_STRING, + /* 288: u1 */ ABSENT_STRING, + /* 289: u2 */ ABSENT_STRING, + /* 290: u3 */ ABSENT_STRING, + /* 291: u4 */ ABSENT_STRING, + /* 292: u5 */ ABSENT_STRING, + /* 293: u6 */ ABSENT_STRING, + /* 294: u7 */ ABSENT_STRING, + /* 295: u8 */ ABSENT_STRING, + /* 296: u9 */ ABSENT_STRING, + /* 297: op */ screen_linux_s_op, + /* 298: oc */ ABSENT_STRING, + /* 299: initc */ ABSENT_STRING, + /* 300: initp */ ABSENT_STRING, + /* 301: scp */ ABSENT_STRING, + /* 302: setf */ ABSENT_STRING, + /* 303: setb */ ABSENT_STRING, + /* 304: cpi */ ABSENT_STRING, + /* 305: lpi */ ABSENT_STRING, + /* 306: chr */ ABSENT_STRING, + /* 307: cvr */ ABSENT_STRING, + /* 308: defc */ ABSENT_STRING, + /* 309: swidm */ ABSENT_STRING, + /* 310: sdrfq */ ABSENT_STRING, + /* 311: sitm */ ABSENT_STRING, + /* 312: slm */ ABSENT_STRING, + /* 313: smicm */ ABSENT_STRING, + /* 314: snlq */ ABSENT_STRING, + /* 315: snrmq */ ABSENT_STRING, + /* 316: sshm */ ABSENT_STRING, + /* 317: ssubm */ ABSENT_STRING, + /* 318: ssupm */ ABSENT_STRING, + /* 319: sum */ ABSENT_STRING, + /* 320: rwidm */ ABSENT_STRING, + /* 321: ritm */ ABSENT_STRING, + /* 322: rlm */ ABSENT_STRING, + /* 323: rmicm */ ABSENT_STRING, + /* 324: rshm */ ABSENT_STRING, + /* 325: rsubm */ ABSENT_STRING, + /* 326: rsupm */ ABSENT_STRING, + /* 327: rum */ ABSENT_STRING, + /* 328: mhpa */ ABSENT_STRING, + /* 329: mcud1 */ ABSENT_STRING, + /* 330: mcub1 */ ABSENT_STRING, + /* 331: mcuf1 */ ABSENT_STRING, + /* 332: mvpa */ ABSENT_STRING, + /* 333: mcuu1 */ ABSENT_STRING, + /* 334: porder */ ABSENT_STRING, + /* 335: mcud */ ABSENT_STRING, + /* 336: mcub */ ABSENT_STRING, + /* 337: mcuf */ ABSENT_STRING, + /* 338: mcuu */ ABSENT_STRING, + /* 339: scs */ ABSENT_STRING, + /* 340: smgb */ ABSENT_STRING, + /* 341: smgbp */ ABSENT_STRING, + /* 342: smglp */ ABSENT_STRING, + /* 343: smgrp */ ABSENT_STRING, + /* 344: smgt */ ABSENT_STRING, + /* 345: smgtp */ ABSENT_STRING, + /* 346: sbim */ ABSENT_STRING, + /* 347: scsd */ ABSENT_STRING, + /* 348: rbim */ ABSENT_STRING, + /* 349: rcsd */ ABSENT_STRING, + /* 350: subcs */ ABSENT_STRING, + /* 351: supcs */ ABSENT_STRING, + /* 352: docr */ ABSENT_STRING, + /* 353: zerom */ ABSENT_STRING, + /* 354: csnm */ ABSENT_STRING, + /* 355: kmous */ screen_linux_s_kmous, + /* 356: minfo */ ABSENT_STRING, + /* 357: reqmp */ ABSENT_STRING, + /* 358: getm */ ABSENT_STRING, + /* 359: setaf */ screen_linux_s_setaf, + /* 360: setab */ screen_linux_s_setab, + /* 361: pfxl */ ABSENT_STRING, + /* 362: devt */ ABSENT_STRING, + /* 363: csin */ ABSENT_STRING, + /* 364: s0ds */ ABSENT_STRING, + /* 365: s1ds */ ABSENT_STRING, + /* 366: s2ds */ ABSENT_STRING, + /* 367: s3ds */ ABSENT_STRING, + /* 368: smglr */ ABSENT_STRING, + /* 369: smgtb */ ABSENT_STRING, + /* 370: birep */ ABSENT_STRING, + /* 371: binel */ ABSENT_STRING, + /* 372: bicr */ ABSENT_STRING, + /* 373: colornm */ ABSENT_STRING, + /* 374: defbi */ ABSENT_STRING, + /* 375: endbi */ ABSENT_STRING, + /* 376: setcolor */ ABSENT_STRING, + /* 377: slines */ ABSENT_STRING, + /* 378: dispc */ ABSENT_STRING, + /* 379: smpch */ ABSENT_STRING, + /* 380: rmpch */ ABSENT_STRING, + /* 381: smsc */ ABSENT_STRING, + /* 382: rmsc */ ABSENT_STRING, + /* 383: pctrm */ ABSENT_STRING, + /* 384: scesc */ ABSENT_STRING, + /* 385: scesa */ ABSENT_STRING, + /* 386: ehhlm */ ABSENT_STRING, + /* 387: elhlm */ ABSENT_STRING, + /* 388: elohlm */ ABSENT_STRING, + /* 389: erhlm */ ABSENT_STRING, + /* 390: ethlm */ ABSENT_STRING, + /* 391: evhlm */ ABSENT_STRING, + /* 392: sgr1 */ ABSENT_STRING, + /* 393: slength */ ABSENT_STRING, + /* 394: OTi2 */ ABSENT_STRING, + /* 395: OTrs */ ABSENT_STRING, + /* 396: OTnl */ ABSENT_STRING, + /* 397: OTbc */ ABSENT_STRING, + /* 398: OTko */ ABSENT_STRING, + /* 399: OTma */ ABSENT_STRING, + /* 400: OTG2 */ ABSENT_STRING, + /* 401: OTG3 */ ABSENT_STRING, + /* 402: OTG1 */ ABSENT_STRING, + /* 403: OTG4 */ ABSENT_STRING, + /* 404: OTGR */ ABSENT_STRING, + /* 405: OTGL */ ABSENT_STRING, + /* 406: OTGU */ ABSENT_STRING, + /* 407: OTGD */ ABSENT_STRING, + /* 408: OTGH */ ABSENT_STRING, + /* 409: OTGV */ ABSENT_STRING, + /* 410: OTGC */ ABSENT_STRING, + /* 411: meml */ ABSENT_STRING, + /* 412: memu */ ABSENT_STRING, + /* 413: box1 */ ABSENT_STRING, +}; +/* screen.rxvt */ + +static char screen_rxvt_alias_data[] = "screen.rxvt|screen in rxvt"; + +static char screen_rxvt_s_cbt [] = "\033[Z"; +static char screen_rxvt_s_bel [] = "\007"; +static char screen_rxvt_s_cr [] = "\015"; +static char screen_rxvt_s_csr [] = "\033[%i%p1%d;%p2%dr"; +static char screen_rxvt_s_tbc [] = "\033[3g"; +static char screen_rxvt_s_clear [] = "\033[H\033[J"; +static char screen_rxvt_s_el [] = "\033[K"; +static char screen_rxvt_s_ed [] = "\033[J"; +static char screen_rxvt_s_hpa [] = "\033[%i%p1%dG"; +static char screen_rxvt_s_cup [] = "\033[%i%p1%d;%p2%dH"; +static char screen_rxvt_s_cud1 [] = "\012"; +static char screen_rxvt_s_home [] = "\033[H"; +static char screen_rxvt_s_civis [] = "\033[?25l"; +static char screen_rxvt_s_cub1 [] = "\010"; +static char screen_rxvt_s_cnorm [] = "\033[34h\033[?25h"; +static char screen_rxvt_s_cuf1 [] = "\033[C"; +static char screen_rxvt_s_cuu1 [] = "\033M"; +static char screen_rxvt_s_dch1 [] = "\033[P"; +static char screen_rxvt_s_dl1 [] = "\033[M"; +static char screen_rxvt_s_smacs [] = "\016"; +static char screen_rxvt_s_blink [] = "\033[5m"; +static char screen_rxvt_s_bold [] = "\033[1m"; +static char screen_rxvt_s_smcup [] = "\033[?1049h"; +static char screen_rxvt_s_dim [] = "\033[2m"; +static char screen_rxvt_s_smir [] = "\033[4h"; +static char screen_rxvt_s_rev [] = "\033[7m"; +static char screen_rxvt_s_smso [] = "\033[3m"; +static char screen_rxvt_s_smul [] = "\033[4m"; +static char screen_rxvt_s_rmacs [] = "\017"; +static char screen_rxvt_s_sgr0 [] = "\033[m\017"; +static char screen_rxvt_s_rmcup [] = "\033[?1049l"; +static char screen_rxvt_s_rmir [] = "\033[4l"; +static char screen_rxvt_s_rmso [] = "\033[23m"; +static char screen_rxvt_s_rmul [] = "\033[24m"; +static char screen_rxvt_s_is2 [] = "\033)0"; +static char screen_rxvt_s_il1 [] = "\033[L"; +static char screen_rxvt_s_kbs [] = "\010"; +static char screen_rxvt_s_kdch1 [] = "\033[3~"; +static char screen_rxvt_s_kcud1 [] = "\033OB"; +static char screen_rxvt_s_kel [] = "\033[8^"; +static char screen_rxvt_s_kf1 [] = "\033OP"; +static char screen_rxvt_s_kf10 [] = "\033[21~"; +static char screen_rxvt_s_kf2 [] = "\033OQ"; +static char screen_rxvt_s_kf3 [] = "\033OR"; +static char screen_rxvt_s_kf4 [] = "\033OS"; +static char screen_rxvt_s_kf5 [] = "\033[15~"; +static char screen_rxvt_s_kf6 [] = "\033[17~"; +static char screen_rxvt_s_kf7 [] = "\033[18~"; +static char screen_rxvt_s_kf8 [] = "\033[19~"; +static char screen_rxvt_s_kf9 [] = "\033[20~"; +static char screen_rxvt_s_khome [] = "\033[1~"; +static char screen_rxvt_s_kich1 [] = "\033[2~"; +static char screen_rxvt_s_kcub1 [] = "\033OD"; +static char screen_rxvt_s_knp [] = "\033[6~"; +static char screen_rxvt_s_kpp [] = "\033[5~"; +static char screen_rxvt_s_kcuf1 [] = "\033OC"; +static char screen_rxvt_s_kind [] = "\033[a"; +static char screen_rxvt_s_kri [] = "\033[b"; +static char screen_rxvt_s_kcuu1 [] = "\033OA"; +static char screen_rxvt_s_rmkx [] = "\033[?1l\033>"; +static char screen_rxvt_s_smkx [] = "\033[?1h\033="; +static char screen_rxvt_s_nel [] = "\033E"; +static char screen_rxvt_s_dch [] = "\033[%p1%dP"; +static char screen_rxvt_s_dl [] = "\033[%p1%dM"; +static char screen_rxvt_s_cud [] = "\033[%p1%dB"; +static char screen_rxvt_s_ich [] = "\033[%p1%d@"; +static char screen_rxvt_s_indn [] = "\033[%p1%dS"; +static char screen_rxvt_s_il [] = "\033[%p1%dL"; +static char screen_rxvt_s_cub [] = "\033[%p1%dD"; +static char screen_rxvt_s_cuf [] = "\033[%p1%dC"; +static char screen_rxvt_s_cuu [] = "\033[%p1%dA"; +static char screen_rxvt_s_rs2 [] = "\033c\033[?1000l\033[?25h"; +static char screen_rxvt_s_rc [] = "\0338"; +static char screen_rxvt_s_vpa [] = "\033[%i%p1%dd"; +static char screen_rxvt_s_sc [] = "\0337"; +static char screen_rxvt_s_ind [] = "\012"; +static char screen_rxvt_s_ri [] = "\033M"; +static char screen_rxvt_s_sgr [] = "\033[0%?%p6%t;1%;%?%p1%t;3%;%?%p2%t;4%;%?%p3%t;7%;%?%p4%t;5%;%?%p5%t;2%;m%?%p9%t\016%e\017%;"; +static char screen_rxvt_s_hts [] = "\033H"; +static char screen_rxvt_s_ht [] = "\011"; +static char screen_rxvt_s_ka1 [] = "\033Ow"; +static char screen_rxvt_s_ka3 [] = "\033Oy"; +static char screen_rxvt_s_kb2 [] = "\033Ou"; +static char screen_rxvt_s_kc1 [] = "\033Oq"; +static char screen_rxvt_s_kc3 [] = "\033Os"; +static char screen_rxvt_s_acsc [] = "++,,--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"; +static char screen_rxvt_s_kcbt [] = "\033[Z"; +static char screen_rxvt_s_enacs [] = "\033(B\033)0"; +static char screen_rxvt_s_kend [] = "\033[4~"; +static char screen_rxvt_s_kent [] = "\033OM"; +static char screen_rxvt_s_kDC [] = "\033[3$"; +static char screen_rxvt_s_kEND [] = "\033[8$"; +static char screen_rxvt_s_kHOM [] = "\033[7$"; +static char screen_rxvt_s_kIC [] = "\033[2$"; +static char screen_rxvt_s_kLFT [] = "\033[d"; +static char screen_rxvt_s_kNXT [] = "\033[6$"; +static char screen_rxvt_s_kPRV [] = "\033[5$"; +static char screen_rxvt_s_kRIT [] = "\033[c"; +static char screen_rxvt_s_kf11 [] = "\033[23~"; +static char screen_rxvt_s_kf12 [] = "\033[24~"; +static char screen_rxvt_s_kf13 [] = "\033[25~"; +static char screen_rxvt_s_kf14 [] = "\033[26~"; +static char screen_rxvt_s_kf15 [] = "\033[28~"; +static char screen_rxvt_s_kf16 [] = "\033[29~"; +static char screen_rxvt_s_kf17 [] = "\033[31~"; +static char screen_rxvt_s_kf18 [] = "\033[32~"; +static char screen_rxvt_s_kf19 [] = "\033[33~"; +static char screen_rxvt_s_kf20 [] = "\033[34~"; +static char screen_rxvt_s_kf21 [] = "\033[23$"; +static char screen_rxvt_s_kf22 [] = "\033[24$"; +static char screen_rxvt_s_kf23 [] = "\033[11^"; +static char screen_rxvt_s_kf24 [] = "\033[12^"; +static char screen_rxvt_s_kf25 [] = "\033[13^"; +static char screen_rxvt_s_kf26 [] = "\033[14^"; +static char screen_rxvt_s_kf27 [] = "\033[15^"; +static char screen_rxvt_s_kf28 [] = "\033[17^"; +static char screen_rxvt_s_kf29 [] = "\033[18^"; +static char screen_rxvt_s_kf30 [] = "\033[19^"; +static char screen_rxvt_s_kf31 [] = "\033[20^"; +static char screen_rxvt_s_kf32 [] = "\033[21^"; +static char screen_rxvt_s_kf33 [] = "\033[23^"; +static char screen_rxvt_s_kf34 [] = "\033[24^"; +static char screen_rxvt_s_kf35 [] = "\033[25^"; +static char screen_rxvt_s_kf36 [] = "\033[26^"; +static char screen_rxvt_s_kf37 [] = "\033[28^"; +static char screen_rxvt_s_kf38 [] = "\033[29^"; +static char screen_rxvt_s_kf39 [] = "\033[31^"; +static char screen_rxvt_s_kf40 [] = "\033[32^"; +static char screen_rxvt_s_kf41 [] = "\033[33^"; +static char screen_rxvt_s_kf42 [] = "\033[34^"; +static char screen_rxvt_s_kf43 [] = "\033[23@"; +static char screen_rxvt_s_kf44 [] = "\033[24@"; +static char screen_rxvt_s_el1 [] = "\033[1K"; +static char screen_rxvt_s_u6 [] = "\033[%i%d;%dR"; +static char screen_rxvt_s_u7 [] = "\033[6n"; +static char screen_rxvt_s_u8 [] = "\033[?1;2c"; +static char screen_rxvt_s_u9 [] = "\033[c"; +static char screen_rxvt_s_op [] = "\033[39;49m"; +static char screen_rxvt_s_kmous [] = "\033[M"; +static char screen_rxvt_s_setaf [] = "\033[3%p1%dm"; +static char screen_rxvt_s_setab [] = "\033[4%p1%dm"; + +static char screen_rxvt_bool_data[] = { + /* 0: bw */ TRUE, + /* 1: am */ TRUE, + /* 2: xsb */ FALSE, + /* 3: xhp */ FALSE, + /* 4: xenl */ TRUE, + /* 5: eo */ FALSE, + /* 6: gn */ FALSE, + /* 7: hc */ FALSE, + /* 8: km */ TRUE, + /* 9: hs */ FALSE, + /* 10: in */ FALSE, + /* 11: da */ FALSE, + /* 12: db */ FALSE, + /* 13: mir */ TRUE, + /* 14: msgr */ TRUE, + /* 15: os */ FALSE, + /* 16: eslok */ FALSE, + /* 17: xt */ FALSE, + /* 18: hz */ FALSE, + /* 19: ul */ FALSE, + /* 20: xon */ FALSE, + /* 21: nxon */ FALSE, + /* 22: mc5i */ FALSE, + /* 23: chts */ FALSE, + /* 24: nrrmc */ FALSE, + /* 25: npc */ FALSE, + /* 26: ndscr */ FALSE, + /* 27: ccc */ FALSE, + /* 28: bce */ FALSE, + /* 29: hls */ FALSE, + /* 30: xhpa */ FALSE, + /* 31: crxm */ FALSE, + /* 32: daisy */ FALSE, + /* 33: xvpa */ FALSE, + /* 34: sam */ FALSE, + /* 35: cpix */ FALSE, + /* 36: lpix */ FALSE, + /* 37: OTbs */ TRUE, + /* 38: OTns */ FALSE, + /* 39: OTnc */ FALSE, + /* 40: OTMT */ FALSE, + /* 41: OTNL */ FALSE, + /* 42: OTpt */ TRUE, + /* 43: OTxr */ FALSE, +}; +static NCURSES_INT2 screen_rxvt_number_data[] = { + /* 0: cols */ 80, + /* 1: it */ 8, + /* 2: lines */ 24, + /* 3: lm */ ABSENT_NUMERIC, + /* 4: xmc */ ABSENT_NUMERIC, + /* 5: pb */ ABSENT_NUMERIC, + /* 6: vt */ ABSENT_NUMERIC, + /* 7: wsl */ ABSENT_NUMERIC, + /* 8: nlab */ ABSENT_NUMERIC, + /* 9: lh */ ABSENT_NUMERIC, + /* 10: lw */ ABSENT_NUMERIC, + /* 11: ma */ ABSENT_NUMERIC, + /* 12: wnum */ ABSENT_NUMERIC, + /* 13: colors */ 8, + /* 14: pairs */ 64, + /* 15: ncv */ ABSENT_NUMERIC, + /* 16: bufsz */ ABSENT_NUMERIC, + /* 17: spinv */ ABSENT_NUMERIC, + /* 18: spinh */ ABSENT_NUMERIC, + /* 19: maddr */ ABSENT_NUMERIC, + /* 20: mjump */ ABSENT_NUMERIC, + /* 21: mcs */ ABSENT_NUMERIC, + /* 22: mls */ ABSENT_NUMERIC, + /* 23: npins */ ABSENT_NUMERIC, + /* 24: orc */ ABSENT_NUMERIC, + /* 25: orl */ ABSENT_NUMERIC, + /* 26: orhi */ ABSENT_NUMERIC, + /* 27: orvi */ ABSENT_NUMERIC, + /* 28: cps */ ABSENT_NUMERIC, + /* 29: widcs */ ABSENT_NUMERIC, + /* 30: btns */ ABSENT_NUMERIC, + /* 31: bitwin */ ABSENT_NUMERIC, + /* 32: bitype */ ABSENT_NUMERIC, + /* 33: OTug */ ABSENT_NUMERIC, + /* 34: OTdC */ ABSENT_NUMERIC, + /* 35: OTdN */ ABSENT_NUMERIC, + /* 36: OTdB */ ABSENT_NUMERIC, + /* 37: OTdT */ ABSENT_NUMERIC, + /* 38: OTkn */ ABSENT_NUMERIC, +}; +static char * screen_rxvt_string_data[] = { + /* 0: cbt */ screen_rxvt_s_cbt, + /* 1: bel */ screen_rxvt_s_bel, + /* 2: cr */ screen_rxvt_s_cr, + /* 3: csr */ screen_rxvt_s_csr, + /* 4: tbc */ screen_rxvt_s_tbc, + /* 5: clear */ screen_rxvt_s_clear, + /* 6: el */ screen_rxvt_s_el, + /* 7: ed */ screen_rxvt_s_ed, + /* 8: hpa */ screen_rxvt_s_hpa, + /* 9: cmdch */ ABSENT_STRING, + /* 10: cup */ screen_rxvt_s_cup, + /* 11: cud1 */ screen_rxvt_s_cud1, + /* 12: home */ screen_rxvt_s_home, + /* 13: civis */ screen_rxvt_s_civis, + /* 14: cub1 */ screen_rxvt_s_cub1, + /* 15: mrcup */ ABSENT_STRING, + /* 16: cnorm */ screen_rxvt_s_cnorm, + /* 17: cuf1 */ screen_rxvt_s_cuf1, + /* 18: ll */ ABSENT_STRING, + /* 19: cuu1 */ screen_rxvt_s_cuu1, + /* 20: cvvis */ CANCELLED_STRING, + /* 21: dch1 */ screen_rxvt_s_dch1, + /* 22: dl1 */ screen_rxvt_s_dl1, + /* 23: dsl */ ABSENT_STRING, + /* 24: hd */ ABSENT_STRING, + /* 25: smacs */ screen_rxvt_s_smacs, + /* 26: blink */ screen_rxvt_s_blink, + /* 27: bold */ screen_rxvt_s_bold, + /* 28: smcup */ screen_rxvt_s_smcup, + /* 29: smdc */ ABSENT_STRING, + /* 30: dim */ screen_rxvt_s_dim, + /* 31: smir */ screen_rxvt_s_smir, + /* 32: invis */ ABSENT_STRING, + /* 33: prot */ ABSENT_STRING, + /* 34: rev */ screen_rxvt_s_rev, + /* 35: smso */ screen_rxvt_s_smso, + /* 36: smul */ screen_rxvt_s_smul, + /* 37: ech */ ABSENT_STRING, + /* 38: rmacs */ screen_rxvt_s_rmacs, + /* 39: sgr0 */ screen_rxvt_s_sgr0, + /* 40: rmcup */ screen_rxvt_s_rmcup, + /* 41: rmdc */ ABSENT_STRING, + /* 42: rmir */ screen_rxvt_s_rmir, + /* 43: rmso */ screen_rxvt_s_rmso, + /* 44: rmul */ screen_rxvt_s_rmul, + /* 45: flash */ CANCELLED_STRING, + /* 46: ff */ ABSENT_STRING, + /* 47: fsl */ ABSENT_STRING, + /* 48: is1 */ ABSENT_STRING, + /* 49: is2 */ screen_rxvt_s_is2, + /* 50: is3 */ ABSENT_STRING, + /* 51: if */ ABSENT_STRING, + /* 52: ich1 */ ABSENT_STRING, + /* 53: il1 */ screen_rxvt_s_il1, + /* 54: ip */ ABSENT_STRING, + /* 55: kbs */ screen_rxvt_s_kbs, + /* 56: ktbc */ ABSENT_STRING, + /* 57: kclr */ ABSENT_STRING, + /* 58: kctab */ ABSENT_STRING, + /* 59: kdch1 */ screen_rxvt_s_kdch1, + /* 60: kdl1 */ ABSENT_STRING, + /* 61: kcud1 */ screen_rxvt_s_kcud1, + /* 62: krmir */ ABSENT_STRING, + /* 63: kel */ screen_rxvt_s_kel, + /* 64: ked */ ABSENT_STRING, + /* 65: kf0 */ ABSENT_STRING, + /* 66: kf1 */ screen_rxvt_s_kf1, + /* 67: kf10 */ screen_rxvt_s_kf10, + /* 68: kf2 */ screen_rxvt_s_kf2, + /* 69: kf3 */ screen_rxvt_s_kf3, + /* 70: kf4 */ screen_rxvt_s_kf4, + /* 71: kf5 */ screen_rxvt_s_kf5, + /* 72: kf6 */ screen_rxvt_s_kf6, + /* 73: kf7 */ screen_rxvt_s_kf7, + /* 74: kf8 */ screen_rxvt_s_kf8, + /* 75: kf9 */ screen_rxvt_s_kf9, + /* 76: khome */ screen_rxvt_s_khome, + /* 77: kich1 */ screen_rxvt_s_kich1, + /* 78: kil1 */ ABSENT_STRING, + /* 79: kcub1 */ screen_rxvt_s_kcub1, + /* 80: kll */ ABSENT_STRING, + /* 81: knp */ screen_rxvt_s_knp, + /* 82: kpp */ screen_rxvt_s_kpp, + /* 83: kcuf1 */ screen_rxvt_s_kcuf1, + /* 84: kind */ screen_rxvt_s_kind, + /* 85: kri */ screen_rxvt_s_kri, + /* 86: khts */ ABSENT_STRING, + /* 87: kcuu1 */ screen_rxvt_s_kcuu1, + /* 88: rmkx */ screen_rxvt_s_rmkx, + /* 89: smkx */ screen_rxvt_s_smkx, + /* 90: lf0 */ ABSENT_STRING, + /* 91: lf1 */ ABSENT_STRING, + /* 92: lf10 */ ABSENT_STRING, + /* 93: lf2 */ ABSENT_STRING, + /* 94: lf3 */ ABSENT_STRING, + /* 95: lf4 */ ABSENT_STRING, + /* 96: lf5 */ ABSENT_STRING, + /* 97: lf6 */ ABSENT_STRING, + /* 98: lf7 */ ABSENT_STRING, + /* 99: lf8 */ ABSENT_STRING, + /* 100: lf9 */ ABSENT_STRING, + /* 101: rmm */ ABSENT_STRING, + /* 102: smm */ ABSENT_STRING, + /* 103: nel */ screen_rxvt_s_nel, + /* 104: pad */ ABSENT_STRING, + /* 105: dch */ screen_rxvt_s_dch, + /* 106: dl */ screen_rxvt_s_dl, + /* 107: cud */ screen_rxvt_s_cud, + /* 108: ich */ screen_rxvt_s_ich, + /* 109: indn */ screen_rxvt_s_indn, + /* 110: il */ screen_rxvt_s_il, + /* 111: cub */ screen_rxvt_s_cub, + /* 112: cuf */ screen_rxvt_s_cuf, + /* 113: rin */ ABSENT_STRING, + /* 114: cuu */ screen_rxvt_s_cuu, + /* 115: pfkey */ ABSENT_STRING, + /* 116: pfloc */ ABSENT_STRING, + /* 117: pfx */ ABSENT_STRING, + /* 118: mc0 */ ABSENT_STRING, + /* 119: mc4 */ ABSENT_STRING, + /* 120: mc5 */ ABSENT_STRING, + /* 121: rep */ ABSENT_STRING, + /* 122: rs1 */ ABSENT_STRING, + /* 123: rs2 */ screen_rxvt_s_rs2, + /* 124: rs3 */ ABSENT_STRING, + /* 125: rf */ ABSENT_STRING, + /* 126: rc */ screen_rxvt_s_rc, + /* 127: vpa */ screen_rxvt_s_vpa, + /* 128: sc */ screen_rxvt_s_sc, + /* 129: ind */ screen_rxvt_s_ind, + /* 130: ri */ screen_rxvt_s_ri, + /* 131: sgr */ screen_rxvt_s_sgr, + /* 132: hts */ screen_rxvt_s_hts, + /* 133: wind */ ABSENT_STRING, + /* 134: ht */ screen_rxvt_s_ht, + /* 135: tsl */ ABSENT_STRING, + /* 136: uc */ ABSENT_STRING, + /* 137: hu */ ABSENT_STRING, + /* 138: iprog */ ABSENT_STRING, + /* 139: ka1 */ screen_rxvt_s_ka1, + /* 140: ka3 */ screen_rxvt_s_ka3, + /* 141: kb2 */ screen_rxvt_s_kb2, + /* 142: kc1 */ screen_rxvt_s_kc1, + /* 143: kc3 */ screen_rxvt_s_kc3, + /* 144: mc5p */ ABSENT_STRING, + /* 145: rmp */ ABSENT_STRING, + /* 146: acsc */ screen_rxvt_s_acsc, + /* 147: pln */ ABSENT_STRING, + /* 148: kcbt */ screen_rxvt_s_kcbt, + /* 149: smxon */ ABSENT_STRING, + /* 150: rmxon */ ABSENT_STRING, + /* 151: smam */ ABSENT_STRING, + /* 152: rmam */ ABSENT_STRING, + /* 153: xonc */ ABSENT_STRING, + /* 154: xoffc */ ABSENT_STRING, + /* 155: enacs */ screen_rxvt_s_enacs, + /* 156: smln */ ABSENT_STRING, + /* 157: rmln */ ABSENT_STRING, + /* 158: kbeg */ ABSENT_STRING, + /* 159: kcan */ ABSENT_STRING, + /* 160: kclo */ ABSENT_STRING, + /* 161: kcmd */ ABSENT_STRING, + /* 162: kcpy */ ABSENT_STRING, + /* 163: kcrt */ ABSENT_STRING, + /* 164: kend */ screen_rxvt_s_kend, + /* 165: kent */ screen_rxvt_s_kent, + /* 166: kext */ ABSENT_STRING, + /* 167: kfnd */ ABSENT_STRING, + /* 168: khlp */ ABSENT_STRING, + /* 169: kmrk */ ABSENT_STRING, + /* 170: kmsg */ ABSENT_STRING, + /* 171: kmov */ ABSENT_STRING, + /* 172: knxt */ ABSENT_STRING, + /* 173: kopn */ ABSENT_STRING, + /* 174: kopt */ ABSENT_STRING, + /* 175: kprv */ ABSENT_STRING, + /* 176: kprt */ ABSENT_STRING, + /* 177: krdo */ ABSENT_STRING, + /* 178: kref */ ABSENT_STRING, + /* 179: krfr */ ABSENT_STRING, + /* 180: krpl */ ABSENT_STRING, + /* 181: krst */ ABSENT_STRING, + /* 182: kres */ ABSENT_STRING, + /* 183: ksav */ ABSENT_STRING, + /* 184: kspd */ ABSENT_STRING, + /* 185: kund */ ABSENT_STRING, + /* 186: kBEG */ ABSENT_STRING, + /* 187: kCAN */ ABSENT_STRING, + /* 188: kCMD */ ABSENT_STRING, + /* 189: kCPY */ ABSENT_STRING, + /* 190: kCRT */ ABSENT_STRING, + /* 191: kDC */ screen_rxvt_s_kDC, + /* 192: kDL */ ABSENT_STRING, + /* 193: kslt */ ABSENT_STRING, + /* 194: kEND */ screen_rxvt_s_kEND, + /* 195: kEOL */ ABSENT_STRING, + /* 196: kEXT */ ABSENT_STRING, + /* 197: kFND */ ABSENT_STRING, + /* 198: kHLP */ ABSENT_STRING, + /* 199: kHOM */ screen_rxvt_s_kHOM, + /* 200: kIC */ screen_rxvt_s_kIC, + /* 201: kLFT */ screen_rxvt_s_kLFT, + /* 202: kMSG */ ABSENT_STRING, + /* 203: kMOV */ ABSENT_STRING, + /* 204: kNXT */ screen_rxvt_s_kNXT, + /* 205: kOPT */ ABSENT_STRING, + /* 206: kPRV */ screen_rxvt_s_kPRV, + /* 207: kPRT */ ABSENT_STRING, + /* 208: kRDO */ ABSENT_STRING, + /* 209: kRPL */ ABSENT_STRING, + /* 210: kRIT */ screen_rxvt_s_kRIT, + /* 211: kRES */ ABSENT_STRING, + /* 212: kSAV */ ABSENT_STRING, + /* 213: kSPD */ ABSENT_STRING, + /* 214: kUND */ ABSENT_STRING, + /* 215: rfi */ ABSENT_STRING, + /* 216: kf11 */ screen_rxvt_s_kf11, + /* 217: kf12 */ screen_rxvt_s_kf12, + /* 218: kf13 */ screen_rxvt_s_kf13, + /* 219: kf14 */ screen_rxvt_s_kf14, + /* 220: kf15 */ screen_rxvt_s_kf15, + /* 221: kf16 */ screen_rxvt_s_kf16, + /* 222: kf17 */ screen_rxvt_s_kf17, + /* 223: kf18 */ screen_rxvt_s_kf18, + /* 224: kf19 */ screen_rxvt_s_kf19, + /* 225: kf20 */ screen_rxvt_s_kf20, + /* 226: kf21 */ screen_rxvt_s_kf21, + /* 227: kf22 */ screen_rxvt_s_kf22, + /* 228: kf23 */ screen_rxvt_s_kf23, + /* 229: kf24 */ screen_rxvt_s_kf24, + /* 230: kf25 */ screen_rxvt_s_kf25, + /* 231: kf26 */ screen_rxvt_s_kf26, + /* 232: kf27 */ screen_rxvt_s_kf27, + /* 233: kf28 */ screen_rxvt_s_kf28, + /* 234: kf29 */ screen_rxvt_s_kf29, + /* 235: kf30 */ screen_rxvt_s_kf30, + /* 236: kf31 */ screen_rxvt_s_kf31, + /* 237: kf32 */ screen_rxvt_s_kf32, + /* 238: kf33 */ screen_rxvt_s_kf33, + /* 239: kf34 */ screen_rxvt_s_kf34, + /* 240: kf35 */ screen_rxvt_s_kf35, + /* 241: kf36 */ screen_rxvt_s_kf36, + /* 242: kf37 */ screen_rxvt_s_kf37, + /* 243: kf38 */ screen_rxvt_s_kf38, + /* 244: kf39 */ screen_rxvt_s_kf39, + /* 245: kf40 */ screen_rxvt_s_kf40, + /* 246: kf41 */ screen_rxvt_s_kf41, + /* 247: kf42 */ screen_rxvt_s_kf42, + /* 248: kf43 */ screen_rxvt_s_kf43, + /* 249: kf44 */ screen_rxvt_s_kf44, + /* 250: kf45 */ ABSENT_STRING, + /* 251: kf46 */ ABSENT_STRING, + /* 252: kf47 */ ABSENT_STRING, + /* 253: kf48 */ ABSENT_STRING, + /* 254: kf49 */ ABSENT_STRING, + /* 255: kf50 */ ABSENT_STRING, + /* 256: kf51 */ ABSENT_STRING, + /* 257: kf52 */ ABSENT_STRING, + /* 258: kf53 */ ABSENT_STRING, + /* 259: kf54 */ ABSENT_STRING, + /* 260: kf55 */ ABSENT_STRING, + /* 261: kf56 */ ABSENT_STRING, + /* 262: kf57 */ ABSENT_STRING, + /* 263: kf58 */ ABSENT_STRING, + /* 264: kf59 */ ABSENT_STRING, + /* 265: kf60 */ ABSENT_STRING, + /* 266: kf61 */ ABSENT_STRING, + /* 267: kf62 */ ABSENT_STRING, + /* 268: kf63 */ ABSENT_STRING, + /* 269: el1 */ screen_rxvt_s_el1, + /* 270: mgc */ ABSENT_STRING, + /* 271: smgl */ ABSENT_STRING, + /* 272: smgr */ ABSENT_STRING, + /* 273: fln */ ABSENT_STRING, + /* 274: sclk */ ABSENT_STRING, + /* 275: dclk */ ABSENT_STRING, + /* 276: rmclk */ ABSENT_STRING, + /* 277: cwin */ ABSENT_STRING, + /* 278: wingo */ ABSENT_STRING, + /* 279: hup */ ABSENT_STRING, + /* 280: dial */ ABSENT_STRING, + /* 281: qdial */ ABSENT_STRING, + /* 282: tone */ ABSENT_STRING, + /* 283: pulse */ ABSENT_STRING, + /* 284: hook */ ABSENT_STRING, + /* 285: pause */ ABSENT_STRING, + /* 286: wait */ ABSENT_STRING, + /* 287: u0 */ ABSENT_STRING, + /* 288: u1 */ ABSENT_STRING, + /* 289: u2 */ ABSENT_STRING, + /* 290: u3 */ ABSENT_STRING, + /* 291: u4 */ ABSENT_STRING, + /* 292: u5 */ ABSENT_STRING, + /* 293: u6 */ screen_rxvt_s_u6, + /* 294: u7 */ screen_rxvt_s_u7, + /* 295: u8 */ screen_rxvt_s_u8, + /* 296: u9 */ screen_rxvt_s_u9, + /* 297: op */ screen_rxvt_s_op, + /* 298: oc */ ABSENT_STRING, + /* 299: initc */ ABSENT_STRING, + /* 300: initp */ ABSENT_STRING, + /* 301: scp */ ABSENT_STRING, + /* 302: setf */ ABSENT_STRING, + /* 303: setb */ ABSENT_STRING, + /* 304: cpi */ ABSENT_STRING, + /* 305: lpi */ ABSENT_STRING, + /* 306: chr */ ABSENT_STRING, + /* 307: cvr */ ABSENT_STRING, + /* 308: defc */ ABSENT_STRING, + /* 309: swidm */ ABSENT_STRING, + /* 310: sdrfq */ ABSENT_STRING, + /* 311: sitm */ ABSENT_STRING, + /* 312: slm */ ABSENT_STRING, + /* 313: smicm */ ABSENT_STRING, + /* 314: snlq */ ABSENT_STRING, + /* 315: snrmq */ ABSENT_STRING, + /* 316: sshm */ ABSENT_STRING, + /* 317: ssubm */ ABSENT_STRING, + /* 318: ssupm */ ABSENT_STRING, + /* 319: sum */ ABSENT_STRING, + /* 320: rwidm */ ABSENT_STRING, + /* 321: ritm */ ABSENT_STRING, + /* 322: rlm */ ABSENT_STRING, + /* 323: rmicm */ ABSENT_STRING, + /* 324: rshm */ ABSENT_STRING, + /* 325: rsubm */ ABSENT_STRING, + /* 326: rsupm */ ABSENT_STRING, + /* 327: rum */ ABSENT_STRING, + /* 328: mhpa */ ABSENT_STRING, + /* 329: mcud1 */ ABSENT_STRING, + /* 330: mcub1 */ ABSENT_STRING, + /* 331: mcuf1 */ ABSENT_STRING, + /* 332: mvpa */ ABSENT_STRING, + /* 333: mcuu1 */ ABSENT_STRING, + /* 334: porder */ ABSENT_STRING, + /* 335: mcud */ ABSENT_STRING, + /* 336: mcub */ ABSENT_STRING, + /* 337: mcuf */ ABSENT_STRING, + /* 338: mcuu */ ABSENT_STRING, + /* 339: scs */ ABSENT_STRING, + /* 340: smgb */ ABSENT_STRING, + /* 341: smgbp */ ABSENT_STRING, + /* 342: smglp */ ABSENT_STRING, + /* 343: smgrp */ ABSENT_STRING, + /* 344: smgt */ ABSENT_STRING, + /* 345: smgtp */ ABSENT_STRING, + /* 346: sbim */ ABSENT_STRING, + /* 347: scsd */ ABSENT_STRING, + /* 348: rbim */ ABSENT_STRING, + /* 349: rcsd */ ABSENT_STRING, + /* 350: subcs */ ABSENT_STRING, + /* 351: supcs */ ABSENT_STRING, + /* 352: docr */ ABSENT_STRING, + /* 353: zerom */ ABSENT_STRING, + /* 354: csnm */ ABSENT_STRING, + /* 355: kmous */ screen_rxvt_s_kmous, + /* 356: minfo */ ABSENT_STRING, + /* 357: reqmp */ ABSENT_STRING, + /* 358: getm */ ABSENT_STRING, + /* 359: setaf */ screen_rxvt_s_setaf, + /* 360: setab */ screen_rxvt_s_setab, + /* 361: pfxl */ ABSENT_STRING, + /* 362: devt */ ABSENT_STRING, + /* 363: csin */ ABSENT_STRING, + /* 364: s0ds */ ABSENT_STRING, + /* 365: s1ds */ ABSENT_STRING, + /* 366: s2ds */ ABSENT_STRING, + /* 367: s3ds */ ABSENT_STRING, + /* 368: smglr */ ABSENT_STRING, + /* 369: smgtb */ ABSENT_STRING, + /* 370: birep */ ABSENT_STRING, + /* 371: binel */ ABSENT_STRING, + /* 372: bicr */ ABSENT_STRING, + /* 373: colornm */ ABSENT_STRING, + /* 374: defbi */ ABSENT_STRING, + /* 375: endbi */ ABSENT_STRING, + /* 376: setcolor */ ABSENT_STRING, + /* 377: slines */ ABSENT_STRING, + /* 378: dispc */ ABSENT_STRING, + /* 379: smpch */ ABSENT_STRING, + /* 380: rmpch */ ABSENT_STRING, + /* 381: smsc */ ABSENT_STRING, + /* 382: rmsc */ ABSENT_STRING, + /* 383: pctrm */ ABSENT_STRING, + /* 384: scesc */ ABSENT_STRING, + /* 385: scesa */ ABSENT_STRING, + /* 386: ehhlm */ ABSENT_STRING, + /* 387: elhlm */ ABSENT_STRING, + /* 388: elohlm */ ABSENT_STRING, + /* 389: erhlm */ ABSENT_STRING, + /* 390: ethlm */ ABSENT_STRING, + /* 391: evhlm */ ABSENT_STRING, + /* 392: sgr1 */ ABSENT_STRING, + /* 393: slength */ ABSENT_STRING, + /* 394: OTi2 */ ABSENT_STRING, + /* 395: OTrs */ ABSENT_STRING, + /* 396: OTnl */ ABSENT_STRING, + /* 397: OTbc */ ABSENT_STRING, + /* 398: OTko */ ABSENT_STRING, + /* 399: OTma */ ABSENT_STRING, + /* 400: OTG2 */ ABSENT_STRING, + /* 401: OTG3 */ ABSENT_STRING, + /* 402: OTG1 */ ABSENT_STRING, + /* 403: OTG4 */ ABSENT_STRING, + /* 404: OTGR */ ABSENT_STRING, + /* 405: OTGL */ ABSENT_STRING, + /* 406: OTGU */ ABSENT_STRING, + /* 407: OTGD */ ABSENT_STRING, + /* 408: OTGH */ ABSENT_STRING, + /* 409: OTGV */ ABSENT_STRING, + /* 410: OTGC */ ABSENT_STRING, + /* 411: meml */ ABSENT_STRING, + /* 412: memu */ ABSENT_STRING, + /* 413: box1 */ ABSENT_STRING, +}; +/* screen.xterm-new */ + +static char screen_xterm_xfree86_alias_data[] = "screen.xterm-xfree86|screen.xterm-new|screen customized for modern xterm"; + +static char screen_xterm_xfree86_s_cbt[] = "\033[Z"; +static char screen_xterm_xfree86_s_bel[] = "\007"; +static char screen_xterm_xfree86_s_cr[] = "\015"; +static char screen_xterm_xfree86_s_csr[] = "\033[%i%p1%d;%p2%dr"; +static char screen_xterm_xfree86_s_tbc[] = "\033[3g"; +static char screen_xterm_xfree86_s_clear[] = "\033[H\033[2J"; +static char screen_xterm_xfree86_s_el[] = "\033[K"; +static char screen_xterm_xfree86_s_ed[] = "\033[J"; +static char screen_xterm_xfree86_s_hpa[] = "\033[%i%p1%dG"; +static char screen_xterm_xfree86_s_cup[] = "\033[%i%p1%d;%p2%dH"; +static char screen_xterm_xfree86_s_cud1[] = "\012"; +static char screen_xterm_xfree86_s_home[] = "\033[H"; +static char screen_xterm_xfree86_s_civis[] = "\033[?25l"; +static char screen_xterm_xfree86_s_cub1[] = "\010"; +static char screen_xterm_xfree86_s_cnorm[] = "\033[?12l\033[?25h"; +static char screen_xterm_xfree86_s_cuf1[] = "\033[C"; +static char screen_xterm_xfree86_s_cuu1[] = "\033[A"; +static char screen_xterm_xfree86_s_cvvis[] = "\033[?12;25h"; +static char screen_xterm_xfree86_s_dch1[] = "\033[P"; +static char screen_xterm_xfree86_s_dl1[] = "\033[M"; +static char screen_xterm_xfree86_s_smacs[] = "\033(0"; +static char screen_xterm_xfree86_s_blink[] = "\033[5m"; +static char screen_xterm_xfree86_s_bold[] = "\033[1m"; +static char screen_xterm_xfree86_s_smcup[] = "\033[?1049h\033[22;0;0t"; +static char screen_xterm_xfree86_s_dim[] = "\033[2m"; +static char screen_xterm_xfree86_s_smir[] = "\033[4h"; +static char screen_xterm_xfree86_s_rev[] = "\033[7m"; +static char screen_xterm_xfree86_s_smso[] = "\033[7m"; +static char screen_xterm_xfree86_s_smul[] = "\033[4m"; +static char screen_xterm_xfree86_s_ech[] = "\033[%p1%dX"; +static char screen_xterm_xfree86_s_rmacs[] = "\033(B"; +static char screen_xterm_xfree86_s_sgr0[] = "\033(B\033[m"; +static char screen_xterm_xfree86_s_rmcup[] = "\033[?1049l\033[23;0;0t"; +static char screen_xterm_xfree86_s_rmir[] = "\033[4l"; +static char screen_xterm_xfree86_s_rmso[] = "\033[27m"; +static char screen_xterm_xfree86_s_rmul[] = "\033[24m"; +static char screen_xterm_xfree86_s_flash[] = "\033[?5h$<100/>\033[?5l"; +static char screen_xterm_xfree86_s_is2[] = "\033[!p\033[?3;4l\033[4l\033>"; +static char screen_xterm_xfree86_s_il1[] = "\033[L"; +static char screen_xterm_xfree86_s_kbs[] = "\010"; +static char screen_xterm_xfree86_s_kdch1[] = "\033[3~"; +static char screen_xterm_xfree86_s_kcud1[] = "\033OB"; +static char screen_xterm_xfree86_s_kf1[] = "\033OP"; +static char screen_xterm_xfree86_s_kf10[] = "\033[21~"; +static char screen_xterm_xfree86_s_kf2[] = "\033OQ"; +static char screen_xterm_xfree86_s_kf3[] = "\033OR"; +static char screen_xterm_xfree86_s_kf4[] = "\033OS"; +static char screen_xterm_xfree86_s_kf5[] = "\033[15~"; +static char screen_xterm_xfree86_s_kf6[] = "\033[17~"; +static char screen_xterm_xfree86_s_kf7[] = "\033[18~"; +static char screen_xterm_xfree86_s_kf8[] = "\033[19~"; +static char screen_xterm_xfree86_s_kf9[] = "\033[20~"; +static char screen_xterm_xfree86_s_khome[] = "\033[1~"; +static char screen_xterm_xfree86_s_kich1[] = "\033[2~"; +static char screen_xterm_xfree86_s_kcub1[] = "\033OD"; +static char screen_xterm_xfree86_s_knp[] = "\033[6~"; +static char screen_xterm_xfree86_s_kpp[] = "\033[5~"; +static char screen_xterm_xfree86_s_kcuf1[] = "\033OC"; +static char screen_xterm_xfree86_s_kind[] = "\033[1;2B"; +static char screen_xterm_xfree86_s_kri[] = "\033[1;2A"; +static char screen_xterm_xfree86_s_kcuu1[] = "\033OA"; +static char screen_xterm_xfree86_s_rmkx[] = "\033[?1l\033>"; +static char screen_xterm_xfree86_s_smkx[] = "\033[?1h\033="; +static char screen_xterm_xfree86_s_rmm[] = "\033[?1034l"; +static char screen_xterm_xfree86_s_smm[] = "\033[?1034h"; +static char screen_xterm_xfree86_s_dch[] = "\033[%p1%dP"; +static char screen_xterm_xfree86_s_dl[] = "\033[%p1%dM"; +static char screen_xterm_xfree86_s_cud[] = "\033[%p1%dB"; +static char screen_xterm_xfree86_s_ich[] = "\033[%p1%d@"; +static char screen_xterm_xfree86_s_indn[] = "\033[%p1%dS"; +static char screen_xterm_xfree86_s_il[] = "\033[%p1%dL"; +static char screen_xterm_xfree86_s_cub[] = "\033[%p1%dD"; +static char screen_xterm_xfree86_s_cuf[] = "\033[%p1%dC"; +static char screen_xterm_xfree86_s_rin[] = "\033[%p1%dT"; +static char screen_xterm_xfree86_s_cuu[] = "\033[%p1%dA"; +static char screen_xterm_xfree86_s_mc0[] = "\033[i"; +static char screen_xterm_xfree86_s_mc4[] = "\033[4i"; +static char screen_xterm_xfree86_s_mc5[] = "\033[5i"; +static char screen_xterm_xfree86_s_rs1[] = "\033c"; +static char screen_xterm_xfree86_s_rs2[] = "\033[!p\033[?3;4l\033[4l\033>"; +static char screen_xterm_xfree86_s_rc[] = "\0338"; +static char screen_xterm_xfree86_s_vpa[] = "\033[%i%p1%dd"; +static char screen_xterm_xfree86_s_sc[] = "\0337"; +static char screen_xterm_xfree86_s_ind[] = "\012"; +static char screen_xterm_xfree86_s_ri[] = "\033M"; +static char screen_xterm_xfree86_s_sgr[] = "%?%p9%t\033(0%e\033(B%;\033[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p5%t;2%;m"; +static char screen_xterm_xfree86_s_hts[] = "\033H"; +static char screen_xterm_xfree86_s_ht[] = "\011"; +static char screen_xterm_xfree86_s_kb2[] = "\033OE"; +static char screen_xterm_xfree86_s_acsc[] = "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"; +static char screen_xterm_xfree86_s_kcbt[] = "\033[Z"; +static char screen_xterm_xfree86_s_smam[] = "\033[?7h"; +static char screen_xterm_xfree86_s_rmam[] = "\033[?7l"; +static char screen_xterm_xfree86_s_kend[] = "\033[4~"; +static char screen_xterm_xfree86_s_kent[] = "\033OM"; +static char screen_xterm_xfree86_s_kDC[] = "\033[3;2~"; +static char screen_xterm_xfree86_s_kEND[] = "\033[1;2F"; +static char screen_xterm_xfree86_s_kHOM[] = "\033[1;2H"; +static char screen_xterm_xfree86_s_kLFT[] = "\033[1;2D"; +static char screen_xterm_xfree86_s_kRIT[] = "\033[1;2C"; +static char screen_xterm_xfree86_s_kf11[] = "\033[23~"; +static char screen_xterm_xfree86_s_kf12[] = "\033[24~"; +static char screen_xterm_xfree86_s_kf13[] = "\033[1;2P"; +static char screen_xterm_xfree86_s_kf14[] = "\033[1;2Q"; +static char screen_xterm_xfree86_s_kf15[] = "\033[1;2R"; +static char screen_xterm_xfree86_s_kf16[] = "\033[1;2S"; +static char screen_xterm_xfree86_s_kf17[] = "\033[15;2~"; +static char screen_xterm_xfree86_s_kf18[] = "\033[17;2~"; +static char screen_xterm_xfree86_s_kf19[] = "\033[18;2~"; +static char screen_xterm_xfree86_s_kf20[] = "\033[19;2~"; +static char screen_xterm_xfree86_s_kf21[] = "\033[20;2~"; +static char screen_xterm_xfree86_s_kf22[] = "\033[21;2~"; +static char screen_xterm_xfree86_s_kf23[] = "\033[23;2~"; +static char screen_xterm_xfree86_s_kf24[] = "\033[24;2~"; +static char screen_xterm_xfree86_s_kf25[] = "\033[1;5P"; +static char screen_xterm_xfree86_s_kf26[] = "\033[1;5Q"; +static char screen_xterm_xfree86_s_kf27[] = "\033[1;5R"; +static char screen_xterm_xfree86_s_kf28[] = "\033[1;5S"; +static char screen_xterm_xfree86_s_kf29[] = "\033[15;5~"; +static char screen_xterm_xfree86_s_kf30[] = "\033[17;5~"; +static char screen_xterm_xfree86_s_kf31[] = "\033[18;5~"; +static char screen_xterm_xfree86_s_kf32[] = "\033[19;5~"; +static char screen_xterm_xfree86_s_kf33[] = "\033[20;5~"; +static char screen_xterm_xfree86_s_kf34[] = "\033[21;5~"; +static char screen_xterm_xfree86_s_kf35[] = "\033[23;5~"; +static char screen_xterm_xfree86_s_kf36[] = "\033[24;5~"; +static char screen_xterm_xfree86_s_kf37[] = "\033[1;6P"; +static char screen_xterm_xfree86_s_kf38[] = "\033[1;6Q"; +static char screen_xterm_xfree86_s_kf39[] = "\033[1;6R"; +static char screen_xterm_xfree86_s_kf40[] = "\033[1;6S"; +static char screen_xterm_xfree86_s_kf41[] = "\033[15;6~"; +static char screen_xterm_xfree86_s_kf42[] = "\033[17;6~"; +static char screen_xterm_xfree86_s_kf43[] = "\033[18;6~"; +static char screen_xterm_xfree86_s_kf44[] = "\033[19;6~"; +static char screen_xterm_xfree86_s_kf45[] = "\033[20;6~"; +static char screen_xterm_xfree86_s_kf46[] = "\033[21;6~"; +static char screen_xterm_xfree86_s_kf47[] = "\033[23;6~"; +static char screen_xterm_xfree86_s_kf48[] = "\033[24;6~"; +static char screen_xterm_xfree86_s_kf49[] = "\033[1;3P"; +static char screen_xterm_xfree86_s_kf50[] = "\033[1;3Q"; +static char screen_xterm_xfree86_s_kf51[] = "\033[1;3R"; +static char screen_xterm_xfree86_s_kf52[] = "\033[1;3S"; +static char screen_xterm_xfree86_s_kf53[] = "\033[15;3~"; +static char screen_xterm_xfree86_s_kf54[] = "\033[17;3~"; +static char screen_xterm_xfree86_s_kf55[] = "\033[18;3~"; +static char screen_xterm_xfree86_s_kf56[] = "\033[19;3~"; +static char screen_xterm_xfree86_s_kf57[] = "\033[20;3~"; +static char screen_xterm_xfree86_s_kf58[] = "\033[21;3~"; +static char screen_xterm_xfree86_s_kf59[] = "\033[23;3~"; +static char screen_xterm_xfree86_s_kf60[] = "\033[24;3~"; +static char screen_xterm_xfree86_s_kf61[] = "\033[1;4P"; +static char screen_xterm_xfree86_s_kf62[] = "\033[1;4Q"; +static char screen_xterm_xfree86_s_kf63[] = "\033[1;4R"; +static char screen_xterm_xfree86_s_el1[] = "\033[1K"; +static char screen_xterm_xfree86_s_u6[] = "\033[%i%d;%dR"; +static char screen_xterm_xfree86_s_u7[] = "\033[6n"; +static char screen_xterm_xfree86_s_u8[] = "\033[?%[;0123456789]c"; +static char screen_xterm_xfree86_s_u9[] = "\033[c"; +static char screen_xterm_xfree86_s_op[] = "\033[39;49m"; +static char screen_xterm_xfree86_s_setf[] = "\033[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m"; +static char screen_xterm_xfree86_s_setb[] = "\033[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m"; +static char screen_xterm_xfree86_s_kmous[] = "\033[M"; +static char screen_xterm_xfree86_s_setaf[] = "\033[3%p1%dm"; +static char screen_xterm_xfree86_s_setab[] = "\033[4%p1%dm"; + +static char screen_xterm_xfree86_bool_data[] = { + /* 0: bw */ TRUE, + /* 1: am */ TRUE, + /* 2: xsb */ FALSE, + /* 3: xhp */ FALSE, + /* 4: xenl */ TRUE, + /* 5: eo */ FALSE, + /* 6: gn */ FALSE, + /* 7: hc */ FALSE, + /* 8: km */ TRUE, + /* 9: hs */ FALSE, + /* 10: in */ FALSE, + /* 11: da */ FALSE, + /* 12: db */ FALSE, + /* 13: mir */ TRUE, + /* 14: msgr */ TRUE, + /* 15: os */ FALSE, + /* 16: eslok */ FALSE, + /* 17: xt */ FALSE, + /* 18: hz */ FALSE, + /* 19: ul */ FALSE, + /* 20: xon */ FALSE, + /* 21: nxon */ FALSE, + /* 22: mc5i */ TRUE, + /* 23: chts */ FALSE, + /* 24: nrrmc */ FALSE, + /* 25: npc */ TRUE, + /* 26: ndscr */ FALSE, + /* 27: ccc */ FALSE, + /* 28: bce */ FALSE, + /* 29: hls */ FALSE, + /* 30: xhpa */ FALSE, + /* 31: crxm */ FALSE, + /* 32: daisy */ FALSE, + /* 33: xvpa */ FALSE, + /* 34: sam */ FALSE, + /* 35: cpix */ FALSE, + /* 36: lpix */ FALSE, + /* 37: OTbs */ TRUE, + /* 38: OTns */ FALSE, + /* 39: OTnc */ FALSE, + /* 40: OTMT */ FALSE, + /* 41: OTNL */ FALSE, + /* 42: OTpt */ FALSE, + /* 43: OTxr */ FALSE, +}; +static NCURSES_INT2 screen_xterm_xfree86_number_data[] = { + /* 0: cols */ 80, + /* 1: it */ 8, + /* 2: lines */ 24, + /* 3: lm */ ABSENT_NUMERIC, + /* 4: xmc */ ABSENT_NUMERIC, + /* 5: pb */ ABSENT_NUMERIC, + /* 6: vt */ ABSENT_NUMERIC, + /* 7: wsl */ ABSENT_NUMERIC, + /* 8: nlab */ ABSENT_NUMERIC, + /* 9: lh */ ABSENT_NUMERIC, + /* 10: lw */ ABSENT_NUMERIC, + /* 11: ma */ ABSENT_NUMERIC, + /* 12: wnum */ ABSENT_NUMERIC, + /* 13: colors */ 8, + /* 14: pairs */ 64, + /* 15: ncv */ ABSENT_NUMERIC, + /* 16: bufsz */ ABSENT_NUMERIC, + /* 17: spinv */ ABSENT_NUMERIC, + /* 18: spinh */ ABSENT_NUMERIC, + /* 19: maddr */ ABSENT_NUMERIC, + /* 20: mjump */ ABSENT_NUMERIC, + /* 21: mcs */ ABSENT_NUMERIC, + /* 22: mls */ ABSENT_NUMERIC, + /* 23: npins */ ABSENT_NUMERIC, + /* 24: orc */ ABSENT_NUMERIC, + /* 25: orl */ ABSENT_NUMERIC, + /* 26: orhi */ ABSENT_NUMERIC, + /* 27: orvi */ ABSENT_NUMERIC, + /* 28: cps */ ABSENT_NUMERIC, + /* 29: widcs */ ABSENT_NUMERIC, + /* 30: btns */ ABSENT_NUMERIC, + /* 31: bitwin */ ABSENT_NUMERIC, + /* 32: bitype */ ABSENT_NUMERIC, + /* 33: OTug */ ABSENT_NUMERIC, + /* 34: OTdC */ ABSENT_NUMERIC, + /* 35: OTdN */ ABSENT_NUMERIC, + /* 36: OTdB */ ABSENT_NUMERIC, + /* 37: OTdT */ ABSENT_NUMERIC, + /* 38: OTkn */ ABSENT_NUMERIC, +}; +static char * screen_xterm_xfree86_string_data[] = { + /* 0: cbt */ screen_xterm_xfree86_s_cbt, + /* 1: bel */ screen_xterm_xfree86_s_bel, + /* 2: cr */ screen_xterm_xfree86_s_cr, + /* 3: csr */ screen_xterm_xfree86_s_csr, + /* 4: tbc */ screen_xterm_xfree86_s_tbc, + /* 5: clear */ screen_xterm_xfree86_s_clear, + /* 6: el */ screen_xterm_xfree86_s_el, + /* 7: ed */ screen_xterm_xfree86_s_ed, + /* 8: hpa */ screen_xterm_xfree86_s_hpa, + /* 9: cmdch */ ABSENT_STRING, + /* 10: cup */ screen_xterm_xfree86_s_cup, + /* 11: cud1 */ screen_xterm_xfree86_s_cud1, + /* 12: home */ screen_xterm_xfree86_s_home, + /* 13: civis */ screen_xterm_xfree86_s_civis, + /* 14: cub1 */ screen_xterm_xfree86_s_cub1, + /* 15: mrcup */ ABSENT_STRING, + /* 16: cnorm */ screen_xterm_xfree86_s_cnorm, + /* 17: cuf1 */ screen_xterm_xfree86_s_cuf1, + /* 18: ll */ ABSENT_STRING, + /* 19: cuu1 */ screen_xterm_xfree86_s_cuu1, + /* 20: cvvis */ screen_xterm_xfree86_s_cvvis, + /* 21: dch1 */ screen_xterm_xfree86_s_dch1, + /* 22: dl1 */ screen_xterm_xfree86_s_dl1, + /* 23: dsl */ ABSENT_STRING, + /* 24: hd */ ABSENT_STRING, + /* 25: smacs */ screen_xterm_xfree86_s_smacs, + /* 26: blink */ screen_xterm_xfree86_s_blink, + /* 27: bold */ screen_xterm_xfree86_s_bold, + /* 28: smcup */ screen_xterm_xfree86_s_smcup, + /* 29: smdc */ ABSENT_STRING, + /* 30: dim */ screen_xterm_xfree86_s_dim, + /* 31: smir */ screen_xterm_xfree86_s_smir, + /* 32: invis */ CANCELLED_STRING, + /* 33: prot */ ABSENT_STRING, + /* 34: rev */ screen_xterm_xfree86_s_rev, + /* 35: smso */ screen_xterm_xfree86_s_smso, + /* 36: smul */ screen_xterm_xfree86_s_smul, + /* 37: ech */ screen_xterm_xfree86_s_ech, + /* 38: rmacs */ screen_xterm_xfree86_s_rmacs, + /* 39: sgr0 */ screen_xterm_xfree86_s_sgr0, + /* 40: rmcup */ screen_xterm_xfree86_s_rmcup, + /* 41: rmdc */ ABSENT_STRING, + /* 42: rmir */ screen_xterm_xfree86_s_rmir, + /* 43: rmso */ screen_xterm_xfree86_s_rmso, + /* 44: rmul */ screen_xterm_xfree86_s_rmul, + /* 45: flash */ screen_xterm_xfree86_s_flash, + /* 46: ff */ ABSENT_STRING, + /* 47: fsl */ ABSENT_STRING, + /* 48: is1 */ ABSENT_STRING, + /* 49: is2 */ screen_xterm_xfree86_s_is2, + /* 50: is3 */ ABSENT_STRING, + /* 51: if */ ABSENT_STRING, + /* 52: ich1 */ ABSENT_STRING, + /* 53: il1 */ screen_xterm_xfree86_s_il1, + /* 54: ip */ ABSENT_STRING, + /* 55: kbs */ screen_xterm_xfree86_s_kbs, + /* 56: ktbc */ ABSENT_STRING, + /* 57: kclr */ ABSENT_STRING, + /* 58: kctab */ ABSENT_STRING, + /* 59: kdch1 */ screen_xterm_xfree86_s_kdch1, + /* 60: kdl1 */ ABSENT_STRING, + /* 61: kcud1 */ screen_xterm_xfree86_s_kcud1, + /* 62: krmir */ ABSENT_STRING, + /* 63: kel */ ABSENT_STRING, + /* 64: ked */ ABSENT_STRING, + /* 65: kf0 */ ABSENT_STRING, + /* 66: kf1 */ screen_xterm_xfree86_s_kf1, + /* 67: kf10 */ screen_xterm_xfree86_s_kf10, + /* 68: kf2 */ screen_xterm_xfree86_s_kf2, + /* 69: kf3 */ screen_xterm_xfree86_s_kf3, + /* 70: kf4 */ screen_xterm_xfree86_s_kf4, + /* 71: kf5 */ screen_xterm_xfree86_s_kf5, + /* 72: kf6 */ screen_xterm_xfree86_s_kf6, + /* 73: kf7 */ screen_xterm_xfree86_s_kf7, + /* 74: kf8 */ screen_xterm_xfree86_s_kf8, + /* 75: kf9 */ screen_xterm_xfree86_s_kf9, + /* 76: khome */ screen_xterm_xfree86_s_khome, + /* 77: kich1 */ screen_xterm_xfree86_s_kich1, + /* 78: kil1 */ ABSENT_STRING, + /* 79: kcub1 */ screen_xterm_xfree86_s_kcub1, + /* 80: kll */ ABSENT_STRING, + /* 81: knp */ screen_xterm_xfree86_s_knp, + /* 82: kpp */ screen_xterm_xfree86_s_kpp, + /* 83: kcuf1 */ screen_xterm_xfree86_s_kcuf1, + /* 84: kind */ screen_xterm_xfree86_s_kind, + /* 85: kri */ screen_xterm_xfree86_s_kri, + /* 86: khts */ ABSENT_STRING, + /* 87: kcuu1 */ screen_xterm_xfree86_s_kcuu1, + /* 88: rmkx */ screen_xterm_xfree86_s_rmkx, + /* 89: smkx */ screen_xterm_xfree86_s_smkx, + /* 90: lf0 */ ABSENT_STRING, + /* 91: lf1 */ ABSENT_STRING, + /* 92: lf10 */ ABSENT_STRING, + /* 93: lf2 */ ABSENT_STRING, + /* 94: lf3 */ ABSENT_STRING, + /* 95: lf4 */ ABSENT_STRING, + /* 96: lf5 */ ABSENT_STRING, + /* 97: lf6 */ ABSENT_STRING, + /* 98: lf7 */ ABSENT_STRING, + /* 99: lf8 */ ABSENT_STRING, + /* 100: lf9 */ ABSENT_STRING, + /* 101: rmm */ screen_xterm_xfree86_s_rmm, + /* 102: smm */ screen_xterm_xfree86_s_smm, + /* 103: nel */ ABSENT_STRING, + /* 104: pad */ ABSENT_STRING, + /* 105: dch */ screen_xterm_xfree86_s_dch, + /* 106: dl */ screen_xterm_xfree86_s_dl, + /* 107: cud */ screen_xterm_xfree86_s_cud, + /* 108: ich */ screen_xterm_xfree86_s_ich, + /* 109: indn */ screen_xterm_xfree86_s_indn, + /* 110: il */ screen_xterm_xfree86_s_il, + /* 111: cub */ screen_xterm_xfree86_s_cub, + /* 112: cuf */ screen_xterm_xfree86_s_cuf, + /* 113: rin */ screen_xterm_xfree86_s_rin, + /* 114: cuu */ screen_xterm_xfree86_s_cuu, + /* 115: pfkey */ ABSENT_STRING, + /* 116: pfloc */ ABSENT_STRING, + /* 117: pfx */ ABSENT_STRING, + /* 118: mc0 */ screen_xterm_xfree86_s_mc0, + /* 119: mc4 */ screen_xterm_xfree86_s_mc4, + /* 120: mc5 */ screen_xterm_xfree86_s_mc5, + /* 121: rep */ CANCELLED_STRING, + /* 122: rs1 */ screen_xterm_xfree86_s_rs1, + /* 123: rs2 */ screen_xterm_xfree86_s_rs2, + /* 124: rs3 */ ABSENT_STRING, + /* 125: rf */ ABSENT_STRING, + /* 126: rc */ screen_xterm_xfree86_s_rc, + /* 127: vpa */ screen_xterm_xfree86_s_vpa, + /* 128: sc */ screen_xterm_xfree86_s_sc, + /* 129: ind */ screen_xterm_xfree86_s_ind, + /* 130: ri */ screen_xterm_xfree86_s_ri, + /* 131: sgr */ screen_xterm_xfree86_s_sgr, + /* 132: hts */ screen_xterm_xfree86_s_hts, + /* 133: wind */ ABSENT_STRING, + /* 134: ht */ screen_xterm_xfree86_s_ht, + /* 135: tsl */ ABSENT_STRING, + /* 136: uc */ ABSENT_STRING, + /* 137: hu */ ABSENT_STRING, + /* 138: iprog */ ABSENT_STRING, + /* 139: ka1 */ ABSENT_STRING, + /* 140: ka3 */ ABSENT_STRING, + /* 141: kb2 */ screen_xterm_xfree86_s_kb2, + /* 142: kc1 */ ABSENT_STRING, + /* 143: kc3 */ ABSENT_STRING, + /* 144: mc5p */ ABSENT_STRING, + /* 145: rmp */ ABSENT_STRING, + /* 146: acsc */ screen_xterm_xfree86_s_acsc, + /* 147: pln */ ABSENT_STRING, + /* 148: kcbt */ screen_xterm_xfree86_s_kcbt, + /* 149: smxon */ ABSENT_STRING, + /* 150: rmxon */ ABSENT_STRING, + /* 151: smam */ screen_xterm_xfree86_s_smam, + /* 152: rmam */ screen_xterm_xfree86_s_rmam, + /* 153: xonc */ ABSENT_STRING, + /* 154: xoffc */ ABSENT_STRING, + /* 155: enacs */ ABSENT_STRING, + /* 156: smln */ ABSENT_STRING, + /* 157: rmln */ ABSENT_STRING, + /* 158: kbeg */ ABSENT_STRING, + /* 159: kcan */ ABSENT_STRING, + /* 160: kclo */ ABSENT_STRING, + /* 161: kcmd */ ABSENT_STRING, + /* 162: kcpy */ ABSENT_STRING, + /* 163: kcrt */ ABSENT_STRING, + /* 164: kend */ screen_xterm_xfree86_s_kend, + /* 165: kent */ screen_xterm_xfree86_s_kent, + /* 166: kext */ ABSENT_STRING, + /* 167: kfnd */ ABSENT_STRING, + /* 168: khlp */ ABSENT_STRING, + /* 169: kmrk */ ABSENT_STRING, + /* 170: kmsg */ ABSENT_STRING, + /* 171: kmov */ ABSENT_STRING, + /* 172: knxt */ ABSENT_STRING, + /* 173: kopn */ ABSENT_STRING, + /* 174: kopt */ ABSENT_STRING, + /* 175: kprv */ ABSENT_STRING, + /* 176: kprt */ ABSENT_STRING, + /* 177: krdo */ ABSENT_STRING, + /* 178: kref */ ABSENT_STRING, + /* 179: krfr */ ABSENT_STRING, + /* 180: krpl */ ABSENT_STRING, + /* 181: krst */ ABSENT_STRING, + /* 182: kres */ ABSENT_STRING, + /* 183: ksav */ ABSENT_STRING, + /* 184: kspd */ ABSENT_STRING, + /* 185: kund */ ABSENT_STRING, + /* 186: kBEG */ ABSENT_STRING, + /* 187: kCAN */ ABSENT_STRING, + /* 188: kCMD */ ABSENT_STRING, + /* 189: kCPY */ ABSENT_STRING, + /* 190: kCRT */ ABSENT_STRING, + /* 191: kDC */ screen_xterm_xfree86_s_kDC, + /* 192: kDL */ ABSENT_STRING, + /* 193: kslt */ ABSENT_STRING, + /* 194: kEND */ screen_xterm_xfree86_s_kEND, + /* 195: kEOL */ ABSENT_STRING, + /* 196: kEXT */ ABSENT_STRING, + /* 197: kFND */ ABSENT_STRING, + /* 198: kHLP */ ABSENT_STRING, + /* 199: kHOM */ screen_xterm_xfree86_s_kHOM, + /* 200: kIC */ CANCELLED_STRING, + /* 201: kLFT */ screen_xterm_xfree86_s_kLFT, + /* 202: kMSG */ ABSENT_STRING, + /* 203: kMOV */ ABSENT_STRING, + /* 204: kNXT */ CANCELLED_STRING, + /* 205: kOPT */ ABSENT_STRING, + /* 206: kPRV */ CANCELLED_STRING, + /* 207: kPRT */ ABSENT_STRING, + /* 208: kRDO */ ABSENT_STRING, + /* 209: kRPL */ ABSENT_STRING, + /* 210: kRIT */ screen_xterm_xfree86_s_kRIT, + /* 211: kRES */ ABSENT_STRING, + /* 212: kSAV */ ABSENT_STRING, + /* 213: kSPD */ ABSENT_STRING, + /* 214: kUND */ ABSENT_STRING, + /* 215: rfi */ ABSENT_STRING, + /* 216: kf11 */ screen_xterm_xfree86_s_kf11, + /* 217: kf12 */ screen_xterm_xfree86_s_kf12, + /* 218: kf13 */ screen_xterm_xfree86_s_kf13, + /* 219: kf14 */ screen_xterm_xfree86_s_kf14, + /* 220: kf15 */ screen_xterm_xfree86_s_kf15, + /* 221: kf16 */ screen_xterm_xfree86_s_kf16, + /* 222: kf17 */ screen_xterm_xfree86_s_kf17, + /* 223: kf18 */ screen_xterm_xfree86_s_kf18, + /* 224: kf19 */ screen_xterm_xfree86_s_kf19, + /* 225: kf20 */ screen_xterm_xfree86_s_kf20, + /* 226: kf21 */ screen_xterm_xfree86_s_kf21, + /* 227: kf22 */ screen_xterm_xfree86_s_kf22, + /* 228: kf23 */ screen_xterm_xfree86_s_kf23, + /* 229: kf24 */ screen_xterm_xfree86_s_kf24, + /* 230: kf25 */ screen_xterm_xfree86_s_kf25, + /* 231: kf26 */ screen_xterm_xfree86_s_kf26, + /* 232: kf27 */ screen_xterm_xfree86_s_kf27, + /* 233: kf28 */ screen_xterm_xfree86_s_kf28, + /* 234: kf29 */ screen_xterm_xfree86_s_kf29, + /* 235: kf30 */ screen_xterm_xfree86_s_kf30, + /* 236: kf31 */ screen_xterm_xfree86_s_kf31, + /* 237: kf32 */ screen_xterm_xfree86_s_kf32, + /* 238: kf33 */ screen_xterm_xfree86_s_kf33, + /* 239: kf34 */ screen_xterm_xfree86_s_kf34, + /* 240: kf35 */ screen_xterm_xfree86_s_kf35, + /* 241: kf36 */ screen_xterm_xfree86_s_kf36, + /* 242: kf37 */ screen_xterm_xfree86_s_kf37, + /* 243: kf38 */ screen_xterm_xfree86_s_kf38, + /* 244: kf39 */ screen_xterm_xfree86_s_kf39, + /* 245: kf40 */ screen_xterm_xfree86_s_kf40, + /* 246: kf41 */ screen_xterm_xfree86_s_kf41, + /* 247: kf42 */ screen_xterm_xfree86_s_kf42, + /* 248: kf43 */ screen_xterm_xfree86_s_kf43, + /* 249: kf44 */ screen_xterm_xfree86_s_kf44, + /* 250: kf45 */ screen_xterm_xfree86_s_kf45, + /* 251: kf46 */ screen_xterm_xfree86_s_kf46, + /* 252: kf47 */ screen_xterm_xfree86_s_kf47, + /* 253: kf48 */ screen_xterm_xfree86_s_kf48, + /* 254: kf49 */ screen_xterm_xfree86_s_kf49, + /* 255: kf50 */ screen_xterm_xfree86_s_kf50, + /* 256: kf51 */ screen_xterm_xfree86_s_kf51, + /* 257: kf52 */ screen_xterm_xfree86_s_kf52, + /* 258: kf53 */ screen_xterm_xfree86_s_kf53, + /* 259: kf54 */ screen_xterm_xfree86_s_kf54, + /* 260: kf55 */ screen_xterm_xfree86_s_kf55, + /* 261: kf56 */ screen_xterm_xfree86_s_kf56, + /* 262: kf57 */ screen_xterm_xfree86_s_kf57, + /* 263: kf58 */ screen_xterm_xfree86_s_kf58, + /* 264: kf59 */ screen_xterm_xfree86_s_kf59, + /* 265: kf60 */ screen_xterm_xfree86_s_kf60, + /* 266: kf61 */ screen_xterm_xfree86_s_kf61, + /* 267: kf62 */ screen_xterm_xfree86_s_kf62, + /* 268: kf63 */ screen_xterm_xfree86_s_kf63, + /* 269: el1 */ screen_xterm_xfree86_s_el1, + /* 270: mgc */ ABSENT_STRING, + /* 271: smgl */ ABSENT_STRING, + /* 272: smgr */ ABSENT_STRING, + /* 273: fln */ ABSENT_STRING, + /* 274: sclk */ ABSENT_STRING, + /* 275: dclk */ ABSENT_STRING, + /* 276: rmclk */ ABSENT_STRING, + /* 277: cwin */ ABSENT_STRING, + /* 278: wingo */ ABSENT_STRING, + /* 279: hup */ ABSENT_STRING, + /* 280: dial */ ABSENT_STRING, + /* 281: qdial */ ABSENT_STRING, + /* 282: tone */ ABSENT_STRING, + /* 283: pulse */ ABSENT_STRING, + /* 284: hook */ ABSENT_STRING, + /* 285: pause */ ABSENT_STRING, + /* 286: wait */ ABSENT_STRING, + /* 287: u0 */ ABSENT_STRING, + /* 288: u1 */ ABSENT_STRING, + /* 289: u2 */ ABSENT_STRING, + /* 290: u3 */ ABSENT_STRING, + /* 291: u4 */ ABSENT_STRING, + /* 292: u5 */ ABSENT_STRING, + /* 293: u6 */ screen_xterm_xfree86_s_u6, + /* 294: u7 */ screen_xterm_xfree86_s_u7, + /* 295: u8 */ screen_xterm_xfree86_s_u8, + /* 296: u9 */ screen_xterm_xfree86_s_u9, + /* 297: op */ screen_xterm_xfree86_s_op, + /* 298: oc */ ABSENT_STRING, + /* 299: initc */ ABSENT_STRING, + /* 300: initp */ ABSENT_STRING, + /* 301: scp */ ABSENT_STRING, + /* 302: setf */ screen_xterm_xfree86_s_setf, + /* 303: setb */ screen_xterm_xfree86_s_setb, + /* 304: cpi */ ABSENT_STRING, + /* 305: lpi */ ABSENT_STRING, + /* 306: chr */ ABSENT_STRING, + /* 307: cvr */ ABSENT_STRING, + /* 308: defc */ ABSENT_STRING, + /* 309: swidm */ ABSENT_STRING, + /* 310: sdrfq */ ABSENT_STRING, + /* 311: sitm */ ABSENT_STRING, + /* 312: slm */ ABSENT_STRING, + /* 313: smicm */ ABSENT_STRING, + /* 314: snlq */ ABSENT_STRING, + /* 315: snrmq */ ABSENT_STRING, + /* 316: sshm */ ABSENT_STRING, + /* 317: ssubm */ ABSENT_STRING, + /* 318: ssupm */ ABSENT_STRING, + /* 319: sum */ ABSENT_STRING, + /* 320: rwidm */ ABSENT_STRING, + /* 321: ritm */ ABSENT_STRING, + /* 322: rlm */ ABSENT_STRING, + /* 323: rmicm */ ABSENT_STRING, + /* 324: rshm */ ABSENT_STRING, + /* 325: rsubm */ ABSENT_STRING, + /* 326: rsupm */ ABSENT_STRING, + /* 327: rum */ ABSENT_STRING, + /* 328: mhpa */ ABSENT_STRING, + /* 329: mcud1 */ ABSENT_STRING, + /* 330: mcub1 */ ABSENT_STRING, + /* 331: mcuf1 */ ABSENT_STRING, + /* 332: mvpa */ ABSENT_STRING, + /* 333: mcuu1 */ ABSENT_STRING, + /* 334: porder */ ABSENT_STRING, + /* 335: mcud */ ABSENT_STRING, + /* 336: mcub */ ABSENT_STRING, + /* 337: mcuf */ ABSENT_STRING, + /* 338: mcuu */ ABSENT_STRING, + /* 339: scs */ ABSENT_STRING, + /* 340: smgb */ ABSENT_STRING, + /* 341: smgbp */ ABSENT_STRING, + /* 342: smglp */ ABSENT_STRING, + /* 343: smgrp */ ABSENT_STRING, + /* 344: smgt */ ABSENT_STRING, + /* 345: smgtp */ ABSENT_STRING, + /* 346: sbim */ ABSENT_STRING, + /* 347: scsd */ ABSENT_STRING, + /* 348: rbim */ ABSENT_STRING, + /* 349: rcsd */ ABSENT_STRING, + /* 350: subcs */ ABSENT_STRING, + /* 351: supcs */ ABSENT_STRING, + /* 352: docr */ ABSENT_STRING, + /* 353: zerom */ ABSENT_STRING, + /* 354: csnm */ ABSENT_STRING, + /* 355: kmous */ screen_xterm_xfree86_s_kmous, + /* 356: minfo */ ABSENT_STRING, + /* 357: reqmp */ ABSENT_STRING, + /* 358: getm */ ABSENT_STRING, + /* 359: setaf */ screen_xterm_xfree86_s_setaf, + /* 360: setab */ screen_xterm_xfree86_s_setab, + /* 361: pfxl */ ABSENT_STRING, + /* 362: devt */ ABSENT_STRING, + /* 363: csin */ ABSENT_STRING, + /* 364: s0ds */ ABSENT_STRING, + /* 365: s1ds */ ABSENT_STRING, + /* 366: s2ds */ ABSENT_STRING, + /* 367: s3ds */ ABSENT_STRING, + /* 368: smglr */ ABSENT_STRING, + /* 369: smgtb */ ABSENT_STRING, + /* 370: birep */ ABSENT_STRING, + /* 371: binel */ ABSENT_STRING, + /* 372: bicr */ ABSENT_STRING, + /* 373: colornm */ ABSENT_STRING, + /* 374: defbi */ ABSENT_STRING, + /* 375: endbi */ ABSENT_STRING, + /* 376: setcolor */ ABSENT_STRING, + /* 377: slines */ ABSENT_STRING, + /* 378: dispc */ ABSENT_STRING, + /* 379: smpch */ ABSENT_STRING, + /* 380: rmpch */ ABSENT_STRING, + /* 381: smsc */ ABSENT_STRING, + /* 382: rmsc */ ABSENT_STRING, + /* 383: pctrm */ ABSENT_STRING, + /* 384: scesc */ ABSENT_STRING, + /* 385: scesa */ ABSENT_STRING, + /* 386: ehhlm */ ABSENT_STRING, + /* 387: elhlm */ ABSENT_STRING, + /* 388: elohlm */ ABSENT_STRING, + /* 389: erhlm */ ABSENT_STRING, + /* 390: ethlm */ ABSENT_STRING, + /* 391: evhlm */ ABSENT_STRING, + /* 392: sgr1 */ ABSENT_STRING, + /* 393: slength */ ABSENT_STRING, + /* 394: OTi2 */ ABSENT_STRING, + /* 395: OTrs */ ABSENT_STRING, + /* 396: OTnl */ ABSENT_STRING, + /* 397: OTbc */ ABSENT_STRING, + /* 398: OTko */ ABSENT_STRING, + /* 399: OTma */ ABSENT_STRING, + /* 400: OTG2 */ ABSENT_STRING, + /* 401: OTG3 */ ABSENT_STRING, + /* 402: OTG1 */ ABSENT_STRING, + /* 403: OTG4 */ ABSENT_STRING, + /* 404: OTGR */ ABSENT_STRING, + /* 405: OTGL */ ABSENT_STRING, + /* 406: OTGU */ ABSENT_STRING, + /* 407: OTGD */ ABSENT_STRING, + /* 408: OTGH */ ABSENT_STRING, + /* 409: OTGV */ ABSENT_STRING, + /* 410: OTGC */ ABSENT_STRING, + /* 411: meml */ CANCELLED_STRING, + /* 412: memu */ CANCELLED_STRING, + /* 413: box1 */ ABSENT_STRING, +}; +/* screen.xterm-256color */ + +static char screen_xterm_256color_alias_data[] = "screen.xterm-256color|GNU Screen with xterm using 256 colors"; + +static char screen_xterm_256color_s_cbt[] = "\033[Z"; +static char screen_xterm_256color_s_bel[] = "\007"; +static char screen_xterm_256color_s_cr[] = "\015"; +static char screen_xterm_256color_s_csr[] = "\033[%i%p1%d;%p2%dr"; +static char screen_xterm_256color_s_tbc[] = "\033[3g"; +static char screen_xterm_256color_s_clear[] = "\033[H\033[2J"; +static char screen_xterm_256color_s_el[] = "\033[K"; +static char screen_xterm_256color_s_ed[] = "\033[J"; +static char screen_xterm_256color_s_hpa[] = "\033[%i%p1%dG"; +static char screen_xterm_256color_s_cup[] = "\033[%i%p1%d;%p2%dH"; +static char screen_xterm_256color_s_cud1[] = "\012"; +static char screen_xterm_256color_s_home[] = "\033[H"; +static char screen_xterm_256color_s_civis[] = "\033[?25l"; +static char screen_xterm_256color_s_cub1[] = "\010"; +static char screen_xterm_256color_s_cnorm[] = "\033[?12l\033[?25h"; +static char screen_xterm_256color_s_cuf1[] = "\033[C"; +static char screen_xterm_256color_s_cuu1[] = "\033[A"; +static char screen_xterm_256color_s_cvvis[] = "\033[?12;25h"; +static char screen_xterm_256color_s_dch1[] = "\033[P"; +static char screen_xterm_256color_s_dl1[] = "\033[M"; +static char screen_xterm_256color_s_smacs[] = "\033(0"; +static char screen_xterm_256color_s_blink[] = "\033[5m"; +static char screen_xterm_256color_s_bold[] = "\033[1m"; +static char screen_xterm_256color_s_smcup[] = "\033[?1049h\033[22;0;0t"; +static char screen_xterm_256color_s_dim[] = "\033[2m"; +static char screen_xterm_256color_s_smir[] = "\033[4h"; +static char screen_xterm_256color_s_rev[] = "\033[7m"; +static char screen_xterm_256color_s_smso[] = "\033[7m"; +static char screen_xterm_256color_s_smul[] = "\033[4m"; +static char screen_xterm_256color_s_ech[] = "\033[%p1%dX"; +static char screen_xterm_256color_s_rmacs[] = "\033(B"; +static char screen_xterm_256color_s_sgr0[] = "\033(B\033[m"; +static char screen_xterm_256color_s_rmcup[] = "\033[?1049l\033[23;0;0t"; +static char screen_xterm_256color_s_rmir[] = "\033[4l"; +static char screen_xterm_256color_s_rmso[] = "\033[27m"; +static char screen_xterm_256color_s_rmul[] = "\033[24m"; +static char screen_xterm_256color_s_flash[] = "\033[?5h$<100/>\033[?5l"; +static char screen_xterm_256color_s_is2[] = "\033[!p\033[?3;4l\033[4l\033>"; +static char screen_xterm_256color_s_il1[] = "\033[L"; +static char screen_xterm_256color_s_kbs[] = "\010"; +static char screen_xterm_256color_s_kdch1[] = "\033[3~"; +static char screen_xterm_256color_s_kcud1[] = "\033OB"; +static char screen_xterm_256color_s_kf1[] = "\033OP"; +static char screen_xterm_256color_s_kf10[] = "\033[21~"; +static char screen_xterm_256color_s_kf2[] = "\033OQ"; +static char screen_xterm_256color_s_kf3[] = "\033OR"; +static char screen_xterm_256color_s_kf4[] = "\033OS"; +static char screen_xterm_256color_s_kf5[] = "\033[15~"; +static char screen_xterm_256color_s_kf6[] = "\033[17~"; +static char screen_xterm_256color_s_kf7[] = "\033[18~"; +static char screen_xterm_256color_s_kf8[] = "\033[19~"; +static char screen_xterm_256color_s_kf9[] = "\033[20~"; +static char screen_xterm_256color_s_khome[] = "\033[1~"; +static char screen_xterm_256color_s_kich1[] = "\033[2~"; +static char screen_xterm_256color_s_kcub1[] = "\033OD"; +static char screen_xterm_256color_s_knp[] = "\033[6~"; +static char screen_xterm_256color_s_kpp[] = "\033[5~"; +static char screen_xterm_256color_s_kcuf1[] = "\033OC"; +static char screen_xterm_256color_s_kind[] = "\033[1;2B"; +static char screen_xterm_256color_s_kri[] = "\033[1;2A"; +static char screen_xterm_256color_s_kcuu1[] = "\033OA"; +static char screen_xterm_256color_s_rmkx[] = "\033[?1l\033>"; +static char screen_xterm_256color_s_smkx[] = "\033[?1h\033="; +static char screen_xterm_256color_s_rmm[] = "\033[?1034l"; +static char screen_xterm_256color_s_smm[] = "\033[?1034h"; +static char screen_xterm_256color_s_dch[] = "\033[%p1%dP"; +static char screen_xterm_256color_s_dl[] = "\033[%p1%dM"; +static char screen_xterm_256color_s_cud[] = "\033[%p1%dB"; +static char screen_xterm_256color_s_ich[] = "\033[%p1%d@"; +static char screen_xterm_256color_s_indn[] = "\033[%p1%dS"; +static char screen_xterm_256color_s_il[] = "\033[%p1%dL"; +static char screen_xterm_256color_s_cub[] = "\033[%p1%dD"; +static char screen_xterm_256color_s_cuf[] = "\033[%p1%dC"; +static char screen_xterm_256color_s_rin[] = "\033[%p1%dT"; +static char screen_xterm_256color_s_cuu[] = "\033[%p1%dA"; +static char screen_xterm_256color_s_mc0[] = "\033[i"; +static char screen_xterm_256color_s_mc4[] = "\033[4i"; +static char screen_xterm_256color_s_mc5[] = "\033[5i"; +static char screen_xterm_256color_s_rs1[] = "\033c"; +static char screen_xterm_256color_s_rs2[] = "\033[!p\033[?3;4l\033[4l\033>"; +static char screen_xterm_256color_s_rc[] = "\0338"; +static char screen_xterm_256color_s_vpa[] = "\033[%i%p1%dd"; +static char screen_xterm_256color_s_sc[] = "\0337"; +static char screen_xterm_256color_s_ind[] = "\012"; +static char screen_xterm_256color_s_ri[] = "\033M"; +static char screen_xterm_256color_s_sgr[] = "%?%p9%t\033(0%e\033(B%;\033[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p5%t;2%;m"; +static char screen_xterm_256color_s_hts[] = "\033H"; +static char screen_xterm_256color_s_ht[] = "\011"; +static char screen_xterm_256color_s_kb2[] = "\033OE"; +static char screen_xterm_256color_s_acsc[] = "``aaffggiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~"; +static char screen_xterm_256color_s_kcbt[] = "\033[Z"; +static char screen_xterm_256color_s_smam[] = "\033[?7h"; +static char screen_xterm_256color_s_rmam[] = "\033[?7l"; +static char screen_xterm_256color_s_kend[] = "\033[4~"; +static char screen_xterm_256color_s_kent[] = "\033OM"; +static char screen_xterm_256color_s_kDC[] = "\033[3;2~"; +static char screen_xterm_256color_s_kEND[] = "\033[1;2F"; +static char screen_xterm_256color_s_kHOM[] = "\033[1;2H"; +static char screen_xterm_256color_s_kLFT[] = "\033[1;2D"; +static char screen_xterm_256color_s_kRIT[] = "\033[1;2C"; +static char screen_xterm_256color_s_kf11[] = "\033[23~"; +static char screen_xterm_256color_s_kf12[] = "\033[24~"; +static char screen_xterm_256color_s_kf13[] = "\033[1;2P"; +static char screen_xterm_256color_s_kf14[] = "\033[1;2Q"; +static char screen_xterm_256color_s_kf15[] = "\033[1;2R"; +static char screen_xterm_256color_s_kf16[] = "\033[1;2S"; +static char screen_xterm_256color_s_kf17[] = "\033[15;2~"; +static char screen_xterm_256color_s_kf18[] = "\033[17;2~"; +static char screen_xterm_256color_s_kf19[] = "\033[18;2~"; +static char screen_xterm_256color_s_kf20[] = "\033[19;2~"; +static char screen_xterm_256color_s_kf21[] = "\033[20;2~"; +static char screen_xterm_256color_s_kf22[] = "\033[21;2~"; +static char screen_xterm_256color_s_kf23[] = "\033[23;2~"; +static char screen_xterm_256color_s_kf24[] = "\033[24;2~"; +static char screen_xterm_256color_s_kf25[] = "\033[1;5P"; +static char screen_xterm_256color_s_kf26[] = "\033[1;5Q"; +static char screen_xterm_256color_s_kf27[] = "\033[1;5R"; +static char screen_xterm_256color_s_kf28[] = "\033[1;5S"; +static char screen_xterm_256color_s_kf29[] = "\033[15;5~"; +static char screen_xterm_256color_s_kf30[] = "\033[17;5~"; +static char screen_xterm_256color_s_kf31[] = "\033[18;5~"; +static char screen_xterm_256color_s_kf32[] = "\033[19;5~"; +static char screen_xterm_256color_s_kf33[] = "\033[20;5~"; +static char screen_xterm_256color_s_kf34[] = "\033[21;5~"; +static char screen_xterm_256color_s_kf35[] = "\033[23;5~"; +static char screen_xterm_256color_s_kf36[] = "\033[24;5~"; +static char screen_xterm_256color_s_kf37[] = "\033[1;6P"; +static char screen_xterm_256color_s_kf38[] = "\033[1;6Q"; +static char screen_xterm_256color_s_kf39[] = "\033[1;6R"; +static char screen_xterm_256color_s_kf40[] = "\033[1;6S"; +static char screen_xterm_256color_s_kf41[] = "\033[15;6~"; +static char screen_xterm_256color_s_kf42[] = "\033[17;6~"; +static char screen_xterm_256color_s_kf43[] = "\033[18;6~"; +static char screen_xterm_256color_s_kf44[] = "\033[19;6~"; +static char screen_xterm_256color_s_kf45[] = "\033[20;6~"; +static char screen_xterm_256color_s_kf46[] = "\033[21;6~"; +static char screen_xterm_256color_s_kf47[] = "\033[23;6~"; +static char screen_xterm_256color_s_kf48[] = "\033[24;6~"; +static char screen_xterm_256color_s_kf49[] = "\033[1;3P"; +static char screen_xterm_256color_s_kf50[] = "\033[1;3Q"; +static char screen_xterm_256color_s_kf51[] = "\033[1;3R"; +static char screen_xterm_256color_s_kf52[] = "\033[1;3S"; +static char screen_xterm_256color_s_kf53[] = "\033[15;3~"; +static char screen_xterm_256color_s_kf54[] = "\033[17;3~"; +static char screen_xterm_256color_s_kf55[] = "\033[18;3~"; +static char screen_xterm_256color_s_kf56[] = "\033[19;3~"; +static char screen_xterm_256color_s_kf57[] = "\033[20;3~"; +static char screen_xterm_256color_s_kf58[] = "\033[21;3~"; +static char screen_xterm_256color_s_kf59[] = "\033[23;3~"; +static char screen_xterm_256color_s_kf60[] = "\033[24;3~"; +static char screen_xterm_256color_s_kf61[] = "\033[1;4P"; +static char screen_xterm_256color_s_kf62[] = "\033[1;4Q"; +static char screen_xterm_256color_s_kf63[] = "\033[1;4R"; +static char screen_xterm_256color_s_el1[] = "\033[1K"; +static char screen_xterm_256color_s_u6[] = "\033[%i%d;%dR"; +static char screen_xterm_256color_s_u7[] = "\033[6n"; +static char screen_xterm_256color_s_u8[] = "\033[?%[;0123456789]c"; +static char screen_xterm_256color_s_u9[] = "\033[c"; +static char screen_xterm_256color_s_op[] = "\033[39;49m"; +static char screen_xterm_256color_s_kmous[] = "\033[M"; +static char screen_xterm_256color_s_setaf[] = "\033[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m"; +static char screen_xterm_256color_s_setab[] = "\033[%?%p1%{8}%<%t4%p1%d%e%p1%{16}%<%t10%p1%{8}%-%d%e48;5;%p1%d%;m"; + +static char screen_xterm_256color_bool_data[] = { + /* 0: bw */ TRUE, + /* 1: am */ TRUE, + /* 2: xsb */ FALSE, + /* 3: xhp */ FALSE, + /* 4: xenl */ TRUE, + /* 5: eo */ FALSE, + /* 6: gn */ FALSE, + /* 7: hc */ FALSE, + /* 8: km */ TRUE, + /* 9: hs */ FALSE, + /* 10: in */ FALSE, + /* 11: da */ FALSE, + /* 12: db */ FALSE, + /* 13: mir */ TRUE, + /* 14: msgr */ TRUE, + /* 15: os */ FALSE, + /* 16: eslok */ FALSE, + /* 17: xt */ FALSE, + /* 18: hz */ FALSE, + /* 19: ul */ FALSE, + /* 20: xon */ FALSE, + /* 21: nxon */ FALSE, + /* 22: mc5i */ TRUE, + /* 23: chts */ FALSE, + /* 24: nrrmc */ FALSE, + /* 25: npc */ TRUE, + /* 26: ndscr */ FALSE, + /* 27: ccc */ FALSE, + /* 28: bce */ FALSE, + /* 29: hls */ FALSE, + /* 30: xhpa */ FALSE, + /* 31: crxm */ FALSE, + /* 32: daisy */ FALSE, + /* 33: xvpa */ FALSE, + /* 34: sam */ FALSE, + /* 35: cpix */ FALSE, + /* 36: lpix */ FALSE, + /* 37: OTbs */ TRUE, + /* 38: OTns */ FALSE, + /* 39: OTnc */ FALSE, + /* 40: OTMT */ FALSE, + /* 41: OTNL */ FALSE, + /* 42: OTpt */ FALSE, + /* 43: OTxr */ FALSE, +}; +static NCURSES_INT2 screen_xterm_256color_number_data[] = { + /* 0: cols */ 80, + /* 1: it */ 8, + /* 2: lines */ 24, + /* 3: lm */ ABSENT_NUMERIC, + /* 4: xmc */ ABSENT_NUMERIC, + /* 5: pb */ ABSENT_NUMERIC, + /* 6: vt */ ABSENT_NUMERIC, + /* 7: wsl */ ABSENT_NUMERIC, + /* 8: nlab */ ABSENT_NUMERIC, + /* 9: lh */ ABSENT_NUMERIC, + /* 10: lw */ ABSENT_NUMERIC, + /* 11: ma */ ABSENT_NUMERIC, + /* 12: wnum */ ABSENT_NUMERIC, + /* 13: colors */ 256, + /* 14: pairs */ 32767, + /* 15: ncv */ ABSENT_NUMERIC, + /* 16: bufsz */ ABSENT_NUMERIC, + /* 17: spinv */ ABSENT_NUMERIC, + /* 18: spinh */ ABSENT_NUMERIC, + /* 19: maddr */ ABSENT_NUMERIC, + /* 20: mjump */ ABSENT_NUMERIC, + /* 21: mcs */ ABSENT_NUMERIC, + /* 22: mls */ ABSENT_NUMERIC, + /* 23: npins */ ABSENT_NUMERIC, + /* 24: orc */ ABSENT_NUMERIC, + /* 25: orl */ ABSENT_NUMERIC, + /* 26: orhi */ ABSENT_NUMERIC, + /* 27: orvi */ ABSENT_NUMERIC, + /* 28: cps */ ABSENT_NUMERIC, + /* 29: widcs */ ABSENT_NUMERIC, + /* 30: btns */ ABSENT_NUMERIC, + /* 31: bitwin */ ABSENT_NUMERIC, + /* 32: bitype */ ABSENT_NUMERIC, + /* 33: OTug */ ABSENT_NUMERIC, + /* 34: OTdC */ ABSENT_NUMERIC, + /* 35: OTdN */ ABSENT_NUMERIC, + /* 36: OTdB */ ABSENT_NUMERIC, + /* 37: OTdT */ ABSENT_NUMERIC, + /* 38: OTkn */ ABSENT_NUMERIC, +}; +static char * screen_xterm_256color_string_data[] = { + /* 0: cbt */ screen_xterm_256color_s_cbt, + /* 1: bel */ screen_xterm_256color_s_bel, + /* 2: cr */ screen_xterm_256color_s_cr, + /* 3: csr */ screen_xterm_256color_s_csr, + /* 4: tbc */ screen_xterm_256color_s_tbc, + /* 5: clear */ screen_xterm_256color_s_clear, + /* 6: el */ screen_xterm_256color_s_el, + /* 7: ed */ screen_xterm_256color_s_ed, + /* 8: hpa */ screen_xterm_256color_s_hpa, + /* 9: cmdch */ ABSENT_STRING, + /* 10: cup */ screen_xterm_256color_s_cup, + /* 11: cud1 */ screen_xterm_256color_s_cud1, + /* 12: home */ screen_xterm_256color_s_home, + /* 13: civis */ screen_xterm_256color_s_civis, + /* 14: cub1 */ screen_xterm_256color_s_cub1, + /* 15: mrcup */ ABSENT_STRING, + /* 16: cnorm */ screen_xterm_256color_s_cnorm, + /* 17: cuf1 */ screen_xterm_256color_s_cuf1, + /* 18: ll */ ABSENT_STRING, + /* 19: cuu1 */ screen_xterm_256color_s_cuu1, + /* 20: cvvis */ screen_xterm_256color_s_cvvis, + /* 21: dch1 */ screen_xterm_256color_s_dch1, + /* 22: dl1 */ screen_xterm_256color_s_dl1, + /* 23: dsl */ ABSENT_STRING, + /* 24: hd */ ABSENT_STRING, + /* 25: smacs */ screen_xterm_256color_s_smacs, + /* 26: blink */ screen_xterm_256color_s_blink, + /* 27: bold */ screen_xterm_256color_s_bold, + /* 28: smcup */ screen_xterm_256color_s_smcup, + /* 29: smdc */ ABSENT_STRING, + /* 30: dim */ screen_xterm_256color_s_dim, + /* 31: smir */ screen_xterm_256color_s_smir, + /* 32: invis */ ABSENT_STRING, + /* 33: prot */ ABSENT_STRING, + /* 34: rev */ screen_xterm_256color_s_rev, + /* 35: smso */ screen_xterm_256color_s_smso, + /* 36: smul */ screen_xterm_256color_s_smul, + /* 37: ech */ screen_xterm_256color_s_ech, + /* 38: rmacs */ screen_xterm_256color_s_rmacs, + /* 39: sgr0 */ screen_xterm_256color_s_sgr0, + /* 40: rmcup */ screen_xterm_256color_s_rmcup, + /* 41: rmdc */ ABSENT_STRING, + /* 42: rmir */ screen_xterm_256color_s_rmir, + /* 43: rmso */ screen_xterm_256color_s_rmso, + /* 44: rmul */ screen_xterm_256color_s_rmul, + /* 45: flash */ screen_xterm_256color_s_flash, + /* 46: ff */ ABSENT_STRING, + /* 47: fsl */ ABSENT_STRING, + /* 48: is1 */ ABSENT_STRING, + /* 49: is2 */ screen_xterm_256color_s_is2, + /* 50: is3 */ ABSENT_STRING, + /* 51: if */ ABSENT_STRING, + /* 52: ich1 */ ABSENT_STRING, + /* 53: il1 */ screen_xterm_256color_s_il1, + /* 54: ip */ ABSENT_STRING, + /* 55: kbs */ screen_xterm_256color_s_kbs, + /* 56: ktbc */ ABSENT_STRING, + /* 57: kclr */ ABSENT_STRING, + /* 58: kctab */ ABSENT_STRING, + /* 59: kdch1 */ screen_xterm_256color_s_kdch1, + /* 60: kdl1 */ ABSENT_STRING, + /* 61: kcud1 */ screen_xterm_256color_s_kcud1, + /* 62: krmir */ ABSENT_STRING, + /* 63: kel */ ABSENT_STRING, + /* 64: ked */ ABSENT_STRING, + /* 65: kf0 */ ABSENT_STRING, + /* 66: kf1 */ screen_xterm_256color_s_kf1, + /* 67: kf10 */ screen_xterm_256color_s_kf10, + /* 68: kf2 */ screen_xterm_256color_s_kf2, + /* 69: kf3 */ screen_xterm_256color_s_kf3, + /* 70: kf4 */ screen_xterm_256color_s_kf4, + /* 71: kf5 */ screen_xterm_256color_s_kf5, + /* 72: kf6 */ screen_xterm_256color_s_kf6, + /* 73: kf7 */ screen_xterm_256color_s_kf7, + /* 74: kf8 */ screen_xterm_256color_s_kf8, + /* 75: kf9 */ screen_xterm_256color_s_kf9, + /* 76: khome */ screen_xterm_256color_s_khome, + /* 77: kich1 */ screen_xterm_256color_s_kich1, + /* 78: kil1 */ ABSENT_STRING, + /* 79: kcub1 */ screen_xterm_256color_s_kcub1, + /* 80: kll */ ABSENT_STRING, + /* 81: knp */ screen_xterm_256color_s_knp, + /* 82: kpp */ screen_xterm_256color_s_kpp, + /* 83: kcuf1 */ screen_xterm_256color_s_kcuf1, + /* 84: kind */ screen_xterm_256color_s_kind, + /* 85: kri */ screen_xterm_256color_s_kri, + /* 86: khts */ ABSENT_STRING, + /* 87: kcuu1 */ screen_xterm_256color_s_kcuu1, + /* 88: rmkx */ screen_xterm_256color_s_rmkx, + /* 89: smkx */ screen_xterm_256color_s_smkx, + /* 90: lf0 */ ABSENT_STRING, + /* 91: lf1 */ ABSENT_STRING, + /* 92: lf10 */ ABSENT_STRING, + /* 93: lf2 */ ABSENT_STRING, + /* 94: lf3 */ ABSENT_STRING, + /* 95: lf4 */ ABSENT_STRING, + /* 96: lf5 */ ABSENT_STRING, + /* 97: lf6 */ ABSENT_STRING, + /* 98: lf7 */ ABSENT_STRING, + /* 99: lf8 */ ABSENT_STRING, + /* 100: lf9 */ ABSENT_STRING, + /* 101: rmm */ screen_xterm_256color_s_rmm, + /* 102: smm */ screen_xterm_256color_s_smm, + /* 103: nel */ ABSENT_STRING, + /* 104: pad */ ABSENT_STRING, + /* 105: dch */ screen_xterm_256color_s_dch, + /* 106: dl */ screen_xterm_256color_s_dl, + /* 107: cud */ screen_xterm_256color_s_cud, + /* 108: ich */ screen_xterm_256color_s_ich, + /* 109: indn */ screen_xterm_256color_s_indn, + /* 110: il */ screen_xterm_256color_s_il, + /* 111: cub */ screen_xterm_256color_s_cub, + /* 112: cuf */ screen_xterm_256color_s_cuf, + /* 113: rin */ screen_xterm_256color_s_rin, + /* 114: cuu */ screen_xterm_256color_s_cuu, + /* 115: pfkey */ ABSENT_STRING, + /* 116: pfloc */ ABSENT_STRING, + /* 117: pfx */ ABSENT_STRING, + /* 118: mc0 */ screen_xterm_256color_s_mc0, + /* 119: mc4 */ screen_xterm_256color_s_mc4, + /* 120: mc5 */ screen_xterm_256color_s_mc5, + /* 121: rep */ ABSENT_STRING, + /* 122: rs1 */ screen_xterm_256color_s_rs1, + /* 123: rs2 */ screen_xterm_256color_s_rs2, + /* 124: rs3 */ ABSENT_STRING, + /* 125: rf */ ABSENT_STRING, + /* 126: rc */ screen_xterm_256color_s_rc, + /* 127: vpa */ screen_xterm_256color_s_vpa, + /* 128: sc */ screen_xterm_256color_s_sc, + /* 129: ind */ screen_xterm_256color_s_ind, + /* 130: ri */ screen_xterm_256color_s_ri, + /* 131: sgr */ screen_xterm_256color_s_sgr, + /* 132: hts */ screen_xterm_256color_s_hts, + /* 133: wind */ ABSENT_STRING, + /* 134: ht */ screen_xterm_256color_s_ht, + /* 135: tsl */ ABSENT_STRING, + /* 136: uc */ ABSENT_STRING, + /* 137: hu */ ABSENT_STRING, + /* 138: iprog */ ABSENT_STRING, + /* 139: ka1 */ ABSENT_STRING, + /* 140: ka3 */ ABSENT_STRING, + /* 141: kb2 */ screen_xterm_256color_s_kb2, + /* 142: kc1 */ ABSENT_STRING, + /* 143: kc3 */ ABSENT_STRING, + /* 144: mc5p */ ABSENT_STRING, + /* 145: rmp */ ABSENT_STRING, + /* 146: acsc */ screen_xterm_256color_s_acsc, + /* 147: pln */ ABSENT_STRING, + /* 148: kcbt */ screen_xterm_256color_s_kcbt, + /* 149: smxon */ ABSENT_STRING, + /* 150: rmxon */ ABSENT_STRING, + /* 151: smam */ screen_xterm_256color_s_smam, + /* 152: rmam */ screen_xterm_256color_s_rmam, + /* 153: xonc */ ABSENT_STRING, + /* 154: xoffc */ ABSENT_STRING, + /* 155: enacs */ ABSENT_STRING, + /* 156: smln */ ABSENT_STRING, + /* 157: rmln */ ABSENT_STRING, + /* 158: kbeg */ ABSENT_STRING, + /* 159: kcan */ ABSENT_STRING, + /* 160: kclo */ ABSENT_STRING, + /* 161: kcmd */ ABSENT_STRING, + /* 162: kcpy */ ABSENT_STRING, + /* 163: kcrt */ ABSENT_STRING, + /* 164: kend */ screen_xterm_256color_s_kend, + /* 165: kent */ screen_xterm_256color_s_kent, + /* 166: kext */ ABSENT_STRING, + /* 167: kfnd */ ABSENT_STRING, + /* 168: khlp */ ABSENT_STRING, + /* 169: kmrk */ ABSENT_STRING, + /* 170: kmsg */ ABSENT_STRING, + /* 171: kmov */ ABSENT_STRING, + /* 172: knxt */ ABSENT_STRING, + /* 173: kopn */ ABSENT_STRING, + /* 174: kopt */ ABSENT_STRING, + /* 175: kprv */ ABSENT_STRING, + /* 176: kprt */ ABSENT_STRING, + /* 177: krdo */ ABSENT_STRING, + /* 178: kref */ ABSENT_STRING, + /* 179: krfr */ ABSENT_STRING, + /* 180: krpl */ ABSENT_STRING, + /* 181: krst */ ABSENT_STRING, + /* 182: kres */ ABSENT_STRING, + /* 183: ksav */ ABSENT_STRING, + /* 184: kspd */ ABSENT_STRING, + /* 185: kund */ ABSENT_STRING, + /* 186: kBEG */ ABSENT_STRING, + /* 187: kCAN */ ABSENT_STRING, + /* 188: kCMD */ ABSENT_STRING, + /* 189: kCPY */ ABSENT_STRING, + /* 190: kCRT */ ABSENT_STRING, + /* 191: kDC */ screen_xterm_256color_s_kDC, + /* 192: kDL */ ABSENT_STRING, + /* 193: kslt */ ABSENT_STRING, + /* 194: kEND */ screen_xterm_256color_s_kEND, + /* 195: kEOL */ ABSENT_STRING, + /* 196: kEXT */ ABSENT_STRING, + /* 197: kFND */ ABSENT_STRING, + /* 198: kHLP */ ABSENT_STRING, + /* 199: kHOM */ screen_xterm_256color_s_kHOM, + /* 200: kIC */ ABSENT_STRING, + /* 201: kLFT */ screen_xterm_256color_s_kLFT, + /* 202: kMSG */ ABSENT_STRING, + /* 203: kMOV */ ABSENT_STRING, + /* 204: kNXT */ ABSENT_STRING, + /* 205: kOPT */ ABSENT_STRING, + /* 206: kPRV */ ABSENT_STRING, + /* 207: kPRT */ ABSENT_STRING, + /* 208: kRDO */ ABSENT_STRING, + /* 209: kRPL */ ABSENT_STRING, + /* 210: kRIT */ screen_xterm_256color_s_kRIT, + /* 211: kRES */ ABSENT_STRING, + /* 212: kSAV */ ABSENT_STRING, + /* 213: kSPD */ ABSENT_STRING, + /* 214: kUND */ ABSENT_STRING, + /* 215: rfi */ ABSENT_STRING, + /* 216: kf11 */ screen_xterm_256color_s_kf11, + /* 217: kf12 */ screen_xterm_256color_s_kf12, + /* 218: kf13 */ screen_xterm_256color_s_kf13, + /* 219: kf14 */ screen_xterm_256color_s_kf14, + /* 220: kf15 */ screen_xterm_256color_s_kf15, + /* 221: kf16 */ screen_xterm_256color_s_kf16, + /* 222: kf17 */ screen_xterm_256color_s_kf17, + /* 223: kf18 */ screen_xterm_256color_s_kf18, + /* 224: kf19 */ screen_xterm_256color_s_kf19, + /* 225: kf20 */ screen_xterm_256color_s_kf20, + /* 226: kf21 */ screen_xterm_256color_s_kf21, + /* 227: kf22 */ screen_xterm_256color_s_kf22, + /* 228: kf23 */ screen_xterm_256color_s_kf23, + /* 229: kf24 */ screen_xterm_256color_s_kf24, + /* 230: kf25 */ screen_xterm_256color_s_kf25, + /* 231: kf26 */ screen_xterm_256color_s_kf26, + /* 232: kf27 */ screen_xterm_256color_s_kf27, + /* 233: kf28 */ screen_xterm_256color_s_kf28, + /* 234: kf29 */ screen_xterm_256color_s_kf29, + /* 235: kf30 */ screen_xterm_256color_s_kf30, + /* 236: kf31 */ screen_xterm_256color_s_kf31, + /* 237: kf32 */ screen_xterm_256color_s_kf32, + /* 238: kf33 */ screen_xterm_256color_s_kf33, + /* 239: kf34 */ screen_xterm_256color_s_kf34, + /* 240: kf35 */ screen_xterm_256color_s_kf35, + /* 241: kf36 */ screen_xterm_256color_s_kf36, + /* 242: kf37 */ screen_xterm_256color_s_kf37, + /* 243: kf38 */ screen_xterm_256color_s_kf38, + /* 244: kf39 */ screen_xterm_256color_s_kf39, + /* 245: kf40 */ screen_xterm_256color_s_kf40, + /* 246: kf41 */ screen_xterm_256color_s_kf41, + /* 247: kf42 */ screen_xterm_256color_s_kf42, + /* 248: kf43 */ screen_xterm_256color_s_kf43, + /* 249: kf44 */ screen_xterm_256color_s_kf44, + /* 250: kf45 */ screen_xterm_256color_s_kf45, + /* 251: kf46 */ screen_xterm_256color_s_kf46, + /* 252: kf47 */ screen_xterm_256color_s_kf47, + /* 253: kf48 */ screen_xterm_256color_s_kf48, + /* 254: kf49 */ screen_xterm_256color_s_kf49, + /* 255: kf50 */ screen_xterm_256color_s_kf50, + /* 256: kf51 */ screen_xterm_256color_s_kf51, + /* 257: kf52 */ screen_xterm_256color_s_kf52, + /* 258: kf53 */ screen_xterm_256color_s_kf53, + /* 259: kf54 */ screen_xterm_256color_s_kf54, + /* 260: kf55 */ screen_xterm_256color_s_kf55, + /* 261: kf56 */ screen_xterm_256color_s_kf56, + /* 262: kf57 */ screen_xterm_256color_s_kf57, + /* 263: kf58 */ screen_xterm_256color_s_kf58, + /* 264: kf59 */ screen_xterm_256color_s_kf59, + /* 265: kf60 */ screen_xterm_256color_s_kf60, + /* 266: kf61 */ screen_xterm_256color_s_kf61, + /* 267: kf62 */ screen_xterm_256color_s_kf62, + /* 268: kf63 */ screen_xterm_256color_s_kf63, + /* 269: el1 */ screen_xterm_256color_s_el1, + /* 270: mgc */ ABSENT_STRING, + /* 271: smgl */ ABSENT_STRING, + /* 272: smgr */ ABSENT_STRING, + /* 273: fln */ ABSENT_STRING, + /* 274: sclk */ ABSENT_STRING, + /* 275: dclk */ ABSENT_STRING, + /* 276: rmclk */ ABSENT_STRING, + /* 277: cwin */ ABSENT_STRING, + /* 278: wingo */ ABSENT_STRING, + /* 279: hup */ ABSENT_STRING, + /* 280: dial */ ABSENT_STRING, + /* 281: qdial */ ABSENT_STRING, + /* 282: tone */ ABSENT_STRING, + /* 283: pulse */ ABSENT_STRING, + /* 284: hook */ ABSENT_STRING, + /* 285: pause */ ABSENT_STRING, + /* 286: wait */ ABSENT_STRING, + /* 287: u0 */ ABSENT_STRING, + /* 288: u1 */ ABSENT_STRING, + /* 289: u2 */ ABSENT_STRING, + /* 290: u3 */ ABSENT_STRING, + /* 291: u4 */ ABSENT_STRING, + /* 292: u5 */ ABSENT_STRING, + /* 293: u6 */ screen_xterm_256color_s_u6, + /* 294: u7 */ screen_xterm_256color_s_u7, + /* 295: u8 */ screen_xterm_256color_s_u8, + /* 296: u9 */ screen_xterm_256color_s_u9, + /* 297: op */ screen_xterm_256color_s_op, + /* 298: oc */ ABSENT_STRING, + /* 299: initc */ ABSENT_STRING, + /* 300: initp */ ABSENT_STRING, + /* 301: scp */ ABSENT_STRING, + /* 302: setf */ ABSENT_STRING, + /* 303: setb */ ABSENT_STRING, + /* 304: cpi */ ABSENT_STRING, + /* 305: lpi */ ABSENT_STRING, + /* 306: chr */ ABSENT_STRING, + /* 307: cvr */ ABSENT_STRING, + /* 308: defc */ ABSENT_STRING, + /* 309: swidm */ ABSENT_STRING, + /* 310: sdrfq */ ABSENT_STRING, + /* 311: sitm */ ABSENT_STRING, + /* 312: slm */ ABSENT_STRING, + /* 313: smicm */ ABSENT_STRING, + /* 314: snlq */ ABSENT_STRING, + /* 315: snrmq */ ABSENT_STRING, + /* 316: sshm */ ABSENT_STRING, + /* 317: ssubm */ ABSENT_STRING, + /* 318: ssupm */ ABSENT_STRING, + /* 319: sum */ ABSENT_STRING, + /* 320: rwidm */ ABSENT_STRING, + /* 321: ritm */ ABSENT_STRING, + /* 322: rlm */ ABSENT_STRING, + /* 323: rmicm */ ABSENT_STRING, + /* 324: rshm */ ABSENT_STRING, + /* 325: rsubm */ ABSENT_STRING, + /* 326: rsupm */ ABSENT_STRING, + /* 327: rum */ ABSENT_STRING, + /* 328: mhpa */ ABSENT_STRING, + /* 329: mcud1 */ ABSENT_STRING, + /* 330: mcub1 */ ABSENT_STRING, + /* 331: mcuf1 */ ABSENT_STRING, + /* 332: mvpa */ ABSENT_STRING, + /* 333: mcuu1 */ ABSENT_STRING, + /* 334: porder */ ABSENT_STRING, + /* 335: mcud */ ABSENT_STRING, + /* 336: mcub */ ABSENT_STRING, + /* 337: mcuf */ ABSENT_STRING, + /* 338: mcuu */ ABSENT_STRING, + /* 339: scs */ ABSENT_STRING, + /* 340: smgb */ ABSENT_STRING, + /* 341: smgbp */ ABSENT_STRING, + /* 342: smglp */ ABSENT_STRING, + /* 343: smgrp */ ABSENT_STRING, + /* 344: smgt */ ABSENT_STRING, + /* 345: smgtp */ ABSENT_STRING, + /* 346: sbim */ ABSENT_STRING, + /* 347: scsd */ ABSENT_STRING, + /* 348: rbim */ ABSENT_STRING, + /* 349: rcsd */ ABSENT_STRING, + /* 350: subcs */ ABSENT_STRING, + /* 351: supcs */ ABSENT_STRING, + /* 352: docr */ ABSENT_STRING, + /* 353: zerom */ ABSENT_STRING, + /* 354: csnm */ ABSENT_STRING, + /* 355: kmous */ screen_xterm_256color_s_kmous, + /* 356: minfo */ ABSENT_STRING, + /* 357: reqmp */ ABSENT_STRING, + /* 358: getm */ ABSENT_STRING, + /* 359: setaf */ screen_xterm_256color_s_setaf, + /* 360: setab */ screen_xterm_256color_s_setab, + /* 361: pfxl */ ABSENT_STRING, + /* 362: devt */ ABSENT_STRING, + /* 363: csin */ ABSENT_STRING, + /* 364: s0ds */ ABSENT_STRING, + /* 365: s1ds */ ABSENT_STRING, + /* 366: s2ds */ ABSENT_STRING, + /* 367: s3ds */ ABSENT_STRING, + /* 368: smglr */ ABSENT_STRING, + /* 369: smgtb */ ABSENT_STRING, + /* 370: birep */ ABSENT_STRING, + /* 371: binel */ ABSENT_STRING, + /* 372: bicr */ ABSENT_STRING, + /* 373: colornm */ ABSENT_STRING, + /* 374: defbi */ ABSENT_STRING, + /* 375: endbi */ ABSENT_STRING, + /* 376: setcolor */ ABSENT_STRING, + /* 377: slines */ ABSENT_STRING, + /* 378: dispc */ ABSENT_STRING, + /* 379: smpch */ ABSENT_STRING, + /* 380: rmpch */ ABSENT_STRING, + /* 381: smsc */ ABSENT_STRING, + /* 382: rmsc */ ABSENT_STRING, + /* 383: pctrm */ ABSENT_STRING, + /* 384: scesc */ ABSENT_STRING, + /* 385: scesa */ ABSENT_STRING, + /* 386: ehhlm */ ABSENT_STRING, + /* 387: elhlm */ ABSENT_STRING, + /* 388: elohlm */ ABSENT_STRING, + /* 389: erhlm */ ABSENT_STRING, + /* 390: ethlm */ ABSENT_STRING, + /* 391: evhlm */ ABSENT_STRING, + /* 392: sgr1 */ ABSENT_STRING, + /* 393: slength */ ABSENT_STRING, + /* 394: OTi2 */ ABSENT_STRING, + /* 395: OTrs */ ABSENT_STRING, + /* 396: OTnl */ ABSENT_STRING, + /* 397: OTbc */ ABSENT_STRING, + /* 398: OTko */ ABSENT_STRING, + /* 399: OTma */ ABSENT_STRING, + /* 400: OTG2 */ ABSENT_STRING, + /* 401: OTG3 */ ABSENT_STRING, + /* 402: OTG1 */ ABSENT_STRING, + /* 403: OTG4 */ ABSENT_STRING, + /* 404: OTGR */ ABSENT_STRING, + /* 405: OTGL */ ABSENT_STRING, + /* 406: OTGU */ ABSENT_STRING, + /* 407: OTGD */ ABSENT_STRING, + /* 408: OTGH */ ABSENT_STRING, + /* 409: OTGV */ ABSENT_STRING, + /* 410: OTGC */ ABSENT_STRING, + /* 411: meml */ ABSENT_STRING, + /* 412: memu */ ABSENT_STRING, + /* 413: box1 */ ABSENT_STRING, +}; +static const TERMTYPE2 fallbacks[10] = +{ + /* linux */ + { + linux_alias_data, + (char *)0, /* pointer to string table */ + linux_bool_data, + linux_number_data, + linux_string_data, +#if NCURSES_XNAMES + (char *)0, /* pointer to extended string table */ + (char **)0, /* ...corresponding names */ + 44, /* count total Booleans */ + 39, /* count total Numbers */ + 414, /* count total Strings */ + 0, /* count extensions to Booleans */ + 0, /* count extensions to Numbers */ + 0, /* count extensions to Strings */ +#endif /* NCURSES_XNAMES */ + } +, /* rxvt */ + { + rxvt_alias_data, + (char *)0, /* pointer to string table */ + rxvt_bool_data, + rxvt_number_data, + rxvt_string_data, +#if NCURSES_XNAMES + (char *)0, /* pointer to extended string table */ + (char **)0, /* ...corresponding names */ + 44, /* count total Booleans */ + 39, /* count total Numbers */ + 414, /* count total Strings */ + 0, /* count extensions to Booleans */ + 0, /* count extensions to Numbers */ + 0, /* count extensions to Strings */ +#endif /* NCURSES_XNAMES */ + } +, /* vt100 */ + { + vt100_alias_data, + (char *)0, /* pointer to string table */ + vt100_bool_data, + vt100_number_data, + vt100_string_data, +#if NCURSES_XNAMES + (char *)0, /* pointer to extended string table */ + (char **)0, /* ...corresponding names */ + 44, /* count total Booleans */ + 39, /* count total Numbers */ + 414, /* count total Strings */ + 0, /* count extensions to Booleans */ + 0, /* count extensions to Numbers */ + 0, /* count extensions to Strings */ +#endif /* NCURSES_XNAMES */ + } +, /* xterm */ + { + xterm_alias_data, + (char *)0, /* pointer to string table */ + xterm_bool_data, + xterm_number_data, + xterm_string_data, +#if NCURSES_XNAMES + (char *)0, /* pointer to extended string table */ + (char **)0, /* ...corresponding names */ + 44, /* count total Booleans */ + 39, /* count total Numbers */ + 414, /* count total Strings */ + 0, /* count extensions to Booleans */ + 0, /* count extensions to Numbers */ + 0, /* count extensions to Strings */ +#endif /* NCURSES_XNAMES */ + } +, /* xterm-256color */ + { + xterm_256color_alias_data, + (char *)0, /* pointer to string table */ + xterm_256color_bool_data, + xterm_256color_number_data, + xterm_256color_string_data, +#if NCURSES_XNAMES + (char *)0, /* pointer to extended string table */ + (char **)0, /* ...corresponding names */ + 44, /* count total Booleans */ + 39, /* count total Numbers */ + 414, /* count total Strings */ + 0, /* count extensions to Booleans */ + 0, /* count extensions to Numbers */ + 0, /* count extensions to Strings */ +#endif /* NCURSES_XNAMES */ + } +, /* screen */ + { + screen_alias_data, + (char *)0, /* pointer to string table */ + screen_bool_data, + screen_number_data, + screen_string_data, +#if NCURSES_XNAMES + (char *)0, /* pointer to extended string table */ + (char **)0, /* ...corresponding names */ + 44, /* count total Booleans */ + 39, /* count total Numbers */ + 414, /* count total Strings */ + 0, /* count extensions to Booleans */ + 0, /* count extensions to Numbers */ + 0, /* count extensions to Strings */ +#endif /* NCURSES_XNAMES */ + } +, /* screen.linux */ + { + screen_linux_alias_data, + (char *)0, /* pointer to string table */ + screen_linux_bool_data, + screen_linux_number_data, + screen_linux_string_data, +#if NCURSES_XNAMES + (char *)0, /* pointer to extended string table */ + (char **)0, /* ...corresponding names */ + 44, /* count total Booleans */ + 39, /* count total Numbers */ + 414, /* count total Strings */ + 0, /* count extensions to Booleans */ + 0, /* count extensions to Numbers */ + 0, /* count extensions to Strings */ +#endif /* NCURSES_XNAMES */ + } +, /* screen.rxvt */ + { + screen_rxvt_alias_data, + (char *)0, /* pointer to string table */ + screen_rxvt_bool_data, + screen_rxvt_number_data, + screen_rxvt_string_data, +#if NCURSES_XNAMES + (char *)0, /* pointer to extended string table */ + (char **)0, /* ...corresponding names */ + 44, /* count total Booleans */ + 39, /* count total Numbers */ + 414, /* count total Strings */ + 0, /* count extensions to Booleans */ + 0, /* count extensions to Numbers */ + 0, /* count extensions to Strings */ +#endif /* NCURSES_XNAMES */ + } +, /* screen.xterm-new */ + { + screen_xterm_xfree86_alias_data, + (char *)0, /* pointer to string table */ + screen_xterm_xfree86_bool_data, + screen_xterm_xfree86_number_data, + screen_xterm_xfree86_string_data, +#if NCURSES_XNAMES + (char *)0, /* pointer to extended string table */ + (char **)0, /* ...corresponding names */ + 44, /* count total Booleans */ + 39, /* count total Numbers */ + 414, /* count total Strings */ + 0, /* count extensions to Booleans */ + 0, /* count extensions to Numbers */ + 0, /* count extensions to Strings */ +#endif /* NCURSES_XNAMES */ + } +, /* screen.xterm-256color */ + { + screen_xterm_256color_alias_data, + (char *)0, /* pointer to string table */ + screen_xterm_256color_bool_data, + screen_xterm_256color_number_data, + screen_xterm_256color_string_data, +#if NCURSES_XNAMES + (char *)0, /* pointer to extended string table */ + (char **)0, /* ...corresponding names */ + 44, /* count total Booleans */ + 39, /* count total Numbers */ + 414, /* count total Strings */ + 0, /* count extensions to Booleans */ + 0, /* count extensions to Numbers */ + 0, /* count extensions to Strings */ +#endif /* NCURSES_XNAMES */ + } +}; + +NCURSES_EXPORT(const TERMTYPE2 *) +_nc_fallback2 (const char *name GCC_UNUSED) +{ + const TERMTYPE2 *tp; + + for (tp = fallbacks; + tp < fallbacks + sizeof(fallbacks)/sizeof(TERMTYPE2); + tp++) { + if (_nc_name_match(tp->term_names, name, "|")) { + return(tp); + } + } + return((const TERMTYPE2 *)0); +} + +#if NCURSES_EXT_NUMBERS +#undef _nc_fallback + +/* + * This entrypoint is used by tack. + */ +NCURSES_EXPORT(const TERMTYPE *) +_nc_fallback (const char *name) +{ + const TERMTYPE2 *tp = _nc_fallback2(name); + const TERMTYPE *result = 0; + if (tp != 0) { + static TERMTYPE temp; + _nc_export_termtype2(&temp, tp); + result = &temp; + } + return result; +} +#endif diff --git a/contrib/depends/patches/openssl/fix_arflags.patch b/contrib/depends/patches/openssl/fix_arflags.patch new file mode 100644 index 000000000..2d2900d80 --- /dev/null +++ b/contrib/depends/patches/openssl/fix_arflags.patch @@ -0,0 +1,24 @@ +--- Makefile.org.O 2019-02-26 14:20:20.000000000 +0000 ++++ Makefile.org 2019-11-15 13:05:54.370086856 +0000 +@@ -63,8 +63,8 @@ + PEX_LIBS= + EX_LIBS= + EXE_EXT= +-ARFLAGS= +-AR=ar $(ARFLAGS) r ++ARFLAGS= r ++AR=ar $(ARFLAGS) + RANLIB= ranlib + RC= windres + NM= nm +--- Configure.O 2019-02-26 14:20:20.000000000 +0000 ++++ Configure 2019-11-16 07:43:14.933990774 +0000 +@@ -1251,7 +1251,7 @@ + my $shared_extension = $fields[$idx_shared_extension]; + my $ranlib = $ENV{'RANLIB'} || $fields[$idx_ranlib]; + my $ar = $ENV{'AR'} || "ar"; +-my $arflags = $fields[$idx_arflags]; ++my $arflags = $ENV{'ARFLAGS'} || $fields[$idx_arflags]; + my $windres = $ENV{'RC'} || $ENV{'WINDRES'} || "windres"; + my $multilib = $fields[$idx_multilib]; + diff --git a/contrib/depends/patches/qt/fix_qt_pkgconfig.patch b/contrib/depends/patches/qt/fix_qt_pkgconfig.patch new file mode 100644 index 000000000..34302a9f2 --- /dev/null +++ b/contrib/depends/patches/qt/fix_qt_pkgconfig.patch @@ -0,0 +1,11 @@ +--- old/qtbase/mkspecs/features/qt_module.prf ++++ new/qtbase/mkspecs/features/qt_module.prf +@@ -245,7 +245,7 @@ + load(qt_targets) + + # this builds on top of qt_common +-!internal_module:!lib_bundle:if(unix|mingw) { ++unix|mingw { + CONFIG += create_pc + QMAKE_PKGCONFIG_DESTDIR = pkgconfig + host_build: \ diff --git a/contrib/depends/patches/qt/pidlist_absolute.patch b/contrib/depends/patches/qt/pidlist_absolute.patch new file mode 100644 index 000000000..c79282417 --- /dev/null +++ b/contrib/depends/patches/qt/pidlist_absolute.patch @@ -0,0 +1,37 @@ +diff -dur old/qtbase/src/plugins/platforms/windows/qwindowscontext.h new/qtbase/src/plugins/platforms/windows/qwindowscontext.h +--- old/qtbase/src/plugins/platforms/windows/qwindowscontext.h ++++ new/qtbase/src/plugins/platforms/windows/qwindowscontext.h +@@ -136,10 +136,18 @@ + inline void init(); + + typedef HRESULT (WINAPI *SHCreateItemFromParsingName)(PCWSTR, IBindCtx *, const GUID&, void **); ++#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) ++ typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, ITEMIDLIST **); ++#else + typedef HRESULT (WINAPI *SHGetKnownFolderIDList)(const GUID &, DWORD, HANDLE, PIDLIST_ABSOLUTE *); ++#endif + typedef HRESULT (WINAPI *SHGetStockIconInfo)(int , int , _SHSTOCKICONINFO *); + typedef HRESULT (WINAPI *SHGetImageList)(int, REFIID , void **); ++#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) ++ typedef HRESULT (WINAPI *SHCreateItemFromIDList)(const ITEMIDLIST *, REFIID, void **); ++#else + typedef HRESULT (WINAPI *SHCreateItemFromIDList)(PCIDLIST_ABSOLUTE, REFIID, void **); ++#endif + + SHCreateItemFromParsingName sHCreateItemFromParsingName; + SHGetKnownFolderIDList sHGetKnownFolderIDList; +diff -dur old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +--- old/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp ++++ new/qtbase/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +@@ -1016,7 +1016,11 @@ + qWarning() << __FUNCTION__ << ": Invalid CLSID: " << url.path(); + return Q_NULLPTR; + } ++#if defined(Q_CC_MINGW) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 3) ++ ITEMIDLIST *idList; ++#else + PIDLIST_ABSOLUTE idList; ++#endif + HRESULT hr = QWindowsContext::shell32dll.sHGetKnownFolderIDList(uuid, 0, 0, &idList); + if (FAILED(hr)) { + qErrnoWarning("%s: SHGetKnownFolderIDList(%s)) failed", __FUNCTION__, qPrintable(url.toString())); diff --git a/contrib/depends/patches/qt/qfixed-coretext.patch b/contrib/depends/patches/qt/qfixed-coretext.patch new file mode 100644 index 000000000..aa56f1e1d --- /dev/null +++ b/contrib/depends/patches/qt/qfixed-coretext.patch @@ -0,0 +1,34 @@ +From dbdd5f0ffbce52c8b789ed09f1aa3f1da6c02e23 Mon Sep 17 00:00:00 2001 +From: Gabriel de Dietrich +Date: Fri, 30 Mar 2018 11:58:16 -0700 +Subject: [PATCH] QCoreTextFontEngine: Fix build with Xcode 9.3 + +Apple LLVM version 9.1.0 (clang-902.0.39.1) + +Error message: + +.../qfontengine_coretext.mm:827:20: error: qualified reference to + 'QFixed' is a constructor name rather than a type in this context + return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont))); + +Change-Id: Iebe26b3b087a16b10664208fc8851cbddb47f043 +Reviewed-by: Konstantin Ritt +--- + src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git old/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm new/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +index 25ff69d877d..98b753eff96 100644 +--- old/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm ++++ new/qtbase/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +@@ -824,7 +824,7 @@ void QCoreTextFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, gl + + QFixed QCoreTextFontEngine::emSquareSize() const + { +- return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont))); ++ return QFixed(int(CTFontGetUnitsPerEm(ctfont))); + } + + QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const +-- +2.16.3 \ No newline at end of file diff --git a/contrib/depends/patches/sodium/disable-glibc-getrandom-getentropy.patch b/contrib/depends/patches/sodium/disable-glibc-getrandom-getentropy.patch new file mode 100644 index 000000000..2f07c1057 --- /dev/null +++ b/contrib/depends/patches/sodium/disable-glibc-getrandom-getentropy.patch @@ -0,0 +1,25 @@ +diff --git a/configure.ac b/configure.ac +index 9e2de27c..0fa85c2d 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -807,6 +807,10 @@ AS_IF([test "x$EMSCRIPTEN" = "x"],[ + # include + #endif + ]], [[ ++#ifdef __linux__ ++# error getrandom() is currently disabled on Linux to support glibc < 2.25 ++#endif ++ + unsigned char buf; + (void) getrandom((void *) &buf, 1U, 0U); + ]])], +@@ -825,6 +829,9 @@ unsigned char buf; + # include + #endif + ]], [[ ++#ifdef __linux__ ++# error getentropy() is currently disabled on Linux to support glibc < 2.25 ++#endif + #ifdef __APPLE__ + # error getentropy() is currently disabled on Apple operating systems + #endif diff --git a/contrib/depends/patches/sodium/fix-whitespace.patch b/contrib/depends/patches/sodium/fix-whitespace.patch new file mode 100644 index 000000000..c3d3af0b4 --- /dev/null +++ b/contrib/depends/patches/sodium/fix-whitespace.patch @@ -0,0 +1,13 @@ +diff --git a/configure b/configure +index b29f769..ca008ae 100755 +--- a/configure ++++ b/configure +@@ -591,7 +591,7 @@ MAKEFLAGS= + PACKAGE_NAME='libsodium' + PACKAGE_TARNAME='libsodium' + PACKAGE_VERSION='1.0.18' +-PACKAGE_STRING='libsodium 1.0.18' ++PACKAGE_STRING='libsodium' + PACKAGE_BUGREPORT='https://github.com/jedisct1/libsodium/issues' + PACKAGE_URL='https://github.com/jedisct1/libsodium' + diff --git a/contrib/depends/patches/unwind/fix_obj_order.patch b/contrib/depends/patches/unwind/fix_obj_order.patch new file mode 100644 index 000000000..374a9f04a --- /dev/null +++ b/contrib/depends/patches/unwind/fix_obj_order.patch @@ -0,0 +1,11 @@ +--- config/ltmain.sh.O 2017-01-13 16:00:54.000000000 +0000 ++++ config/ltmain.sh 2019-11-17 06:46:51.994402494 +0000 +@@ -7957,6 +7957,8 @@ + esac + done + fi ++ oldobjs=`for obj in $oldobjs; do echo $obj; done | sort` ++ oldobjs=" `echo $oldobjs`" + eval cmds=\"$old_archive_cmds\" + + func_len " $cmds" diff --git a/contrib/depends/patches/zeromq/9114d3957725acd34aa8b8d011585812f3369411.patch b/contrib/depends/patches/zeromq/9114d3957725acd34aa8b8d011585812f3369411.patch new file mode 100644 index 000000000..f704b3d94 --- /dev/null +++ b/contrib/depends/patches/zeromq/9114d3957725acd34aa8b8d011585812f3369411.patch @@ -0,0 +1,22 @@ +From 9114d3957725acd34aa8b8d011585812f3369411 Mon Sep 17 00:00:00 2001 +From: Jeroen Ooms +Date: Tue, 20 Oct 2015 13:10:38 +0200 +Subject: [PATCH] enable static libraries on mingw + +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 393505b..e92131a 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -265,7 +265,7 @@ case "${host_os}" in + libzmq_dso_visibility="no" + + if test "x$enable_static" = "xyes"; then +- AC_MSG_ERROR([Building static libraries is not supported under MinGW32]) ++ CPPFLAGS="-DZMQ_STATIC" + fi + + # Set FD_SETSIZE to 1024 \ No newline at end of file diff --git a/contrib/depends/patches/zeromq/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch b/contrib/depends/patches/zeromq/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch new file mode 100644 index 000000000..9aff2c179 --- /dev/null +++ b/contrib/depends/patches/zeromq/9e6745c12e0b100cd38acecc16ce7db02905e27c.patch @@ -0,0 +1,22 @@ +From 9e6745c12e0b100cd38acecc16ce7db02905e27c Mon Sep 17 00:00:00 2001 +From: David Millard +Date: Tue, 10 May 2016 13:53:53 -0700 +Subject: [PATCH] Fix autotools for static MinGW builds + +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 5a0fa14..def6ea7 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -259,7 +259,7 @@ case "${host_os}" in + libzmq_dso_visibility="no" + + if test "x$enable_static" = "xyes"; then +- CPPFLAGS="-DZMQ_STATIC" ++ CPPFLAGS="-DZMQ_STATIC $CPPFLAGS" + fi + + # Set FD_SETSIZE to 1024 \ No newline at end of file diff --git a/contrib/depends/patches/zeromq/ffe62d3398d5e0191f554f61049aa7ec9fc892ae.patch b/contrib/depends/patches/zeromq/ffe62d3398d5e0191f554f61049aa7ec9fc892ae.patch new file mode 100644 index 000000000..a532df1b6 --- /dev/null +++ b/contrib/depends/patches/zeromq/ffe62d3398d5e0191f554f61049aa7ec9fc892ae.patch @@ -0,0 +1,38 @@ +From ffe62d3398d5e0191f554f61049aa7ec9fc892ae Mon Sep 17 00:00:00 2001 +From: Gregory Lemercier +Date: Sun, 7 Oct 2018 18:06:54 +0200 +Subject: [PATCH] Fix build on arm64 architectures with some strict compilers + +This patch fixes an issue that occurs on 64-bit architetures under +strict compiler rules. The code initially checked that the received +size stored in 'uint64_t' was not bigger than the max value of a +'size_t' variable, which is legitimate on 32-bit architectures where +'size_t' variables are stored on 32 bits. On 64-bit architectures, +this test no longer makes sense since 'uint64_t' and 'size_t' types +have the same size. The issue is fixed by ignoring this portion +of code when built for arm64. +--- + src/v1_decoder.cpp | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/v1_decoder.cpp b/src/v1_decoder.cpp +index b002dc9d..2c8c97a7 100644 +--- a/src/v1_decoder.cpp ++++ b/src/v1_decoder.cpp +@@ -114,11 +114,13 @@ int zmq::v1_decoder_t::eight_byte_size_ready () + return -1; + } + ++#ifndef __aarch64__ + // Message size must fit within range of size_t data type. + if (payload_length - 1 > std::numeric_limits ::max ()) { + errno = EMSGSIZE; + return -1; + } ++#endif + + const size_t msg_size = static_cast (payload_length - 1); + +-- +2.20.1 + diff --git a/contrib/depends/protobuf.mk b/contrib/depends/protobuf.mk new file mode 100644 index 000000000..54d3fd924 --- /dev/null +++ b/contrib/depends/protobuf.mk @@ -0,0 +1,29 @@ +package=protobuf +$(package)_version=$(native_$(package)_version) +$(package)_download_path=$(native_$(package)_download_path) +$(package)_file_name=$(native_$(package)_file_name) +$(package)_sha256_hash=$(native_$(package)_sha256_hash) +$(package)_dependencies=native_$(package) +$(package)_cxxflags=-std=c++11 + +define $(package)_set_vars + $(package)_config_opts=--disable-shared --with-protoc=$(build_prefix)/bin/protoc + $(package)_config_opts_linux=--with-pic +endef + +define $(package)_config_cmds + $($(package)_autoconf) +endef + +define $(package)_build_cmds + $(MAKE) -C src libprotobuf.la +endef + +define $(package)_stage_cmds + $(MAKE) DESTDIR=$($(package)_staging_dir) -C src install-libLTLIBRARIES install-nobase_includeHEADERS &&\ + $(MAKE) DESTDIR=$($(package)_staging_dir) install-pkgconfigDATA +endef + +define $(package)_postprocess_cmds + rm lib/libprotoc.a +endef diff --git a/contrib/depends/toolchain.cmake.in b/contrib/depends/toolchain.cmake.in new file mode 100644 index 000000000..2634423ab --- /dev/null +++ b/contrib/depends/toolchain.cmake.in @@ -0,0 +1,158 @@ +# Set the system name to one of Android, Darwin, FreeBSD, Linux, or Windows +SET(CMAKE_SYSTEM_NAME @depends@) +SET(CMAKE_BUILD_TYPE @release_type@) + +OPTION(STATIC "Link libraries statically" ON) +OPTION(TREZOR_DEBUG "Main trezor debugging switch" OFF) +OPTION(BUILD_TESTS "Build tests." OFF) + +SET(STATIC ON) +SET(UNBOUND_STATIC ON) +SET(ARCH "default") + +SET(BUILD_TESTS @build_tests@) +SET(TREZOR_DEBUG @build_tests@) + +# where is the target environment +SET(CMAKE_FIND_ROOT_PATH @prefix@ /usr) + +SET(ENV{PKG_CONFIG_PATH} @prefix@/lib/pkgconfig) + +SET(Readline_ROOT_DIR @prefix@) +SET(Readline_INCLUDE_DIR @prefix@/include) +SET(Readline_LIBRARY @prefix@/lib/libreadline.a) +SET(Terminfo_LIBRARY @prefix@/lib/libtinfo.a) + +SET(LRELEASE_PATH @prefix@/native/bin CACHE FILEPATH "path to lrelease" FORCE) + +if(NOT CMAKE_SYSTEM_NAME STREQUAL "Android") +SET(LIBUNWIND_INCLUDE_DIR @prefix@/include) +SET(LIBUNWIND_LIBRARIES @prefix@/lib/libunwind.a) +SET(LIBUNWIND_LIBRARY_DIRS @prefix@/lib) + +if(NOT CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") +SET(LIBUSB-1.0_LIBRARY @prefix@/lib/libusb-1.0.a) +SET(LIBUDEV_LIBRARY @prefix@/lib/libudev.a) + +SET(Protobuf_FOUND 1) +SET(Protobuf_PROTOC_EXECUTABLE @prefix@/native/bin/protoc CACHE FILEPATH "Path to the native protoc") +SET(Protobuf_INCLUDE_DIR @prefix@/include CACHE PATH "Protobuf include dir") +SET(Protobuf_INCLUDE_DIRS @prefix@/include CACHE PATH "Protobuf include dir") +SET(Protobuf_LIBRARY @prefix@/lib/libprotobuf.a CACHE FILEPATH "Protobuf library") +endif() + +endif() + +SET(ZMQ_INCLUDE_PATH @prefix@/include) +SET(ZMQ_LIB @prefix@/lib/libzmq.a) + +SET(Boost_IGNORE_SYSTEM_PATH ON) +SET(BOOST_ROOT @prefix@) +SET(BOOST_INCLUDEDIR @prefix@/include) +SET(BOOST_LIBRARYDIR @prefix@/lib) +SET(Boost_IGNORE_SYSTEM_PATHS_DEFAULT OFF) +SET(Boost_NO_SYSTEM_PATHS ON) +SET(Boost_USE_STATIC_LIBS ON) +SET(Boost_USE_STATIC_RUNTIME ON) + +SET(OpenSSL_DIR @prefix@/lib) +SET(ARCHITECTURE @arch@) + +# for libraries and headers in the target directories +set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) # Find programs on host +set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) # Find libs in target +set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) # Find includes in target + +set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR} CACHE STRING "" FORCE) + +# specify the cross compiler to be used. Darwin uses clang provided by the SDK. +if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + SET(CMAKE_C_COMPILER @prefix@/native/bin/clang) + SET(CMAKE_C_COMPILER_TARGET x86_64-apple-darwin11) + SET(CMAKE_CXX_COMPILER @prefix@/native/bin/clang++ -stdlib=libc++) + SET(CMAKE_CXX_COMPILER_TARGET x86_64-apple-darwin11) + SET(_CMAKE_TOOLCHAIN_PREFIX x86_64-apple-darwin11-) + SET(APPLE True) + SET(BUILD_TAG "mac-x64") + SET(BUILD_64 ON) + SET(BREW OFF) + SET(PORT OFF) + SET(CMAKE_OSX_SYSROOT "@sdk@/MacOSX10.11.sdk/") + SET(CMAKE_OSX_DEPLOYMENT_TARGET "10.08") + SET(CMAKE_CXX_STANDARD 11) + SET(CMAKE_OSX_ARCHITECTURES "x86_64") + SET(LLVM_ENABLE_PIC OFF) + SET(LLVM_ENABLE_PIE OFF) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") + SET(ANDROID TRUE) + if(ARCHITECTURE STREQUAL "arm") + SET(CMAKE_ANDROID_ARCH_ABI "armeabi-v7a") + SET(CMAKE_SYSTEM_PROCESSOR "armv7-a") + SET(CMAKE_ANDROID_ARM_MODE ON) + SET(CMAKE_C_COMPILER_TARGET arm-linux-androideabi) + SET(CMAKE_CXX_COMPILER_TARGET arm-linux-androideabi) + SET(_CMAKE_TOOLCHAIN_PREFIX arm-linux-androideabi-) + elseif(ARCHITECTURE STREQUAL "aarch64") + SET(CMAKE_ANDROID_ARCH_ABI "arm64-v8a") + SET(CMAKE_SYSTEM_PROCESSOR "aarch64") + endif() + SET(CMAKE_ANDROID_STANDALONE_TOOLCHAIN @prefix@/native) + SET(CMAKE_C_COMPILER "${_CMAKE_TOOLCHAIN_PREFIX}clang") + SET(CMAKE_CXX_COMPILER "${_CMAKE_TOOLCHAIN_PREFIX}clang++") +else() + SET(CMAKE_C_COMPILER @CC@) + SET(CMAKE_CXX_COMPILER @CXX@) +endif() + +if(ARCHITECTURE STREQUAL "arm") + set(ARCH "armv7-a") + set(ARM ON) + set(ARM_ID "armv7-a") + set(BUILD_64 OFF) + set(CMAKE_BUILD_TYPE release) + if(ANDROID) + set(BUILD_TAG "android-armv7") + else() + set(BUILD_TAG "linux-armv7") + endif() + set(ARM7) +elseif(ARCHITECTURE STREQUAL "aarch64") + set(ARCH "armv8-a") + set(ARM ON) + set(ARM_ID "armv8-a") + if(ANDROID) + set(BUILD_TAG "android-armv8") + else() + set(BUILD_TAG "linux-armv8") + endif() + set(BUILD_64 ON) +endif() + +if(ARCHITECTURE STREQUAL "riscv64") + set(NO_AES ON) + set(ARCH "rv64imafdc") +endif() + +if(ARCHITECTURE STREQUAL "i686") + SET(ARCH_ID "i386") + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(BUILD_TAG "linux-x86") + SET(LINUX_32 ON) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(BUILD_TAG "win-x32") + endif() +endif() + +if(ARCHITECTURE STREQUAL "x86_64") + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(BUILD_TAG "linux-x64") + elseif(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + set(BUILD_TAG "freebsd-x64") + elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set(BUILD_TAG "win-x64") + endif() + SET(ARCH_ID "x86_64") +endif() + +#Create a new global cmake flag that indicates building with depends +set (DEPENDS true) diff --git a/contrib/epee/include/math_helper.h b/contrib/epee/include/math_helper.h index ef839f609..4cda875da 100644 --- a/contrib/epee/include/math_helper.h +++ b/contrib/epee/include/math_helper.h @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include diff --git a/contrib/epee/include/misc_os_dependent.h b/contrib/epee/include/misc_os_dependent.h index ffe575501..0d09683d6 100644 --- a/contrib/epee/include/misc_os_dependent.h +++ b/contrib/epee/include/misc_os_dependent.h @@ -24,7 +24,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // #ifdef _WIN32 -#include +#include #endif #ifdef WIN32 diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h index da7d0a098..221f3ca89 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -257,6 +257,11 @@ namespace net_utils m_current_speed_up(0) {} + connection_context_base(const connection_context_base& a): connection_context_base() + { + set_details(a.m_connection_id, a.m_remote_address, a.m_is_income); + } + connection_context_base& operator=(const connection_context_base& a) { set_details(a.m_connection_id, a.m_remote_address, a.m_is_income); diff --git a/contrib/epee/include/storages/portable_storage_val_converters.h b/contrib/epee/include/storages/portable_storage_val_converters.h index 36bb28627..13380e235 100644 --- a/contrib/epee/include/storages/portable_storage_val_converters.h +++ b/contrib/epee/include/storages/portable_storage_val_converters.h @@ -68,6 +68,7 @@ POP_WARNINGS PUSH_WARNINGS DISABLE_VS_WARNINGS(4018) DISABLE_CLANG_WARNING(tautological-constant-out-of-range-compare) +DISABLE_GCC_AND_CLANG_WARNING(sign-compare) CHECK_AND_ASSERT_THROW_MES(from <= std::numeric_limits::max(), "uint value overhead: try to set value " << from << " to type " << typeid(to_type).name() << " with max possible value = " << std::numeric_limits::max()); to = static_cast(from); POP_WARNINGS diff --git a/external/boost/archive/portable_binary_archive.hpp b/external/boost/archive/portable_binary_archive.hpp index e940c5b9e..7ae01a225 100644 --- a/external/boost/archive/portable_binary_archive.hpp +++ b/external/boost/archive/portable_binary_archive.hpp @@ -22,7 +22,7 @@ #endif #include -#include +#include #include diff --git a/external/boost/archive/portable_binary_iarchive.hpp b/external/boost/archive/portable_binary_iarchive.hpp index 7792b530d..bd19599f3 100644 --- a/external/boost/archive/portable_binary_iarchive.hpp +++ b/external/boost/archive/portable_binary_iarchive.hpp @@ -226,7 +226,7 @@ class portable_binary_iarchive : #include #include -#include +#include #include #include @@ -252,12 +252,12 @@ portable_binary_iarchive::load_impl(boost::intmax_t & l, char maxsize){ ); char * cptr = reinterpret_cast(& l); - #ifdef BOOST_BIG_ENDIAN + #if BOOST_ENDIAN_BIG_BYTE cptr += (sizeof(boost::intmax_t) - size); #endif this->primitive_base_t::load_binary(cptr, size); - #ifdef BOOST_BIG_ENDIAN + #if BOOST_ENDIAN_BIG_BYTE if(m_flags & endian_little) #else if(m_flags & endian_big) diff --git a/external/boost/archive/portable_binary_oarchive.hpp b/external/boost/archive/portable_binary_oarchive.hpp index e2dcb9456..783c7f7c9 100644 --- a/external/boost/archive/portable_binary_oarchive.hpp +++ b/external/boost/archive/portable_binary_oarchive.hpp @@ -221,7 +221,7 @@ class portable_binary_oarchive : // See http://www.boost.org for updates, documentation, and revision history. #include -#include +#include namespace boost { namespace archive { @@ -258,7 +258,7 @@ portable_binary_oarchive::save_impl( else ll = l; char * cptr = reinterpret_cast(& ll); - #ifdef BOOST_BIG_ENDIAN + #if BOOST_ENDIAN_BIG_BYTE cptr += (sizeof(boost::intmax_t) - size); if(m_flags & endian_little) reverse_bytes(size, cptr); diff --git a/external/unbound b/external/unbound index 7f2396795..0f6c0579d 160000 --- a/external/unbound +++ b/external/unbound @@ -1 +1 @@ -Subproject commit 7f23967954736dcaa366806b9eaba7e2bdfede11 +Subproject commit 0f6c0579d66b65f86066e30e7876105ba2775ef4 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b5467ee84..0f327f098 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -116,6 +116,7 @@ add_subdirectory(checkpoints) add_subdirectory(cryptonote_basic) add_subdirectory(cryptonote_core) add_subdirectory(multisig) +add_subdirectory(safex) if(NOT IOS) add_subdirectory(blockchain_db) endif() diff --git a/src/advancedwallet/advancedwallet.cpp b/src/advancedwallet/advancedwallet.cpp index 925b5ed7c..a73429f22 100644 --- a/src/advancedwallet/advancedwallet.cpp +++ b/src/advancedwallet/advancedwallet.cpp @@ -62,7 +62,6 @@ #include "rapidjson/document.h" #include "common/json_util.h" #include "ringct/rctSigs.h" -#include "multisig/multisig.h" #include "wallet/wallet_args.h" #include "version.h" #include @@ -88,7 +87,6 @@ typedef cryptonote::advanced_wallet sw; #define EXTENDED_LOGS_FILE "wallet_details.log" -#define MULTISIG_ACTIVE 0 //multisig is not yet implemented for tokens #define BLACKBALL_ACTIVE 0 //blackball is not yet needed, we are starting blokcchain from scratch #define MIN_RING_SIZE 7 // Used to inform user about min ring size -- does not track actual protocol @@ -128,12 +126,10 @@ namespace const command_line::arg_descriptor arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""}; const command_line::arg_descriptor arg_generate_from_spend_key = {"generate-from-spend-key", sw::tr("Generate deterministic wallet from spend key"), ""}; const command_line::arg_descriptor arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""}; - const command_line::arg_descriptor arg_generate_from_multisig_keys = {"generate-from-multisig-keys", sw::tr("Generate a master wallet from multisig wallet keys"), ""}; const auto arg_generate_from_json = wallet_args::arg_generate_from_json(); const command_line::arg_descriptor arg_mnemonic_language = {"mnemonic-language", sw::tr("Language for mnemonic"), ""}; const command_line::arg_descriptor arg_electrum_seed = {"electrum-seed", sw::tr("Specify Electrum seed for wallet recovery/creation"), ""}; const command_line::arg_descriptor arg_restore_deterministic_wallet = {"restore-deterministic-wallet", sw::tr("Recover wallet using Electrum-style mnemonic seed"), false}; - const command_line::arg_descriptor arg_restore_multisig_wallet = {"restore-multisig-wallet", sw::tr("Recover multisig wallet using Electrum-style mnemonic seed"), false}; const command_line::arg_descriptor arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false}; const command_line::arg_descriptor arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false}; const command_line::arg_descriptor arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false}; @@ -426,7 +422,7 @@ namespace { fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what(); } - catch (const tools::error::not_enough_unlocked_money& e) + catch (const tools::error::not_enough_unlocked_cash& e) { LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") % print_money(e.available()) % @@ -442,7 +438,7 @@ namespace fail_msg_writer() << tr("Not enough tokens in unlocked balance"); warn_of_possible_attack = false; } - catch (const tools::error::not_enough_money& e) + catch (const tools::error::not_enough_cash& e) { LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") % print_money(e.available()) % @@ -502,12 +498,6 @@ namespace LOG_ERROR("unknown transfer error: " << e.to_string()); fail_msg_writer() << tr("unknown transfer error: ") << e.what(); } - catch (const tools::error::multisig_export_needed& e) - { - LOG_ERROR("Multisig error: " << e.to_string()); - fail_msg_writer() << tr("Multisig error: ") << e.what(); - warn_of_possible_attack = false; - } catch (const tools::error::wallet_internal_error& e) { LOG_ERROR("internal error: " << e.to_string()); @@ -621,7 +611,7 @@ bool advanced_wallet::print_seed(bool encrypted) { bool success = false; std::string seed; - bool ready, multisig; + bool ready; if (m_wallet->key_on_device()) { @@ -635,16 +625,7 @@ bool advanced_wallet::print_seed(bool encrypted) } if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } - multisig = m_wallet->multisig(&ready); - if (multisig) - { - if (!ready) - { - fail_msg_writer() << tr("wallet is multisig but not yet finalized"); - return true; - } - } - else if (!m_wallet->is_deterministic()) + if (!m_wallet->is_deterministic()) { fail_msg_writer() << tr("wallet is non-deterministic and has no seed"); return true; @@ -659,9 +640,7 @@ bool advanced_wallet::print_seed(bool encrypted) seed_pass = pwd_container->password(); } - if (multisig) - success = m_wallet->get_multisig_seed(seed, seed_pass); - else if (m_wallet->is_deterministic()) + if (m_wallet->is_deterministic()) success = m_wallet->get_seed(seed, seed_pass); if (success) @@ -692,11 +671,6 @@ bool advanced_wallet::seed_set_language(const std::vector &args/* = fail_msg_writer() << tr("command not supported by HW wallet"); return true; } - if (m_wallet->multisig()) - { - fail_msg_writer() << tr("wallet is multisig and has no seed"); - return true; - } if (m_wallet->watch_only()) { fail_msg_writer() << tr("wallet is watch-only and has no seed"); @@ -818,516 +792,8 @@ bool advanced_wallet::print_fee_info(const std::vector &args/* = st return true; } -bool advanced_wallet::prepare_multisig(const std::vector &args) -{ - if (m_wallet->key_on_device()) - { - fail_msg_writer() << tr("command not supported by HW wallet"); - return true; - } - if (m_wallet->multisig()) - { - fail_msg_writer() << tr("This wallet is already multisig"); - return true; - } - if (m_wallet->watch_only()) - { - fail_msg_writer() << tr("wallet is watch-only and cannot be made multisig"); - return true; - } - - if(m_wallet->get_num_transfer_details()) - { - fail_msg_writer() << tr("This wallet has been used before, please use a new wallet to create a multisig wallet"); - return true; - } - - const auto orig_pwd_container = get_and_verify_password(); - if(orig_pwd_container == boost::none) - { - fail_msg_writer() << tr("Your password is incorrect."); - return true; - } - - std::string multisig_info = m_wallet->get_multisig_info(); - success_msg_writer() << multisig_info; - success_msg_writer() << tr("Send this multisig info to all other participants, then use make_multisig [...] with others' multisig info"); - success_msg_writer() << tr("This includes the PRIVATE view key, so needs to be disclosed only to that multisig wallet's participants "); - return true; -} - -bool advanced_wallet::make_multisig(const std::vector &args) -{ - if (m_wallet->key_on_device()) - { - fail_msg_writer() << tr("command not supported by HW wallet"); - return true; - } - if (m_wallet->multisig()) - { - fail_msg_writer() << tr("This wallet is already multisig"); - return true; - } - if (m_wallet->watch_only()) - { - fail_msg_writer() << tr("wallet is watch-only and cannot be made multisig"); - return true; - } - - if(m_wallet->get_num_transfer_details()) - { - fail_msg_writer() << tr("This wallet has been used before, please use a new wallet to create a multisig wallet"); - return true; - } - - const auto orig_pwd_container = get_and_verify_password(); - if(orig_pwd_container == boost::none) - { - fail_msg_writer() << tr("Your original password was incorrect."); - return true; - } - - if (args.size() < 2) - { - fail_msg_writer() << tr("usage: make_multisig [...]"); - return true; - } - - // parse threshold - uint32_t threshold; - if (!string_tools::get_xtype_from_string(threshold, args[0])) - { - fail_msg_writer() << tr("Invalid threshold"); - return true; - } - - LOCK_IDLE_SCOPE(); - - try - { - 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); - if (!multisig_extra_info.empty()) - { - success_msg_writer() << tr("Another step is needed"); - success_msg_writer() << multisig_extra_info; - success_msg_writer() << tr("Send this multisig info to all other participants, then use finalize_multisig [...] with others' multisig info"); - return true; - } - } - catch (const std::exception &e) - { - fail_msg_writer() << tr("Error creating multisig: ") << e.what(); - return true; - } - - uint32_t total; - if (!m_wallet->multisig(NULL, &threshold, &total)) - { - fail_msg_writer() << tr("Error creating multisig: new wallet is not multisig"); - return true; - } - success_msg_writer() << std::to_string(threshold) << "/" << total << tr(" multisig address: ") - << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); - - return true; -} - -bool advanced_wallet::finalize_multisig(const std::vector &args) -{ - bool ready; - if (m_wallet->key_on_device()) - { - fail_msg_writer() << tr("command not supported by HW wallet"); - return true; - } - if (!m_wallet->multisig(&ready)) - { - fail_msg_writer() << tr("This wallet is not multisig"); - return true; - } - if (ready) - { - fail_msg_writer() << tr("This wallet is already finalized"); - return true; - } - - const auto orig_pwd_container = get_and_verify_password(); - if(orig_pwd_container == boost::none) - { - fail_msg_writer() << tr("Your original password was incorrect."); - return true; - } - - if (args.size() < 2) - { - fail_msg_writer() << tr("usage: finalize_multisig [...]"); - return true; - } - - try - { - if (!m_wallet->finalize_multisig(orig_pwd_container->password(), args)) - { - fail_msg_writer() << tr("Failed to finalize multisig"); - return true; - } - } - catch (const std::exception &e) - { - fail_msg_writer() << tr("Failed to finalize multisig: ") << e.what(); - return true; - } - - return true; -} - -bool advanced_wallet::export_multisig(const std::vector &args) -{ - bool ready; - if (m_wallet->key_on_device()) - { - fail_msg_writer() << tr("command not supported by HW wallet"); - return true; - } - if (!m_wallet->multisig(&ready)) - { - fail_msg_writer() << tr("This wallet is not multisig"); - return true; - } - if (!ready) - { - fail_msg_writer() << tr("This multisig wallet is not yet finalized"); - return true; - } - if (args.size() != 1) - { - fail_msg_writer() << tr("usage: export_multisig_info "); - return true; - } - if (m_wallet->ask_password() && !get_and_verify_password()) - return true; - - const std::string filename = args[0]; - if (m_wallet->confirm_export_overwrite() && !check_file_overwrite(filename)) - return true; - try - { - cryptonote::blobdata ciphertext = m_wallet->export_multisig(); - - bool r = epee::file_io_utils::save_string_to_file(filename, ciphertext); - if (!r) - { - fail_msg_writer() << tr("failed to save file ") << filename; - return true; - } - } - catch (const std::exception &e) - { - LOG_ERROR("Error exporting multisig info: " << e.what()); - fail_msg_writer() << tr("Error exporting multisig info: ") << e.what(); - return true; - } - - success_msg_writer() << tr("Multisig info exported to ") << filename; - return true; -} - -bool advanced_wallet::import_multisig(const std::vector &args) -{ - bool ready; - uint32_t threshold, total; - if (m_wallet->key_on_device()) - { - fail_msg_writer() << tr("command not supported by HW wallet"); - return true; - } - if (!m_wallet->multisig(&ready, &threshold, &total)) - { - fail_msg_writer() << tr("This wallet is not multisig"); - return true; - } - if (!ready) - { - fail_msg_writer() << tr("This multisig wallet is not yet finalized"); - return true; - } - if (args.size() < threshold - 1) - { - fail_msg_writer() << tr("usage: import_multisig_info [...] - one for each other participant"); - return true; - } - if (m_wallet->ask_password() && !get_and_verify_password()) - return true; - - std::vector info; - for (size_t n = 0; n < args.size(); ++n) - { - const std::string filename = args[n]; - std::string data; - bool r = epee::file_io_utils::load_file_to_string(filename, data); - if (!r) - { - fail_msg_writer() << tr("failed to read file ") << filename; - return true; - } - info.push_back(std::move(data)); - } - - LOCK_IDLE_SCOPE(); - - // all read and parsed, actually import - try - { - size_t n_outputs = m_wallet->import_multisig(info); - // Clear line "Height xxx of xxx" - std::cout << "\r \r"; - success_msg_writer() << tr("Multisig info imported"); - } - catch (const std::exception &e) - { - fail_msg_writer() << tr("Failed to import multisig info: ") << e.what(); - return true; - } - if (m_trusted_daemon) - { - try - { - m_wallet->rescan_spent(); - } - catch (const std::exception &e) - { - message_writer() << tr("Failed to update spent status after importing multisig info: ") << e.what(); - } - } - else - { - message_writer() << tr("Untrusted daemon, spent status may be incorrect. Use a trusted daemon and run \"rescan_spent\""); - } - return true; -} - -bool advanced_wallet::accept_loaded_tx(const tools::wallet::multisig_tx_set &txs) -{ - std::string extra_message; - return accept_loaded_tx([&txs](){return txs.m_ptx.size();}, [&txs](size_t n)->const tools::wallet::tx_construction_data&{return txs.m_ptx[n].construction_data;}, extra_message); -} - -bool advanced_wallet::sign_multisig(const std::vector &args) -{ - bool ready; - if (m_wallet->key_on_device()) - { - fail_msg_writer() << tr("command not supported by HW wallet"); - return true; - } - if(!m_wallet->multisig(&ready)) - { - fail_msg_writer() << tr("This is not a multisig wallet"); - return true; - } - if (!ready) - { - fail_msg_writer() << tr("This multisig wallet is not yet finalized"); - return true; - } - if (args.size() != 1) - { - fail_msg_writer() << tr("usage: sign_multisig "); - return true; - } - if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } - - std::string filename = args[0]; - std::vector txids; - uint32_t signers = 0; - try - { - bool r = m_wallet->sign_multisig_tx_from_file(filename, txids, [&](const tools::wallet::multisig_tx_set &tx){ signers = tx.m_signers.size(); return accept_loaded_tx(tx); }); - if (!r) - { - fail_msg_writer() << tr("Failed to sign multisig transaction"); - return true; - } - } - catch (const tools::error::multisig_export_needed& e) - { - fail_msg_writer() << tr("Multisig error: ") << e.what(); - return true; - } - catch (const std::exception &e) - { - fail_msg_writer() << tr("Failed to sign multisig transaction: ") << e.what(); - return true; - } - - if (txids.empty()) - { - uint32_t threshold; - m_wallet->multisig(NULL, &threshold); - uint32_t signers_needed = threshold - signers - 1; - success_msg_writer(true) << tr("Transaction successfully signed to file ") << filename << ", " - << signers_needed << " more signer(s) needed"; - return true; - } - else - { - std::string txids_as_text; - for (const auto &txid: txids) - { - if (!txids_as_text.empty()) - txids_as_text += (", "); - txids_as_text += epee::string_tools::pod_to_hex(txid); - } - success_msg_writer(true) << tr("Transaction successfully signed to file ") << filename << ", txid " << txids_as_text; - success_msg_writer(true) << tr("It may be relayed to the network with submit_multisig"); - } - return true; -} - -bool advanced_wallet::submit_multisig(const std::vector &args) -{ - bool ready; - uint32_t threshold; - if (m_wallet->key_on_device()) - { - fail_msg_writer() << tr("command not supported by HW wallet"); - return true; - } - if (!m_wallet->multisig(&ready, &threshold)) - { - fail_msg_writer() << tr("This is not a multisig wallet"); - return true; - } - if (!ready) - { - fail_msg_writer() << tr("This multisig wallet is not yet finalized"); - return true; - } - if (args.size() != 1) - { - fail_msg_writer() << tr("usage: submit_multisig "); - return true; - } - if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } - - if (!try_connect_to_daemon()) - return true; - - std::string filename = args[0]; - try - { - tools::wallet::multisig_tx_set txs; - bool r = m_wallet->load_multisig_tx_from_file(filename, txs, [&](const tools::wallet::multisig_tx_set &tx){ return accept_loaded_tx(tx); }); - if (!r) - { - fail_msg_writer() << tr("Failed to load multisig transaction from file"); - return true; - } - if (txs.m_signers.size() < 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(); - return true; - } - - // actually commit the transactions - for (auto &ptx: txs.m_ptx) - { - m_wallet->commit_tx(ptx); - success_msg_writer(true) << tr("Transaction successfully submitted, transaction ") << get_transaction_hash(ptx.tx) << ENDL - << tr("You can check its status by using the `show_transfers` command."); - } - } - catch (const std::exception &e) - { - handle_transfer_exception(std::current_exception(), m_trusted_daemon); - } - catch (...) - { - LOG_ERROR("unknown error"); - fail_msg_writer() << tr("unknown error"); - } - - return true; -} - -bool advanced_wallet::export_raw_multisig(const std::vector &args) -{ - bool ready; - uint32_t threshold; - if (m_wallet->key_on_device()) - { - fail_msg_writer() << tr("command not supported by HW wallet"); - return true; - } - if (!m_wallet->multisig(&ready, &threshold)) - { - fail_msg_writer() << tr("This is not a multisig wallet"); - return true; - } - if (!ready) - { - fail_msg_writer() << tr("This multisig wallet is not yet finalized"); - return true; - } - if (args.size() != 1) - { - fail_msg_writer() << tr("usage: export_raw_multisig "); - return true; - } - if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } - std::string filename = args[0]; - if (m_wallet->confirm_export_overwrite() && !check_file_overwrite(filename)) - return true; - try - { - tools::wallet::multisig_tx_set txs; - bool r = m_wallet->load_multisig_tx_from_file(filename, txs, [&](const tools::wallet::multisig_tx_set &tx){ return accept_loaded_tx(tx); }); - if (!r) - { - fail_msg_writer() << tr("Failed to load multisig transaction from file"); - return true; - } - if (txs.m_signers.size() < 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(); - return true; - } - // save the transactions - std::string filenames; - for (auto &ptx: txs.m_ptx) - { - const crypto::hash txid = cryptonote::get_transaction_hash(ptx.tx); - const std::string filename = std::string("raw_multisig_safex_tx_") + epee::string_tools::pod_to_hex(txid); - if (!filenames.empty()) - filenames += ", "; - filenames += filename; - if (!epee::file_io_utils::save_string_to_file(filename, cryptonote::tx_to_blob(ptx.tx))) - { - fail_msg_writer() << tr("Failed to export multisig transaction to file ") << filename; - return true; - } - } - success_msg_writer() << tr("Saved exported multisig transaction file(s): ") << filenames; - } - catch (const std::exception& e) - { - LOG_ERROR("unexpected error: " << e.what()); - fail_msg_writer() << tr("unexpected error: ") << e.what(); - } - catch (...) - { - LOG_ERROR("Unknown error"); - fail_msg_writer() << tr("unknown error"); - } - - return true; -} bool advanced_wallet::print_ring(const std::vector &args) { @@ -2181,7 +1647,7 @@ advanced_wallet::advanced_wallet() "refresh-type \n " " Set the wallet's refresh behaviour.\n " "priority [0|1|2|3|4]\n " - " Set the fee too default/unimportant/normal/elevated/priority.\n " + " Set the fee to default/unimportant/normal/elevated/priority.\n " "confirm-missing-payment-id <1|0>\n " "ask-password <1|0>\n " "unit \n " @@ -2263,7 +1729,9 @@ advanced_wallet::advanced_wallet() tr("Show the unspent token outputs of a specified address within an optional amount range.")); m_cmd_binder.set_handler("rescan_bc", boost::bind(&advanced_wallet::rescan_blockchain, this, _1), - tr("Rescan the blockchain from scratch.")); + tr("rescan_bc [hard]"), + tr("Rescan the blockchain from scratch. If \"hard\" is specified, the wallet will scan the whole blockchain no matter when the wallet is created.\n" + "The \"hard\" option is useful when you want to get advanced outputs that are created earlier on a different wallet and \"rescan_bc\" is not enough.")); m_cmd_binder.set_handler("set_tx_note", boost::bind(&advanced_wallet::set_tx_note, this, _1), tr("set_tx_note [free text note]"), @@ -2322,37 +1790,6 @@ advanced_wallet::advanced_wallet() m_cmd_binder.set_handler("fee", boost::bind(&advanced_wallet::print_fee_info, this, _1), tr("Print the information about the current fee and transaction backlog.")); -#if MULTISIG_ACTIVE - m_cmd_binder.set_handler("prepare_multisig", boost::bind(&advanced_wallet::prepare_multisig, this, _1), - tr("Export data needed to create a multisig wallet")); - m_cmd_binder.set_handler("make_multisig", boost::bind(&advanced_wallet::make_multisig, this, _1), - tr("make_multisig [...]"), - tr("Turn this wallet into a multisig wallet")); - m_cmd_binder.set_handler("finalize_multisig", - boost::bind(&advanced_wallet::finalize_multisig, this, _1), - tr("finalize_multisig [...]"), - tr("Turn this wallet into a multisig wallet, extra step for N-1/N wallets")); - m_cmd_binder.set_handler("export_multisig_info", - boost::bind(&advanced_wallet::export_multisig, this, _1), - tr("export_multisig_info "), - tr("Export multisig info for other participants")); - m_cmd_binder.set_handler("import_multisig_info", - boost::bind(&advanced_wallet::import_multisig, this, _1), - tr("import_multisig_info [...]"), - tr("Import multisig info from other participants")); - m_cmd_binder.set_handler("sign_multisig", - boost::bind(&advanced_wallet::sign_multisig, this, _1), - tr("sign_multisig "), - tr("Sign a multisig transaction from a file")); - m_cmd_binder.set_handler("submit_multisig", - boost::bind(&advanced_wallet::submit_multisig, this, _1), - tr("submit_multisig "), - tr("Submit a signed multisig transaction from a file")); - m_cmd_binder.set_handler("export_raw_multisig_tx", - boost::bind(&advanced_wallet::export_raw_multisig, this, _1), - tr("export_raw_multisig_tx "), - tr("Export a signed multisig transaction to a file")); -#endif m_cmd_binder.set_handler("print_ring", boost::bind(&advanced_wallet::print_ring, this, _1), tr("print_ring | "), @@ -2612,17 +2049,15 @@ bool advanced_wallet::init(const boost::program_options::variables_map& vm) } const network_type nettype = testnet ? TESTNET : stagenet ? STAGENET : MAINNET; - std::string multisig_keys; - if (!handle_command_line(vm)) return false; - if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_device.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_spend_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_multisig_keys.empty()) + (!m_generate_from_json.empty()) > 1) + if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_device.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_spend_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_json.empty()) > 1) { - fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-spend-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-multisig-keys=\"wallet_name\", --generate-from-json=\"jsonfilename\" and --generate-from-device=\"wallet_name\""); + fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-spend-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-json=\"jsonfilename\" and --generate-from-device=\"wallet_name\""); return false; } - else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_device.empty() && m_generate_from_view_key.empty() && m_generate_from_spend_key.empty() && m_generate_from_keys.empty() && m_generate_from_multisig_keys.empty() && m_generate_from_json.empty()) + else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_device.empty() && m_generate_from_view_key.empty() && m_generate_from_spend_key.empty() && m_generate_from_keys.empty() && m_generate_from_json.empty()) { if(!ask_wallet_create_if_needed()) return false; } @@ -2634,86 +2069,53 @@ bool advanced_wallet::init(const boost::program_options::variables_map& vm) std::string old_language; // check for recover flag. if present, require electrum word list (only recovery option for now). - if (m_restore_deterministic_wallet || m_restore_multisig_wallet) + if (m_restore_deterministic_wallet) { if (m_non_deterministic) { - fail_msg_writer() << tr("can't specify both --restore-deterministic-wallet or --restore-multisig-wallet and --non-deterministic"); + fail_msg_writer() << tr("can't specify both --restore-deterministic-wallet or --non-deterministic"); return false; } if (!m_wallet_file.empty()) { - if (m_restore_multisig_wallet) - fail_msg_writer() << tr("--restore-multisig-wallet uses --generate-new-wallet, not --wallet-file"); - else - fail_msg_writer() << tr("--restore-deterministic-wallet uses --generate-new-wallet, not --wallet-file"); + + fail_msg_writer() << tr("--restore-deterministic-wallet uses --generate-new-wallet, not --wallet-file"); return false; } if (m_electrum_seed.empty()) { - if (m_restore_multisig_wallet) - { - const char *prompt = "Specify multisig seed: "; - m_electrum_seed = input_line(prompt); - if (std::cin.eof()) - return false; - if (m_electrum_seed.empty()) - { - fail_msg_writer() << tr("specify a recovery parameter with the --electrum-seed=\"multisig seed here\""); - return false; - } - } - else + m_electrum_seed = ""; + do { - m_electrum_seed = ""; - do + const char *prompt = m_electrum_seed.empty() ? "Specify Electrum seed: " : "Electrum seed continued: "; + std::string electrum_seed = input_line(prompt); + if (std::cin.eof()) + return false; + if (electrum_seed.empty()) { - const char *prompt = m_electrum_seed.empty() ? "Specify Electrum seed: " : "Electrum seed continued: "; - std::string electrum_seed = input_line(prompt); - if (std::cin.eof()) - return false; - if (electrum_seed.empty()) - { - fail_msg_writer() << tr("specify a recovery parameter with the --electrum-seed=\"words list here\""); - return false; - } - m_electrum_seed += electrum_seed + " "; - } while (might_be_partial_seed(m_electrum_seed)); - } - } + fail_msg_writer() << tr("specify a recovery parameter with the --electrum-seed=\"words list here\""); + return false; + } + m_electrum_seed += electrum_seed + " "; + } while (might_be_partial_seed(m_electrum_seed)); - if (m_restore_multisig_wallet) - { - if (!epee::string_tools::parse_hexstr_to_binbuff(m_electrum_seed, multisig_keys)) - { - fail_msg_writer() << tr("Multisig seed failed verification"); - return false; - } } - else + + + if (!crypto::ElectrumWords::words_to_bytes(m_electrum_seed, m_recovery_key, old_language)) { - if (!crypto::ElectrumWords::words_to_bytes(m_electrum_seed, m_recovery_key, old_language)) - { - fail_msg_writer() << tr("Electrum-style word list failed verification"); - return false; - } + fail_msg_writer() << tr("Electrum-style word list failed verification"); + return false; } + auto pwd_container = password_prompter(tr("Enter seed encryption passphrase, empty if none"), false); if (std::cin.eof() || !pwd_container) return false; epee::wipeable_string seed_pass = pwd_container->password(); if (!seed_pass.empty()) { - if (m_restore_multisig_wallet) - { - crypto::secret_key key; - crypto::cn_slow_hash(seed_pass.data(), seed_pass.size(), (crypto::hash&)key); - sc_reduce32((unsigned char*)key.data); - multisig_keys = m_wallet->decrypt(multisig_keys, key, true); - } - else m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass); } } @@ -2869,141 +2271,6 @@ bool advanced_wallet::init(const boost::program_options::variables_map& vm) bool r = new_wallet(vm, info.address, spendkey, viewkey); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); } - - // Asks user for all the data required to merge secret keys from multisig wallets into one master wallet, which then gets full control of the multisig wallet. The resulting wallet will be the same as any other regular wallet. - else if (!m_generate_from_multisig_keys.empty()) - { - m_wallet_file = m_generate_from_multisig_keys; - unsigned int multisig_m; - unsigned int multisig_n; - - // parse multisig type - std::string multisig_type_string = input_line("Multisig type (input as M/N with M <= N and M > 1): "); - if (std::cin.eof()) - return false; - if (multisig_type_string.empty()) - { - fail_msg_writer() << tr("No data supplied, cancelled"); - return false; - } - if (sscanf(multisig_type_string.c_str(), "%u/%u", &multisig_m, &multisig_n) != 2) - { - fail_msg_writer() << tr("Error: expected M/N, but got: ") << multisig_type_string; - return false; - } - if (multisig_m <= 1 || multisig_m > multisig_n) - { - fail_msg_writer() << tr("Error: expected N > 1 and N <= M, but got: ") << multisig_type_string; - return false; - } - if (multisig_m != multisig_n) - { - fail_msg_writer() << tr("Error: M/N is currently unsupported. "); - return false; - } - message_writer() << boost::format(tr("Generating master wallet from %u of %u multisig wallet keys")) % multisig_m % multisig_n; - - // parse multisig address - std::string address_string = input_line("Multisig wallet address: "); - if (std::cin.eof()) - return false; - if (address_string.empty()) { - fail_msg_writer() << tr("No data supplied, cancelled"); - return false; - } - cryptonote::address_parse_info info; - if(!get_account_address_from_str(info, nettype, address_string)) - { - fail_msg_writer() << tr("failed to parse address"); - return false; - } - - // parse secret view key - std::string viewkey_string = input_line("Secret view key: "); - if (std::cin.eof()) - return false; - if (viewkey_string.empty()) - { - fail_msg_writer() << tr("No data supplied, cancelled"); - return false; - } - cryptonote::blobdata viewkey_data; - if(!epee::string_tools::parse_hexstr_to_binbuff(viewkey_string, viewkey_data) || viewkey_data.size() != sizeof(crypto::secret_key)) - { - fail_msg_writer() << tr("failed to parse secret view key"); - return false; - } - crypto::secret_key viewkey = *reinterpret_cast(viewkey_data.data()); - - // check that the view key matches the given address - crypto::public_key pkey; - if (!crypto::secret_key_to_public_key(viewkey, pkey)) - { - fail_msg_writer() << tr("failed to verify secret view key"); - return false; - } - if (info.address.m_view_public_key != pkey) - { - fail_msg_writer() << tr("view key does not match standard address"); - return false; - } - - // parse multisig spend keys - crypto::secret_key spendkey; - // parsing N/N - if(multisig_m == multisig_n) - { - std::vector multisig_secret_spendkeys(multisig_n); - std::string spendkey_string; - cryptonote::blobdata spendkey_data; - // get N secret spend keys from user - for(unsigned int i=0; i(spendkey_data.data()); - } - - // sum the spend keys together to get the master spend key - spendkey = multisig_secret_spendkeys[0]; - for(unsigned int i=1; i(&spendkey), reinterpret_cast(&spendkey), reinterpret_cast(&multisig_secret_spendkeys[i])); - } - // parsing M/N - else - { - fail_msg_writer() << tr("Error: M/N is currently unsupported"); - return false; - } - - // check that the spend key matches the given address - if (!crypto::secret_key_to_public_key(spendkey, pkey)) - { - fail_msg_writer() << tr("failed to verify spend key secret key"); - return false; - } - if (info.address.m_spend_public_key != pkey) - { - fail_msg_writer() << tr("spend key does not match standard address"); - return false; - } - - // create wallet - bool r = new_wallet(vm, info.address, spendkey, viewkey); - CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); - } - else if (!m_generate_from_json.empty()) { m_wallet_file = m_generate_from_json; @@ -3050,10 +2317,7 @@ bool advanced_wallet::init(const boost::program_options::variables_map& vm) } m_wallet_file = m_generate_new; bool r; - if (m_restore_multisig_wallet) - r = new_wallet(vm, multisig_keys, old_language); - else - r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language); + r = new_wallet(vm, m_recovery_key, m_restore_deterministic_wallet, m_non_deterministic, old_language); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); } @@ -3192,12 +2456,10 @@ bool advanced_wallet::handle_command_line(const boost::program_options::variable m_generate_from_view_key = command_line::get_arg(vm, arg_generate_from_view_key); m_generate_from_spend_key = command_line::get_arg(vm, arg_generate_from_spend_key); m_generate_from_keys = command_line::get_arg(vm, arg_generate_from_keys); - m_generate_from_multisig_keys = command_line::get_arg(vm, arg_generate_from_multisig_keys); m_generate_from_json = command_line::get_arg(vm, arg_generate_from_json); m_mnemonic_language = command_line::get_arg(vm, arg_mnemonic_language); m_electrum_seed = command_line::get_arg(vm, arg_electrum_seed); m_restore_deterministic_wallet = command_line::get_arg(vm, arg_restore_deterministic_wallet); - m_restore_multisig_wallet = command_line::get_arg(vm, arg_restore_multisig_wallet); m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic); m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon); m_allow_mismatched_daemon_version = command_line::get_arg(vm, arg_allow_mismatched_daemon_version); @@ -3208,11 +2470,9 @@ bool advanced_wallet::handle_command_line(const boost::program_options::variable m_restoring = !m_generate_from_view_key.empty() || !m_generate_from_spend_key.empty() || !m_generate_from_keys.empty() || - !m_generate_from_multisig_keys.empty() || !m_generate_from_json.empty() || !m_generate_from_device.empty() || - m_restore_deterministic_wallet || - m_restore_multisig_wallet; + m_restore_deterministic_wallet; return true; } @@ -3467,58 +2727,6 @@ bool advanced_wallet::new_wallet(const boost::program_options::variables_map& vm return true; } //---------------------------------------------------------------------------------------------------- -bool advanced_wallet::new_wallet(const boost::program_options::variables_map& vm, - const std::string &multisig_keys, const std::string &old_language) -{ - auto rc = tools::wallet::make_new(vm, password_prompter); - m_wallet = std::move(rc.first); - if (!m_wallet) - { - return false; - } - - if (!m_subaddress_lookahead.empty()) - { - auto lookahead = parse_subaddress_lookahead(m_subaddress_lookahead); - assert(lookahead); - m_wallet->set_subaddress_lookahead(lookahead->first, lookahead->second); - } - - std::string mnemonic_language = old_language; - - std::vector language_list; - crypto::ElectrumWords::get_language_list(language_list); - if (mnemonic_language.empty() && std::find(language_list.begin(), language_list.end(), m_mnemonic_language) != language_list.end()) - { - mnemonic_language = m_mnemonic_language; - } - - m_wallet->set_seed_language(mnemonic_language); - - bool create_address_file = command_line::get_arg(vm, arg_create_address_file); - - try - { - m_wallet->generate(m_wallet_file, std::move(rc.second).password(), multisig_keys, create_address_file); - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total) || !ready) - { - fail_msg_writer() << tr("failed to generate new mutlisig wallet"); - return false; - } - message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % threshold % total - << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); - } - catch (const std::exception& e) - { - fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); - return false; - } - - return true; -} -//---------------------------------------------------------------------------------------------------- bool advanced_wallet::open_wallet(const boost::program_options::variables_map& vm) { if (!tools::wallet::wallet_valid_path_format(m_wallet_file)) @@ -3542,8 +2750,6 @@ bool advanced_wallet::open_wallet(const boost::program_options::variables_map& v uint32_t threshold, total; 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 prefix = tr("Opened wallet"); message_writer(console_color_white, true) << @@ -3655,11 +2861,6 @@ bool advanced_wallet::save(const std::vector &args) //---------------------------------------------------------------------------------------------------- bool advanced_wallet::save_watch_only(const std::vector &args/* = std::vector()*/) { - if (m_wallet->multisig()) - { - fail_msg_writer() << tr("wallet is multisig and cannot save a watch-only version"); - return true; - } const auto pwd_container = password_prompter(tr("Password for new watch-only wallet"), true); @@ -3990,8 +3191,6 @@ bool advanced_wallet::refresh(const std::vector& args) bool advanced_wallet::show_balance_unlocked(bool detailed) { std::string extra; - if (m_wallet->has_multisig_partial_key_images()) - extra = tr(" (Some owned outputs have partial key images - import_multisig_info needed)"); success_msg_writer() << tr("Currently selected account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0}); const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account]; success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag); @@ -4043,8 +3242,6 @@ bool advanced_wallet::show_cash_balance(const std::vector& args/* = bool advanced_wallet::show_token_balance_unlocked(bool detailed) { std::string extra; - if (m_wallet->has_multisig_partial_key_images()) - extra = tr(" (Some owned token outputs have partial key images - import_multisig_info needed)"); success_msg_writer() << tr("Currently selected token account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0}); const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account]; success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag); @@ -4585,7 +3782,7 @@ bool advanced_wallet::transfer_main(int transfer_type, const std::vectormultisig()) - { - bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_safex_tx"); - if (!r) - { - fail_msg_writer() << tr("Failed to write transaction(s) to file"); - } - else - { - success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_safex_tx"; - } - } - else if (m_wallet->watch_only()) + if (m_wallet->watch_only()) { bool r = m_wallet->save_tx(ptx_vector, "unsigned_safex_tx"); if (!r) @@ -4874,6 +4059,7 @@ bool advanced_wallet::migrate(const std::vector &args_) token_destination.addr = info.address; token_destination.is_subaddress = info.is_subaddress; token_destination.token_transaction = true; + token_destination.output_type = cryptonote::tx_out_type::out_token; //parse bitcoin transaction hash cryptonote::blobdata expected_bitcoin_hash_data; @@ -4892,32 +4078,12 @@ bool advanced_wallet::migrate(const std::vector &args_) return true; } - if(!tools::is_whole_coin_amount(token_destination.token_amount)) + if(!tools::is_whole_token_amount(token_destination.token_amount)) { fail_msg_writer() << tr("token amount must be whole number. ") << local_args[0] << ' ' << local_args[2]; return true; } - std::stringstream prompt; - prompt << "Perform migration transaction: address: " << cryptonote::get_account_address_as_str(m_wallet->nettype(), false, token_destination.addr) \ - << " bitcoin tx hash:" << epee::string_tools::pod_to_hex(bitcoin_burn_transaction) \ - << " token amount:" << print_money(token_destination.token_amount) \ - << tr("Is this okay anyway? (Y/Yes/N/No): "); - std::string prompt_str = prompt.str(); - if (!prompt_str.empty()) - { - std::string accepted = input_line(prompt_str); - if (std::cin.eof()) - return true; - if (!command_line::is_yes(accepted)) - { - fail_msg_writer() << tr("transaction cancelled."); - - return true; - } - } - - //airdrop reward calculation cryptonote::tx_destination_entry airdrop_destination = AUTO_VAL_INIT(airdrop_destination); airdrop_destination.addr = info.address; @@ -4950,6 +4116,26 @@ bool advanced_wallet::migrate(const std::vector &args_) return true; } + std::stringstream prompt; + prompt << "Perform migration transaction: address: " << cryptonote::get_account_address_as_str(m_wallet->nettype(), false, token_destination.addr) \ + << " bitcoin tx hash:" << epee::string_tools::pod_to_hex(bitcoin_burn_transaction) \ + << " token amount:" << print_money(token_destination.token_amount) \ + << " transaction fee:" << print_money(ptx_vector[0].fee) \ + << tr("Is this okay anyway? (Y/Yes/N/No): "); + std::string prompt_str = prompt.str(); + if (!prompt_str.empty()) + { + std::string accepted = input_line(prompt_str); + if (std::cin.eof()) + return true; + if (!command_line::is_yes(accepted)) + { + fail_msg_writer() << tr("transaction cancelled."); + + return true; + } + } + // if we need to check for backlog, check the worst case tx if (m_wallet->confirm_backlog()) { @@ -4998,19 +4184,7 @@ bool advanced_wallet::migrate(const std::vector &args_) } // actually commit the transactions - if (m_wallet->multisig()) - { - bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_safex_tx"); - if (!r) - { - fail_msg_writer() << tr("Failed to write transaction(s) to file"); - } - else - { - success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_safex_tx"; - } - } - else if (m_wallet->watch_only()) + if (m_wallet->watch_only()) { // ugly hack... used bitcoin_hash noy saved in sources for (auto &ptx : ptx_vector) { @@ -5128,19 +4302,7 @@ bool advanced_wallet::sweep_unmixable(const std::vector &args_) } // actually commit the transactions - if (m_wallet->multisig()) - { - bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_safex_tx"); - if (!r) - { - fail_msg_writer() << tr("Failed to write transaction(s) to file"); - } - else - { - success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_safex_tx"; - } - } - else if (m_wallet->watch_only()) + if (m_wallet->watch_only()) { bool r = m_wallet->save_tx(ptx_vector, "unsigned_safex_tx"); if (!r) @@ -5289,7 +4451,7 @@ bool advanced_wallet::sweep_main(uint64_t below, const std::vector payment_id_seen = true; } - // prompt is there is no payment id and confirmation is required + // prompt if there is no payment id and confirmation is required if (!payment_id_seen && m_wallet->confirm_missing_payment_id()) { std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): ")); @@ -5361,19 +4523,7 @@ bool advanced_wallet::sweep_main(uint64_t below, const std::vector } // actually commit the transactions - if (m_wallet->multisig()) - { - bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_safex_tx"); - if (!r) - { - fail_msg_writer() << tr("Failed to write transaction(s) to file"); - } - else - { - success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_safex_tx"; - } - } - else if (m_wallet->watch_only()) + if (m_wallet->watch_only()) { bool r = m_wallet->save_tx(ptx_vector, "unsigned_safex_tx"); if (!r) @@ -5558,19 +4708,7 @@ bool advanced_wallet::sweep_single(const std::vector &args_) } // actually commit the transactions - if (m_wallet->multisig()) - { - bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_safex_tx"); - if (!r) - { - fail_msg_writer() << tr("Failed to write transaction(s) to file"); - } - else - { - success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_safex_tx"; - } - } - else if (m_wallet->watch_only()) + if (m_wallet->watch_only()) { bool r = m_wallet->save_tx(ptx_vector, "unsigned_safex_tx"); if (!r) @@ -5779,11 +4917,7 @@ bool advanced_wallet::sign_transfer(const std::vector &args_) fail_msg_writer() << tr("command not supported by HW wallet"); return true; } - if(m_wallet->multisig()) - { - fail_msg_writer() << tr("This is a multisig wallet, it can only sign with sign_multisig"); - return true; - } + if(m_wallet->watch_only()) { fail_msg_writer() << tr("This is a watch only wallet"); @@ -5842,11 +4976,7 @@ bool advanced_wallet::sign_migration(const std::vector &args_) fail_msg_writer() << tr("command not supported by HW wallet"); return true; } - if(m_wallet->multisig()) - { - fail_msg_writer() << tr("This is a multisig wallet, it can only sign with sign_multisig"); - return true; - } + if(m_wallet->watch_only()) { fail_msg_writer() << tr("This is a watch only wallet"); @@ -6295,7 +5425,7 @@ bool advanced_wallet::get_reserve_proof(const std::vector &args) return true; } - if (m_wallet->watch_only() || m_wallet->multisig()) + if (m_wallet->watch_only()) { fail_msg_writer() << tr("The reserve proof can be generated only by a full wallet"); return true; @@ -6725,7 +5855,7 @@ bool advanced_wallet::unspent_outputs(const std::vector &args_, boo << tr("\nMin block height: ") << min_height << tr("\nMax block height: ") << max_height << tr("\nMin") << tr(string_prefix) << tr(" amount found: ") << print_money(found_min_amount) - << tr("\nMin") << tr(string_prefix) << tr(" amount found: ") << print_money(found_max_amount) + << tr("\nMax") << tr(string_prefix) << tr(" amount found: ") << print_money(found_max_amount) << tr("\nTotal count: ") << count; const size_t histogram_height = 10; const size_t histogram_width = 50; @@ -7419,8 +6549,6 @@ bool advanced_wallet::wallet_info(const std::vector &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 type = tr("Normal"); message_writer() << tr("Type: ") << type; @@ -7447,11 +6575,6 @@ bool advanced_wallet::sign(const std::vector &args) fail_msg_writer() << tr("wallet is watch-only and cannot sign"); return true; } - if (m_wallet->multisig()) - { - fail_msg_writer() << tr("This wallet is multisig and cannot sign"); - return true; - } if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } std::string filename = args[0]; std::string data; @@ -7937,13 +7060,11 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_generate_from_view_key); command_line::add_arg(desc_params, arg_generate_from_spend_key); command_line::add_arg(desc_params, arg_generate_from_keys); - command_line::add_arg(desc_params, arg_generate_from_multisig_keys); command_line::add_arg(desc_params, arg_generate_from_json); command_line::add_arg(desc_params, arg_mnemonic_language); command_line::add_arg(desc_params, arg_command); command_line::add_arg(desc_params, arg_restore_deterministic_wallet ); - command_line::add_arg(desc_params, arg_restore_multisig_wallet ); command_line::add_arg(desc_params, arg_non_deterministic ); command_line::add_arg(desc_params, arg_electrum_seed ); command_line::add_arg(desc_params, arg_trusted_daemon); diff --git a/src/advancedwallet/advancedwallet.h b/src/advancedwallet/advancedwallet.h index ace28116a..66221c320 100644 --- a/src/advancedwallet/advancedwallet.h +++ b/src/advancedwallet/advancedwallet.h @@ -94,8 +94,6 @@ namespace cryptonote bool recover, bool two_random, const std::string &old_language); bool new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address, const boost::optional& spendkey, const crypto::secret_key& viewkey); - bool new_wallet(const boost::program_options::variables_map& vm, - const std::string &multisig_keys, const std::string &old_language); bool new_wallet(const boost::program_options::variables_map& vm, const std::string& device_name); bool open_wallet(const boost::program_options::variables_map& vm); bool close_wallet(); @@ -208,15 +206,6 @@ namespace cryptonote bool change_password(const std::vector& args); bool payment_id(const std::vector &args); bool print_fee_info(const std::vector &args); - bool prepare_multisig(const std::vector& args); - bool make_multisig(const std::vector& args); - bool finalize_multisig(const std::vector &args); - bool export_multisig(const std::vector& args); - bool import_multisig(const std::vector& args); - bool accept_loaded_tx(const tools::wallet::multisig_tx_set &txs); - bool sign_multisig(const std::vector& args); - bool submit_multisig(const std::vector& args); - bool export_raw_multisig(const std::vector& args); bool print_ring(const std::vector& args); bool set_ring(const std::vector& args); bool save_known_rings(const std::vector& args); @@ -327,7 +316,6 @@ namespace cryptonote std::string m_generate_from_view_key; std::string m_generate_from_spend_key; std::string m_generate_from_keys; - std::string m_generate_from_multisig_keys; std::string m_generate_from_json; std::string m_mnemonic_language; std::string m_import_path; @@ -337,7 +325,6 @@ namespace cryptonote crypto::secret_key m_recovery_key; // recovery key (used as random for wallet gen) bool m_restore_deterministic_wallet; // recover flag - bool m_restore_multisig_wallet; // recover flag bool m_non_deterministic; // old 2-random generation bool m_trusted_daemon; bool m_allow_mismatched_daemon_version; diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp deleted file mode 100644 index fa50976d1..000000000 --- a/src/blockchain_db/berkeleydb/db_bdb.cpp +++ /dev/null @@ -1,2346 +0,0 @@ -// Copyright (c) 2018, The Safex 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) 2014-2018 The Monero Project - -#include "db_bdb.h" - -#include -#include // std::unique_ptr -#include // memcpy - -#include "cryptonote_basic/cryptonote_format_utils.h" -#include "crypto/crypto.h" -#include "profile_tools.h" - -using epee::string_tools::pod_to_hex; -#define DB_DEFAULT_TX (m_write_txn != nullptr ? *m_write_txn : (DbTxn*) nullptr) - -// Increase when the DB changes in a non backward compatible way, and there -// is no automatic conversion, so that a full resync is needed. -#define VERSION 0 - -namespace -{ - -template -inline void throw0(const T &e) -{ - LOG_PRINT_L0(e.what()); - throw e; -} - -template -inline void throw1(const T &e) -{ - LOG_PRINT_L1(e.what()); - throw e; -} - -// cursor needs to be closed when it goes out of scope, -// this helps if the function using it throws -struct bdb_cur -{ - bdb_cur(DbTxn* txn, Db* dbi) - { - if (dbi->cursor(txn, &m_cur, 0)) - throw0(cryptonote::DB_ERROR("Error opening db cursor")); - done = false; - } - - ~bdb_cur() - { - close(); - } - - operator Dbc*() - { - return m_cur; - } - operator Dbc**() - { - return &m_cur; - } - Dbc* operator->() - { - return m_cur; - } - - void close() - { - if (!done) - { - m_cur->close(); - done = true; - } - } - -private: - Dbc* m_cur; - bool done; -}; - -const char* const BDB_BLOCKS = "blocks"; -const char* const BDB_BLOCK_TIMESTAMPS = "block_timestamps"; -const char* const BDB_BLOCK_HEIGHTS = "block_heights"; -const char* const BDB_BLOCK_HASHES = "block_hashes"; -const char* const BDB_BLOCK_SIZES = "block_sizes"; -const char* const BDB_BLOCK_DIFFS = "block_diffs"; -const char* const BDB_BLOCK_COINS = "block_coins"; - -const char* const BDB_TXS = "txs"; -const char* const BDB_TX_UNLOCKS = "tx_unlocks"; -const char* const BDB_TX_HEIGHTS = "tx_heights"; -const char* const BDB_TX_OUTPUTS = "tx_outputs"; - -const char* const BDB_OUTPUT_TXS = "output_txs"; -const char* const BDB_OUTPUT_INDICES = "output_indices"; -const char* const BDB_OUTPUT_AMOUNTS = "output_amounts"; -const char* const BDB_OUTPUT_KEYS = "output_keys"; - -const char* const BDB_SPENT_KEYS = "spent_keys"; - -const char* const BDB_HF_STARTING_HEIGHTS = "hf_starting_heights"; -const char* const BDB_HF_VERSIONS = "hf_versions"; - -const char* const BDB_PROPERTIES = "properties"; - -const unsigned int MB = 1024 * 1024; -// ND: FIXME: db keeps running out of locks when doing full syncs. Possible bug??? Set it to 5K for now. -const unsigned int DB_MAX_LOCKS = 5000; -const unsigned int DB_BUFFER_LENGTH = 32 * MB; -// 256MB cache adjust as necessary using DB_CONFIG -const unsigned int DB_DEF_CACHESIZE = 256 * MB; - -#if defined(BDB_BULK_CAN_THREAD) -const unsigned int DB_BUFFER_COUNT = tools::get_max_concurrency(); -#else -const unsigned int DB_BUFFER_COUNT = 1; -#endif - -template -struct Dbt_copy: public Dbt -{ - Dbt_copy(const T &t) : - t_copy(t) - { - init(); - } - - Dbt_copy() - { - init(); - } - - void init() - { - set_data(&t_copy); - set_size(sizeof(T)); - set_ulen(sizeof(T)); - set_flags(DB_DBT_USERMEM); - } - - operator T() - { - return t_copy; - } -private: - T t_copy; -}; - -template<> -struct Dbt_copy: public Dbt -{ - Dbt_copy(const cryptonote::blobdata &bd) : - m_data(new char[bd.size()]) - { - memcpy(m_data.get(), bd.data(), bd.size()); - set_data(m_data.get()); - set_size(bd.size()); - set_ulen(bd.size()); - set_flags(DB_DBT_USERMEM); - } -private: - std::unique_ptr m_data; -}; - -template<> -struct Dbt_copy: public Dbt -{ - Dbt_copy(const char *s) : - m_data(strdup(s)) - { - size_t len = strlen(s) + 1; // include the NUL, makes it easier for compare - set_data(m_data.get()); - set_size(len); - set_ulen(len); - set_flags(DB_DBT_USERMEM); - } -private: - std::unique_ptr m_data; -}; - -struct Dbt_safe : public Dbt -{ - Dbt_safe() - { - set_data(NULL); - set_flags(DB_DBT_MALLOC); - } - ~Dbt_safe() - { - void* buf = get_data(); - if (buf != NULL) - { - free(buf); - } - } -}; - -} // anonymous namespace - -namespace cryptonote -{ - -void BlockchainBDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const crypto::hash& blk_hash) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy val_h(blk_hash); - if (m_block_heights->exists(DB_DEFAULT_TX, &val_h, 0) == 0) - throw1(BLOCK_EXISTS("Attempting to add block that's already in the db")); - - if (m_height > 0) - { - Dbt_copy parent_key(blk.prev_id); - Dbt_copy parent_h; - if (m_block_heights->get(DB_DEFAULT_TX, &parent_key, &parent_h, 0)) - { - LOG_PRINT_L3("m_height: " << m_height); - LOG_PRINT_L3("parent_key: " << blk.prev_id); - throw0(DB_ERROR("Failed to get top block hash to check for new block's parent")); - } - uint32_t parent_height = parent_h; - if (parent_height != m_height) - throw0(BLOCK_PARENT_DNE("Top block is not new block's parent")); - } - - Dbt_copy key(m_height + 1); - - Dbt_copy blob(block_to_blob(blk)); - auto res = m_blocks->put(DB_DEFAULT_TX, &key, &blob, 0); - if (res) - throw0(DB_ERROR("Failed to add block blob to db transaction.")); - - Dbt_copy sz(block_size); - if (m_block_sizes->put(DB_DEFAULT_TX, &key, &sz, 0)) - throw0(DB_ERROR("Failed to add block size to db transaction.")); - - Dbt_copy ts(blk.timestamp); - if (m_block_timestamps->put(DB_DEFAULT_TX, &key, &ts, 0)) - throw0(DB_ERROR("Failed to add block timestamp to db transaction.")); - - Dbt_copy diff(cumulative_difficulty); - if (m_block_diffs->put(DB_DEFAULT_TX, &key, &diff, 0)) - throw0(DB_ERROR("Failed to add block cumulative difficulty to db transaction.")); - - Dbt_copy coinsgen(coins_generated); - if (m_block_coins->put(DB_DEFAULT_TX, &key, &coinsgen, 0)) - throw0(DB_ERROR("Failed to add block total generated coins to db transaction.")); - - if (m_block_heights->put(DB_DEFAULT_TX, &val_h, &key, 0)) - throw0(DB_ERROR("Failed to add block height by hash to db transaction.")); - - if (m_block_hashes->put(DB_DEFAULT_TX, &key, &val_h, 0)) - throw0(DB_ERROR("Failed to add block hash to db transaction.")); -} - -void BlockchainBDB::remove_block() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - if (m_height == 0) - throw0(BLOCK_DNE ("Attempting to remove block from an empty blockchain")); - - Dbt_copy k(m_height); - Dbt_copy h; - if (m_block_hashes->get(DB_DEFAULT_TX, &k, &h, 0)) - throw1(BLOCK_DNE("Attempting to remove block that's not in the db")); - - if (m_blocks->del(DB_DEFAULT_TX, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block to db transaction")); - - if (m_block_sizes->del(DB_DEFAULT_TX, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block size to db transaction")); - - if (m_block_diffs->del(DB_DEFAULT_TX, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block cumulative difficulty to db transaction")); - - if (m_block_coins->del(DB_DEFAULT_TX, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block total generated coins to db transaction")); - - if (m_block_timestamps->del(DB_DEFAULT_TX, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block timestamp to db transaction")); - - if (m_block_heights->del(DB_DEFAULT_TX, &h, 0)) - throw1(DB_ERROR("Failed to add removal of block height by hash to db transaction")); - - if (m_block_hashes->del(DB_DEFAULT_TX, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block hash to db transaction")); -} - -void BlockchainBDB::add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy val_h(tx_hash); - - if (m_txs->exists(DB_DEFAULT_TX, &val_h, 0) == 0) - throw1(TX_EXISTS("Attempting to add transaction that's already in the db")); - - Dbt_copy blob(tx_to_blob(tx)); - if (m_txs->put(DB_DEFAULT_TX, &val_h, &blob, 0)) - throw0(DB_ERROR("Failed to add tx blob to db transaction")); - - Dbt_copy height(m_height + 1); - if (m_tx_heights->put(DB_DEFAULT_TX, &val_h, &height, 0)) - throw0(DB_ERROR("Failed to add tx block height to db transaction")); - - Dbt_copy unlock_time(tx.unlock_time); - if (m_tx_unlocks->put(DB_DEFAULT_TX, &val_h, &unlock_time, 0)) - throw0(DB_ERROR("Failed to add tx unlock time to db transaction")); -} - -void BlockchainBDB::remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy val_h(tx_hash); - if (m_txs->exists(DB_DEFAULT_TX, &val_h, 0)) - throw1(TX_DNE("Attempting to remove transaction that isn't in the db")); - - if (m_txs->del(DB_DEFAULT_TX, &val_h, 0)) - throw1(DB_ERROR("Failed to add removal of tx to db transaction")); - if (m_tx_unlocks->del(DB_DEFAULT_TX, &val_h, 0)) - throw1(DB_ERROR("Failed to add removal of tx unlock time to db transaction")); - if (m_tx_heights->del(DB_DEFAULT_TX, &val_h, 0)) - throw1(DB_ERROR("Failed to add removal of tx block height to db transaction")); - - remove_tx_outputs(tx_hash, tx); - - auto result = m_tx_outputs->del(DB_DEFAULT_TX, &val_h, 0); - if (result == DB_NOTFOUND) - LOG_PRINT_L1("tx has no outputs to remove: " << tx_hash); - else if (result) - throw1(DB_ERROR("Failed to add removal of tx outputs to db transaction")); -} - -void BlockchainBDB::add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy k(m_num_outputs + 1); - Dbt_copy v(tx_hash); - - if (m_output_txs->put(DB_DEFAULT_TX, &k, &v, 0)) - throw0(DB_ERROR("Failed to add output tx hash to db transaction")); - if (m_tx_outputs->put(DB_DEFAULT_TX, &v, &k, 0)) - throw0(DB_ERROR("Failed to add tx output index to db transaction")); - - Dbt_copy val_local_index(local_index); - if (m_output_indices->put(DB_DEFAULT_TX, &k, &val_local_index, 0)) - throw0(DB_ERROR("Failed to add tx output index to db transaction")); - - Dbt_copy val_amount(tx_output.amount); - if (m_output_amounts->put(DB_DEFAULT_TX, &val_amount, &k, 0)) - throw0(DB_ERROR("Failed to add output amount to db transaction.")); - - if (tx_output.target.type() == typeid(txout_to_key)) - { - output_data_t od; - od.pubkey = boost::get < txout_to_key > (tx_output.target).key; - od.unlock_time = unlock_time; - od.height = m_height; - - Dbt_copy data(od); - if (m_output_keys->put(DB_DEFAULT_TX, &k, &data, 0)) - throw0(DB_ERROR("Failed to add output pubkey to db transaction")); - } - else - { - throw0(DB_ERROR("Wrong output type: expected txout_to_key")); - } - - m_num_outputs++; -} - -void BlockchainBDB::remove_tx_outputs(const crypto::hash& tx_hash, const transaction& tx) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - - bdb_cur cur(DB_DEFAULT_TX, m_tx_outputs); - - Dbt_copy k(tx_hash); - Dbt_copy v; - - auto result = cur->get(&k, &v, DB_SET); - if (result == DB_NOTFOUND) - { - LOG_PRINT_L2("tx has no outputs, so no global output indices"); - } - else if (result) - { - throw0(DB_ERROR("DB error attempting to get an output")); - } - else - { - result = cur->get(&k, &v, DB_NEXT_NODUP); - if (result != 0 && result != DB_NOTFOUND) - throw0(DB_ERROR("DB error attempting to get next non-duplicate tx hash")); - - if (result == 0) - result = cur->get(&k, &v, DB_PREV); - else if (result == DB_NOTFOUND) - result = cur->get(&k, &v, DB_LAST); - - db_recno_t num_elems = 0; - cur->count(&num_elems, 0); - - // remove in order: from newest to oldest - for (uint64_t i = num_elems; i > 0; --i) - { - const tx_out tx_output = tx.vout[i-1]; - remove_output(v, tx_output.amount); - if (i > 1) - { - cur->get(&k, &v, DB_PREV_DUP); - } - } - } - - cur.close(); -} - -// TODO: probably remove this function -void BlockchainBDB::remove_output(const tx_out& tx_output) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__ << " (unused version - does nothing)"); - return; -} - -void BlockchainBDB::remove_output(const uint64_t& out_index, const uint64_t amount) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy k(out_index); - - auto result = m_output_indices->del(DB_DEFAULT_TX, &k, 0); - if (result == DB_NOTFOUND) - { - LOG_PRINT_L0("Unexpected: global output index not found in m_output_indices"); - } - else if (result) - { - throw1(DB_ERROR("Error adding removal of output tx index to db transaction")); - } - - result = m_output_txs->del(DB_DEFAULT_TX, &k, 0); - // if (result != 0 && result != DB_NOTFOUND) - // throw1(DB_ERROR("Error adding removal of output tx hash to db transaction")); - if (result == DB_NOTFOUND) - { - LOG_PRINT_L0("Unexpected: global output index not found in m_output_txs"); - } - else if (result) - { - throw1(DB_ERROR("Error adding removal of output tx hash to db transaction")); - } - - result = m_output_keys->del(DB_DEFAULT_TX, &k, 0); - if (result == DB_NOTFOUND) - { - LOG_PRINT_L0("Unexpected: global output index not found in m_output_keys"); - } - else if (result) - throw1(DB_ERROR("Error adding removal of output pubkey to db transaction")); - - remove_amount_output_index(amount, out_index); - - m_num_outputs--; -} - -void BlockchainBDB::remove_amount_output_index(const uint64_t amount, const uint64_t global_output_index) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - bdb_cur cur(DB_DEFAULT_TX, m_output_amounts); - - Dbt_copy k(amount); - Dbt_copy v; - - auto result = cur->get(&k, &v, DB_SET); - if (result == DB_NOTFOUND) - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but amount not found")); - else if (result) - throw0(DB_ERROR("DB error attempting to get an output")); - - db_recno_t num_elems = 0; - cur->count(&num_elems, 0); - - // workaround for Berkeley DB to start at end of k's duplicate list: - // if next key exists: - // - move cursor to start of next key's duplicate list, then move back one - // duplicate element to reach the end of the original key's duplicate - // list. - // - // else if the next key doesn't exist: - // - that means we're already on the last key. - // - move cursor to last element in the db, which is the last element of - // the desired key's duplicate list. - - result = cur->get(&k, &v, DB_NEXT_NODUP); - if (result != 0 && result != DB_NOTFOUND) - throw0(DB_ERROR("DB error attempting to get next non-duplicate output amount")); - - if (result == 0) - result = cur->get(&k, &v, DB_PREV); - else if (result == DB_NOTFOUND) - result = cur->get(&k, &v, DB_LAST); - - bool found_index = false; - uint64_t amount_output_index = 0; - uint64_t goi = 0; - - for (uint64_t i = num_elems; i > 0; --i) - { - goi = v; - if (goi == global_output_index) - { - amount_output_index = i-1; - found_index = true; - break; - } - if (i > 1) - cur->get(&k, &v, DB_PREV_DUP); - } - - if (found_index) - { - // found the amount output index - // now delete it - result = cur->del(0); - if (result) - throw0(DB_ERROR(std::string("Error deleting amount output index ").append(boost::lexical_cast(amount_output_index)).c_str())); - } - else - { - // not found - throw1(OUTPUT_DNE("Failed to find amount output index")); - } - cur.close(); -} - -void BlockchainBDB::add_spent_key(const crypto::key_image& k_image) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy val_key(k_image); - if (m_spent_keys->exists(DB_DEFAULT_TX, &val_key, 0) == 0) - throw1(KEY_IMAGE_EXISTS("Attempting to add spent key image that's already in the db")); - - Dbt_copy val('\0'); - if (m_spent_keys->put(DB_DEFAULT_TX, &val_key, &val, 0)) - throw1(DB_ERROR("Error adding spent key image to db transaction.")); -} - -void BlockchainBDB::remove_spent_key(const crypto::key_image& k_image) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy k(k_image); - auto result = m_spent_keys->del(DB_DEFAULT_TX, &k, 0); - if (result != 0 && result != DB_NOTFOUND) - throw1(DB_ERROR("Error adding removal of key image to db transaction")); -} - -bool BlockchainBDB::for_all_key_images(std::function f) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - bdb_cur cur(DB_DEFAULT_TX, m_spent_keys); - - Dbt_copy k; - Dbt_copy v; - bool ret = true; - int result; - while ((result = cur->get(&k, &v, DB_NEXT)) == 0) - { - if (!f(k)) - { - ret = false; - break; - } - } - if (result != DB_NOTFOUND) - ret = false; - - cur.close(); - return ret; -} - -bool BlockchainBDB::for_all_blocks(std::function f) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - bdb_cur cur(DB_DEFAULT_TX, m_blocks); - - Dbt_copy k; - Dbt_safe v; - bool ret = true; - int result; - while ((result = cur->get(&k, &v, DB_NEXT)) == 0) - { - uint64_t height = k - 1; - blobdata bd; - bd.assign(reinterpret_cast(v.get_data()), v.get_size()); - block b; - if (!parse_and_validate_block_from_blob(bd, b)) - throw0(DB_ERROR("Failed to parse block from blob retrieved from the db")); - crypto::hash hash; - if (!get_block_hash(b, hash)) - throw0(DB_ERROR("Failed to get block hash from blob retrieved from the db")); - if (!f(height, hash, b)) - { - ret = false; - break; - } - } - if (result != DB_NOTFOUND) - ret = false; - - cur.close(); - return ret; -} - -bool BlockchainBDB::for_all_transactions(std::function f) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - bdb_cur cur(DB_DEFAULT_TX, m_txs); - - Dbt_copy k; - Dbt_safe v; - bool ret = true; - int result; - while ((result = cur->get(&k, &v, DB_NEXT)) == 0) - { - blobdata bd; - bd.assign(reinterpret_cast(v.get_data()), v.get_size()); - transaction tx; - if (!parse_and_validate_tx_from_blob(bd, tx)) - throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db")); - if (!f(k, tx)) - { - ret = false; - break; - } - } - if (result != DB_NOTFOUND) - ret = false; - - cur.close(); - return ret; -} - -bool BlockchainBDB::for_all_outputs(std::function f) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - bdb_cur cur(DB_DEFAULT_TX, m_output_amounts); - - Dbt_copy k; - Dbt_copy v; - bool ret = true; - int result; - while ((result = cur->get(&k, &v, DB_NEXT)) == 0) - { - uint32_t global_index = v - 1; - tx_out_index toi = get_output_tx_and_index_from_global(global_index); - if (!f(k, toi.first, toi.second)) - { - ret = false; - break; - } - } - if (result != DB_NOTFOUND) - ret = false; - - cur.close(); - return ret; -} - -blobdata BlockchainBDB::output_to_blob(const tx_out& output) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - blobdata b; - if (!t_serializable_object_to_blob(output, b)) - throw1(DB_ERROR("Error serializing output to blob")); - return b; -} - -tx_out BlockchainBDB::output_from_blob(const blobdata& blob) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - std::stringstream ss; - ss << blob; - binary_archive ba(ss); - tx_out o; - - if (!(::serialization::serialize(ba, o))) - throw1(DB_ERROR("Error deserializing tx output blob")); - - return o; -} - -uint64_t BlockchainBDB::get_output_global_index(const uint64_t& amount, const uint64_t& index) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - std::vector < uint64_t > offsets; - std::vector < uint64_t > global_indices; - offsets.push_back(index); - get_output_global_indices(amount, offsets, global_indices); - if (!global_indices.size()) - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but amount not found")); - - return global_indices[0]; -} - -void BlockchainBDB::check_open() const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - if (!m_open) - throw0(DB_ERROR("DB operation attempted on a not-open DB instance")); -} - -BlockchainBDB::~BlockchainBDB() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - - if (m_open) - { - close(); - } -} - -BlockchainBDB::BlockchainBDB(bool batch_transactions) : - BlockchainDB(), - m_buffer(DB_BUFFER_COUNT, DB_BUFFER_LENGTH) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - // initialize folder to something "safe" just in case - // someone accidentally misuses this class... - m_folder = "thishsouldnotexistbecauseitisgibberish"; - m_run_checkpoint = 0; - m_batch_transactions = batch_transactions; - m_write_txn = nullptr; - m_height = 0; - - m_hardfork = nullptr; -} - -void BlockchainBDB::open(const std::string& filename, const int db_flags) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - - if (m_open) - throw0(DB_OPEN_FAILURE("Attempted to open db, but it's already open")); - - boost::filesystem::path direc(filename); - if (boost::filesystem::exists(direc)) - { - if (!boost::filesystem::is_directory(direc)) - throw0(DB_OPEN_FAILURE("DB needs a directory path, but a file was passed")); - } - else - { - if (!boost::filesystem::create_directories(direc)) - throw0(DB_OPEN_FAILURE(std::string("Failed to create directory ").append(filename).c_str())); - } - - m_folder = filename; - - try - { - - //Create BerkeleyDB environment - m_env = new DbEnv(0); // no flags needed for DbEnv - - uint32_t db_env_open_flags = DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN | DB_RECOVER | DB_THREAD; - - // Set some default values for these parameters. - // They can be overridden using the DB_CONFIG file. - m_env->set_cachesize(0, DB_DEF_CACHESIZE, 1); - m_env->set_lk_max_locks(DB_MAX_LOCKS); - m_env->set_lk_max_lockers(DB_MAX_LOCKS); - m_env->set_lk_max_objects(DB_MAX_LOCKS); - - #ifndef __OpenBSD__ //OpenBSD's DB package is too old to support this feature - if(m_auto_remove_logs) - m_env->log_set_config(DB_LOG_AUTO_REMOVE, 1); - #endif - - // last parameter left 0, files will be created with default rw access - m_env->open(filename.c_str(), db_env_open_flags, 0); - m_env->set_flags(db_flags, 1); - - // begin transaction to init dbs - bdb_txn_safe txn; - m_env->txn_begin(NULL, txn, 0); - - // create Dbs in the environment - m_blocks = new Db(m_env, 0); - m_block_heights = new Db(m_env, 0); - m_block_hashes = new Db(m_env, 0); - m_block_timestamps = new Db(m_env, 0); - m_block_sizes = new Db(m_env, 0); - m_block_diffs = new Db(m_env, 0); - m_block_coins = new Db(m_env, 0); - - m_txs = new Db(m_env, 0); - m_tx_unlocks = new Db(m_env, 0); - m_tx_heights = new Db(m_env, 0); - m_tx_outputs = new Db(m_env, 0); - - m_output_txs = new Db(m_env, 0); - m_output_indices = new Db(m_env, 0); - m_output_amounts = new Db(m_env, 0); - m_output_keys = new Db(m_env, 0); - - m_spent_keys = new Db(m_env, 0); - - m_hf_starting_heights = new Db(m_env, 0); - m_hf_versions = new Db(m_env, 0); - - m_properties = new Db(m_env, 0); - - // Tell DB about Dbs that need duplicate support - // Note: no need to tell about sorting, - // as the default is insertion order, which we want - m_tx_outputs->set_flags(DB_DUP); - m_output_amounts->set_flags(DB_DUP); - - // Tell DB about fixed-size values. - m_block_hashes->set_re_len(sizeof(crypto::hash)); - m_block_timestamps->set_re_len(sizeof(uint64_t)); - m_block_sizes->set_re_len(sizeof(size_t)); // should really store block size as uint64_t... - m_block_diffs->set_re_len(sizeof(difficulty_type)); - m_block_coins->set_re_len(sizeof(uint64_t)); - - m_output_txs->set_re_len(sizeof(crypto::hash)); - m_output_indices->set_re_len(sizeof(uint64_t)); - m_output_keys->set_re_len(sizeof(output_data_t)); - - m_hf_starting_heights->set_re_len(sizeof(uint64_t)); - m_hf_versions->set_re_len(sizeof(uint8_t)); - - //TODO: Find out if we need to do Db::set_flags(DB_RENUMBER) - // for the RECNO databases. We shouldn't as we're only - // inserting/removing from the end, but we'll see. - - // open Dbs in the environment - // m_tx_outputs and m_output_amounts must be DB_HASH or DB_BTREE - // because they need duplicate entry support. The rest are DB_RECNO, - // as it seems that will be the most performant choice. - m_blocks->open(txn, BDB_BLOCKS, NULL, DB_RECNO, DB_CREATE, 0); - - m_block_timestamps->open(txn, BDB_BLOCK_TIMESTAMPS, NULL, DB_RECNO, DB_CREATE, 0); - m_block_heights->open(txn, BDB_BLOCK_HEIGHTS, NULL, DB_HASH, DB_CREATE, 0); - m_block_hashes->open(txn, BDB_BLOCK_HASHES, NULL, DB_RECNO, DB_CREATE, 0); - m_block_sizes->open(txn, BDB_BLOCK_SIZES, NULL, DB_RECNO, DB_CREATE, 0); - m_block_diffs->open(txn, BDB_BLOCK_DIFFS, NULL, DB_RECNO, DB_CREATE, 0); - m_block_coins->open(txn, BDB_BLOCK_COINS, NULL, DB_RECNO, DB_CREATE, 0); - - m_txs->open(txn, BDB_TXS, NULL, DB_HASH, DB_CREATE, 0); - m_tx_unlocks->open(txn, BDB_TX_UNLOCKS, NULL, DB_HASH, DB_CREATE, 0); - m_tx_heights->open(txn, BDB_TX_HEIGHTS, NULL, DB_HASH, DB_CREATE, 0); - m_tx_outputs->open(txn, BDB_TX_OUTPUTS, NULL, DB_HASH, DB_CREATE, 0); - - m_output_txs->open(txn, BDB_OUTPUT_TXS, NULL, DB_RECNO, DB_CREATE, 0); - m_output_indices->open(txn, BDB_OUTPUT_INDICES, NULL, DB_RECNO, DB_CREATE, 0); - m_output_amounts->open(txn, BDB_OUTPUT_AMOUNTS, NULL, DB_HASH, DB_CREATE, 0); - m_output_keys->open(txn, BDB_OUTPUT_KEYS, NULL, DB_RECNO, DB_CREATE, 0); - - m_spent_keys->open(txn, BDB_SPENT_KEYS, NULL, DB_HASH, DB_CREATE, 0); - - m_hf_starting_heights->open(txn, BDB_HF_STARTING_HEIGHTS, NULL, DB_RECNO, DB_CREATE, 0); - m_hf_versions->open(txn, BDB_HF_VERSIONS, NULL, DB_RECNO, DB_CREATE, 0); - - m_properties->open(txn, BDB_PROPERTIES, NULL, DB_HASH, DB_CREATE, 0); - - txn.commit(); - - DB_BTREE_STAT* stats; - - // DB_FAST_STAT can apparently cause an incorrect number of records - // to be returned. The flag should be set to 0 instead if this proves - // to be the case. - - // ND: The bug above can occur when a block is popped and the application - // exits without pushing a new block to the db. Set txn to NULL and DB_FAST_STAT - // to zero (0) for reliability. - m_blocks->stat(NULL, &stats, 0); - m_height = stats->bt_nkeys; - free(stats); - - // see above comment about DB_FAST_STAT - m_output_indices->stat(NULL, &stats, 0); - m_num_outputs = stats->bt_nkeys; - free(stats); - - // checks for compatibility - bool compatible = true; - - Dbt_copy key("version"); - Dbt_copy result; - auto get_result = m_properties->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == 0) - { - if (result > VERSION) - { - LOG_PRINT_RED_L0("Existing BerkeleyDB database was made by a later version. We don't know how it will change yet."); - compatible = false; - } -#if VERSION > 0 - else if (result < VERSION) - { - compatible = false; - } -#endif - } - else - { - // if not found, but we're on version 0, it's fine. If the DB's empty, it's fine too. - if (VERSION > 0 && m_height > 0) - compatible = false; - } - - if (!compatible) - { - m_open = false; - LOG_PRINT_RED_L0("Existing BerkeleyDB database is incompatible with this version."); - LOG_PRINT_RED_L0("Please delete the existing database and resync."); - return; - } - - if (1 /* this can't be set readonly atm */) - { - // only write version on an empty DB - if (m_height == 0) - { - Dbt_copy k("version"); - Dbt_copy v(VERSION); - auto put_result = m_properties->put(DB_DEFAULT_TX, &k, &v, 0); - if (put_result != 0) - { - m_open = false; - LOG_PRINT_RED_L0("Failed to write version to database."); - return; - } - } - } - - // run checkpoint thread - m_run_checkpoint = true; - m_checkpoint_thread.reset(new boost::thread(&BlockchainBDB::checkpoint_worker, this)); - } - catch (const std::exception& e) - { - throw0(DB_OPEN_FAILURE(e.what())); - } - - m_open = true; -} - -void BlockchainBDB::close() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - this->sync(); - - m_run_checkpoint = false; - m_checkpoint_thread->join(); - m_checkpoint_thread.reset(); - - // FIXME: not yet thread safe!!! Use with care. - m_open = false; - - // DB_FORCESYNC is only available on newer version of libdb. - // The libdb doc says using the DB_FORCESYNC flag to DB_ENV->close - // is "similar to calling the DB->close(0) method to close each - // database handle". So this is what we do here as a fallback. -#ifdef DB_FORCESYNC - m_env->close(DB_FORCESYNC); -#else - m_blocks->close(0); - m_block_heights->close(0); - m_block_hashes->close(0); - m_block_timestamps->close(0); - m_block_sizes->close(0); - m_block_diffs->close(0); - m_block_coins->close(0); - - m_txs->close(0); - m_tx_unlocks->close(0); - m_tx_heights->close(0); - m_tx_outputs->close(0); - - m_output_txs->close(0); - m_output_indices->close(0); - m_output_amounts->close(0); - m_output_keys->close(0); - - m_spent_keys->close(0); - - m_hf_starting_heights->close(0); - m_hf_versions->close(0); - - m_properties->close(0); - - m_env->close(0); -#endif -} - -void BlockchainBDB::sync() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - try - { - m_blocks->sync(0); - m_block_heights->sync(0); - m_block_hashes->sync(0); - m_block_timestamps->sync(0); - m_block_sizes->sync(0); - m_block_diffs->sync(0); - m_block_coins->sync(0); - - m_txs->sync(0); - m_tx_unlocks->sync(0); - m_tx_heights->sync(0); - m_tx_outputs->sync(0); - - m_output_txs->sync(0); - m_output_indices->sync(0); - m_output_amounts->sync(0); - m_output_keys->sync(0); - - m_spent_keys->sync(0); - - if (m_hf_starting_heights != nullptr) - m_hf_starting_heights->sync(0); - if (m_hf_versions != nullptr) - m_hf_versions->sync(0); - - m_properties->sync(0); - } - catch (const std::exception& e) - { - throw0(DB_ERROR(std::string("Failed to sync database: ").append(e.what()).c_str())); - } -} - -void BlockchainBDB::reset() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - m_write_txn = &txn; - try - { - uint32_t count; - - m_blocks->truncate(*m_write_txn, &count, 0); - m_block_heights->truncate(*m_write_txn, &count, 0); - m_block_hashes->truncate(*m_write_txn, &count, 0); - m_block_timestamps->truncate(*m_write_txn, &count, 0); - m_block_sizes->truncate(*m_write_txn, &count, 0); - m_block_diffs->truncate(*m_write_txn, &count, 0); - m_block_coins->truncate(*m_write_txn, &count, 0); - - m_txs->truncate(*m_write_txn, &count, 0); - m_tx_unlocks->truncate(*m_write_txn, &count, 0); - m_tx_heights->truncate(*m_write_txn, &count, 0); - m_tx_outputs->truncate(*m_write_txn, &count, 0); - - m_output_txs->truncate(*m_write_txn, &count, 0); - m_output_indices->truncate(*m_write_txn, &count, 0); - m_output_amounts->truncate(*m_write_txn, &count, 0); - m_output_keys->truncate(*m_write_txn, &count, 0); - - m_spent_keys->truncate(*m_write_txn, &count, 0); - - m_hf_starting_heights->truncate(*m_write_txn, &count, 0); - m_hf_versions->truncate(*m_write_txn, &count, 0); - - m_properties->truncate(*m_write_txn, &count, 0); - } - catch (const std::exception& e) - { - throw0(DB_ERROR(std::string("Failed to reset database: ").append(e.what()).c_str())); - } - m_write_txn = NULL; -} - -std::vector BlockchainBDB::get_filenames() const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - std::vector filenames; - - char *fname, *dbname; - const char **pfname, **pdbname; - - pfname = (const char **)&fname; - pdbname = (const char **)&dbname; - - m_blocks->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_block_heights->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_block_hashes->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_block_timestamps->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_block_sizes->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_block_diffs->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_block_coins->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_txs->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_tx_unlocks->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_tx_heights->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_tx_outputs->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_output_txs->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_output_indices->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_output_amounts->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_output_keys->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_spent_keys->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_hf_starting_heights->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_hf_versions->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - m_properties->get_dbname(pfname, pdbname); - filenames.push_back(fname); - - std::vector full_paths; - - for (auto& filename : filenames) - { - boost::filesystem::path p(m_folder); - p /= filename; - full_paths.push_back(p.string()); - } - - return full_paths; -} - -std::string BlockchainBDB::get_db_name() const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - - return std::string("BerkeleyDB"); -} - -// TODO: this? -bool BlockchainBDB::lock() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - return false; -} - -// TODO: this? -void BlockchainBDB::unlock() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); -} - -bool BlockchainBDB::block_exists(const crypto::hash& h, uint64_t *height) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(h); - - auto get_result = m_block_heights->exists(DB_DEFAULT_TX, &key, 0); - if (get_result == DB_NOTFOUND) - { - LOG_PRINT_L3("Block with hash " << epee::string_tools::pod_to_hex(h) << " not found in db"); - return false; - } - else if (get_result) - throw0(DB_ERROR("DB error attempting to fetch block index from hash")); - - if (height) - *height = get_result - 1; - - return true; -} - -block BlockchainBDB::get_block(const crypto::hash& h) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - return get_block_from_height(get_block_height(h)); -} - -uint64_t BlockchainBDB::get_block_height(const crypto::hash& h) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(h); - Dbt_copy result; - - auto get_result = m_block_heights->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == DB_NOTFOUND) - throw1(BLOCK_DNE("Attempted to retrieve non-existent block height")); - else if (get_result) - throw0(DB_ERROR("Error attempting to retrieve a block height from the db")); - - return result - 1; -} - -block_header BlockchainBDB::get_block_header(const crypto::hash& h) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - // block_header object is automatically cast from block object - return get_block(h); -} - -block BlockchainBDB::get_block_from_height(const uint64_t& height) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(height + 1); - Dbt_safe result; - auto get_result = m_blocks->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw0(BLOCK_DNE(std::string("Attempt to get block from height ").append(boost::lexical_cast(height)).append(" failed -- block not in db").c_str())); - } - else if (get_result) - throw0(DB_ERROR("Error attempting to retrieve a block from the db")); - - blobdata bd; - bd.assign(reinterpret_cast(result.get_data()), result.get_size()); - - block b; - if (!parse_and_validate_block_from_blob(bd, b)) - throw0(DB_ERROR("Failed to parse block from blob retrieved from the db")); - - return b; -} - -uint64_t BlockchainBDB::get_block_timestamp(const uint64_t& height) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(height + 1); - Dbt_copy result; - auto get_result = m_block_timestamps->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw0(BLOCK_DNE(std::string("Attempt to get timestamp from height ").append(boost::lexical_cast(height)).append(" failed -- timestamp not in db").c_str())); - } - else if (get_result) - throw0(DB_ERROR("Error attempting to retrieve a timestamp from the db")); - - return result; -} - -uint64_t BlockchainBDB::get_top_block_timestamp() const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - // if no blocks, return 0 - if (m_height == 0) - { - return 0; - } - - return get_block_timestamp(m_height - 1); -} - -size_t BlockchainBDB::get_block_size(const uint64_t& height) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(height + 1); - Dbt_copy result; - auto get_result = m_block_sizes->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw0(BLOCK_DNE(std::string("Attempt to get block size from height ").append(boost::lexical_cast(height)).append(" failed -- block size not in db").c_str())); - } - else if (get_result) - throw0(DB_ERROR("Error attempting to retrieve a block size from the db")); - - return result; -} - -difficulty_type BlockchainBDB::get_block_cumulative_difficulty(const uint64_t& height) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__ << " height: " << height); - check_open(); - - Dbt_copy key(height + 1); - Dbt_copy result; - auto get_result = m_block_diffs->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw0(BLOCK_DNE(std::string("Attempt to get cumulative difficulty from height ").append(boost::lexical_cast(height)).append(" failed -- difficulty not in db").c_str())); - } - else if (get_result) - throw0(DB_ERROR("Error attempting to retrieve a cumulative difficulty from the db")); - - return result; -} - -difficulty_type BlockchainBDB::get_block_difficulty(const uint64_t& height) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - difficulty_type diff1 = 0; - difficulty_type diff2 = 0; - - diff1 = get_block_cumulative_difficulty(height); - if (height != 0) - { - diff2 = get_block_cumulative_difficulty(height - 1); - } - - return diff1 - diff2; -} - -uint64_t BlockchainBDB::get_block_already_generated_coins(const uint64_t& height) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(height + 1); - Dbt_copy result; - auto get_result = m_block_coins->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw0(BLOCK_DNE(std::string("Attempt to get generated coins from height ").append(boost::lexical_cast(height)).append(" failed -- block size not in db").c_str())); - } - else if (get_result) - throw0(DB_ERROR("Error attempting to retrieve a total generated coins from the db")); - - return result; -} - -crypto::hash BlockchainBDB::get_block_hash_from_height(const uint64_t& height) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(height + 1); - Dbt_copy result; - auto get_result = m_block_hashes->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw0(BLOCK_DNE(std::string("Attempt to get hash from height ").append(boost::lexical_cast(height)).append(" failed -- hash not in db").c_str())); - } - else if (get_result) - throw0(DB_ERROR("Error attempting to retrieve a block hash from the db.")); - - return result; -} - -std::vector BlockchainBDB::get_blocks_range(const uint64_t& h1, const uint64_t& h2) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - std::vector v; - - for (uint64_t height = h1; height <= h2; ++height) - { - v.push_back(get_block_from_height(height)); - } - - return v; -} - -std::vector BlockchainBDB::get_hashes_range(const uint64_t& h1, const uint64_t& h2) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - std::vector v; - - for (uint64_t height = h1; height <= h2; ++height) - { - v.push_back(get_block_hash_from_height(height)); - } - - return v; -} - -crypto::hash BlockchainBDB::top_block_hash() const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - if (m_height > 0) - { - return get_block_hash_from_height(m_height - 1); - } - - return null_hash; -} - -block BlockchainBDB::get_top_block() const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - if (m_height > 0) - { - return get_block_from_height(m_height - 1); - } - - block b; - return b; -} - -uint64_t BlockchainBDB::height() const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - return m_height; -} - -bool BlockchainBDB::tx_exists(const crypto::hash& h) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(h); - - TIME_MEASURE_START(time1); - auto get_result = m_txs->exists(DB_DEFAULT_TX, &key, 0); - TIME_MEASURE_FINISH(time1); - time_tx_exists += time1; - if (get_result == DB_NOTFOUND) - { - LOG_PRINT_L1("transaction with hash " << epee::string_tools::pod_to_hex(h) << " not found in db"); - return false; - } - else if (get_result) - throw0(DB_ERROR("DB error attempting to fetch transaction from hash")); - - return true; -} - -uint64_t BlockchainBDB::get_tx_unlock_time(const crypto::hash& h) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(h); - Dbt_copy result; - auto get_result = m_tx_unlocks->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == DB_NOTFOUND) - throw1(TX_DNE(std::string("tx unlock time with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str())); - else if (get_result) - throw0(DB_ERROR("DB error attempting to fetch tx unlock time from hash")); - - return result; -} - -transaction BlockchainBDB::get_tx(const crypto::hash& h) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(h); - Dbt_safe result; - auto get_result = m_txs->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == DB_NOTFOUND) - throw1(TX_DNE(std::string("tx with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str())); - else if (get_result) - throw0(DB_ERROR("DB error attempting to fetch tx from hash")); - - blobdata bd; - bd.assign(reinterpret_cast(result.get_data()), result.get_size()); - - transaction tx; - if (!parse_and_validate_tx_from_blob(bd, tx)) - throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db")); - - return tx; -} - -uint64_t BlockchainBDB::get_tx_count() const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - DB_BTREE_STAT* stats; - - // DB_FAST_STAT can apparently cause an incorrect number of records - // to be returned. The flag should be set to 0 instead if this proves - // to be the case. - m_txs->stat(DB_DEFAULT_TX, &stats, DB_FAST_STAT); - auto num_txs = stats->bt_nkeys; - delete stats; - - return num_txs; -} - -std::vector BlockchainBDB::get_tx_list(const std::vector& hlist) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - std::vector v; - -for (auto& h : hlist) - { - v.push_back(get_tx(h)); - } - - return v; -} - -uint64_t BlockchainBDB::get_tx_block_height(const crypto::hash& h) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(h); - Dbt_copy result; - auto get_result = m_tx_heights->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw1(TX_DNE(std::string("tx height with hash ").append(epee::string_tools::pod_to_hex(h)).append(" not found in db").c_str())); - } - else if (get_result) - throw0(DB_ERROR("DB error attempting to fetch tx height from hash")); - - return (uint64_t)result - 1; -} - -uint64_t BlockchainBDB::get_num_outputs(const uint64_t& amount) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - bdb_cur cur(DB_DEFAULT_TX, m_output_amounts); - - Dbt_copy k(amount); - Dbt_copy v; - auto result = cur->get(&k, &v, DB_SET); - if (result == DB_NOTFOUND) - { - return 0; - } - else if (result) - throw0(DB_ERROR("DB error attempting to get number of outputs of an amount")); - - db_recno_t num_elems = 0; - cur->count(&num_elems, 0); - - cur.close(); - - return num_elems; -} - -output_data_t BlockchainBDB::get_output_key(const uint64_t& global_index) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy k(global_index); - Dbt_copy v; - auto get_result = m_output_keys->get(DB_DEFAULT_TX, &k, &v, 0); - if (get_result == DB_NOTFOUND) - throw1(OUTPUT_DNE("Attempting to get output pubkey by global index, but key does not exist")); - else if (get_result) - throw0(DB_ERROR("Error attempting to retrieve an output pubkey from the db")); - - return v; -} - -output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64_t& index) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - uint64_t glob_index = get_output_global_index(amount, index); - return get_output_key(glob_index); -} - -tx_out_index BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - std::vector < uint64_t > offsets; - std::vector indices; - offsets.push_back(index); - get_output_tx_and_index(amount, offsets, indices); - if (!indices.size()) - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but amount not found")); - - return indices[0]; -} - -std::vector BlockchainBDB::get_tx_output_indices(const crypto::hash& h) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - std::vector index_vec; - - bdb_cur cur(DB_DEFAULT_TX, m_tx_outputs); - - Dbt_copy k(h); - Dbt_copy v; - auto result = cur->get(&k, &v, DB_SET); - if (result == DB_NOTFOUND) - throw1(OUTPUT_DNE("Attempting to get an output by tx hash and tx index, but output not found")); - else if (result) - throw0(DB_ERROR("DB error attempting to get an output")); - - db_recno_t num_elems = 0; - cur->count(&num_elems, 0); - - for (uint64_t i = 0; i < num_elems; ++i) - { - index_vec.push_back(v); - cur->get(&k, &v, DB_NEXT_DUP); - } - - cur.close(); - - return index_vec; -} - -std::vector BlockchainBDB::get_tx_amount_output_indices(const crypto::hash& h) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - std::vector index_vec; - std::vector index_vec2; - - // get the transaction's global output indices first - index_vec = get_tx_output_indices(h); - // these are next used to obtain the amount output indices - - transaction tx = get_tx(h); - - uint64_t i = 0; - uint64_t global_index; - for (const auto& vout : tx.vout) - { - uint64_t amount = vout.amount; - - global_index = index_vec[i]; - - bdb_cur cur(DB_DEFAULT_TX, m_output_amounts); - - Dbt_copy k(amount); - Dbt_copy v; - - auto result = cur->get(&k, &v, DB_SET); - if (result == DB_NOTFOUND) - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but amount not found")); - else if (result) - throw0(DB_ERROR("DB error attempting to get an output")); - - db_recno_t num_elems = 0; - cur->count(&num_elems, 0); - - uint64_t amount_output_index = 0; - uint64_t output_index = 0; - bool found_index = false; - for (uint64_t j = 0; j < num_elems; ++j) - { - output_index = v; - if (output_index == global_index) - { - amount_output_index = j; - found_index = true; - break; - } - cur->get(&k, &v, DB_NEXT_DUP); - } - if (found_index) - { - index_vec2.push_back(amount_output_index); - } - else - { - // not found - cur.close(); - throw1(OUTPUT_DNE("specified output not found in db")); - } - - cur.close(); - ++i; - } - - return index_vec2; -} - - -tx_out_index BlockchainBDB::get_output_tx_and_index_from_global(const uint64_t& index) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy k(index); - Dbt_copy v; - - auto get_result = m_output_txs->get(DB_DEFAULT_TX, &k, &v, 0); - if (get_result == DB_NOTFOUND) - throw1(OUTPUT_DNE("output with given index not in db")); - else if (get_result) - throw0(DB_ERROR("DB error attempting to fetch output tx hash")); - - crypto::hash tx_hash = v; - - Dbt_copy result; - get_result = m_output_indices->get(DB_DEFAULT_TX, &k, &result, 0); - if (get_result == DB_NOTFOUND) - throw1(OUTPUT_DNE("output with given index not in db")); - else if (get_result) - throw0(DB_ERROR("DB error attempting to fetch output tx index")); - - return tx_out_index(tx_hash, result); -} - -bool BlockchainBDB::has_key_image(const crypto::key_image& img) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy val_key(img); - if (m_spent_keys->exists(DB_DEFAULT_TX, &val_key, 0) == 0) - { - return true; - } - - return false; -} - -// Ostensibly BerkeleyDB has batch transaction support built-in, -// so the following few functions will be NOP. - -bool BlockchainBDB::batch_start(uint64_t batch_num_blocks) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - return false; -} - -void BlockchainBDB::batch_commit() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); -} - -void BlockchainBDB::batch_stop() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); -} - -void BlockchainBDB::batch_abort() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); -} - -void BlockchainBDB::set_batch_transactions(bool batch_transactions) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - m_batch_transactions = batch_transactions; - LOG_PRINT_L3("batch transactions " << (m_batch_transactions ? "enabled" : "disabled")); -} - -void BlockchainBDB::block_txn_start(bool readonly) -{ - // TODO -} - -void BlockchainBDB::block_txn_stop() -{ - // TODO -} - -void BlockchainBDB::block_txn_abort() -{ - // TODO -} - -uint64_t BlockchainBDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const std::vector& txs) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - m_write_txn = &txn; - - uint64_t num_outputs = m_num_outputs; - try - { - BlockchainDB::add_block(blk, block_size, cumulative_difficulty, coins_generated, txs); - m_write_txn = NULL; - - TIME_MEASURE_START(time1); - txn.commit(); - TIME_MEASURE_FINISH(time1); - time_commit1 += time1; - } - catch (const std::exception& e) - { - m_num_outputs = num_outputs; - m_write_txn = NULL; - throw; - } - - return ++m_height; -} - -void BlockchainBDB::pop_block(block& blk, std::vector& txs) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - m_write_txn = &txn; - - uint64_t num_outputs = m_num_outputs; - try - { - BlockchainDB::pop_block(blk, txs); - - m_write_txn = NULL; - txn.commit(); - } - catch (...) - { - m_num_outputs = num_outputs; - m_write_txn = NULL; - throw; - } - - --m_height; -} - -void BlockchainBDB::get_output_tx_and_index_from_global(const std::vector &global_indices, std::vector &tx_out_indices) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - tx_out_indices.clear(); - - for (const uint64_t &index : global_indices) - { - Dbt_copy k(index); - Dbt_copy v; - - auto get_result = m_output_txs->get(DB_DEFAULT_TX, &k, &v, 0); - if (get_result == DB_NOTFOUND) - throw1(OUTPUT_DNE("output with given index not in db")); - else if (get_result) - throw0(DB_ERROR("DB error attempting to fetch output tx hash")); - - crypto::hash tx_hash = v; - - Dbt_copy result; - get_result = m_output_indices->get(DB_DEFAULT_TX, &k, &result, 0); - if (get_result == DB_NOTFOUND) - throw1(OUTPUT_DNE("output with given index not in db")); - else if (get_result) - throw0(DB_ERROR("DB error attempting to fetch output tx index")); - auto hashindex = tx_out_index(tx_hash, result); - tx_out_indices.push_back(hashindex); - } -} - -void BlockchainBDB::get_output_global_indices(const uint64_t& amount, const std::vector &offsets, std::vector &global_indices) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - TIME_MEASURE_START(txx); - check_open(); - - bdb_cur cur(DB_DEFAULT_TX, m_output_amounts); - uint64_t max = 0; - for (const uint64_t& index : offsets) - { - if (index > max) - max = index; - } - - // get returned keypairs count -#define DB_COUNT_RECORDS(dbt, cnt) \ - do { \ - uint32_t *_p = (uint32_t *) ((uint8_t *)(dbt)->data + \ - (dbt)->ulen - sizeof(uint32_t)); \ - cnt = 0; \ - while(*_p != (uint32_t) -1) { \ - _p -= 2; \ - ++cnt; \ - } \ - } while(0); \ - - Dbt_copy k(amount); - Dbt_copy v; - uint64_t buflen = 0; - uint64_t t_dbmul = 0; - uint64_t t_dbscan = 0; - - auto result = cur->get(&k, &v, DB_SET); - if (result == DB_NOTFOUND) - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but amount not found")); - else if (result) - throw0(DB_ERROR("DB error attempting to get an output")); - - db_recno_t num_elems = 0; - cur->count(&num_elems, 0); - - if (max <= 1 && num_elems <= max) - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but output not found")); - - TIME_MEASURE_START(db2); - if (max <= 1) - { - for (const uint64_t& index : offsets) - { - TIME_MEASURE_START(t_seek); - - auto result = cur->get(&k, &v, DB_SET); - if (result == DB_NOTFOUND) - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but amount not found")); - else if (result) - throw0(DB_ERROR("DB error attempting to get an output")); - - for (uint64_t i = 0; i < index; ++i) - cur->get(&k, &v, DB_NEXT_DUP); - - uint64_t glob_index = v; - - LOG_PRINT_L3("L0->v: " << glob_index); - global_indices.push_back(glob_index); - - TIME_MEASURE_FINISH(t_seek); - } - } - else - { - // setup a 256KB minimum buffer size - uint32_t pagesize = 256 * 1024; - - // Retrieve only a suitable portion of the kvp data, up to somewhere near - // the maximum offset value being retrieved - buflen = (max + 1) * 4 * sizeof(uint64_t); - buflen = ((buflen / pagesize) + ((buflen % pagesize) > 0 ? 1 : 0)) * pagesize; - - bool nomem = false; - Dbt data; - - bool singlebuff = buflen <= m_buffer.get_buffer_size(); - buflen = buflen < m_buffer.get_buffer_size() ? buflen : m_buffer.get_buffer_size(); - bdb_safe_buffer_t::type buffer = nullptr; - bdb_safe_buffer_autolock lock(m_buffer, buffer); - - data.set_data(buffer); - data.set_ulen(buflen); - data.set_size(buflen); - data.set_flags(DB_DBT_USERMEM); - - uint32_t curcount = 0; - uint32_t blockstart = 0; - for (const uint64_t& index : offsets) - { - if (index >= num_elems) - { - LOG_PRINT_L1("Index: " << index << " Elems: " << num_elems << " partial results found for get_output_tx_and_index"); - break; - } - - // fixme! for whatever reason, the first call to DB_MULTIPLE | DB_SET does not - // retrieve the first value. - if (index <= 1 || nomem) - { - auto result = cur->get(&k, &v, DB_SET); - if (result == DB_NOTFOUND) - { - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but amount not found")); - } - else if (result) - { - throw0(DB_ERROR("DB error attempting to get an output")); - } - - for (uint64_t i = 0; i < index; ++i) - cur->get(&k, &v, DB_NEXT_DUP); - } - else - { - while (index >= curcount) - { - TIME_MEASURE_START(t_db1); - try - { - cur->get(&k, &data, DB_MULTIPLE | (curcount == 0 ? DB_SET : DB_NEXT_DUP)); - blockstart = curcount; - - int count = 0; - DB_COUNT_RECORDS((DBT * ) &data, count); - curcount += count; - } - catch (const std::exception &e) - { - cur.close(); - throw0(DB_ERROR(std::string("Failed on DB_MULTIPLE: ").append(e.what()).c_str())); - } - - TIME_MEASURE_FINISH(t_db1); - t_dbmul += t_db1; - if (singlebuff) - break; - } - - LOG_PRINT_L3("Records returned: " << curcount << " Index: " << index); - TIME_MEASURE_START(t_db2); - DBT *pdata = (DBT *) &data; - - uint8_t *value; - uint64_t dlen = 0; - - void *pbase = ((uint8_t *) (pdata->data)) + pdata->ulen - sizeof(uint32_t); - uint32_t *p = (uint32_t *) pbase; - if (*p == (uint32_t) -1) - { - value = NULL; - } - else - { - p -= (index - blockstart) * 2; // index * 4 + 2; <- if DB_MULTIPLE_KEY - value = (uint8_t *) pdata->data + *p--; - dlen = *p--; - if (value == (uint8_t *) pdata->data) - value = NULL; - } - - if (value != NULL) - { - v = dlen == sizeof(uint64_t) ? *((uint64_t *) value) : *((uint32_t *) value); - } - TIME_MEASURE_FINISH(t_db2); - t_dbscan += t_db2; - } - - uint64_t glob_index = v; - - LOG_PRINT_L3("L1->v: " << glob_index); - global_indices.push_back(glob_index); - } - } - TIME_MEASURE_FINISH(db2); - - cur.close(); - - TIME_MEASURE_FINISH(txx); - - LOG_PRINT_L3("blen: " << buflen << " txx: " << txx << " db1: " << t_dbmul << " db2: " << t_dbscan); - -} - -void BlockchainBDB::get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - TIME_MEASURE_START(txx); - outputs.clear(); - - std::vector < uint64_t > global_indices; - get_output_global_indices(amount, offsets, global_indices); - - TIME_MEASURE_START(db3); - if (global_indices.size() > 0) - { - for (const uint64_t &index : global_indices) - { - Dbt_copy k(index); - Dbt_copy v; - - auto get_result = m_output_keys->get(DB_DEFAULT_TX, &k, &v, 0); - if (get_result == DB_NOTFOUND) - throw1(OUTPUT_DNE("output with given index not in db")); - else if (get_result) - throw0(DB_ERROR("DB error attempting to fetch output tx hash")); - - output_data_t data = *(output_data_t *) v.get_data(); - outputs.push_back(data); - } - } - - TIME_MEASURE_FINISH(txx); - LOG_PRINT_L3("db3: " << db3); -} - -void BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - std::vector < uint64_t > global_indices; - get_output_global_indices(amount, offsets, global_indices); - - TIME_MEASURE_START(db3); - if (global_indices.size() > 0) - get_output_tx_and_index_from_global(global_indices, indices); - TIME_MEASURE_FINISH(db3); - - LOG_PRINT_L3("db3: " << db3); -} - -std::map::BlockchainBDB::get_output_histogram(const std::vector &amounts) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - throw1(DB_ERROR("Not implemented.")); -} - -void BlockchainBDB::check_hard_fork_info() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - if (m_hf_versions == nullptr) - { - LOG_PRINT_L0("hf versions DB not open, so not checking"); - return; - } - - DB_BTREE_STAT* db_stat1, * db_stat2; - - // DB_FAST_STAT can apparently cause an incorrect number of records - // to be returned. The flag should be set to 0 instead if this proves - // to be the case. - - // Set txn to NULL and DB_FAST_STAT to zero (0) for reliability. - m_blocks->stat(NULL, &db_stat1, 0); - m_hf_versions->stat(NULL, &db_stat2, 0); - if (db_stat1->bt_nkeys != db_stat2->bt_nkeys) - { - LOG_PRINT_L0("num blocks " << db_stat1->bt_nkeys << " != " << "num hf_versions " << db_stat2->bt_nkeys << " - will clear the two hard fork DBs"); - - bdb_txn_safe txn; - bdb_txn_safe* txn_ptr = &txn; - if (m_write_txn) - txn_ptr = m_write_txn; - else - { - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - } - - try - { - uint32_t count; - m_hf_starting_heights->truncate(*txn_ptr, &count, 0); - LOG_PRINT_L0("hf_starting_heights count: " << count); - m_hf_versions->truncate(*txn_ptr, &count, 0); - LOG_PRINT_L0("hf_versions count: " << count); - - if (!m_write_txn) - txn.commit(); - } - catch (const std::exception& e) - { - throw0(DB_ERROR(std::string("Failed to clear two hard fork DBs: ").append(e.what()).c_str())); - } - } - delete db_stat1; - delete db_stat2; -} - -void BlockchainBDB::drop_hard_fork_info() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - bdb_txn_safe txn; - bdb_txn_safe* txn_ptr = &txn; - if (m_write_txn) - txn_ptr = m_write_txn; - else - { - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - } - - try - { - m_hf_starting_heights->close(0); - m_hf_versions->close(0); - m_hf_starting_heights = nullptr; - m_hf_versions = nullptr; - if (m_env->dbremove(*txn_ptr, BDB_HF_STARTING_HEIGHTS, NULL, 0) != 0) - LOG_ERROR("Error removing hf_starting_heights"); - if (m_env->dbremove(*txn_ptr, BDB_HF_VERSIONS, NULL, 0) != 0) - LOG_ERROR("Error removing hf_versions"); - - if (!m_write_txn) - txn.commit(); - } - catch (const std::exception& e) - { - throw0(DB_ERROR(std::string("Failed to drop hard fork info: ").append(e.what()).c_str())); - } -} - -void BlockchainBDB::set_hard_fork_version(uint64_t height, uint8_t version) -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy val_key(height + 1); - Dbt_copy val(version); - if (m_hf_versions->put(DB_DEFAULT_TX, &val_key, &val, 0)) - throw1(DB_ERROR("Error adding hard fork version to db transaction.")); -} - -uint8_t BlockchainBDB::get_hard_fork_version(uint64_t height) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - Dbt_copy key(height + 1); - Dbt_copy result; - - auto get_result = m_hf_versions->get(DB_DEFAULT_TX, &key, &result, 0); - if (get_result == DB_NOTFOUND || get_result == DB_KEYEMPTY) - throw0(OUTPUT_DNE("Error attempting to retrieve hard fork version from the db")); - else if (get_result) - throw0(DB_ERROR("Error attempting to retrieve hard fork version from the db")); - - return result; -} - -void BlockchainBDB::checkpoint_worker() const -{ - LOG_PRINT_L0("Entering BDB checkpoint thread."); - int count = 0; - while(m_run_checkpoint && m_open) - { - // sleep every second, so we don't delay exit condition m_run_checkpoint = false - sleep(1); - // checkpoint every 5 minutes - if(count++ >= 300) - { - count = 0; - if(m_env->txn_checkpoint(0, 0, 0) != 0) - { - LOG_PRINT_L0("BDB txn_checkpoint failed."); - break; - } - } - } - LOG_PRINT_L0("Leaving BDB checkpoint thread."); -} - -bool BlockchainBDB::is_read_only() const -{ - return false; -} - -void BlockchainBDB::fixup() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - // Always call parent as well - BlockchainDB::fixup(); -} - -} // namespace cryptonote diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h deleted file mode 100644 index 9d02309df..000000000 --- a/src/blockchain_db/berkeleydb/db_bdb.h +++ /dev/null @@ -1,471 +0,0 @@ -// Copyright (c) 2018, The Safex 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) 2014-2018 The Monero Project - -#include - -#include "blockchain_db/blockchain_db.h" -#include "cryptonote_basic/blobdatatype.h" // for type blobdata - -#include -#include - -// ND: Enables multi-threaded bulk reads for when getting indices. -// TODO: Disabled for now, as it doesn't seem to provide noticeable improvements (??. Reason: TBD. -// #define BDB_BULK_CAN_THREAD -namespace cryptonote -{ - -struct bdb_txn_safe -{ - bdb_txn_safe() : m_txn(NULL) { } - ~bdb_txn_safe() - { - LOG_PRINT_L3("bdb_txn_safe: destructor"); - - if (m_txn != NULL) - abort(); - } - - void commit(std::string message = "") - { - if (message.size() == 0) - { - message = "Failed to commit a transaction to the db"; - } - - if (m_txn->commit(0)) - { - m_txn = NULL; - LOG_PRINT_L0(message); - throw DB_ERROR(message.c_str()); - } - m_txn = NULL; - } - - void abort() - { - LOG_PRINT_L3("bdb_txn_safe: abort()"); - if(m_txn != NULL) - { - m_txn->abort(); - m_txn = NULL; - } - else - { - LOG_PRINT_L0("WARNING: bdb_txn_safe: abort() called, but m_txn is NULL"); - } - } - - operator DbTxn*() - { - return m_txn; - } - - operator DbTxn**() - { - return &m_txn; - } -private: - DbTxn* m_txn; -}; - -// ND: Class to handle buffer management when doing bulk queries -// (DB_MULTIPLE). Allocates buffers then handles thread queuing -// so a fixed set of buffers can be used (instead of allocating -// every time a bulk query is needed). -template -class bdb_safe_buffer -{ - // limit the number of buffers to 8 - const size_t MaxAllowedBuffers = 8; -public: - bdb_safe_buffer(size_t num_buffers, size_t count) - { - if(num_buffers > MaxAllowedBuffers) - num_buffers = MaxAllowedBuffers; - - set_count(num_buffers); - for (size_t i = 0; i < num_buffers; i++) - m_buffers.push_back((T) malloc(sizeof(T) * count)); - m_buffer_count = count; - } - - ~bdb_safe_buffer() - { - for (size_t i = 0; i < m_buffers.size(); i++) - { - if (m_buffers[i]) - { - free(m_buffers[i]); - m_buffers[i] = nullptr; - } - } - - m_buffers.resize(0); - } - - T acquire_buffer() - { - boost::unique_lock lock(m_lock); - m_cv.wait(lock, [&]{ return m_count > 0; }); - - --m_count; - size_t index = -1; - for (size_t i = 0; i < m_open_slot.size(); i++) - { - if (m_open_slot[i]) - { - m_open_slot[i] = false; - index = i; - break; - } - } - - assert(index >= 0); - - T buffer = m_buffers[index]; - m_buffer_map.emplace(buffer, index); - return buffer; - } - - void release_buffer(T buffer) - { - boost::unique_lock lock(m_lock); - - assert(buffer != nullptr); - auto it = m_buffer_map.find(buffer); - if (it != m_buffer_map.end()) - { - auto index = it->second; - - assert(index < m_open_slot.size()); - assert(m_open_slot[index] == false); - assert(m_count < m_open_slot.size()); - - ++m_count; - m_open_slot[index] = true; - m_buffer_map.erase(it); - m_cv.notify_one(); - } - } - - size_t get_buffer_size() const - { - return m_buffer_count * sizeof(T); - } - - size_t get_buffer_count() const - { - return m_buffer_count; - } - - typedef T type; - -private: - void set_count(size_t count) - { - assert(count > 0); - m_open_slot.resize(count, true); - m_count = count; - } - - std::vector m_buffers; - std::unordered_map m_buffer_map; - - boost::condition_variable m_cv; - std::vector m_open_slot; - size_t m_count; - boost::mutex m_lock; - - size_t m_buffer_count; -}; - -template -class bdb_safe_buffer_autolock -{ -public: - bdb_safe_buffer_autolock(T &safe_buffer, typename T::type &buffer) : - m_safe_buffer(safe_buffer), m_buffer(nullptr) - { - m_buffer = m_safe_buffer.acquire_buffer(); - buffer = m_buffer; - } - - ~bdb_safe_buffer_autolock() - { - if (m_buffer != nullptr) - { - m_safe_buffer.release_buffer(m_buffer); - m_buffer = nullptr; - } - } -private: - T &m_safe_buffer; - typename T::type m_buffer; -}; - -class BlockchainBDB : public BlockchainDB -{ -public: - BlockchainBDB(bool batch_transactions=false); - ~BlockchainBDB(); - - virtual void open(const std::string& filename, const int db_flags); - - virtual void close(); - - virtual void sync(); - - virtual void reset(); - - virtual std::vector get_filenames() const; - - virtual std::string get_db_name() const; - - virtual bool lock(); - - virtual void unlock(); - - virtual bool block_exists(const crypto::hash& h, uint64_t *height = NULL) const; - - virtual block get_block(const crypto::hash& h) const; - - virtual uint64_t get_block_height(const crypto::hash& h) const; - - virtual block_header get_block_header(const crypto::hash& h) const; - - virtual block get_block_from_height(const uint64_t& height) const; - - virtual uint64_t get_block_timestamp(const uint64_t& height) const; - - virtual uint64_t get_top_block_timestamp() const; - - virtual size_t get_block_size(const uint64_t& height) const; - - virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const; - - virtual difficulty_type get_block_difficulty(const uint64_t& height) const; - - virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const; - - virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const; - - virtual std::vector get_blocks_range(const uint64_t& h1, const uint64_t& h2) const; - - virtual std::vector get_hashes_range(const uint64_t& h1, const uint64_t& h2) const; - - virtual crypto::hash top_block_hash() const; - - virtual block get_top_block() const; - - virtual uint64_t height() const; - - virtual bool tx_exists(const crypto::hash& h) const; - - virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const; - - virtual transaction get_tx(const crypto::hash& h) const; - - virtual uint64_t get_tx_count() const; - - virtual std::vector get_tx_list(const std::vector& hlist) const; - - virtual uint64_t get_tx_block_height(const crypto::hash& h) const; - - virtual uint64_t get_num_outputs(const uint64_t& amount) const; - - virtual uint64_t get_indexing_base() const { return 1; } - - virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index); - virtual output_data_t get_output_key(const uint64_t& global_index) const; - virtual void get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs); - - virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const; - virtual void get_output_tx_and_index_from_global(const std::vector &global_indices, - std::vector &tx_out_indices) const; - - virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index); - virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices); - - virtual std::vector get_tx_output_indices(const crypto::hash& h) const; - virtual std::vector get_tx_amount_output_indices(const crypto::hash& h) const; - - virtual bool has_key_image(const crypto::key_image& img) const; - - virtual uint64_t add_block( const block& blk - , const size_t& block_size - , const difficulty_type& cumulative_difficulty - , const uint64_t& coins_generated - , const std::vector& txs - ); - - virtual void set_batch_transactions(bool batch_transactions); - virtual bool batch_start(uint64_t batch_num_blocks=0); - virtual void batch_commit(); - virtual void batch_stop(); - virtual void batch_abort(); - - virtual void block_txn_start(bool readonly); - virtual void block_txn_stop(); - virtual void block_txn_abort(); - - virtual void pop_block(block& blk, std::vector& txs); - -#if defined(BDB_BULK_CAN_THREAD) - virtual bool can_thread_bulk_indices() const { return true; } -#else - virtual bool can_thread_bulk_indices() const { return false; } -#endif - - /** - * @brief return a histogram of outputs on the blockchain - * - * @param amounts optional set of amounts to lookup - * - * @return a set of amount/instances - */ - std::map get_output_histogram(const std::vector &amounts) const; - -private: - virtual void add_block( const block& blk - , const size_t& block_size - , const difficulty_type& cumulative_difficulty - , const uint64_t& coins_generated - , const crypto::hash& block_hash - ); - - virtual void remove_block(); - - virtual void add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash); - - virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx); - - virtual void add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment); - - virtual void remove_output(const tx_out& tx_output); - - void remove_tx_outputs(const crypto::hash& tx_hash, const transaction& tx); - - void remove_output(const uint64_t& out_index, const uint64_t amount); - void remove_amount_output_index(const uint64_t amount, const uint64_t global_output_index); - - virtual void add_spent_key(const crypto::key_image& k_image); - - virtual void remove_spent_key(const crypto::key_image& k_image); - - void get_output_global_indices(const uint64_t& amount, const std::vector &offsets, std::vector &global_indices); - - virtual bool for_all_key_images(std::function) const; - virtual bool for_all_blocks(std::function) const; - virtual bool for_all_transactions(std::function) const; - virtual bool for_all_outputs(std::function f) const; - - // Hard fork related storage - virtual void set_hard_fork_version(uint64_t height, uint8_t version); - virtual uint8_t get_hard_fork_version(uint64_t height) const; - virtual void check_hard_fork_info(); - virtual void drop_hard_fork_info(); - - /** - * @brief convert a tx output to a blob for storage - * - * @param output the output to convert - * - * @return the resultant blob - */ - blobdata output_to_blob(const tx_out& output) const; - - /** - * @brief convert a tx output blob to a tx output - * - * @param blob the blob to convert - * - * @return the resultant tx output - */ - tx_out output_from_blob(const blobdata& blob) const; - - /** - * @brief get the global index of the index-th output of the given amount - * - * @param amount the output amount - * @param index the index into the set of outputs of that amount - * - * @return the global index of the desired output - */ - uint64_t get_output_global_index(const uint64_t& amount, const uint64_t& index); - void checkpoint_worker() const; - void check_open() const; - - virtual bool is_read_only() const; - - // - // fix up anything that may be wrong due to past bugs - virtual void fixup(); - - bool m_run_checkpoint; - std::unique_ptr m_checkpoint_thread; - typedef bdb_safe_buffer bdb_safe_buffer_t; - bdb_safe_buffer_t m_buffer; - - DbEnv* m_env; - - Db* m_blocks; - Db* m_block_heights; - Db* m_block_hashes; - Db* m_block_timestamps; - Db* m_block_sizes; - Db* m_block_diffs; - Db* m_block_coins; - - Db* m_txs; - Db* m_tx_unlocks; - Db* m_tx_heights; - Db* m_tx_outputs; - - Db* m_output_txs; - Db* m_output_indices; - Db* m_output_amounts; - Db* m_output_keys; - - Db* m_spent_keys; - - Db* m_hf_starting_heights; - Db* m_hf_versions; - - Db* m_properties; - - uint64_t m_height; - uint64_t m_num_outputs; - std::string m_folder; - bdb_txn_safe *m_write_txn; - - bool m_batch_transactions; // support for batch transactions -}; - -} // namespace cryptonote diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp index 4af8e3a4f..d9f96f0be 100644 --- a/src/blockchain_db/blockchain_db.cpp +++ b/src/blockchain_db/blockchain_db.cpp @@ -30,12 +30,15 @@ #include + #include "string_tools.h" #include "blockchain_db.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "profile_tools.h" #include "ringct/rctOps.h" +#include "safex/safex_core.h" + #include "lmdb/db_lmdb.h" #ifdef BERKELEY_DB #include "berkeleydb/db_bdb.h" @@ -98,10 +101,10 @@ const command_line::arg_descriptor arg_db_salvage = { , false }; -BlockchainDB *new_db(const std::string& db_type) +BlockchainDB *new_db(const std::string& db_type, cryptonote::network_type nettype) { if (db_type == "lmdb") - return new BlockchainLMDB(); + return new BlockchainLMDB(false, nettype); #if defined(BERKELEY_DB) if (db_type == "berkeley") return new BlockchainBDB(); @@ -125,7 +128,6 @@ void BlockchainDB::pop_block() void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr) { - bool miner_tx = false; crypto::hash tx_hash; if (!tx_hash_ptr) { @@ -138,41 +140,73 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti tx_hash = *tx_hash_ptr; } + for (const txin_v& tx_input : tx.vin) + if(tx_input.type() == typeid(txin_to_script)){ + const cryptonote::txin_to_script &txin = boost::get(tx_input); + if (!safex::validate_safex_command(*this, txin)) { + throw SAFEX_TX_CONFLICT(tx_hash); + } + } + for (const txin_v& tx_input : tx.vin) { - if (tx_input.type() == typeid(txin_to_key)) - { - add_spent_key(boost::get(tx_input).k_image); - } - else if (tx_input.type() == typeid(txin_token_to_key)) + + if ((tx_input.type() == typeid(txin_to_key)) + || (tx_input.type() == typeid(txin_token_to_key)) + || (tx_input.type() == typeid(txin_token_migration))) { - add_spent_key(boost::get(tx_input).k_image); + auto k_image_opt = boost::apply_visitor(key_image_visitor(), tx_input); + if (!k_image_opt) + throw DB_ERROR("Output does not have proper key image"); + const crypto::key_image &k_image = *k_image_opt; + add_spent_key(k_image); } - else if (tx_input.type() == typeid(txin_token_migration)) + else if (tx_input.type() == typeid(txin_to_script)) { - add_spent_key(boost::get(tx_input).k_image); + + //process command specific data here + const cryptonote::txin_to_script &txin = boost::get(tx_input); + process_command_input(txin); + + + //mark key image as spent + auto k_image_opt = boost::apply_visitor(key_image_visitor(), tx_input); + if (!k_image_opt) + throw DB_ERROR("Output does not have proper key image"); + const crypto::key_image &k_image = *k_image_opt; + + if(is_safex_key_image_verification_needed(txin.command_type)) + add_spent_key(k_image); + + } else if (tx_input.type() == typeid(txin_gen)) { /* nothing to do here */ - miner_tx = true; } else { LOG_PRINT_L1("Unsupported input type, removing key images and aborting transaction addition"); - for (const txin_v& tx_input : tx.vin) + for (const txin_v &tx_input : tx.vin) { - if (tx_input.type() == typeid(txin_to_key)) + if ((tx_input.type() == typeid(txin_to_key)) + || (tx_input.type() == typeid(txin_token_to_key)) + || (tx_input.type() == typeid(txin_token_migration))) { - remove_spent_key(boost::get(tx_input).k_image); - } - else if (tx_input.type() == typeid(txin_token_to_key)) - { - remove_spent_key(boost::get(tx_input).k_image); - } - else if (tx_input.type() == typeid(txin_token_migration)) - { - remove_spent_key(boost::get(tx_input).k_image); + auto k_image_opt = boost::apply_visitor(key_image_visitor(), tx_input); + if (!k_image_opt) continue; + const crypto::key_image &k_image = *k_image_opt; + remove_spent_key(k_image); + } else if (tx_input.type() == typeid(txin_to_script)){ + auto input = boost::get(tx_input); + + if(safex::is_safex_key_image_verification_needed(input.command_type)) + { + auto k_image_opt = boost::apply_visitor(key_image_visitor(), tx_input); + if (!k_image_opt) continue; + const crypto::key_image &k_image = *k_image_opt; + remove_spent_key(k_image); + } } } return; @@ -187,21 +221,7 @@ void BlockchainDB::add_transaction(const crypto::hash& blk_hash, const transacti // we need the index for (uint64_t i = 0; i < tx.vout.size(); ++i) { - // miner v2 txes have their coinbase output in one single out to save space, - // and we store them as rct outputs with an identity mask - if (miner_tx && tx.version == 2) - { - cryptonote::tx_out vout = tx.vout[i]; - rct::key commitment = rct::zeroCommit(vout.amount); - vout.amount = 0; - amount_output_indices.push_back(add_output(tx_hash, vout, i, tx.unlock_time, - &commitment)); - } - else - { - amount_output_indices.push_back(add_output(tx_hash, tx.vout[i], i, tx.unlock_time, - tx.version > 1 ? &tx.rct_signatures.outPk[i].mask : NULL)); - } + amount_output_indices.push_back(add_output(tx_hash, tx.vout[i], i, tx.unlock_time, NULL)); } add_tx_amount_output_indices(tx_id, amount_output_indices); } @@ -233,11 +253,34 @@ uint64_t BlockchainDB::add_block( const block& blk add_transaction(blk_hash, blk.miner_tx); int tx_i = 0; crypto::hash tx_hash = crypto::null_hash; - for (const transaction& tx : txs) + + // Safex related vectors + // We are denying blocks that have multiple txs with same account, offer, price_peg, of offer/pricepeg + purchase combination + std::vector safex_accounts_in_use; + std::vector safex_offers_in_use; + std::vector safex_offer_purchase_in_progress; + std::vector safex_price_peg_update_in_progress; + + try { - tx_hash = blk.tx_hashes[tx_i]; - add_transaction(blk_hash, tx, &tx_hash); - ++tx_i; + + for (const transaction& tx : txs) + { + + bool res = insert_and_check_safex_restrictions(tx, safex_accounts_in_use, safex_offers_in_use, safex_offer_purchase_in_progress, safex_price_peg_update_in_progress); + + if(!res) + throw SAFEX_TX_CONFLICT(tx_hash); + + tx_hash = blk.tx_hashes[tx_i]; + add_transaction(blk_hash, tx, &tx_hash); + ++tx_i; + } + } + catch(SAFEX_TX_CONFLICT& e) + { + block_txn_abort(); + throw e; } TIME_MEASURE_FINISH(time1); time_add_transaction += time1; @@ -248,10 +291,18 @@ uint64_t BlockchainDB::add_block( const block& blk TIME_MEASURE_FINISH(time1); time_add_block1 += time1; + uint64_t blk_height = get_block_height(blk_hash); + if (safex::is_interval_last_block(blk_height, m_nettype)) + { + //update staked token sum for interval for whitch this blok is last + update_staked_token_for_interval(safex::calculate_interval_for_height(blk_height, m_nettype), get_current_staked_token_sum()); + } + m_hardfork->add(blk, prev_height); block_txn_stop(); + ++num_calls; return prev_height; @@ -266,6 +317,13 @@ void BlockchainDB::pop_block(block& blk, std::vector& txs) { blk = get_top_block(); + uint64_t blk_height = height()-1; + if (safex::is_interval_last_block(blk_height, m_nettype)) + { + //update staked token sum for interval for whitch this blok is last + remove_staked_token_for_interval(safex::calculate_interval_for_height(blk_height, m_nettype)); + } + remove_block(); for (const auto& h : boost::adaptors::reverse(blk.tx_hashes)) @@ -299,12 +357,27 @@ void BlockchainDB::remove_transaction(const crypto::hash& tx_hash) { remove_spent_key(boost::get(tx_input).k_image); } + else if (tx_input.type() == typeid(txin_to_script)) + { + auto input = boost::get(tx_input); + if(input.command_type == safex::command_t::token_unstake) + remove_unstake_token(tx_hash, tx); + + if(safex::is_safex_key_image_verification_needed(input.command_type)) + remove_spent_key(boost::get(tx_input).k_image); + } + } // need tx as tx.vout has the tx outputs, and the output amounts are needed remove_transaction_data(tx_hash, tx); } +void BlockchainDB::revert_transaction(const crypto::hash &tx_hash) +{ + remove_transaction(tx_hash); +} + block BlockchainDB::get_block_from_height(const uint64_t& height) const { blobdata bd = get_block_blob_from_height(height); diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 4d1c5660b..1a4c7dca3 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -36,6 +36,10 @@ #include #include #include +#include +#include +#include +#include #include "common/command_line.h" #include "crypto/hash.h" #include "cryptonote_basic/blobdatatype.h" @@ -103,60 +107,75 @@ namespace cryptonote { /** a pair of , typedef for convenience */ -typedef std::pair tx_out_index; + typedef std::pair tx_out_index; - -extern const command_line::arg_descriptor arg_db_type; -extern const command_line::arg_descriptor arg_db_sync_mode; -extern const command_line::arg_descriptor arg_db_salvage; + extern const command_line::arg_descriptor arg_db_type; + extern const command_line::arg_descriptor arg_db_sync_mode; + extern const command_line::arg_descriptor arg_db_salvage; #pragma pack(push, 1) - - - -/** + /** * @brief a struct containing output metadata */ -struct output_data_t -{ - crypto::public_key pubkey; //!< the output's public key (for spend verification) - uint64_t unlock_time; //!< the output's unlock time (or height) - uint64_t height; //!< the height of the block which created the output - rct::key commitment; //!< the output's amount commitment (for spend verification) -}; + struct output_data_t + { + crypto::public_key pubkey; //!< the output's public key (for spend verification) + uint64_t unlock_time; //!< the output's unlock time (or height) + uint64_t height; //!< the height of the block which created the output + rct::key commitment; //!< the output's amount commitment (for spend verification) + }; #pragma pack(pop) #pragma pack(push, 1) -struct tx_data_t -{ - uint64_t tx_id; - uint64_t unlock_time; - uint64_t block_id; -}; + struct tx_data_t + { + uint64_t tx_id; + uint64_t unlock_time; + uint64_t block_id; + }; #pragma pack(pop) + +#pragma pack(push, 1) + /** Struct that holds info about advanced output */ + typedef struct output_advanced_data_t + { + uint64_t type_index; //!< the output's index for particular type + uint64_t unlock_time; //!< the output's unlock time (or height) + uint64_t height; //!< the height of the block which created the output + uint64_t output_id; + uint64_t output_type; + crypto::public_key pubkey; + blobdata data; //Blob of txoutput + + size_t size() const { return 5 * sizeof(uint64_t) + sizeof(pubkey) + data.size();} + } output_advanced_data_t; +#pragma pack(pop) + + /** * @brief a struct containing txpool per transaction metadata */ -struct txpool_tx_meta_t -{ - crypto::hash max_used_block_id; - crypto::hash last_failed_id; - uint64_t blob_size; - uint64_t fee; - uint64_t max_used_block_height; - uint64_t last_failed_height; - uint64_t receive_time; - uint64_t last_relayed_time; - // 112 bytes - uint8_t kept_by_block; - uint8_t relayed; - uint8_t do_not_relay; - uint8_t double_spend_seen: 1; - - uint8_t padding[76]; // till 192 bytes -}; + struct txpool_tx_meta_t + { + crypto::hash max_used_block_id; + crypto::hash last_failed_id; + uint64_t blob_size; + uint64_t fee; + uint64_t max_used_block_height; + uint64_t last_failed_height; + uint64_t receive_time; + uint64_t last_relayed_time; + // 112 bytes + uint8_t kept_by_block; + uint8_t relayed; + uint8_t do_not_relay; + uint8_t double_spend_seen: 1; + uint8_t safex_tx{0}; + + uint8_t padding[75]; // till 192 bytes + }; #define DBF_SAFE 1 #define DBF_FAST 2 @@ -171,162 +190,234 @@ struct txpool_tx_meta_t /** * @brief A base class for BlockchainDB exceptions */ -class DB_EXCEPTION : public std::exception -{ - private: - std::string m; + class DB_EXCEPTION : public std::exception + { + private: + std::string m; - protected: - DB_EXCEPTION(const char *s) : m(s) { } + protected: + DB_EXCEPTION(const char *s) : m(s) + {} - public: - virtual ~DB_EXCEPTION() { } + public: + virtual ~DB_EXCEPTION() + {} - const char* what() const throw() - { - return m.c_str(); - } -}; + const char *what() const throw() + { + return m.c_str(); + } + }; /** * @brief A generic BlockchainDB exception */ -class DB_ERROR : public DB_EXCEPTION -{ - public: - DB_ERROR() : DB_EXCEPTION("Generic DB Error") { } - DB_ERROR(const char* s) : DB_EXCEPTION(s) { } -}; + class DB_ERROR : public DB_EXCEPTION + { + public: + DB_ERROR() : DB_EXCEPTION("Generic DB Error") + {} + + DB_ERROR(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when there is an error starting a DB transaction */ -class DB_ERROR_TXN_START : public DB_EXCEPTION -{ - public: - DB_ERROR_TXN_START() : DB_EXCEPTION("DB Error in starting txn") { } - DB_ERROR_TXN_START(const char* s) : DB_EXCEPTION(s) { } -}; + class DB_ERROR_TXN_START : public DB_EXCEPTION + { + public: + DB_ERROR_TXN_START() : DB_EXCEPTION("DB Error in starting txn") + {} + + DB_ERROR_TXN_START(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when opening the BlockchainDB fails */ -class DB_OPEN_FAILURE : public DB_EXCEPTION -{ - public: - DB_OPEN_FAILURE() : DB_EXCEPTION("Failed to open the db") { } - DB_OPEN_FAILURE(const char* s) : DB_EXCEPTION(s) { } -}; + class DB_OPEN_FAILURE : public DB_EXCEPTION + { + public: + DB_OPEN_FAILURE() : DB_EXCEPTION("Failed to open the db") + {} + + DB_OPEN_FAILURE(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when creating the BlockchainDB fails */ -class DB_CREATE_FAILURE : public DB_EXCEPTION -{ - public: - DB_CREATE_FAILURE() : DB_EXCEPTION("Failed to create the db") { } - DB_CREATE_FAILURE(const char* s) : DB_EXCEPTION(s) { } -}; + class DB_CREATE_FAILURE : public DB_EXCEPTION + { + public: + DB_CREATE_FAILURE() : DB_EXCEPTION("Failed to create the db") + {} + + DB_CREATE_FAILURE(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when synchronizing the BlockchainDB to disk fails */ -class DB_SYNC_FAILURE : public DB_EXCEPTION -{ - public: - DB_SYNC_FAILURE() : DB_EXCEPTION("Failed to sync the db") { } - DB_SYNC_FAILURE(const char* s) : DB_EXCEPTION(s) { } -}; + class DB_SYNC_FAILURE : public DB_EXCEPTION + { + public: + DB_SYNC_FAILURE() : DB_EXCEPTION("Failed to sync the db") + {} + + DB_SYNC_FAILURE(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when a requested block does not exist */ -class BLOCK_DNE : public DB_EXCEPTION -{ - public: - BLOCK_DNE() : DB_EXCEPTION("The block requested does not exist") { } - BLOCK_DNE(const char* s) : DB_EXCEPTION(s) { } -}; + class BLOCK_DNE : public DB_EXCEPTION + { + public: + BLOCK_DNE() : DB_EXCEPTION("The block requested does not exist") + {} + + BLOCK_DNE(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when a block's parent does not exist (and it needed to) */ -class BLOCK_PARENT_DNE : public DB_EXCEPTION -{ - public: - BLOCK_PARENT_DNE() : DB_EXCEPTION("The parent of the block does not exist") { } - BLOCK_PARENT_DNE(const char* s) : DB_EXCEPTION(s) { } -}; + class BLOCK_PARENT_DNE : public DB_EXCEPTION + { + public: + BLOCK_PARENT_DNE() : DB_EXCEPTION("The parent of the block does not exist") + {} + + BLOCK_PARENT_DNE(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when a block exists, but shouldn't, namely when adding a block */ -class BLOCK_EXISTS : public DB_EXCEPTION -{ - public: - BLOCK_EXISTS() : DB_EXCEPTION("The block to be added already exists!") { } - BLOCK_EXISTS(const char* s) : DB_EXCEPTION(s) { } -}; + class BLOCK_EXISTS : public DB_EXCEPTION + { + public: + BLOCK_EXISTS() : DB_EXCEPTION("The block to be added already exists!") + {} + + BLOCK_EXISTS(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when something is wrong with the block to be added */ -class BLOCK_INVALID : public DB_EXCEPTION -{ - public: - BLOCK_INVALID() : DB_EXCEPTION("The block to be added did not pass validation!") { } - BLOCK_INVALID(const char* s) : DB_EXCEPTION(s) { } -}; + class BLOCK_INVALID : public DB_EXCEPTION + { + public: + BLOCK_INVALID() : DB_EXCEPTION("The block to be added did not pass validation!") + {} + + BLOCK_INVALID(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when a requested transaction does not exist */ -class TX_DNE : public DB_EXCEPTION -{ - public: - TX_DNE() : DB_EXCEPTION("The transaction requested does not exist") { } - TX_DNE(const char* s) : DB_EXCEPTION(s) { } -}; + class TX_DNE : public DB_EXCEPTION + { + public: + TX_DNE() : DB_EXCEPTION("The transaction requested does not exist") + {} + + TX_DNE(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when a transaction exists, but shouldn't, namely when adding a block */ -class TX_EXISTS : public DB_EXCEPTION -{ - public: - TX_EXISTS() : DB_EXCEPTION("The transaction to be added already exists!") { } - TX_EXISTS(const char* s) : DB_EXCEPTION(s) { } -}; + class TX_EXISTS : public DB_EXCEPTION + { + public: + TX_EXISTS() : DB_EXCEPTION("The transaction to be added already exists!") + {} + + TX_EXISTS(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when a requested output does not exist */ -class OUTPUT_DNE : public DB_EXCEPTION -{ - public: - OUTPUT_DNE() : DB_EXCEPTION("The output requested does not exist!") { } - OUTPUT_DNE(const char* s) : DB_EXCEPTION(s) { } -}; + class OUTPUT_DNE : public DB_EXCEPTION + { + public: + OUTPUT_DNE() : DB_EXCEPTION("The output requested does not exist!") + {} + + OUTPUT_DNE(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when an output exists, but shouldn't, namely when adding a block */ -class OUTPUT_EXISTS : public DB_EXCEPTION -{ - public: - OUTPUT_EXISTS() : DB_EXCEPTION("The output to be added already exists!") { } - OUTPUT_EXISTS(const char* s) : DB_EXCEPTION(s) { } -}; + class OUTPUT_EXISTS : public DB_EXCEPTION + { + public: + OUTPUT_EXISTS() : DB_EXCEPTION("The output to be added already exists!") + {} + + OUTPUT_EXISTS(const char *s) : DB_EXCEPTION(s) + {} + }; /** * @brief thrown when a spent key image exists, but shouldn't, namely when adding a block */ -class KEY_IMAGE_EXISTS : public DB_EXCEPTION -{ + class KEY_IMAGE_EXISTS : public DB_EXCEPTION + { + public: + KEY_IMAGE_EXISTS() : DB_EXCEPTION("The spent key image to be added already exists!") + {} + + KEY_IMAGE_EXISTS(const char *s) : DB_EXCEPTION(s) + {} + }; + + /** + * @brief thrown when a safex account trying to be added already exists + */ + class SAFEX_ACCOUNT_EXISTS : public DB_EXCEPTION + { + public: + SAFEX_ACCOUNT_EXISTS() : DB_EXCEPTION("The safex account to be added already exists!") + {} + + SAFEX_ACCOUNT_EXISTS(const char *s) : DB_EXCEPTION(s) + {} + }; + + /** + * @brief thrown when a transaction cannot be added due to conflict with another tx in the block + */ + class SAFEX_TX_CONFLICT : public DB_EXCEPTION + { public: - KEY_IMAGE_EXISTS() : DB_EXCEPTION("The spent key image to be added already exists!") { } - KEY_IMAGE_EXISTS(const char* s) : DB_EXCEPTION(s) { } -}; + SAFEX_TX_CONFLICT() : DB_EXCEPTION("The safex transaction verification failed!") + {} + + SAFEX_TX_CONFLICT(const crypto::hash& _tx_hash) : DB_EXCEPTION("The safex transaction verification failed!"), tx_hash(_tx_hash) + {} + + crypto::hash tx_hash; + }; /*********************************** * End of Exception Definitions @@ -345,1219 +436,1590 @@ class KEY_IMAGE_EXISTS : public DB_EXCEPTION * A subclass which encounters an issue should report that issue by throwing * a DB_EXCEPTION which adequately conveys the issue. */ -class BlockchainDB -{ -private: - /********************************************************************* - * private virtual members - *********************************************************************/ - - /** - * @brief add the block and metadata to the db - * - * The subclass implementing this will add the specified block and - * block metadata to its backing store. This does not include its - * transactions, those are added in a separate step. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param blk the block to be added - * @param block_size the size of the block (transactions and all) - * @param cumulative_difficulty the accumulated difficulty after this block - * @param coins_generated the number of coins generated total after this block - * @param tokens_migrated the number of tokens migrated from Bitcoin blockchain - * @param blk_hash the hash of the block - */ - virtual void add_block( const block& blk - , const size_t& block_size - , const difficulty_type& cumulative_difficulty - , const uint64_t& coins_generated - , const uint64_t& tokens_migrated - , const crypto::hash& blk_hash - ) = 0; - - /** - * @brief remove data about the top block - * - * The subclass implementing this will remove the block data from the top - * block in the chain. The data to be removed is that which was added in - * BlockchainDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const crypto::hash& blk_hash) - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - */ - virtual void remove_block() = 0; - - /** - * @brief store the transaction and its metadata - * - * The subclass implementing this will add the specified transaction data - * to its backing store. This includes only the transaction blob itself - * and the other data passed here, not the separate outputs of the - * transaction. - * - * It returns a tx ID, which is a mapping from the tx_hash. The tx ID - * is used in #add_tx_amount_output_indices(). - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param blk_hash the hash of the block containing the transaction - * @param tx the transaction to be added - * @param tx_hash the hash of the transaction - * @return the transaction ID - */ - virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) = 0; - - /** - * @brief remove data about a transaction - * - * The subclass implementing this will remove the transaction data - * for the passed transaction. The data to be removed was added in - * add_transaction_data(). Additionally, current subclasses have behavior - * which requires the transaction itself as a parameter here. Future - * implementations should note that this parameter is subject to be removed - * at a later time. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param tx_hash the hash of the transaction to be removed - * @param tx the transaction - */ - virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) = 0; - - /** - * @brief store an output - * - * The subclass implementing this will add the output data passed to its - * backing store in a suitable manner. In addition, the subclass is responsible - * for keeping track of the global output count in some manner, so that - * outputs may be indexed by the order in which they were created. In the - * future, this tracking (of the number, at least) should be moved to - * this class, as it is necessary and the same among all BlockchainDB. - * - * It returns an amount output index, which is the index of the output - * for its specified amount. - * - * This data should be stored in such a manner that the only thing needed to - * reverse the process is the tx_out. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param tx_hash hash of the transaction the output was created by - * @param tx_output the output - * @param local_index index of the output in its transaction - * @param unlock_time unlock time/height of the output - * @param commitment the rct commitment to the output amount - * @return amount output index - */ - virtual uint64_t add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) = 0; - - /** - * @brief store amount output indices for a tx's outputs - * - * The subclass implementing this will add the amount output indices to its - * backing store in a suitable manner. The tx_id will be the same one that - * was returned from #add_output(). - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param tx_id ID of the transaction containing these outputs - * @param amount_output_indices the amount output indices of the transaction - */ - virtual void add_tx_amount_output_indices(const uint64_t tx_id, const std::vector& amount_output_indices) = 0; - - /** - * @brief store a spent key - * - * The subclass implementing this will store the spent key image. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param k_image the spent key image to store - */ - virtual void add_spent_key(const crypto::key_image& k_image) = 0; - - /** - * @brief remove a spent key - * - * The subclass implementing this will remove the key image. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param k_image the spent key image to remove - */ - virtual void remove_spent_key(const crypto::key_image& k_image) = 0; - - - /********************************************************************* - * private concrete members - *********************************************************************/ - /** - * @brief private version of pop_block, for undoing if an add_block fails - * - * This function simply calls pop_block(block& blk, std::vector& txs) - * with dummy parameters, as the returns-by-reference can be discarded. - */ - void pop_block(); - - // helper function to remove transaction from blockchain - /** - * @brief helper function to remove transaction from the blockchain - * - * This function encapsulates aspects of removing a transaction. - * - * @param tx_hash the hash of the transaction to be removed - */ - void remove_transaction(const crypto::hash& tx_hash); - - uint64_t num_calls = 0; //!< a performance metric - uint64_t time_blk_hash = 0; //!< a performance metric - uint64_t time_add_block1 = 0; //!< a performance metric - uint64_t time_add_transaction = 0; //!< a performance metric - - -protected: - - /** - * @brief helper function for add_transactions, to add each individual transaction - * - * This function is called by add_transactions() for each transaction to be - * added. - * - * @param blk_hash hash of the block which has the transaction - * @param tx the transaction to add - * @param tx_hash_ptr the hash of the transaction, if already calculated - */ - void add_transaction(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash* tx_hash_ptr = NULL); - - mutable uint64_t time_tx_exists = 0; //!< a performance metric - uint64_t time_commit1 = 0; //!< a performance metric - bool m_auto_remove_logs = true; //!< whether or not to automatically remove old logs - - HardFork* m_hardfork; - -public: - - /** - * @brief An empty constructor. - */ - BlockchainDB(): m_open(false) { } - - /** - * @brief An empty destructor. - */ - virtual ~BlockchainDB() { }; - - /** - * @brief init command line options - */ - static void init_options(boost::program_options::options_description& desc); - - /** - * @brief reset profiling stats - */ - void reset_stats(); - - /** - * @brief show profiling stats - * - * This function prints current performance/profiling data to whichever - * log file(s) are set up (possibly including stdout or stderr) - */ - void show_stats(); - - /** - * @brief open a db, or create it if necessary. - * - * This function opens an existing database or creates it if it - * does not exist. - * - * The subclass implementing this will handle all file opening/creation, - * and is responsible for maintaining its state. - * - * The parameter may not refer to a file name, necessarily, but - * could be an IP:PORT for a database which needs it, and so on. Calling it - * is convenient and should be descriptive enough, however. - * - * For now, db_flags are - * specific to the subclass being instantiated. This is subject to change, - * and the db_flags parameter may be deprecated. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param filename a string referring to the BlockchainDB to open - * @param db_flags flags relevant to how to open/use the BlockchainDB - */ - virtual void open(const std::string& filename, const int db_flags = 0) = 0; - - /** - * @brief Gets the current open/ready state of the BlockchainDB - * - * @return true if open/ready, otherwise false - */ - bool is_open() const; - - /** - * @brief close the BlockchainDB - * - * At minimum, this call ensures that further use of the BlockchainDB - * instance will not have effect. In any case where it is necessary - * to do so, a subclass implementing this will sync with disk. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - */ - virtual void close() = 0; - - /** - * @brief sync the BlockchainDB with disk - * - * This function should write any changes to whatever permanent backing - * store the subclass uses. Example: a BlockchainDB instance which - * keeps the whole blockchain in RAM won't need to regularly access a - * disk, but should write out its state when this is called. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - */ - virtual void sync() = 0; - - /** - * @brief toggle safe syncs for the DB - * - * Used to switch DBF_SAFE on or off after starting up with DBF_FAST. - */ - virtual void safesyncmode(const bool onoff) = 0; - - /** - * @brief Remove everything from the BlockchainDB - * - * This function should completely remove all data from a BlockchainDB. - * - * Use with caution! - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - */ - virtual void reset() = 0; - - /** - * @brief get all files used by the BlockchainDB (if any) - * - * This function is largely for ease of automation, namely for unit tests. - * - * The subclass implementation should return all filenames it uses. - * - * @return a list of filenames - */ - virtual std::vector get_filenames() const = 0; - - // return the name of the folder the db's file(s) should reside in - /** - * @brief gets the name of the folder the BlockchainDB's file(s) should be in - * - * The subclass implementation should return the name of the folder in which - * it stores files, or an empty string if there is none. - * - * @return the name of the folder with the BlockchainDB's files, if any. - */ - virtual std::string get_db_name() const = 0; - - - // FIXME: these are just for functionality mocking, need to implement - // RAII-friendly and multi-read one-write friendly locking mechanism - // - // acquire db lock - /** - * @brief acquires the BlockchainDB lock - * - * This function is a stub until such a time as locking is implemented at - * this level. - * - * The subclass implementation should return true unless implementing a - * locking scheme of some sort, in which case it should return true upon - * acquisition of the lock and block until then. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @return true, unless at a future time false makes sense (timeout, etc) - */ - virtual bool lock() = 0; - - // release db lock - /** - * @brief This function releases the BlockchainDB lock - * - * The subclass, should it have implemented lock(), will release any lock - * held by the calling thread. In the case of recursive locking, it should - * release one instance of a lock. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - */ - virtual void unlock() = 0; - - /** - * @brief tells the BlockchainDB to start a new "batch" of blocks - * - * If the subclass implements a batching method of caching blocks in RAM to - * be added to a backing store in groups, it should start a batch which will - * end either when has been added or batch_stop() has - * been called. In either case, it should end the batch and write to its - * backing store. - * - * If a batch is already in-progress, this function must return false. - * If a batch was started by this call, it must return true. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param batch_num_blocks number of blocks to batch together - * - * @return true if we started the batch, false if already started - */ - virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) = 0; - - /** - * @brief ends a batch transaction - * - * If the subclass implements batching, this function should store the - * batch it is currently on and mark it finished. - * - * If no batch is in-progress, this function should throw a DB_ERROR. - * This exception may change in the future if it is deemed necessary to - * have a more granular exception type for this scenario. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - */ - virtual void batch_stop() = 0; - - /** - * @brief sets whether or not to batch transactions - * - * If the subclass implements batching, this function tells it to begin - * batching automatically. - * - * If the subclass implements batching and has a batch in-progress, a - * parameter of false should disable batching and call batch_stop() to - * store the current batch. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param bool batch whether or not to use batch transactions. - */ - virtual void set_batch_transactions(bool) = 0; - - virtual void block_txn_start(bool readonly=false) = 0; - virtual void block_txn_stop() = 0; - virtual void block_txn_abort() = 0; - - virtual void set_hard_fork(HardFork* hf); - - // adds a block with the given metadata to the top of the blockchain, returns the new height - /** - * @brief handles the addition of a new block to BlockchainDB - * - * This function organizes block addition and calls various functions as - * necessary. - * - * NOTE: subclass implementations of this (or the functions it calls) need - * to handle undoing any partially-added blocks in the event of a failure. - * - * If any of this cannot be done, the subclass should throw the corresponding - * subclass of DB_EXCEPTION - * - * @param blk the block to be added - * @param block_size the size of the block (transactions and all) - * @param cumulative_difficulty the accumulated difficulty after this block - * @param coins_generated the number of coins generated total after this block - * @param tokens_migrated the number of tokens migrated from Bitcoin blockchain - * @param txs the transactions in the block - * - * @return the height of the chain post-addition - */ - virtual uint64_t add_block( const block& blk - , const size_t& block_size - , const difficulty_type& cumulative_difficulty - , const uint64_t& coins_generated - , const uint64_t& tokens_migrated - , const std::vector& txs - ); - - /** - * @brief checks if a block exists - * - * @param h the hash of the requested block - * @param height if non NULL, returns the block's height if found - * - * @return true of the block exists, otherwise false - */ - virtual bool block_exists(const crypto::hash& h, uint64_t *height = NULL) const = 0; - - /** - * @brief fetches the block with the given hash - * - * The subclass should return the requested block. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param h the hash to look for - * - * @return the block requested - */ - virtual cryptonote::blobdata get_block_blob(const crypto::hash& h) const = 0; - - /** - * @brief fetches the block with the given hash - * - * Returns the requested block. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param h the hash to look for - * - * @return the block requested - */ - virtual block get_block(const crypto::hash& h) const; - - /** - * @brief gets the height of the block with a given hash - * - * The subclass should return the requested height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param h the hash to look for - * - * @return the height - */ - virtual uint64_t get_block_height(const crypto::hash& h) const = 0; - - /** - * @brief fetch a block header - * - * The subclass should return the block header from the block with - * the given hash. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param h the hash to look for - * - * @return the block header - */ - virtual block_header get_block_header(const crypto::hash& h) const = 0; - - /** - * @brief fetch a block blob by height - * - * The subclass should return the block at the given height. - * - * If the block does not exist, that is to say if the blockchain is not - * that high, then the subclass should throw BLOCK_DNE - * - * @param height the height to look for - * - * @return the block blob - */ - virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t& height) const = 0; - - /** - * @brief fetch a block by height - * - * If the block does not exist, that is to say if the blockchain is not - * that high, then the subclass should throw BLOCK_DNE - * - * @param height the height to look for - * - * @return the block - */ - virtual block get_block_from_height(const uint64_t& height) const; - - /** - * @brief fetch a block's timestamp - * - * The subclass should return the timestamp of the block with the - * given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the timestamp - */ - virtual uint64_t get_block_timestamp(const uint64_t& height) const = 0; - - /** - * @brief fetch the top block's timestamp - * - * The subclass should return the timestamp of the most recent block. - * - * @return the top block's timestamp - */ - virtual uint64_t get_top_block_timestamp() const = 0; - - /** - * @brief fetch a block's size - * - * The subclass should return the size of the block with the - * given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the size - */ - virtual size_t get_block_size(const uint64_t& height) const = 0; - - /** - * @brief fetch a block's cumulative difficulty - * - * The subclass should return the cumulative difficulty of the block with the - * given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the cumulative difficulty - */ - virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const = 0; - - /** - * @brief fetch a block's difficulty - * - * The subclass should return the difficulty of the block with the - * given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the difficulty - */ - virtual difficulty_type get_block_difficulty(const uint64_t& height) const = 0; - - /** - * @brief fetch a block's already generated coins - * - * The subclass should return the total coins generated as of the block - * with the given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the already generated coins - */ - virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const = 0; - - - /** - * @brief fetch a block's already migrated tokens - * - * The subclass should return the total tokens migrated from Bitcoin platform - * as of block with the given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return number of already migrated tokens - */ - virtual uint64_t get_block_already_migrated_tokens(const uint64_t& height) const = 0; - - /** - * @brief fetch a block's hash - * - * The subclass should return hash of the block with the - * given height. - * - * If the block does not exist, the subclass should throw BLOCK_DNE - * - * @param height the height requested - * - * @return the hash - */ - virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const = 0; - - /** - * @brief fetch a list of blocks - * - * The subclass should return a vector of blocks with heights starting at - * h1 and ending at h2, inclusively. - * - * If the height range requested goes past the end of the blockchain, - * the subclass should throw BLOCK_DNE. (current implementations simply - * don't catch this exception as thrown by methods called within) - * - * @param h1 the start height - * @param h2 the end height - * - * @return a vector of blocks - */ - virtual std::vector get_blocks_range(const uint64_t& h1, const uint64_t& h2) const = 0; - - /** - * @brief fetch a list of block hashes - * - * The subclass should return a vector of block hashes from blocks with - * heights starting at h1 and ending at h2, inclusively. - * - * If the height range requested goes past the end of the blockchain, - * the subclass should throw BLOCK_DNE. (current implementations simply - * don't catch this exception as thrown by methods called within) - * - * @param h1 the start height - * @param h2 the end height - * - * @return a vector of block hashes - */ - virtual std::vector get_hashes_range(const uint64_t& h1, const uint64_t& h2) const = 0; - - /** - * @brief fetch the top block's hash - * - * The subclass should return the hash of the most recent block - * - * @return the top block's hash - */ - virtual crypto::hash top_block_hash() const = 0; - - /** - * @brief fetch the top block - * - * The subclass should return most recent block - * - * @return the top block - */ - virtual block get_top_block() const = 0; - - /** - * @brief fetch the current blockchain height - * - * The subclass should return the current blockchain height - * - * @return the current blockchain height - */ - virtual uint64_t height() const = 0; - - - /** - * - * - * @brief pops the top block off the blockchain - * - * The subclass should remove the most recent block from the blockchain, - * along with all transactions, outputs, and other metadata created as - * a result of its addition to the blockchain. Most of this is handled - * by the concrete members of the base class provided the subclass correctly - * implements remove_* functions. - * - * The subclass should return by reference the popped block and - * its associated transactions - * - * @param blk return-by-reference the block which was popped - * @param txs return-by-reference the transactions from the popped block - */ - virtual void pop_block(block& blk, std::vector& txs); - - - /** - * @brief check if a transaction with a given hash exists - * - * The subclass should check if a transaction is stored which has the - * given hash and return true if so, false otherwise. - * - * @param h the hash to check against - * @param tx_id (optional) returns the tx_id for the tx hash - * - * @return true if the transaction exists, otherwise false - */ - virtual bool tx_exists(const crypto::hash& h) const = 0; - virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_id) const = 0; - - // return unlock time of tx with hash - /** - * @brief fetch a transaction's unlock time/height - * - * The subclass should return the stored unlock time for the transaction - * with the given hash. - * - * If no such transaction exists, the subclass should throw TX_DNE. - * - * @param h the hash of the requested transaction - * - * @return the unlock time/height - */ - virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const = 0; - - // return tx with hash - // throw if no such tx exists - /** - * @brief fetches the transaction with the given hash - * - * If the transaction does not exist, the subclass should throw TX_DNE. - * - * @param h the hash to look for - * - * @return the transaction with the given hash - */ - virtual transaction get_tx(const crypto::hash& h) const; - - /** - * @brief fetches the transaction with the given hash - * - * If the transaction does not exist, the subclass should return false. - * - * @param h the hash to look for - * - * @return true iff the transaction was found - */ - virtual bool get_tx(const crypto::hash& h, transaction &tx) const; - - /** - * @brief fetches the transaction blob with the given hash - * - * The subclass should return the transaction stored which has the given - * hash. - * - * If the transaction does not exist, the subclass should return false. - * - * @param h the hash to look for - * - * @return true iff the transaction was found - */ - virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const = 0; - - /** - * @brief fetches the total number of transactions ever - * - * The subclass should return a count of all the transactions from - * all blocks. - * - * @return the number of transactions in the blockchain - */ - virtual uint64_t get_tx_count() const = 0; - - /** - * @brief fetches a list of transactions based on their hashes - * - * The subclass should attempt to fetch each transaction referred to by - * the hashes passed. - * - * Currently, if any of the transactions is not in BlockchainDB, the call - * to get_tx in the implementation will throw TX_DNE. - * - * - * - * @param hlist a list of hashes - * - * @return the list of transactions - */ - virtual std::vector get_tx_list(const std::vector& hlist) const = 0; - - // returns height of block that contains transaction with hash - /** - * @brief fetches the height of a transaction's block - * - * The subclass should attempt to return the height of the block containing - * the transaction with the given hash. - * - * If the transaction cannot be found, the subclass should throw TX_DNE. - * - * @param h the hash of the transaction - * - * @return the height of the transaction's block - */ - virtual uint64_t get_tx_block_height(const crypto::hash& h) const = 0; - - // returns the total number of outputs of amount - /** - * @brief fetches the number of outputs of a given amount - * - * The subclass should return a count of outputs of the given amount, - * or zero if there are none. - * - * - * - * @param amount the output amount being looked up - * @param output_type utxo type (cash, token, ...) - * - * @return the number of outputs of the given amount - */ - virtual uint64_t get_num_outputs(const uint64_t& amount, const tx_out_type output_type) const = 0; - - /** - * @brief return index of the first element (should be hidden, but isn't) - * - * @return the index - */ - virtual uint64_t get_indexing_base() const { return 0; } - - /** - * @brief get some of an output's data - * - * The subclass should return the public key, unlock time, and block height - * for the output with the given amount and index, collected in a struct. - * - * If the output cannot be found, the subclass should throw OUTPUT_DNE. - * - * If any of these parts cannot be found, but some are, the subclass - * should throw DB_ERROR with a message stating as much. - * - * @param amount the output amount - * @param index the output's index (indexed by amount) - * @param output_type utxo type (cash, token, ...) - * - * @return the requested output data - */ - virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) = 0; - - /** - * @brief get some of an output's data - * - * The subclass should return the public key, unlock time, and block height - * for the output with the given global index, collected in a struct. - * - * If the output cannot be found, the subclass should throw OUTPUT_DNE. - * - * If any of these parts cannot be found, but some are, the subclass - * should throw DB_ERROR with a message stating as much. - * - * @param global_index the output's index (global) - * - * @return the requested output data - */ - virtual output_data_t get_output_key(const uint64_t& global_index) const = 0; - - /** - * @brief gets an output's tx hash and index - * - * The subclass should return the hash of the transaction which created the - * output with the global index given, as well as its index in that transaction. - * - * @param index an output's global index - * - * @return the tx hash and output index - */ - virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const = 0; - - /** - * @brief gets an output's tx hash and index - * - * The subclass should return the hash of the transaction which created the - * output with the amount and index given, as well as its index in that - * transaction. - * - * @param amount an output amount - * @param index an output's amount-specific index - * @param output_type a utxo type (cash, token, ...) - * - * @return the tx hash and output index - */ - virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const = 0; - - /** - * @brief gets some outputs' tx hashes and indices - * - * This function is a mirror of - * get_output_tx_and_index(const uint64_t& amount, const uint64_t& index), - * but for a list of outputs rather than just one. - * - * @param amount an output amount - * @param offsets a list of amount-specific output indices - * @param indices return-by-reference a list of tx hashes and output indices (as pairs) - * @param output_type a utxo type (cash, token, ...) - */ - virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices, const tx_out_type output_type) const = 0; - - /** - * @brief gets outputs' data - * - * This function is a mirror of - * get_output_data(const uint64_t& amount, const uint64_t& index) - * but for a list of outputs rather than just one. - * - * @param amount an output amount - * @param offsets a list of amount-specific output indices - * @param outputs return-by-reference a list of outputs' metadata - * @param output_type a utxo type (cash, token, ...) - */ - virtual void get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs, const tx_out_type output_type, bool allow_partial = false) = 0; - - /* - * FIXME: Need to check with git blame and ask what this does to - * document it - */ - virtual bool can_thread_bulk_indices() const = 0; - - /** - * @brief gets output indices (amount-specific) for a transaction's outputs - * - * The subclass should fetch the amount-specific output indices for each - * output in the transaction with the given ID. - * - * If the transaction does not exist, the subclass should throw TX_DNE. - * - * If an output cannot be found, the subclass should throw OUTPUT_DNE. - * - * @param tx_id a transaction ID - * - * @return a list of amount-specific output indices - */ - virtual std::vector get_tx_amount_output_indices(const uint64_t tx_id) const = 0; - - /** - * @brief check if a key image is stored as spent - * - * @param img the key image to check for - * - * @return true if the image is present, otherwise false - */ - virtual bool has_key_image(const crypto::key_image& img) const = 0; - - /** - * @brief add a txpool transaction - * - * @param details the details of the transaction to add - */ - virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t& details) = 0; - - /** - * @brief update a txpool transaction's metadata - * - * @param txid the txid of the transaction to update - * @param details the details of the transaction to update - */ - virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& details) = 0; - - /** - * @brief get the number of transactions in the txpool - */ - virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const = 0; - - /** - * @brief check whether a txid is in the txpool - */ - virtual bool txpool_has_tx(const crypto::hash &txid) const = 0; - - /** - * @brief remove a txpool transaction - * - * @param txid the transaction id of the transation to remove - */ - virtual void remove_txpool_tx(const crypto::hash& txid) = 0; - - /** - * @brief get a txpool transaction's metadata - * - * @param txid the transaction id of the transation to lookup - * @param meta the metadata to return - * - * @return true if the tx meta was found, false otherwise - */ - virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const = 0; - - /** - * @brief get a txpool transaction's blob - * - * @param txid the transaction id of the transation to lookup - * @param bd the blob to return - * - * @return true if the txid was in the txpool, false otherwise - */ - virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const = 0; - - /** - * @brief get a txpool transaction's blob - * - * @param txid the transaction id of the transation to lookup - * - * @return the blob for that transaction - */ - virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const = 0; - - /** - * @brief runs a function over all txpool transactions - * - * The subclass should run the passed function for each txpool tx it has - * stored, passing the tx id and metadata as its parameters. - * - * If any call to the function returns false, the subclass should return - * false. Otherwise, the subclass returns true. - * - * @param std::function fn the function to run - * - * @return false if the function returns false for any transaction, otherwise true - */ - virtual bool for_all_txpool_txes(std::function, bool include_blob = false, bool include_unrelayed_txes = true) const = 0; - - /** - * @brief runs a function over all key images stored - * - * The subclass should run the passed function for each key image it has - * stored, passing the key image as its parameter. - * - * If any call to the function returns false, the subclass should return - * false. Otherwise, the subclass returns true. - * - * @param std::function fn the function to run - * - * @return false if the function returns false for any key image, otherwise true - */ - virtual bool for_all_key_images(std::function) const = 0; - - /** - * @brief runs a function over a range of blocks - * - * The subclass should run the passed function for each block in the - * specified range, passing (block_height, block_hash, block) as its parameters. - * - * If any call to the function returns false, the subclass should return - * false. Otherwise, the subclass returns true. - * - * The subclass should throw DB_ERROR if any of the expected values are - * not found. Current implementations simply return false. - * - * @param h1 the start height - * @param h2 the end height - * @param std::function fn the function to run - * - * @return false if the function returns false for any block, otherwise true - */ - virtual bool for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::function) const = 0; - - /** - * @brief runs a function over all transactions stored - * - * The subclass should run the passed function for each transaction it has - * stored, passing (transaction_hash, transaction) as its parameters. - * - * If any call to the function returns false, the subclass should return - * false. Otherwise, the subclass returns true. - * - * The subclass should throw DB_ERROR if any of the expected values are - * not found. Current implementations simply return false. - * - * @param std::function fn the function to run - * - * @return false if the function returns false for any transaction, otherwise true - */ - virtual bool for_all_transactions(std::function) const = 0; - - /** - * @brief runs a function over all outputs stored - * - * The subclass should run the passed function for each output it has - * stored, passing (amount, transaction_hash, tx_local_output_index) - * as its parameters. - * - * If any call to the function returns false, the subclass should return - * false. Otherwise, the subclass returns true. - * - * The subclass should throw DB_ERROR if any of the expected values are - * not found. Current implementations simply return false. - * - * @param std::function f the function to run - * @param output_type a utxo type (cash, token, ...) - * - * @return false if the function returns false for any output, otherwise true - */ - virtual bool for_all_outputs(std::function f, const tx_out_type output_type) const = 0; - virtual bool for_all_outputs(uint64_t amount, const std::function &f, const tx_out_type output_type) const = 0; - - - - // - // Hard fork related storage - // - - /** - * @brief sets which hardfork version a height is on - * - * @param height the height - * @param version the version - */ - virtual void set_hard_fork_version(uint64_t height, uint8_t version) = 0; - - /** - * @brief checks which hardfork version a height is on - * - * @param height the height - * - * @return the version - */ - virtual uint8_t get_hard_fork_version(uint64_t height) const = 0; - - /** - * @brief verify hard fork info in database - */ - virtual void check_hard_fork_info() = 0; - - /** - * @brief delete hard fork info from database - */ - virtual void drop_hard_fork_info() = 0; - - /** - * @brief return a histogram of outputs on the blockchain - * - * @param amounts optional set of amounts to lookup - * @param unlocked whether to restrict count to unlocked outputs - * @param recent_cutoff timestamp to determine whether an output is recent - * @param output_type a utxo type (cash, token, ...) - * - * @return a set of amount/instances - */ - virtual std::map> get_output_histogram(const std::vector &amounts, bool unlocked, uint64_t recent_cutoff, const tx_out_type output_type) const = 0; - - /** - * @brief is BlockchainDB in read-only mode? - * - * @return true if in read-only mode, otherwise false - */ - virtual bool is_read_only() const = 0; - - // TODO: this should perhaps be (or call) a series of functions which - // progressively update through version updates - /** - * @brief fix up anything that may be wrong due to past bugs - */ - virtual void fixup(); - - - /** - * @brief set whether or not to automatically remove logs - * - * This function is only relevant for one implementation (BlockchainBDB), but - * is here to keep BlockchainDB users implementation-agnostic. - * - * @param auto_remove whether or not to auto-remove logs - */ - void set_auto_remove_logs(bool auto_remove) { m_auto_remove_logs = auto_remove; } - - bool m_open; //!< Whether or not the BlockchainDB is open/ready for use - mutable epee::critical_section m_synchronization_lock; //!< A lock, currently for when BlockchainLMDB needs to resize the backing db file - -}; // class BlockchainDB - -BlockchainDB *new_db(const std::string& db_type); + class BlockchainDB + { + private: + /********************************************************************* + * private virtual members + *********************************************************************/ + + /** + * @brief add the block and metadata to the db + * + * The subclass implementing this will add the specified block and + * block metadata to its backing store. This does not include its + * transactions, those are added in a separate step. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param blk the block to be added + * @param block_size the size of the block (transactions and all) + * @param cumulative_difficulty the accumulated difficulty after this block + * @param coins_generated the number of coins generated total after this block + * @param tokens_migrated the number of tokens migrated from Bitcoin blockchain + * @param blk_hash the hash of the block + */ + virtual void add_block(const block &blk, const size_t &block_size, const difficulty_type &cumulative_difficulty, const uint64_t &coins_generated, const uint64_t &tokens_migrated, const crypto::hash &blk_hash + ) = 0; + + /** + * @brief remove data about the top block + * + * The subclass implementing this will remove the block data from the top + * block in the chain. The data to be removed is that which was added in + * BlockchainDB::add_block(const block& blk, const size_t& block_size, const difficulty_type& cumulative_difficulty, const uint64_t& coins_generated, const crypto::hash& blk_hash) + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ + virtual void remove_block() = 0; + + /** + * @brief store the transaction and its metadata + * + * The subclass implementing this will add the specified transaction data + * to its backing store. This includes only the transaction blob itself + * and the other data passed here, not the separate outputs of the + * transaction. + * + * It returns a tx ID, which is a mapping from the tx_hash. The tx ID + * is used in #add_tx_amount_output_indices(). + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param blk_hash the hash of the block containing the transaction + * @param tx the transaction to be added + * @param tx_hash the hash of the transaction + * @return the transaction ID + */ + virtual uint64_t add_transaction_data(const crypto::hash &blk_hash, const transaction &tx, const crypto::hash &tx_hash) = 0; + + /** + * @brief remove data about a transaction + * + * The subclass implementing this will remove the transaction data + * for the passed transaction. The data to be removed was added in + * add_transaction_data(). Additionally, current subclasses have behavior + * which requires the transaction itself as a parameter here. Future + * implementations should note that this parameter is subject to be removed + * at a later time. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param tx_hash the hash of the transaction to be removed + * @param tx the transaction + */ + virtual void remove_transaction_data(const crypto::hash &tx_hash, const transaction &tx) = 0; + + /** + * @brief remove data about a unstake token tx + * + * The subclass implementing this will remove unstake token data from DB + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param tx_hash the hash of the transaction to be removed + * @param tx the transaction + */ + virtual void remove_unstake_token(const crypto::hash &tx_hash, const transaction &tx) = 0; + + /** + * @brief store an output + * + * The subclass implementing this will add the output data passed to its + * backing store in a suitable manner. In addition, the subclass is responsible + * for keeping track of the global output count in some manner, so that + * outputs may be indexed by the order in which they were created. In the + * future, this tracking (of the number, at least) should be moved to + * this class, as it is necessary and the same among all BlockchainDB. + * + * It returns an amount output index, which is the index of the output + * for its specified amount. + * + * This data should be stored in such a manner that the only thing needed to + * reverse the process is the tx_out. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param tx_hash hash of the transaction the output was created by + * @param tx_output the output + * @param local_index index of the output in its transaction + * @param unlock_time unlock time/height of the output + * @param commitment the rct commitment to the output amount + * @return amount/token_amount/advanced output output index + */ + virtual uint64_t add_output(const crypto::hash &tx_hash, const tx_out &tx_output, const uint64_t &local_index, const uint64_t unlock_time, const rct::key *commitment) = 0; + + /** + * @brief store amount output indices for a tx's outputs. + * + * For cash and token outputs, their amount output indice in output_amounts + * and output_token_amounts tables is stored. For advanced outputs, + * output id from output_advanced table is stored. + * + * The subclass implementing this will add the amount output indices to its + * backing store in a suitable manner. The tx_id will be the same one that + * was returned from #add_output(). + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param tx_id ID of the transaction containing these outputs + * @param amount_output_indices the amount output indices of the transaction + */ + virtual void add_tx_amount_output_indices(const uint64_t tx_id, const std::vector &amount_output_indices) = 0; + + /** + * @brief store a spent key + * + * The subclass implementing this will store the spent key image. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param k_image the spent key image to store + */ + virtual void add_spent_key(const crypto::key_image &k_image) = 0; + + /** + * @brief remove a spent key + * + * The subclass implementing this will remove the key image. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param k_image the spent key image to remove + */ + virtual void remove_spent_key(const crypto::key_image &k_image) = 0; + + + + /* Safex related private db api */ + /********************************/ + + + /** + * @brief function that takes into account data changes as consequence of input command execution + * + * This function is called by add_transactions() txin_to_script + * with command + * + * @param txin input with safex command + */ + virtual void process_command_input(const cryptonote::txin_to_script &txin) = 0; + + + /** + * Updates staked token sum + * + * + * + * + * @param delta amount of locked or unlocked tokens + * @param sign positive if tokens are locked, otherwise negative + * @return new total current token staked sum + */ + uint64_t update_current_staked_token_sum(const uint64_t delta, int sign); + + /** + * Changes collected fee sum for delta + * + * Delta could only be positive + * + * + * @param interval_starting_block block that represents interval, for example 1001 for second interval + * @param collected_fee newly collected fee + * @return new total collected fee value for interval + */ + virtual uint64_t update_network_fee_sum_for_interval(const uint64_t interval_starting_block, const uint64_t collected_fee) = 0; + + + + + /********************************************************************* + * private concrete members + *********************************************************************/ + /** + * @brief private version of pop_block, for undoing if an add_block fails + * + * This function simply calls pop_block(block& blk, std::vector& txs) + * with dummy parameters, as the returns-by-reference can be discarded. + */ + void pop_block(); + + // helper function to remove transaction from blockchain + /** + * @brief helper function to remove transaction from the blockchain + * + * This function encapsulates aspects of removing a transaction. + * + * @param tx_hash the hash of the transaction to be removed + */ + void remove_transaction(const crypto::hash &tx_hash); + + uint64_t num_calls = 0; //!< a performance metric + uint64_t time_blk_hash = 0; //!< a performance metric + uint64_t time_add_block1 = 0; //!< a performance metric + uint64_t time_add_transaction = 0; //!< a performance metric + + + protected: + + /** + * @brief helper function for add_transactions, to add each individual transaction + * + * This function is called by add_transactions() for each transaction to be + * added. + * + * @param blk_hash hash of the block which has the transaction + * @param tx the transaction to add + * @param tx_hash_ptr the hash of the transaction, if already calculated + */ + void add_transaction(const crypto::hash &blk_hash, const transaction &tx, const crypto::hash *tx_hash_ptr = NULL); + + /** + * Updates token staked sum for interval + * + * @return token staked sum for this interval + */ + virtual uint64_t update_staked_token_for_interval(const uint64_t interval, const uint64_t new_staked_tokens_in_interval) = 0; + /** + * Remove token staked sum for interval + * + * @return true if it runs OK, false if it fails + */ + virtual bool remove_staked_token_for_interval(const uint64_t interval) = 0; + + mutable uint64_t time_tx_exists = 0; //!< a performance metric + uint64_t time_commit1 = 0; //!< a performance metric + bool m_auto_remove_logs = true; //!< whether or not to automatically remove old logs + + HardFork *m_hardfork; + + cryptonote::network_type m_nettype{cryptonote::network_type::MAINNET}; //for which network is database + + public: + + /** + * @brief An empty constructor. + */ + BlockchainDB() : m_open(false) + {} + + /** + * @brief Constructor specifiying network type + */ + BlockchainDB(cryptonote::network_type nettype) : m_open(false), m_nettype(nettype) + {} + + + + /** + * @brief An empty destructor. + */ + virtual ~BlockchainDB() + {}; + + /** + * @brief init command line options + */ + static void init_options(boost::program_options::options_description &desc); + + /** + * @brief reset profiling stats + */ + void reset_stats(); + + /** + * @brief show profiling stats + * + * This function prints current performance/profiling data to whichever + * log file(s) are set up (possibly including stdout or stderr) + */ + void show_stats(); + + /** + * @brief open a db, or create it if necessary. + * + * This function opens an existing database or creates it if it + * does not exist. + * + * The subclass implementing this will handle all file opening/creation, + * and is responsible for maintaining its state. + * + * The parameter may not refer to a file name, necessarily, but + * could be an IP:PORT for a database which needs it, and so on. Calling it + * is convenient and should be descriptive enough, however. + * + * For now, db_flags are + * specific to the subclass being instantiated. This is subject to change, + * and the db_flags parameter may be deprecated. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param filename a string referring to the BlockchainDB to open + * @param db_flags flags relevant to how to open/use the BlockchainDB + */ + virtual void open(const std::string &filename, const int db_flags = 0) = 0; + + /** + * @brief Gets the current open/ready state of the BlockchainDB + * + * @return true if open/ready, otherwise false + */ + bool is_open() const; + + /** + * @brief close the BlockchainDB + * + * At minimum, this call ensures that further use of the BlockchainDB + * instance will not have effect. In any case where it is necessary + * to do so, a subclass implementing this will sync with disk. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ + virtual void close() = 0; + + /** + * @brief sync the BlockchainDB with disk + * + * This function should write any changes to whatever permanent backing + * store the subclass uses. Example: a BlockchainDB instance which + * keeps the whole blockchain in RAM won't need to regularly access a + * disk, but should write out its state when this is called. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ + virtual void sync() = 0; + + /** + * @brief toggle safe syncs for the DB + * + * Used to switch DBF_SAFE on or off after starting up with DBF_FAST. + */ + virtual void safesyncmode(const bool onoff) = 0; + + /** + * @brief Remove everything from the BlockchainDB + * + * This function should completely remove all data from a BlockchainDB. + * + * Use with caution! + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ + virtual void reset() = 0; + + /** + * @brief get all files used by the BlockchainDB (if any) + * + * This function is largely for ease of automation, namely for unit tests. + * + * The subclass implementation should return all filenames it uses. + * + * @return a list of filenames + */ + virtual std::vector get_filenames() const = 0; + + // return the name of the folder the db's file(s) should reside in + /** + * @brief gets the name of the folder the BlockchainDB's file(s) should be in + * + * The subclass implementation should return the name of the folder in which + * it stores files, or an empty string if there is none. + * + * @return the name of the folder with the BlockchainDB's files, if any. + */ + virtual std::string get_db_name() const = 0; + + + // FIXME: these are just for functionality mocking, need to implement + // RAII-friendly and multi-read one-write friendly locking mechanism + // + // acquire db lock + /** + * @brief acquires the BlockchainDB lock + * + * This function is a stub until such a time as locking is implemented at + * this level. + * + * The subclass implementation should return true unless implementing a + * locking scheme of some sort, in which case it should return true upon + * acquisition of the lock and block until then. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @return true, unless at a future time false makes sense (timeout, etc) + */ + virtual bool lock() = 0; + + // release db lock + /** + * @brief This function releases the BlockchainDB lock + * + * The subclass, should it have implemented lock(), will release any lock + * held by the calling thread. In the case of recursive locking, it should + * release one instance of a lock. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ + virtual void unlock() = 0; + + /** + * @brief tells the BlockchainDB to start a new "batch" of blocks + * + * If the subclass implements a batching method of caching blocks in RAM to + * be added to a backing store in groups, it should start a batch which will + * end either when has been added or batch_stop() has + * been called. In either case, it should end the batch and write to its + * backing store. + * + * If a batch is already in-progress, this function must return false. + * If a batch was started by this call, it must return true. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param batch_num_blocks number of blocks to batch together + * + * @return true if we started the batch, false if already started + */ + virtual bool batch_start(uint64_t batch_num_blocks = 0, uint64_t batch_bytes = 0) = 0; + + /** + * @brief ends a batch transaction + * + * If the subclass implements batching, this function should store the + * batch it is currently on and mark it finished. + * + * If no batch is in-progress, this function should throw a DB_ERROR. + * This exception may change in the future if it is deemed necessary to + * have a more granular exception type for this scenario. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ + virtual void batch_stop() = 0; + + /** + * @brief aborts a batch transaction + * + * If the subclass implements batching, this function should abort the + * batch it is currently on. + * + * If no batch is in-progress, this function should throw a DB_ERROR. + * This exception may change in the future if it is deemed necessary to + * have a more granular exception type for this scenario. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + */ + virtual void batch_abort() = 0; + + /** + * @brief sets whether or not to batch transactions + * + * If the subclass implements batching, this function tells it to begin + * batching automatically. + * + * If the subclass implements batching and has a batch in-progress, a + * parameter of false should disable batching and call batch_stop() to + * store the current batch. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param bool batch whether or not to use batch transactions. + */ + virtual void set_batch_transactions(bool) = 0; + + virtual void block_txn_start(bool readonly = false) = 0; + + virtual void block_txn_stop() = 0; + + virtual void block_txn_abort() = 0; + + virtual void set_hard_fork(HardFork *hf); + + // adds a block with the given metadata to the top of the blockchain, returns the new height + /** + * @brief handles the addition of a new block to BlockchainDB + * + * This function organizes block addition and calls various functions as + * necessary. + * + * NOTE: subclass implementations of this (or the functions it calls) need + * to handle undoing any partially-added blocks in the event of a failure. + * + * If any of this cannot be done, the subclass should throw the corresponding + * subclass of DB_EXCEPTION + * + * @param blk the block to be added + * @param block_size the size of the block (transactions and all) + * @param cumulative_difficulty the accumulated difficulty after this block + * @param coins_generated the number of coins generated total after this block + * @param tokens_migrated the number of tokens migrated from Bitcoin blockchain + * @param txs the transactions in the block + * + * @return the height of the chain post-addition + */ + virtual uint64_t add_block(const block &blk, const size_t &block_size, const difficulty_type &cumulative_difficulty, const uint64_t &coins_generated, const uint64_t &tokens_migrated, const std::vector &txs + ); + + /** + * @brief checks if a block exists + * + * @param h the hash of the requested block + * @param height if non NULL, returns the block's height if found + * + * @return true of the block exists, otherwise false + */ + virtual bool block_exists(const crypto::hash &h, uint64_t *height = NULL) const = 0; + + /** + * @brief fetches the block with the given hash + * + * The subclass should return the requested block. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param h the hash to look for + * + * @return the block requested + */ + virtual cryptonote::blobdata get_block_blob(const crypto::hash &h) const = 0; + + /** + * @brief fetches the block with the given hash + * + * Returns the requested block. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param h the hash to look for + * + * @return the block requested + */ + virtual block get_block(const crypto::hash &h) const; + + /** + * @brief gets the height of the block with a given hash + * + * The subclass should return the requested height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param h the hash to look for + * + * @return the height + */ + virtual uint64_t get_block_height(const crypto::hash &h) const = 0; + + /** + * @brief fetch a block header + * + * The subclass should return the block header from the block with + * the given hash. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param h the hash to look for + * + * @return the block header + */ + virtual block_header get_block_header(const crypto::hash &h) const = 0; + + /** + * @brief fetch a block blob by height + * + * The subclass should return the block at the given height. + * + * If the block does not exist, that is to say if the blockchain is not + * that high, then the subclass should throw BLOCK_DNE + * + * @param height the height to look for + * + * @return the block blob + */ + virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t &height) const = 0; + + /** + * @brief fetch a block by height + * + * If the block does not exist, that is to say if the blockchain is not + * that high, then the subclass should throw BLOCK_DNE + * + * @param height the height to look for + * + * @return the block + */ + virtual block get_block_from_height(const uint64_t &height) const; + + /** + * @brief fetch a block's timestamp + * + * The subclass should return the timestamp of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the timestamp + */ + virtual uint64_t get_block_timestamp(const uint64_t &height) const = 0; + + /** + * @brief fetch the top block's timestamp + * + * The subclass should return the timestamp of the most recent block. + * + * @return the top block's timestamp + */ + virtual uint64_t get_top_block_timestamp() const = 0; + + /** + * @brief fetch a block's size + * + * The subclass should return the size of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the size + */ + virtual size_t get_block_size(const uint64_t &height) const = 0; + + /** + * @brief fetch a block's cumulative difficulty + * + * The subclass should return the cumulative difficulty of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the cumulative difficulty + */ + virtual difficulty_type get_block_cumulative_difficulty(const uint64_t &height) const = 0; + + /** + * @brief fetch a block's difficulty + * + * The subclass should return the difficulty of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the difficulty + */ + virtual difficulty_type get_block_difficulty(const uint64_t &height) const = 0; + + /** + * @brief fetch a block's already generated coins + * + * The subclass should return the total coins generated as of the block + * with the given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the already generated coins + */ + virtual uint64_t get_block_already_generated_coins(const uint64_t &height) const = 0; + + + /** + * @brief fetch a block's already migrated tokens + * + * The subclass should return the total tokens migrated from Bitcoin platform + * as of block with the given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return number of already migrated tokens + */ + virtual uint64_t get_block_already_migrated_tokens(const uint64_t &height) const = 0; + + /** + * @brief fetch a block's hash + * + * The subclass should return hash of the block with the + * given height. + * + * If the block does not exist, the subclass should throw BLOCK_DNE + * + * @param height the height requested + * + * @return the hash + */ + virtual crypto::hash get_block_hash_from_height(const uint64_t &height) const = 0; + + /** + * @brief fetch a list of blocks + * + * The subclass should return a vector of blocks with heights starting at + * h1 and ending at h2, inclusively. + * + * If the height range requested goes past the end of the blockchain, + * the subclass should throw BLOCK_DNE. (current implementations simply + * don't catch this exception as thrown by methods called within) + * + * @param h1 the start height + * @param h2 the end height + * + * @return a vector of blocks + */ + virtual std::vector get_blocks_range(const uint64_t &h1, const uint64_t &h2) const = 0; + + /** + * @brief fetch a list of block hashes + * + * The subclass should return a vector of block hashes from blocks with + * heights starting at h1 and ending at h2, inclusively. + * + * If the height range requested goes past the end of the blockchain, + * the subclass should throw BLOCK_DNE. (current implementations simply + * don't catch this exception as thrown by methods called within) + * + * @param h1 the start height + * @param h2 the end height + * + * @return a vector of block hashes + */ + virtual std::vector get_hashes_range(const uint64_t &h1, const uint64_t &h2) const = 0; + + /** + * @brief fetch the top block's hash + * + * The subclass should return the hash of the most recent block + * + * @return the top block's hash + */ + virtual crypto::hash top_block_hash() const = 0; + + /** + * @brief fetch the top block + * + * The subclass should return most recent block + * + * @return the top block + */ + virtual block get_top_block() const = 0; + + /** + * @brief fetch the current blockchain height + * + * The subclass should return the current blockchain height + * + * @return the current blockchain height + */ + virtual uint64_t height() const = 0; + + + // helper function to remove transaction from blockchain + /** + * @brief helper function to remove transaction from the blockchain + * + * This function encapsulates aspects of removing a transaction. + * + * @param tx_hash the hash of the transaction to be removed + */ + void revert_transaction(const crypto::hash &tx_hash); + + + /** + * + * + * @brief pops the top block off the blockchain + * + * The subclass should remove the most recent block from the blockchain, + * along with all transactions, outputs, and other metadata created as + * a result of its addition to the blockchain. Most of this is handled + * by the concrete members of the base class provided the subclass correctly + * implements remove_* functions. + * + * The subclass should return by reference the popped block and + * its associated transactions + * + * @param blk return-by-reference the block which was popped + * @param txs return-by-reference the transactions from the popped block + */ + virtual void pop_block(block &blk, std::vector &txs); + + + /** + * @brief check if a transaction with a given hash exists + * + * The subclass should check if a transaction is stored which has the + * given hash and return true if so, false otherwise. + * + * @param h the hash to check against + * @param tx_id (optional) returns the tx_id for the tx hash + * + * @return true if the transaction exists, otherwise false + */ + virtual bool tx_exists(const crypto::hash &h) const = 0; + + virtual bool tx_exists(const crypto::hash &h, uint64_t &tx_id) const = 0; + + // return unlock time of tx with hash + /** + * @brief fetch a transaction's unlock time/height + * + * The subclass should return the stored unlock time for the transaction + * with the given hash. + * + * If no such transaction exists, the subclass should throw TX_DNE. + * + * @param h the hash of the requested transaction + * + * @return the unlock time/height + */ + virtual uint64_t get_tx_unlock_time(const crypto::hash &h) const = 0; + + // return tx with hash + // throw if no such tx exists + /** + * @brief fetches the transaction with the given hash + * + * If the transaction does not exist, the subclass should throw TX_DNE. + * + * @param h the hash to look for + * + * @return the transaction with the given hash + */ + virtual transaction get_tx(const crypto::hash &h) const; + + /** + * @brief fetches the transaction with the given hash + * + * If the transaction does not exist, the subclass should return false. + * + * @param h the hash to look for + * + * @return true iff the transaction was found + */ + virtual bool get_tx(const crypto::hash &h, transaction &tx) const; + + /** + * @brief fetches the transaction blob with the given hash + * + * The subclass should return the transaction stored which has the given + * hash. + * + * If the transaction does not exist, the subclass should return false. + * + * @param h the hash to look for + * + * @return true iff the transaction was found + */ + virtual bool get_tx_blob(const crypto::hash &h, cryptonote::blobdata &tx) const = 0; + + /** + * @brief fetches the total number of transactions ever + * + * The subclass should return a count of all the transactions from + * all blocks. + * + * @return the number of transactions in the blockchain + */ + virtual uint64_t get_tx_count() const = 0; + + /** + * @brief fetches a list of transactions based on their hashes + * + * The subclass should attempt to fetch each transaction referred to by + * the hashes passed. + * + * Currently, if any of the transactions is not in BlockchainDB, the call + * to get_tx in the implementation will throw TX_DNE. + * + * + * + * @param hlist a list of hashes + * + * @return the list of transactions + */ + virtual std::vector get_tx_list(const std::vector &hlist) const = 0; + + // returns height of block that contains transaction with hash + /** + * @brief fetches the height of a transaction's block + * + * The subclass should attempt to return the height of the block containing + * the transaction with the given hash. + * + * If the transaction cannot be found, the subclass should throw TX_DNE. + * + * @param h the hash of the transaction + * + * @return the height of the transaction's block + */ + virtual uint64_t get_tx_block_height(const crypto::hash &h) const = 0; + + // returns the total number of outputs of amount + /** + * @brief fetches the number of outputs of a given amount + * + * The subclass should return a count of outputs of the given amount, + * or zero if there are none. + * + * + * + * @param amount the output amount being looked up + * @param output_type utxo type (cash, token, ...) + * + * @return the number of outputs of the given amount + */ + virtual uint64_t get_num_outputs(const uint64_t &amount, const tx_out_type output_type) const = 0; + + // returns the total number of outputs of type + /** + * @brief fetches the number advanced outputs of particular type + * + * The subclass should return a count of outputs of particular tx_out_type, + * or zero if there are none. + * + * For cash and token outputs, use overloading function that also specifies amount + * + * @param output_type utxo type (locked token outputs, ...) + * + * @return the number of advanced outputs of given type + */ + virtual uint64_t get_num_outputs(const tx_out_type output_type) const = 0; + + /** + * @brief return index of the first element (should be hidden, but isn't) + * + * @return the index + */ + virtual uint64_t get_indexing_base() const + { return 0; } + + /** + * @brief get some of an output's data + * + * The subclass should return the public key, unlock time, and block height + * for the output with the given amount and index, collected in a struct. + * + * If the output cannot be found, the subclass should throw OUTPUT_DNE. + * + * If any of these parts cannot be found, but some are, the subclass + * should throw DB_ERROR with a message stating as much. + * + * @param amount the output amount + * @param index the output's index (indexed by amount) + * @param output_type utxo type (cash, token, ...) + * + * @return the requested output data + */ + virtual output_data_t get_output_key(const uint64_t &amount, const uint64_t &index, const tx_out_type output_type) const = 0; + + /** + * @brief get some of an output's data + * + * The subclass should return the advanced data, collected in a struct. + * + * If the output cannot be found, the subclass should throw OUTPUT_DNE. + * + * If any of these parts cannot be found, but some are, the subclass + * should throw DB_ERROR with a message stating as much. + * + * @param output_type type of output(e.g. staked token output + * @param output_index index of the output for selected type + * + * @return list of advanced output data + */ + virtual output_advanced_data_t get_output_advanced_data(const tx_out_type output_type, const uint64_t output_index) const = 0; + + /** + * @brief get output id for given type and index + * + * The subclass should return the global output id + * + * If the output cannot be found, the subclass should throw OUTPUT_DNE. + * + * If any of these parts cannot be found, but some are, the subclass + * should throw DB_ERROR with a message stating as much. + * + * @param output_type type of output(e.g. staked token output + * @param output_index index of the output for selected type + * @param output_id reference to var where output_id will be returned + * + * @return true if it can find output id, false if it is not found + */ + virtual bool get_output_id(const tx_out_type output_type, const uint64_t output_index, uint64_t& output_id) const = 0; + /** + * @brief gets an output's tx hash and index + * + * The subclass should return the hash of the transaction which created the + * output with the global index given, as well as its index in that transaction. + * + * @param index an output's global index + * + * @return the tx hash and output index + */ + virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t &index) const = 0; + + /** + * @brief gets an output's tx hash and index + * + * The subclass should return the hash of the transaction which created the + * output with the amount and index given, as well as its index in that + * transaction. + * + * @param amount an output amount + * @param index an output's amount-specific index + * @param output_type a utxo type (cash, token, ...) + * + * @return the tx hash and output index + */ + virtual tx_out_index get_output_tx_and_index(const uint64_t &amount, const uint64_t &index, const tx_out_type output_type) const = 0; + + /** + * @brief gets some outputs' tx hashes and indices + * + * This function is a mirror of + * get_output_tx_and_index(const uint64_t& amount, const uint64_t& index), + * but for a list of outputs rather than just one. + * + * @param amount an output amount + * @param offsets a list of amount-specific output indices + * @param indices return-by-reference a list of tx hashes and output indices (as pairs) + * @param output_type a utxo type (cash, token, ...) + */ + virtual void get_output_tx_and_index(const uint64_t &amount, const std::vector &offsets, std::vector &indices, const tx_out_type output_type) const = 0; + + /** + * @brief gets outputs' data + * + * This function is a mirror of + * get_output_data(const uint64_t& amount, const uint64_t& index) + * but for a list of outputs rather than just one. + * + * @param amount an output amount + * @param offsets a list of amount-specific output indices + * @param outputs return-by-reference a list of outputs' metadata + * @param output_type a utxo type (cash, token, ...) + */ + virtual void get_amount_output_key(const uint64_t &amount, const std::vector &offsets, + std::vector &outputs, const tx_out_type output_type, + bool allow_partial = false) const = 0; + + /** + * @brief gets outputs' data + * + * This function is a mirror of + * get_output_data(const uint64_t& amount, const uint64_t& index) + * but for a list of outputs rather than just one. + * + * @param output_indexes a list of output indexes for that type + * @param outputs return-by-reference a list of outputs' metadata + * @param output_type a utxo type (locked token, ...) + */ + virtual void get_advanced_output_key(const std::vector &output_indexes, + std::vector &outputs, const tx_out_type output_type, + bool allow_partial = false) const = 0; + + /* + * FIXME: Need to check with git blame and ask what this does to + * document it + */ + virtual bool can_thread_bulk_indices() const = 0; + + /** + * @brief gets output indices (amount-specific) for a transaction's outputs + * + * The subclass should fetch the amount-specific output indices for each + * output in the transaction with the given ID. + * + * If the transaction does not exist, the subclass should throw TX_DNE. + * + * If an output cannot be found, the subclass should throw OUTPUT_DNE. + * + * @param tx_id a transaction ID + * + * @return a list of amount-specific output indices + */ + virtual std::vector get_tx_amount_output_indices(const uint64_t tx_id) const = 0; + + /** + * @brief check if a key image is stored as spent + * + * @param img the key image to check for + * + * @return true if the image is present, otherwise false + */ + virtual bool has_key_image(const crypto::key_image &img) const = 0; + + /** + * @brief add a txpool transaction + * + * @param details the details of the transaction to add + */ + virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t &details) = 0; + + /** + * @brief update a txpool transaction's metadata + * + * @param txid the txid of the transaction to update + * @param details the details of the transaction to update + */ + virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t &details) = 0; + + /** + * @brief get the number of transactions in the txpool + */ + virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const = 0; + + /** + * @brief check whether a txid is in the txpool + */ + virtual bool txpool_has_tx(const crypto::hash &txid) const = 0; + + /** + * @brief remove a txpool transaction + * + * @param txid the transaction id of the transation to remove + */ + virtual void remove_txpool_tx(const crypto::hash &txid) = 0; + + /** + * @brief get a txpool transaction's metadata + * + * @param txid the transaction id of the transation to lookup + * @param meta the metadata to return + * + * @return true if the tx meta was found, false otherwise + */ + virtual bool get_txpool_tx_meta(const crypto::hash &txid, txpool_tx_meta_t &meta) const = 0; + + /** + * @brief get a txpool transaction's blob + * + * @param txid the transaction id of the transation to lookup + * @param bd the blob to return + * + * @return true if the txid was in the txpool, false otherwise + */ + virtual bool get_txpool_tx_blob(const crypto::hash &txid, cryptonote::blobdata &bd) const = 0; + + /** + * @brief get a txpool transaction's blob + * + * @param txid the transaction id of the transation to lookup + * + * @return the blob for that transaction + */ + virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash &txid) const = 0; + + /** + * @brief runs a function over all txpool transactions + * + * The subclass should run the passed function for each txpool tx it has + * stored, passing the tx id and metadata as its parameters. + * + * If any call to the function returns false, the subclass should return + * false. Otherwise, the subclass returns true. + * + * @param std::function fn the function to run + * + * @return false if the function returns false for any transaction, otherwise true + */ + virtual bool for_all_txpool_txes(std::function, bool include_blob = false, bool include_unrelayed_txes = true) const = 0; + + /** + * @brief runs a function over all key images stored + * + * The subclass should run the passed function for each key image it has + * stored, passing the key image as its parameter. + * + * If any call to the function returns false, the subclass should return + * false. Otherwise, the subclass returns true. + * + * @param std::function fn the function to run + * + * @return false if the function returns false for any key image, otherwise true + */ + virtual bool for_all_key_images(std::function) const = 0; + + /** + * @brief runs a function over a range of blocks + * + * The subclass should run the passed function for each block in the + * specified range, passing (block_height, block_hash, block) as its parameters. + * + * If any call to the function returns false, the subclass should return + * false. Otherwise, the subclass returns true. + * + * The subclass should throw DB_ERROR if any of the expected values are + * not found. Current implementations simply return false. + * + * @param h1 the start height + * @param h2 the end height + * @param std::function fn the function to run + * + * @return false if the function returns false for any block, otherwise true + */ + virtual bool for_blocks_range(const uint64_t &h1, const uint64_t &h2, std::function) const = 0; + + /** + * @brief runs a function over all transactions stored + * + * The subclass should run the passed function for each transaction it has + * stored, passing (transaction_hash, transaction) as its parameters. + * + * If any call to the function returns false, the subclass should return + * false. Otherwise, the subclass returns true. + * + * The subclass should throw DB_ERROR if any of the expected values are + * not found. Current implementations simply return false. + * + * @param std::function fn the function to run + * + * @return false if the function returns false for any transaction, otherwise true + */ + virtual bool for_all_transactions(std::function) const = 0; + + /** + * @brief runs a function over all outputs stored + * + * The subclass should run the passed function for each output it has + * stored, passing (amount, transaction_hash, tx_local_output_index) + * as its parameters. + * + * If any call to the function returns false, the subclass should return + * false. Otherwise, the subclass returns true. + * + * The subclass should throw DB_ERROR if any of the expected values are + * not found. Current implementations simply return false. + * + * @param std::function f the function to run + * @param output_type a utxo type (cash, token, ...) + * + * @return false if the function returns false for any output, otherwise true + */ + virtual bool for_all_outputs(std::function f, const tx_out_type output_type) const = 0; + + virtual bool for_all_outputs(uint64_t amount, const std::function &f, const tx_out_type output_type) const = 0; + + virtual bool for_all_advanced_outputs(std::function f, const tx_out_type output_type) const = 0; //todo + + + + + + /* Safex related db api */ + /***********************/ + + + /** + * Returns current number of staked tokens + * + * + * @return number of staked tokens at current height + */ + virtual uint64_t get_current_staked_token_sum() const = 0; + + /** + * Returns number of staked tokens that should receive interest in particular interval. + * + * Tokens unlocked in interval 5 do not receive interest in interval 5, but up to interval 4 + * Tokens locked in interval 5 receive interest for interval 6 + * + * + * @param interval interval number + * @return number of staked tokens in that interval, used for interest calculation + */ + virtual uint64_t get_staked_token_sum_for_interval(const uint64_t interval) const = 0; + + /** + * Returns collected network fee sum for particular interval + * + * + * @param interval interval number + * @return amount of collected fee sum + */ + virtual uint64_t get_network_fee_sum_for_interval(const uint64_t interval) const = 0; + + + /** + * Returns array of output id-s which stake expires on particular block + * + * + * @param block_height block height + * @return array of output id-s + */ + virtual std::vector get_token_stake_expiry_outputs(const uint64_t block_height) const = 0; + + + + /** + * Returns map where key is interval and value is interest per token for that interval + * + */ + virtual bool get_interval_interest_map(const uint64_t start_height, const uint64_t end_height, safex::map_interval_interest &map) const = 0; + + + /** + * Returns accumulated interest for given output + * + * + * @param txin script of unstake command + * @param unlock_height height of the Blockchain when the command is called + * @return Total SFX network fee for given output + */ + virtual uint64_t calculate_staked_token_interest_for_output(const txin_to_script &txin, const uint64_t unlock_height) const = 0; + + /** + * Get safex account public key + * + * @param username safex account username + * @param pkey publik key output parameter + * + * @return true if account exists, false otherwise + */ + virtual bool get_account_key(const safex::account_username &username, crypto::public_key &pkey) const = 0; + + /** + * Get safex account data + * + * @param username safex account username + * @param data publik key output parameter + * + * @return true if account exists, false otherwise + */ + virtual bool get_account_data(const safex::account_username &username, std::vector &data) const = 0; + + /** + * Get safex offer data + * + * @param offer_id safex offer id + * @param offer data offer + * + * @return true if offer exists, false otherwise + */ + virtual bool get_offer(const crypto::hash offer_id, safex::safex_offer &offer) const = 0; + + /** + * Get safex offer username of seller + * + * @param offer_id safex offer id + * @param username username of offer seller + * + * @return true if offer exists, false otherwise + */ + virtual bool get_offer_seller(const crypto::hash offer_id, std::string &username) const = 0; + + + /** + * Get safex offer price + * + * @param offer_id safex offer id + * @param price price of offer + * + * @return true if offer exists, false otherwise + */ + virtual bool get_offer_price(const crypto::hash offer_id, uint64_t &price) const = 0; + + + /** + * Get safex offer quantity + * + * @param offer_id safex offer id + * @param quantity quantity of offer + * + * @return true if offer exists, false otherwise + */ + virtual bool get_offer_quantity(const crypto::hash offer_id, uint64_t &quantity) const = 0; + + /** + * Get safex offer active status + * + * @param offer_id safex offer id + * @param active offer status is active + * + * @return true if offer exists, false otherwise + */ + virtual bool get_offer_active_status(const crypto::hash offer_id, bool &active) const = 0; + + + /** + * @brief fetch safex accounts from the blockchain + * + * The subclass should return safex account usernames and descriptions + * + * @return True if no error ocurred + */ + virtual bool get_safex_accounts( std::vector> &safex_accounts) const = 0; + + + /** + * @brief fetch safex offers from the blockchain + * + * The subclass should return safex offers data + * + * @return True if no error ocurred + */ + virtual bool get_safex_offers( std::vector &safex_offers) const = 0; + + + /** + * @brief fetch safex offer height from blockchain + * + * The subclass should return safex offer height + * + * @return True if no error ocurred + */ + virtual bool get_safex_offer_height( crypto::hash &offer_id, uint64_t &height) const = 0; + + /** + * @brief fetch safex price pegs from the blockchain + * + * The subclass should return safex price pegs data + * @param currency string of currency, empty string for all price pegs + * + * @return True if no error ocurred + */ + virtual bool get_safex_price_pegs( std::vector &safex_price_pegs, const std::string& currency) const = 0; + + /** + * @brief fetch safex price peg from the blockchain + * + * The subclass should return safex price peg data + * @param price_peg_id price peg id + * + * @return True if no error ocurred + */ + virtual bool get_safex_price_peg( const crypto::hash& price_peg_id,safex::safex_price_peg &safex_price_peg) const = 0; + /** + * @brief fetch safex feedbacks for given offer id from the blockchain + * + * The subclass should return safex feedbacks data + * + * @return True if no error ocurred + */ + virtual bool get_safex_feedbacks( std::vector &safex_feedbacks, const crypto::hash& offer_id) const = 0; + + /** + * @brief fetch safex offer's stars from the blockchain + * + * The subclass should return safex offer stars received + * + * @return True if no error ocurred + */ + virtual bool get_offer_stars_given(const crypto::hash offer_id, uint64_t &stars_received) const = 0; + + /** + * @brief fetch safex tables sizes from the blockchain + * + * The subclass should return safex tables sizes + * + * @return True if no error ocurred + */ + virtual bool get_table_sizes( std::vector &table_sizes) const = 0; + + // + // Hard fork related storage + // + + /** + * @brief sets which hardfork version a height is on + * + * @param height the height + * @param version the version + */ + virtual void set_hard_fork_version(uint64_t height, uint8_t version) = 0; + + /** + * @brief checks which hardfork version a height is on + * + * @param height the height + * + * @return the version + */ + virtual uint8_t get_hard_fork_version(uint64_t height) const = 0; + + /** + * @brief verify hard fork info in database + */ + virtual void check_hard_fork_info() = 0; + + /** + * @brief delete hard fork info from database + */ + virtual void drop_hard_fork_info() = 0; + + /** + * @brief return a histogram of outputs on the blockchain + * + * @param amounts optional set of amounts to lookup + * @param unlocked whether to restrict count to unlocked outputs + * @param recent_cutoff timestamp to determine whether an output is recent + * @param output_type a utxo type (cash, token, ...) + * + * @return a set of amount/instances + */ + virtual std::map> get_output_histogram(const std::vector &amounts, bool unlocked, uint64_t recent_cutoff, const tx_out_type output_type) const = 0; + + /** + * @brief is BlockchainDB in read-only mode? + * + * @return true if in read-only mode, otherwise false + */ + virtual bool is_read_only() const = 0; + + // TODO: this should perhaps be (or call) a series of functions which + // progressively update through version updates + /** + * @brief fix up anything that may be wrong due to past bugs + */ + virtual void fixup(); + + /** + * @brief set whether or not to automatically remove logs + * + * This function is only relevant for one implementation (BlockchainBDB), but + * is here to keep BlockchainDB users implementation-agnostic. + * + * @param auto_remove whether or not to auto-remove logs + */ + void set_auto_remove_logs(bool auto_remove) + { m_auto_remove_logs = auto_remove; } + + bool m_open; //!< Whether or not the BlockchainDB is open/ready for use + mutable epee::critical_section m_synchronization_lock; //!< A lock, currently for when BlockchainLMDB needs to resize the backing db file + + cryptonote::network_type get_net_type() const { return m_nettype; }; + + }; // class BlockchainDB + + BlockchainDB *new_db(const std::string &db_type, cryptonote::network_type nettype); } // namespace cryptonote diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 5b1163c2b..741ec00c9 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -43,6 +43,9 @@ #include "profile_tools.h" #include "ringct/rctOps.h" +#include "safex/safex_core.h" +#include "safex/command.h" + #undef SAFEX_DEFAULT_LOG_CATEGORY #define SAFEX_DEFAULT_LOG_CATEGORY "blockchain.db.lmdb" @@ -71,6 +74,16 @@ struct pre_rct_output_data_t }; #pragma pack(pop) +#pragma pack(push, 1) + typedef struct sfx_acc_data_t + { + crypto::public_key pkey; + cryptonote::blobdata data; + + size_t size() const { return sizeof(pkey) + data.size();} + } sfx_acc_data_t; +#pragma pack(pop) + template inline void throw0(const T &e) { @@ -100,6 +113,31 @@ struct MDB_val_copy: public MDB_val T t_copy; }; +template +struct MDB_val_copy2 : public MDB_val +{ + MDB_val_copy2(const P1 &p1, const P2 &p2) : t_copy{} + { + t_copy = std::vector(std::begin(p1), std::end(p1)); + t_copy.insert(std::end(t_copy), std::begin(p2), std::end(p2)); + + mv_size = p1.size() + p2.size(); + mv_data = (void *) t_copy.data(); + } + + MDB_val_copy2(const P1 &p1, size_t p1_size, const P2 &p2) : t_copy{} + { + t_copy = std::vector(p1, p1 + p1_size); + t_copy.insert(std::end(t_copy), std::begin(p2), std::end(p2)); + + mv_size = p1_size + p2.size(); + mv_data = (void *) t_copy.data(); + } + +private: + std::vector t_copy; +}; + template<> struct MDB_val_copy: public MDB_val { @@ -114,6 +152,7 @@ struct MDB_val_copy: public MDB_val std::unique_ptr data; }; + template<> struct MDB_val_copy: public MDB_val { @@ -130,6 +169,62 @@ struct MDB_val_copy: public MDB_val std::unique_ptr data; }; + +template<> +struct MDB_val_copy: public MDB_val +{ + MDB_val_copy(const cryptonote::output_advanced_data_t &okadv) : + data(new char[okadv.size()]) + { + memcpy(data.get(), (void *)&okadv, 5*sizeof(uint64_t)); + memcpy(data.get()+5*sizeof(uint64_t), (void *)&okadv.pubkey, sizeof(okadv.pubkey)); + memcpy(data.get()+5*sizeof(uint64_t)+sizeof(okadv.pubkey), (void *)&okadv.data[0], okadv.data.size()); + mv_size = okadv.size(); + mv_data = data.get(); + } + private: + std::unique_ptr data; +}; + + +cryptonote::output_advanced_data_t parse_output_advanced_data_from_mdb(const MDB_val& val) { + cryptonote::output_advanced_data_t result = AUTO_VAL_INIT(result); + memcpy((void *)&result, val.mv_data, 5*sizeof(uint64_t)); + memcpy((void *)&result.pubkey, (char *)val.mv_data+5*sizeof(uint64_t), sizeof(result.pubkey)); + const size_t data_size = val.mv_size-5*sizeof(uint64_t)-sizeof(result.pubkey); + result.data.resize(data_size); + memcpy((void *)&result.data[0], (char *)val.mv_data+5*sizeof(uint64_t)+sizeof(result.pubkey), data_size); + return result; +} + +template<> //here we do not use sfx_acc_data_t to prevent double copying of blobdata func parameter +struct MDB_val_copy2: public MDB_val +{ + MDB_val_copy2(const crypto::public_key &pkey, const cryptonote::blobdata& accdata): + data(new char[sizeof(pkey) + accdata.size()]) + { + memcpy(data.get(), (void *)&pkey, sizeof(pkey)); + memcpy(data.get()+sizeof(pkey), (void *)&accdata[0], accdata.size()); + mv_size = sizeof(pkey)+ accdata.size(); + mv_data = data.get(); + } + private: + std::unique_ptr data; +}; + + +#if 0 //currently not used so disabled to pass build +static sfx_acc_data_t parse_sfx_acc_data_from_mdb(const MDB_val &val) +{ + sfx_acc_data_t result = AUTO_VAL_INIT(result); + memcpy((void *) &result, val.mv_data, sizeof(result.pkey)); + const size_t data_size = val.mv_size - sizeof(result.pkey); + result.data.resize(data_size); + memcpy((void *) &result.data[0], (char *) val.mv_data + sizeof(result.pkey), data_size); + return result; +} +#endif + int compare_uint64(const MDB_val *a, const MDB_val *b) { const uint64_t va = *(const uint64_t *)a->mv_data; @@ -160,23 +255,32 @@ int compare_string(const MDB_val *a, const MDB_val *b) /* DB schema: * - * Table Key Data - * ----- --- ---- - * blocks block ID block blob - * block_heights block hash block height - * block_info block ID {block metadata} + * Table Key Data + * ----- --- ---- + * blocks block ID block blob + * block_heights block hash block height + * block_info block ID {block metadata} + * + * txs txn ID txn blob + * tx_indices txn hash {txn ID, metadata} + * tx_outputs txn ID [txn amount output indices] * - * txs txn ID txn blob - * tx_indices txn hash {txn ID, metadata} - * tx_outputs txn ID [txn amount output indices] + * output_txs output ID {txn hash, local index} + * output_amounts amount [{amount output index, metadata}...] + * output_token_amounts token_amount [{token amount output index, metadata}...] * - * output_txs output ID {txn hash, local index} - * output_amounts amount [{amount output index, metadata}...] + * spent_keys input hash - * - * spent_keys input hash - + * txpool_meta txn hash txn metadata + * txpool_blob txn hash txn blob * - * txpool_meta txn hash txn metadata - * txpool_blob txn hash txn blob + * output_advanced output ID {output type specific data}... + * output_advanced_type output type {Output Id of outputs from `output_advanced` table}... + * token_staked_sum interval token sum + * token_staked_sum_total 0 total_token sum + * network_fee_sum interval collected fee sum + * token_lock_expiry block_number {list of loked outputs that expiry on this block number} + * safex_account username hash {public_key, description data blob} * * Note: where the data items are of uniform size, DUPFIXED tables have * been used to save space. In most of these cases, a dummy "zerokval" @@ -184,7 +288,8 @@ int compare_string(const MDB_val *a, const MDB_val *b) * attached as a prefix on the Data to serve as the DUPSORT key. * (DUPFIXED saves 8 bytes per record.) * - * The output_amounts table doesn't use a dummy key, but uses DUPSORT. + * The output_amounts, output_token_amounts, output_advanced_type, token_lock_expiry tables + * doesn't use a dummy key, but use DUPSORT. */ const char* const LMDB_BLOCKS = "blocks"; const char* const LMDB_BLOCK_HEIGHTS = "block_heights"; @@ -205,6 +310,18 @@ const char* const LMDB_TXPOOL_BLOB = "txpool_blob"; const char* const LMDB_HF_STARTING_HEIGHTS = "hf_starting_heights"; const char* const LMDB_HF_VERSIONS = "hf_versions"; + +const char* const LMDB_OUTPUT_ADVANCED = "output_advanced"; +const char* const LMDB_OUTPUT_ADVANCED_TYPE = "output_advanced_type"; +const char* const LMDB_TOKEN_STAKED_SUM = "token_staked_sum"; +const char* const LMDB_TOKEN_STAKED_SUM_TOTAL = "token_staked_sum_total"; +const char* const LMDB_NETWORK_FEE_SUM = "network_fee_sum"; +const char* const LMDB_TOKEN_LOCK_EXPIRY = "token_lock_expiry"; +const char* const LMDB_SAFEX_ACCOUNT = "safex_account"; +const char* const LMDB_SAFEX_OFFER = "safex_offer"; +const char* const LMDB_SAFEX_FEEDBACK = "output_safex_feedback"; +const char* const LMDB_SAFEX_PRICE_PEG = "safex_price_peg"; + const char* const LMDB_PROPERTIES = "properties"; const char zerokey[8] = {0}; @@ -288,6 +405,13 @@ typedef struct outtx { uint64_t local_index; } outtx; +typedef struct outkey_advanced { + uint64_t type_index; + uint64_t output_id; +} outkey_advanced; + + + std::atomic mdb_txn_safe::num_active_txns{0}; std::atomic_flag mdb_txn_safe::creation_gate = ATOMIC_FLAG_INIT; @@ -813,6 +937,7 @@ uint64_t BlockchainLMDB::add_transaction_data(const crypto::hash& blk_hash, cons return tx_id; } + // TODO: compare pros and cons of looking up the tx hash's tx index once and // passing it in to functions like this void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) @@ -859,6 +984,301 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const throw1(DB_ERROR("Failed to add removal of tx index to db transaction")); } +void BlockchainLMDB::remove_unstake_token(const crypto::hash& tx_hash, const transaction& tx) +{ + + for (const txin_v& tx_input : tx.vin) + { + if (tx_input.type() == typeid(txin_to_script)) + { + auto input = boost::get(tx_input); + if(input.command_type == safex::command_t::token_unstake) + update_current_staked_token_sum(input.token_amount, +1); + } + } + + +// int result; + +// LOG_PRINT_L3("BlockchainLMDB::" << __func__); +// check_open(); + +// mdb_txn_cursors *m_cursors = &m_wcursors; +// CURSOR(tx_indices) +// CURSOR(txs) +// CURSOR(tx_outputs) + +// MDB_val_set(val_h, tx_hash); + +// if (mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH)) +// throw1(TX_DNE("Attempting to remove transaction that isn't in the db")); +// txindex *tip = (txindex *)val_h.mv_data; +// MDB_val_set(val_tx_id, tip->data.tx_id); + +// if ((result = mdb_cursor_get(m_cur_txs, &val_tx_id, NULL, MDB_SET))) +// throw1(DB_ERROR(lmdb_error("Failed to locate tx for removal: ", result).c_str())); +// result = mdb_cursor_del(m_cur_txs, 0); +// if (result) +// throw1(DB_ERROR(lmdb_error("Failed to add removal of tx to db transaction: ", result).c_str())); + +// remove_tx_outputs(tip->data.tx_id, tx); + +// result = mdb_cursor_get(m_cur_tx_outputs, &val_tx_id, NULL, MDB_SET); +// if (result == MDB_NOTFOUND) +// LOG_PRINT_L1("tx has no outputs to remove: " << tx_hash); +// else if (result) +// throw1(DB_ERROR(lmdb_error("Failed to locate tx outputs for removal: ", result).c_str())); +// if (!result) +// { +// result = mdb_cursor_del(m_cur_tx_outputs, 0); +// if (result) +// throw1(DB_ERROR(lmdb_error("Failed to add removal of tx outputs to db transaction: ", result).c_str())); +// } + +// // Don't delete the tx_indices entry until the end, after we're done with val_tx_id +// if (mdb_cursor_del(m_cur_tx_indices, 0)) +// throw1(DB_ERROR("Failed to add removal of tx index to db transaction")); +} + +uint64_t BlockchainLMDB::add_token_output(const tx_out& tx_output, const uint64_t unlock_time, const uint64_t total_output_number) +{ + + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + MDB_cursor *cur_token_output_amount; + uint64_t blockchain_height = height(); + int result = 0; + uint64_t out_token_amount = 0; + + CURSOR(output_token_amounts); + out_token_amount = tx_output.token_amount; + cur_token_output_amount = m_cur_output_token_amounts; + + outkey ok = AUTO_VAL_INIT(ok); + MDB_val data; + MDB_val_copy token_amount(out_token_amount); + result = mdb_cursor_get(cur_token_output_amount, &token_amount, &data, MDB_SET); + if (!result) + { + mdb_size_t num_elems = 0; + result = mdb_cursor_count(cur_token_output_amount, &num_elems); + if (result) + throw0(DB_ERROR(std::string("Failed to get number of outputs for amount: ").append(mdb_strerror(result)).c_str())); + ok.amount_index = num_elems; + } + else if (result != MDB_NOTFOUND) + throw0(DB_ERROR(lmdb_error("Failed to get output token amount in db transaction: ", result).c_str())); + else + ok.amount_index = 0; + + ok.output_id = total_output_number; + ok.data.pubkey = *boost::apply_visitor(destination_public_key_visitor(), tx_output.target); + ok.data.unlock_time = unlock_time; + ok.data.height = blockchain_height; + data.mv_size = sizeof(pre_rct_outkey); + data.mv_data = &ok; + + if ((result = mdb_cursor_put(cur_token_output_amount, &token_amount, &data, MDB_APPENDDUP))) + throw0(DB_ERROR(lmdb_error("Failed to add token output amount: ", result).c_str())); + + return ok.amount_index; +} + +uint64_t BlockchainLMDB::add_cash_output(const tx_out& tx_output, const uint64_t unlock_time, const uint64_t total_output_number) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + uint64_t blockchain_height = height(); + MDB_cursor *cur_cash_output_amount; + int result = 0; + uint64_t out_cash_amount = 0; + + CURSOR(output_amounts); + out_cash_amount = tx_output.amount; + cur_cash_output_amount = m_cur_output_amounts; + + outkey ok = AUTO_VAL_INIT(ok); + MDB_val data; + MDB_val_copy cash_amount(out_cash_amount); + result = mdb_cursor_get(cur_cash_output_amount, &cash_amount, &data, MDB_SET); + if (!result) + { + mdb_size_t num_elems = 0; + result = mdb_cursor_count(cur_cash_output_amount, &num_elems); + if (result) + throw0(DB_ERROR(std::string("Failed to get number of outputs for amount: ").append(mdb_strerror(result)).c_str())); + ok.amount_index = num_elems; + } + else if (result != MDB_NOTFOUND) + throw0(DB_ERROR(lmdb_error("Failed to get output amount in db transaction: ", result).c_str())); + else + ok.amount_index = 0; + + ok.output_id = total_output_number; + ok.data.pubkey = *boost::apply_visitor(destination_public_key_visitor(), tx_output.target); + ok.data.unlock_time = unlock_time; + ok.data.height = blockchain_height; + data.mv_size = sizeof(pre_rct_outkey); + data.mv_data = &ok; + + if ((result = mdb_cursor_put(cur_cash_output_amount, &cash_amount, &data, MDB_APPENDDUP))) + throw0(DB_ERROR(lmdb_error("Failed to add cash output amount: ", result).c_str())); + + return ok.amount_index; +} + + + +void BlockchainLMDB::process_advanced_output(const tx_out& tx_output, const uint64_t output_id, const uint8_t output_type) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + uint64_t m_height = height(); + + const cryptonote::tx_out_type output_type_c = static_cast(output_type); + + if (output_type_c == cryptonote::tx_out_type::out_staked_token) + { + + uint64_t interval = safex::calculate_interval_for_height(m_height, m_nettype); // interval for currently processed output + update_current_staked_token_sum(tx_output.token_amount, +1); + + //Add token lock expiry values + //SAFEX_DEFAULT_TOKEN_STAKE_EXPIRY_PERIOD + MDB_cursor *cur_token_lock_expiry; + CURSOR(token_lock_expiry); + cur_token_lock_expiry = m_cur_token_lock_expiry; + const uint64_t expiry_block = m_height + SAFEX_DEFAULT_TOKEN_STAKE_EXPIRY_PERIOD; + + MDB_val data; + MDB_val_copy block_number(expiry_block); + auto result = mdb_cursor_get(cur_token_lock_expiry, &block_number, &data, MDB_SET); + if (result != MDB_SUCCESS && result != MDB_NOTFOUND) + throw0(DB_ERROR(lmdb_error("Failed to get data for staked token output expiry: ", result).c_str())); + + data.mv_size = sizeof(uint64_t); + data.mv_data = (void*)(&output_id); + if ((result = mdb_cursor_put(cur_token_lock_expiry, &block_number, &data, MDB_APPENDDUP))) + throw0(DB_ERROR(lmdb_error("Failed to add staked token output expiry entry: ", result).c_str())); + + LOG_PRINT_L2("Updated db lock expiry data, to block height: " << expiry_block << " added output: " << output_id); + } + else if (output_type_c == cryptonote::tx_out_type::out_network_fee) + { + uint64_t interval = safex::calculate_interval_for_height(m_height, m_nettype); + update_network_fee_sum_for_interval(interval, tx_output.amount); + } + else if (output_type_c == cryptonote::tx_out_type::out_safex_offer || output_type_c == cryptonote::tx_out_type::out_safex_offer_update){ + //Add TX output_id to the safex_offer table + MDB_cursor *cur_safex_offer; + CURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; + + crypto::hash offer_id; + + if (tx_output.target.type() == typeid(txout_to_script) && get_tx_out_type(tx_output.target) == cryptonote::tx_out_type::out_safex_offer){ + const txout_to_script &out = boost::get(tx_output.target); + safex::create_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + offer_id = offer.offer_id; + } + + if (tx_output.target.type() == typeid(txout_to_script) && get_tx_out_type(tx_output.target) == cryptonote::tx_out_type::out_safex_offer_update){ + const txout_to_script &out = boost::get(tx_output.target); + safex::edit_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + offer_id = offer.offer_id; + } + + MDB_val_set(val_offer_id, offer_id); + MDB_val val_data; + auto result = mdb_cursor_get(cur_safex_offer, (MDB_val *)&val_offer_id, (MDB_val*)&val_data, MDB_SET); + if(result) + LOG_PRINT_L0(result); + + safex::create_offer_result offer; + std::string tmp{(char*)val_data.mv_data, val_data.mv_size}; + parse_and_validate_object_from_blob(tmp,offer); + + offer.output_id = output_id; + if(tx_output.target.type() == typeid(txout_to_script) && get_tx_out_type(tx_output.target) == cryptonote::tx_out_type::out_safex_offer) + offer.output_id_creation = output_id; + + blobdata blob{}; + t_serializable_object_to_blob(offer,blob); + MDB_val_copy offer_info(blob); + + result = mdb_cursor_put(cur_safex_offer, (MDB_val *)&val_offer_id, &offer_info, (unsigned int) MDB_CURRENT); + + if (result != MDB_SUCCESS) + throw0(DB_ERROR(lmdb_error("Failed to add output id to refer safex offer entry: ", result).c_str())); + } +} + + +uint64_t BlockchainLMDB::add_advanced_output(const tx_out& tx_output, const uint64_t unlock_time, const uint64_t output_id, const tx_out_type out_type) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + MDB_cursor *cur_output_advanced; + MDB_cursor *cur_output_advanced_type; + uint64_t blockchain_height = height(); + int result = 0; + + //put advanced output blob to the output_advanced table, then update output_advanced_type table with id of new output + + CURSOR(output_advanced); + CURSOR(output_advanced_type); + cur_output_advanced = m_cur_output_advanced; + cur_output_advanced_type = m_cur_output_advanced_type; + + MDB_val_set(val_output_id, output_id); + + + + const txout_to_script& txout = boost::get(tx_output.target); + + output_advanced_data_t okadv = AUTO_VAL_INIT(okadv); + okadv.type_index = get_num_outputs(out_type); + okadv.output_type = static_cast(out_type); + okadv.height = blockchain_height; + okadv.unlock_time = unlock_time; + okadv.output_id = output_id; + okadv.pubkey = txout.key; //todo if there are multiple keys, rest will go to data + + if(out_type == tx_out_type::out_staked_token) + okadv.data = std::to_string(tx_output.token_amount); + else + okadv.data = blobdata(txout.data.begin(),txout.data.end()); //no need to serialize vector to blob. Just copy it. + + MDB_val_copy adv_value(okadv); + + result = mdb_cursor_put(cur_output_advanced, &val_output_id, &adv_value, MDB_APPEND); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to add advanced output to database: ", result).c_str())); + + + //cache output id per type + const uint64_t output_type = boost::get(tx_output.target).output_type; + MDB_val_set(k_output_type, output_type); + outkey_advanced outkey_adv{okadv.type_index, okadv.output_id}; + MDB_val_set(value, outkey_adv); + if ((result = mdb_cursor_put(cur_output_advanced_type, &k_output_type, &value, MDB_APPENDDUP))) + throw0(DB_ERROR(lmdb_error("Failed to add advanced output index: ", result).c_str())); + + process_advanced_output(tx_output, okadv.type_index, output_type); + + + return okadv.type_index; +} + + uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, @@ -868,40 +1288,14 @@ uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash, LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); mdb_txn_cursors *m_cursors = &m_wcursors; - uint64_t m_height = height(); uint64_t m_num_outputs = num_outputs(); - MDB_cursor *cur_output_amount; int result = 0; if (!is_valid_transaction_output_type(tx_output.target)) - throw0(DB_ERROR("Wrong output type: expected txout_to_key or txout_token_to_key")); - - const tx_out_type output_type = get_tx_out_type(tx_output.target); - uint64_t out_value_amount = 0; + throw0(DB_ERROR("Wrong output type: expected txout_to_key, txout_token_to_key or txout_to_script")); CURSOR(output_txs) - - switch (output_type) - { - case tx_out_type::out_cash: - CURSOR(output_amounts); - out_value_amount = tx_output.amount; - cur_output_amount = m_cur_output_amounts; - break; - case tx_out_type::out_token: - CURSOR(output_token_amounts); - out_value_amount = tx_output.token_amount; - cur_output_amount = m_cur_output_token_amounts; - break; - default: - throw0(DB_ERROR("Unknown utxo output type")); - break; - } - - if (out_value_amount == 0 && !commitment) - throw0(DB_ERROR("RCT output without commitment")); - outtx ot = {m_num_outputs, tx_hash, local_index}; MDB_val_set(vot, ot); @@ -909,41 +1303,27 @@ uint64_t BlockchainLMDB::add_output(const crypto::hash& tx_hash, if (result) throw0(DB_ERROR(lmdb_error("Failed to add output tx hash to db transaction: ", result).c_str())); - outkey ok; - MDB_val data; - MDB_val_copy val_amount(out_value_amount); - result = mdb_cursor_get(cur_output_amount, &val_amount, &data, MDB_SET); - if (!result) - { - mdb_size_t num_elems = 0; - result = mdb_cursor_count(cur_output_amount, &num_elems); - if (result) - throw0(DB_ERROR(std::string("Failed to get number of outputs for amount: ").append(mdb_strerror(result)).c_str())); - ok.amount_index = num_elems; - } - else if (result != MDB_NOTFOUND) - throw0(DB_ERROR(lmdb_error("Failed to get output amount in db transaction: ", result).c_str())); - else - ok.amount_index = 0; - ok.output_id = m_num_outputs; - ok.data.pubkey = *boost::apply_visitor(destination_public_key_visitor(), tx_output.target); - ok.data.unlock_time = unlock_time; - ok.data.height = m_height; - if (out_value_amount == 0) + + const tx_out_type output_type = get_tx_out_type(tx_output.target); + if (output_type == tx_out_type::out_cash) { - ok.data.commitment = *commitment; - data.mv_size = sizeof(ok); + return add_cash_output(tx_output, unlock_time, m_num_outputs); + } + else if (output_type == tx_out_type::out_token) + { + return add_token_output(tx_output, unlock_time, m_num_outputs); + } + else if (output_type >= tx_out_type::out_advanced && output_type < tx_out_type::out_invalid) + { + return add_advanced_output(tx_output, unlock_time, m_num_outputs, output_type); } else { - data.mv_size = sizeof(pre_rct_outkey); + throw0(DB_ERROR("Unknown utxo output type")); } - data.mv_data = &ok; - if ((result = mdb_cursor_put(cur_output_amount, &val_amount, &data, MDB_APPENDDUP))) - throw0(DB_ERROR(lmdb_error("Failed to add output pubkey to db transaction: ", result).c_str())); + return 0; - return ok.amount_index; } void BlockchainLMDB::add_tx_amount_output_indices(const uint64_t tx_id, @@ -983,21 +1363,122 @@ void BlockchainLMDB::remove_tx_outputs(const uint64_t tx_id, const transaction& throw0(DB_ERROR("tx has outputs, but no output indices found")); } - //bool is_pseudo_rct = tx.version >= 2 && tx.vin.size() == 1 && tx.vin[0].type() == typeid(txin_gen); for (size_t i = tx.vout.size(); i-- > 0;) { const tx_out_type output_type = get_tx_out_type(tx.vout[i].target); - const uint64_t out_amount = (output_type == tx_out_type::out_token) ? tx.vout[i].token_amount : tx.vout[i].amount; - remove_output(out_amount, amount_output_indices[i], output_type); + + if (output_type == tx_out_type::out_token) { + remove_output(tx.vout[i].token_amount, amount_output_indices[i], output_type); + } + else if (output_type == tx_out_type::out_cash) { + remove_output(tx.vout[i].amount, amount_output_indices[i], output_type); + } + else if (output_type == tx_out_type::out_safex_account) { + const txout_to_script& txout_to_script1 = boost::get(tx.vout[i].target); + const cryptonote::blobdata blobdata1(begin(txout_to_script1.data), end(txout_to_script1.data)); + safex::create_account_data account_output_data; + parse_and_validate_object_from_blob(blobdata1, account_output_data); + remove_safex_account(account_output_data.username, amount_output_indices[i]); + } else if (output_type == tx_out_type::out_safex_account_update) { + const txout_to_script& txout_to_script1 = boost::get(tx.vout[i].target); + const cryptonote::blobdata blobdata1(begin(txout_to_script1.data), end(txout_to_script1.data)); + safex::edit_account_data account_output_data; + parse_and_validate_object_from_blob(blobdata1, account_output_data); + remove_safex_account_update(account_output_data.username, amount_output_indices[i]); + } else if (output_type == tx_out_type::out_safex_offer) { + const txout_to_script& txout_to_script1 = boost::get(tx.vout[i].target); + const cryptonote::blobdata blobdata1(begin(txout_to_script1.data), end(txout_to_script1.data)); + safex::create_offer_data offer_output_data; + parse_and_validate_object_from_blob(blobdata1, offer_output_data); + remove_safex_offer(offer_output_data.offer_id, amount_output_indices[i]); + } else if(output_type == tx_out_type::out_safex_offer_update) { + const txout_to_script& txout_to_script1 = boost::get(tx.vout[i].target); + const cryptonote::blobdata blobdata1(begin(txout_to_script1.data), end(txout_to_script1.data)); + safex::edit_offer_data offer_output_data; + parse_and_validate_object_from_blob(blobdata1, offer_output_data); + remove_safex_offer_update(offer_output_data.offer_id, amount_output_indices[i]); + } else if(output_type == tx_out_type::out_staked_token){ + remove_staked_token(tx.vout[i].token_amount, amount_output_indices[i]); + } else if(output_type == tx_out_type::out_safex_purchase){ + const txout_to_script& txout_to_script1 = boost::get(tx.vout[i].target); + const cryptonote::blobdata blobdata1(begin(txout_to_script1.data), end(txout_to_script1.data)); + safex::create_purchase_data purchase_output_data; + parse_and_validate_object_from_blob(blobdata1, purchase_output_data); + remove_safex_purchase(purchase_output_data.offer_id,purchase_output_data.quantity, amount_output_indices[i]); + } else if(output_type == tx_out_type::out_network_fee){ + remove_network_fee_output(tx.vout[i].amount, amount_output_indices[i]); + } else if (output_type == tx_out_type::out_safex_feedback_token){ + remove_advanced_output(output_type, amount_output_indices[i]); + } else if (output_type == tx_out_type::out_safex_feedback) { + const txout_to_script& txout_to_script1 = boost::get(tx.vout[i].target); + const cryptonote::blobdata blobdata1(begin(txout_to_script1.data), end(txout_to_script1.data)); + safex::create_feedback_data feedback_output_data; + parse_and_validate_object_from_blob(blobdata1, feedback_output_data); + remove_safex_feedback(feedback_output_data.offer_id, feedback_output_data, amount_output_indices[i]); + } else if (output_type == tx_out_type::out_safex_price_peg) { + const txout_to_script& txout_to_script1 = boost::get(tx.vout[i].target); + const cryptonote::blobdata blobdata1(begin(txout_to_script1.data), end(txout_to_script1.data)); + safex::create_price_peg_data price_peg_output_data; + parse_and_validate_object_from_blob(blobdata1, price_peg_output_data); + remove_safex_price_peg(price_peg_output_data.price_peg_id, amount_output_indices[i]); + } else if(output_type == tx_out_type::out_safex_price_peg_update) { + const txout_to_script& txout_to_script1 = boost::get(tx.vout[i].target); + const cryptonote::blobdata blobdata1(begin(txout_to_script1.data), end(txout_to_script1.data)); + safex::update_price_peg_data price_peg_output_data; + parse_and_validate_object_from_blob(blobdata1, price_peg_output_data); + remove_safex_price_peg_update(price_peg_output_data.price_peg_id, amount_output_indices[i]); + } + else { + throw0(DB_ERROR((std::string("output type removal unsuported, tx_out_type:")+std::to_string(static_cast(output_type))).c_str())); + } + } } +void BlockchainLMDB::remove_staked_token(const uint64_t token_amount, const uint64_t& output_id){ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + update_current_staked_token_sum(token_amount, -1); + + MDB_cursor *cur_token_lock_expiry; + CURSOR(token_lock_expiry); + cur_token_lock_expiry = m_cur_token_lock_expiry; + + MDB_val data; + MDB_val block_number; + auto result = mdb_cursor_get(cur_token_lock_expiry, &block_number, &data, MDB_LAST); + if (result != MDB_SUCCESS) + throw0(DB_ERROR(lmdb_error("Failed to get data for staked token output expiry: ", result).c_str())); + + uint64_t mdb_output_id; + + memcpy(&mdb_output_id, data.mv_data,sizeof(uint64_t)); + + while(mdb_output_id != output_id && result==MDB_SUCCESS){ + + result = mdb_cursor_get(cur_token_lock_expiry, &block_number, &data, MDB_PREV); + + if(result!=MDB_SUCCESS) + throw0(DB_ERROR(lmdb_error("Failed to get data for staked token output expiry: ", result).c_str())); + + memcpy(&mdb_output_id, data.mv_data,sizeof(uint64_t)); + + } + + remove_advanced_output(cryptonote::tx_out_type::out_staked_token, output_id); + + if ((result = mdb_cursor_del(cur_token_lock_expiry, 0))) + throw0(DB_ERROR(lmdb_error("Failed to remove staked token output expiry entry: ", result).c_str())); +} + void BlockchainLMDB::remove_output(const uint64_t amount, const uint64_t& out_index, tx_out_type output_type) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); mdb_txn_cursors *m_cursors = &m_wcursors; - MDB_cursor *cur_output_amount; + MDB_cursor *cur_output_amount = nullptr; switch (output_type) { @@ -1084,31 +1565,186 @@ void BlockchainLMDB::remove_spent_key(const crypto::key_image& k_image) } } -blobdata BlockchainLMDB::output_to_blob(const tx_out& output) const -{ - LOG_PRINT_L3("BlockchainLMDB::" << __func__); - blobdata b; - if (!t_serializable_object_to_blob(output, b)) - throw1(DB_ERROR("Error serializing output to blob")); - return b; -} - -tx_out BlockchainLMDB::output_from_blob(const blobdata& blob) const -{ +void BlockchainLMDB::process_command_input(const cryptonote::txin_to_script &txin) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); - std::stringstream ss; - ss << blob; - binary_archive ba(ss); - tx_out o; + check_open(); + const uint64_t current_height = height(); - if (!(::serialization::serialize(ba, o))) - throw1(DB_ERROR("Error deserializing tx output blob")); + if (txin.command_type == safex::command_t::token_stake) + { + //staked token sum is updated when processing outputs + } + else if (txin.command_type == safex::command_t::token_unstake) + { + update_current_staked_token_sum(txin.token_amount, -1); - return o; -} + //this latest unstaked tokens will not receive fee for this interval + //lower the staked tokens amount written in table at the end of previous interval + const uint64_t previous_interval = safex::calculate_interval_for_height(current_height, m_nettype)-1; + const uint64_t previous_interval_end_sum = get_staked_token_sum_for_interval(previous_interval+1); + if (previous_interval_end_sum - txin.token_amount > previous_interval_end_sum) //check for overflow + throw1(DB_ERROR("Negative amount of staked tokens")); + update_staked_token_for_interval(previous_interval, previous_interval_end_sum - txin.token_amount); -void BlockchainLMDB::check_open() const -{ + } + else if (txin.command_type == safex::command_t::donate_network_fee) + { + //network_fee_sum is updated at place of output processing + } + else if (txin.command_type == safex::command_t::create_account) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_object(txin.script, txin.command_type); + std::unique_ptr result(dynamic_cast(cmd->execute(*this, txin))); + if (result->status != safex::execution_status::ok) + { + LOG_ERROR("Execution of create account command failed, status:" << static_cast(result->status)); + throw1(DB_ERROR("Error executing add safex account command")); + } + + blobdata blob{}; + t_serializable_object_to_blob(*result,blob); + + add_safex_account(safex::account_username{result->username}, blob); + + } + else if (txin.command_type == safex::command_t::edit_account) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_object(txin.script, txin.command_type); + std::unique_ptr result(dynamic_cast(cmd->execute(*this, txin))); + if (result->status != safex::execution_status::ok) + { + LOG_ERROR("Execution of edit account command failed, status:" << static_cast(result->status)); + throw1(DB_ERROR("Error executing add safex account command")); + } + + blobdata blob{}; + t_serializable_object_to_blob(*result,blob); + + edit_safex_account(safex::account_username{result->username}, result->account_data); + + } + else if (txin.command_type == safex::command_t::create_offer) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_object(txin.script, txin.command_type); + std::unique_ptr result(dynamic_cast(cmd->execute(*this, txin))); + if (result->status != safex::execution_status::ok) + { + LOG_ERROR("Execution of add safex offer command failed, status:" << static_cast(result->status)); + throw1(DB_ERROR("Error executing add safex offer command")); + } + blobdata blob{}; + t_serializable_object_to_blob(*result,blob); + add_safex_offer(result->offer_id, blob); + + } + else if (txin.command_type == safex::command_t::edit_offer) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_object(txin.script, txin.command_type); + std::unique_ptr result(dynamic_cast(cmd->execute(*this, txin))); + if (result->status != safex::execution_status::ok) + { + LOG_ERROR("Execution of edit safex offer command failed, status:" << static_cast(result->status)); + throw1(DB_ERROR("Error executing edit safex offer command")); + } + blobdata blob{}; + t_serializable_object_to_blob(*result,blob); + edit_safex_offer(result->offer_id, result->active, result->price, result->quantity); + + } + else if (txin.command_type == safex::command_t::simple_purchase) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_object(txin.script, txin.command_type); + std::unique_ptr result(dynamic_cast(cmd->execute(*this, txin))); + if (result->status != safex::execution_status::ok) + { + LOG_ERROR("Execution of safex purchase command failed, status:" << static_cast(result->status)); + throw1(DB_ERROR("Error executing safex purchase command")); + } + + safex::safex_purchase sfx_purchase{result->quantity, result->price, result->offer_id, result->offer_hash, result->shipping}; + create_safex_purchase(sfx_purchase); + + } + else if (txin.command_type == safex::command_t::create_feedback) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_object(txin.script, txin.command_type); + std::unique_ptr result(dynamic_cast(cmd->execute(*this, txin))); + if (result->status != safex::execution_status::ok) + { + LOG_ERROR("Execution of safex purchase command failed, status:" << static_cast(result->status)); + throw1(DB_ERROR("Error executing safex purchase command")); + } + + std::string comment{result->comment.begin(),result->comment.end()}; + safex::safex_feedback sfx_feedback{result->stars_given, comment, result->offer_id}; + create_safex_feedback(sfx_feedback); + + } + else if (txin.command_type == safex::command_t::create_price_peg) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_object(txin.script, txin.command_type); + std::unique_ptr result(dynamic_cast(cmd->execute(*this, txin))); + if (result->status != safex::execution_status::ok) + { + LOG_ERROR("Execution of add safex price peg command failed, status:" << static_cast(result->status)); + throw1(DB_ERROR("Error executing add safex peg command")); + } + blobdata blob{}; + t_serializable_object_to_blob(*result,blob); + add_safex_price_peg(result->price_peg_id, blob); + + } + else if (txin.command_type == safex::command_t::update_price_peg) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_object(txin.script, txin.command_type); + std::unique_ptr result(dynamic_cast(cmd->execute(*this, txin))); + if (result->status != safex::execution_status::ok) + { + LOG_ERROR("Execution of update safex price peg command failed, status:" << static_cast(result->status)); + throw1(DB_ERROR("Error executing update safex peg command")); + } + update_safex_price_peg(result->price_peg_id, *result); + + } + else { + throw1(DB_ERROR("Unknown safex command type")); + } + +} + +blobdata BlockchainLMDB::output_to_blob(const tx_out& output) const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + blobdata b; + if (!t_serializable_object_to_blob(output, b)) + throw1(DB_ERROR("Error serializing output to blob")); + return b; +} + +tx_out BlockchainLMDB::output_from_blob(const blobdata& blob) const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + std::stringstream ss; + ss << blob; + binary_archive ba(ss); + tx_out o; + + if (!(::serialization::serialize(ba, o))) + throw1(DB_ERROR("Error deserializing tx output blob")); + + return o; +} + +void BlockchainLMDB::check_open() const +{ // LOG_PRINT_L3("BlockchainLMDB::" << __func__); if (!m_open) throw0(DB_ERROR("DB operation attempted on a not-open DB instance")); @@ -1125,7 +1761,7 @@ BlockchainLMDB::~BlockchainLMDB() close(); } -BlockchainLMDB::BlockchainLMDB(bool batch_transactions): BlockchainDB() +BlockchainLMDB::BlockchainLMDB(bool batch_transactions, cryptonote::network_type nettype): BlockchainDB(nettype) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); // initialize folder to something "safe" just in case @@ -1185,7 +1821,7 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) // set up lmdb environment if ((result = mdb_env_create(&m_env))) throw0(DB_ERROR(lmdb_error("Failed to create lmdb environment: ", result).c_str())); - if ((result = mdb_env_set_maxdbs(m_env, 20))) + if ((result = mdb_env_set_maxdbs(m_env, 25))) throw0(DB_ERROR(lmdb_error("Failed to set max number of dbs: ", result).c_str())); int threads = tools::get_max_concurrency(); @@ -1263,6 +1899,18 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) lmdb_db_open(txn, LMDB_HF_VERSIONS, MDB_INTEGERKEY | MDB_CREATE, m_hf_versions, "Failed to open db handle for m_hf_versions"); + //safex related + lmdb_db_open(txn, LMDB_OUTPUT_ADVANCED, MDB_INTEGERKEY | MDB_CREATE, m_output_advanced, "Failed to open db handle for m_output_advanced"); + lmdb_db_open(txn, LMDB_OUTPUT_ADVANCED_TYPE, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED , m_output_advanced_type, "Failed to open db handle for m_output_advanced_type"); + lmdb_db_open(txn, LMDB_TOKEN_STAKED_SUM, MDB_INTEGERKEY | MDB_CREATE, m_token_staked_sum, "Failed to open db handle for m_token_staked_sum"); //use zero key + lmdb_db_open(txn, LMDB_TOKEN_STAKED_SUM_TOTAL, MDB_INTEGERKEY | MDB_CREATE, m_token_staked_sum_total, "Failed to open db handle for m_token_staked_sum_total"); + lmdb_db_open(txn, LMDB_NETWORK_FEE_SUM, MDB_INTEGERKEY | MDB_CREATE, m_network_fee_sum, "Failed to open db handle for m_network_fee_sum");//use zero key + lmdb_db_open(txn, LMDB_TOKEN_LOCK_EXPIRY, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_token_lock_expiry, "Failed to open db handle for m_token_lock_expiry"); + lmdb_db_open(txn, LMDB_SAFEX_ACCOUNT, MDB_CREATE, m_safex_account, "Failed to open db handle for m_safex_account"); + lmdb_db_open(txn, LMDB_SAFEX_OFFER, MDB_CREATE, m_safex_offer, "Failed to open db handle for m_safex_offer"); + lmdb_db_open(txn, LMDB_SAFEX_FEEDBACK, MDB_CREATE | MDB_DUPSORT, m_safex_feedback, "Failed to open db handle for m_safex_feedback"); + lmdb_db_open(txn, LMDB_SAFEX_PRICE_PEG, MDB_CREATE, m_safex_price_peg, "Failed to open db handle for m_safex_price_peg"); + lmdb_db_open(txn, LMDB_PROPERTIES, MDB_CREATE, m_properties, "Failed to open db handle for m_properties"); mdb_set_dupsort(txn, m_spent_keys, compare_hash32); @@ -1272,10 +1920,18 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) mdb_set_dupsort(txn, m_output_token_amounts, compare_uint64); mdb_set_dupsort(txn, m_output_txs, compare_uint64); mdb_set_dupsort(txn, m_block_info, compare_uint64); + mdb_set_dupsort(txn, m_output_advanced_type, compare_uint64); + mdb_set_dupsort(txn, m_token_lock_expiry, compare_uint64); + mdb_set_dupsort(txn, m_safex_feedback, compare_uint64); + mdb_set_compare(txn, m_txpool_meta, compare_hash32); mdb_set_compare(txn, m_txpool_blob, compare_hash32); - mdb_set_compare(txn, m_properties, compare_string); + mdb_set_compare(txn, m_safex_account, compare_hash32); + mdb_set_compare(txn, m_safex_offer, compare_hash32); + mdb_set_compare(txn, m_safex_price_peg, compare_hash32); + + mdb_set_compare(txn, m_properties, compare_string); if (!(mdb_flags & MDB_RDONLY)) { @@ -1306,9 +1962,6 @@ void BlockchainLMDB::open(const std::string& filename, const int db_flags) #if VERSION > 0 else if (*(const uint32_t*)v.mv_data < VERSION) { - // Note that there was a schema change within version 0 as well. - // See commit e5d2680094ee15889934fe28901e4e133cda56f2 2015/07/10 - // We don't handle the old format previous to that commit. txn.commit(); m_open = true; migrate(*(const uint32_t *)v.mv_data); @@ -1428,6 +2081,27 @@ void BlockchainLMDB::reset() (void)mdb_drop(txn, m_hf_starting_heights, 0); // this one is dropped in new code if (auto result = mdb_drop(txn, m_hf_versions, 0)) throw0(DB_ERROR(lmdb_error("Failed to drop m_hf_versions: ", result).c_str())); + if (auto result = mdb_drop(txn, m_output_advanced, 0)) + throw0(DB_ERROR(lmdb_error("Failed to drop m_output_advanced: ", result).c_str())); + if (auto result = mdb_drop(txn, m_output_advanced_type, 0)) + throw0(DB_ERROR(lmdb_error("Failed to drop m_output_advanced_type: ", result).c_str())); + if (auto result = mdb_drop(txn, m_token_staked_sum, 0)) + throw0(DB_ERROR(lmdb_error("Failed to drop m_token_staked_sum: ", result).c_str())); + if (auto result = mdb_drop(txn, m_token_staked_sum_total, 0)) + throw0(DB_ERROR(lmdb_error("Failed to drop m_token_staked_sum_total: ", result).c_str())); + if (auto result = mdb_drop(txn, m_network_fee_sum, 0)) + throw0(DB_ERROR(lmdb_error("Failed to drop m_network_fee_sum: ", result).c_str())); + if (auto result = mdb_drop(txn, m_token_lock_expiry, 0)) + throw0(DB_ERROR(lmdb_error("Failed to drop m_token_lock_expiry: ", result).c_str())); + if (auto result = mdb_drop(txn, m_safex_account, 0)) + throw0(DB_ERROR(lmdb_error("Failed to drop m_safex_account: ", result).c_str())); + if (auto result = mdb_drop(txn, m_safex_offer, 0)) + throw0(DB_ERROR(lmdb_error("Failed to drop m_safex_offer: ", result).c_str())); + if (auto result = mdb_drop(txn, m_safex_feedback, 0)) + throw0(DB_ERROR(lmdb_error("Failed to drop m_safex_feedback: ", result).c_str())); + if (auto result = mdb_drop(txn, m_safex_price_peg, 0)) + throw0(DB_ERROR(lmdb_error("Failed to drop m_safex_price_peg: ", result).c_str())); + if (auto result = mdb_drop(txn, m_properties, 0)) throw0(DB_ERROR(lmdb_error("Failed to drop m_properties: ", result).c_str())); @@ -2313,9 +2987,13 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount, const tx_out_ty LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); + if (output_type >= cryptonote::tx_out_type::out_advanced && output_type < cryptonote::tx_out_type::out_invalid) + throw0(DB_ERROR("Unsupported advanced output type")); + + TXN_PREFIX_RDONLY(); - MDB_cursor *cur_output_amount; + MDB_cursor *cur_output_amount = nullptr; switch (output_type) { @@ -2350,64 +3028,49 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount, const tx_out_ty return num_elems; } -// This is a lot harder now that we've removed the output_keys index -output_data_t BlockchainLMDB::get_output_key(const uint64_t &global_index) const -{ - LOG_PRINT_L3("BlockchainLMDB::" << __func__ << " (unused version - does nothing)"); - check_open(); - TXN_PREFIX_RDONLY(); - RCURSOR(output_txs); - RCURSOR(tx_indices); - RCURSOR(txs); - - output_data_t od; - MDB_val_set(v, global_index); - auto get_result = mdb_cursor_get(m_cur_output_txs, (MDB_val *)&zerokval, &v, MDB_GET_BOTH); - if (get_result == MDB_NOTFOUND) - throw1(OUTPUT_DNE("output with given index not in db")); - else if (get_result) - throw0(DB_ERROR("DB error attempting to fetch output tx hash")); - outtx *ot = (outtx *)v.mv_data; +uint64_t BlockchainLMDB::get_num_outputs(const tx_out_type output_type) const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); - MDB_val_set(val_h, ot->tx_hash); - get_result = mdb_cursor_get(m_cur_tx_indices, (MDB_val *)&zerokval, &val_h, MDB_GET_BOTH); - if (get_result) - throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch transaction index from hash ") + epee::string_tools::pod_to_hex(ot->tx_hash) + ": ", get_result).c_str())); + if (!(output_type >= cryptonote::tx_out_type::out_advanced && output_type < cryptonote::tx_out_type::out_invalid)) + throw0(DB_ERROR("Unknown advanced output type")); - txindex *tip = (txindex *)val_h.mv_data; - MDB_val_set(val_tx_id, tip->data.tx_id); - MDB_val result; - get_result = mdb_cursor_get(m_cur_txs, &val_tx_id, &result, MDB_SET); - if (get_result == MDB_NOTFOUND) - throw1(TX_DNE(std::string("tx with hash ").append(epee::string_tools::pod_to_hex(ot->tx_hash)).append(" not found in db").c_str())); - else if (get_result) - throw0(DB_ERROR(lmdb_error("DB error attempting to fetch tx from hash", get_result).c_str())); + check_open(); - blobdata bd; - bd.assign(reinterpret_cast(result.mv_data), result.mv_size); + TXN_PREFIX_RDONLY(); - transaction tx; - if (!parse_and_validate_tx_from_blob(bd, tx)) - throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db")); + MDB_cursor *cur_output_advanced_type; + RCURSOR(output_advanced_type); + cur_output_advanced_type = m_cur_output_advanced_type; - const tx_out tx_output = tx.vout[ot->local_index]; - od.unlock_time = tip->data.unlock_time; - od.height = tip->data.block_id; - od.pubkey = *boost::apply_visitor(destination_public_key_visitor(), tx_output.target); + MDB_val_copy k_output_type(static_cast(output_type)); + MDB_val v; + mdb_size_t num_elems = 0; + auto result = mdb_cursor_get(cur_output_advanced_type, &k_output_type, &v, MDB_SET); + if (result == MDB_SUCCESS) + { + mdb_cursor_count(cur_output_advanced_type, &num_elems); + } + else if (result != MDB_NOTFOUND) + { + throw0(DB_ERROR("DB error attempting to get number of outputs of an amount")); + } TXN_POSTFIX_RDONLY(); - return od; + + return num_elems; } -output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) + +output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); TXN_PREFIX_RDONLY(); - MDB_cursor *cur_output_amount; + MDB_cursor *cur_output_amount = nullptr; switch (output_type) { case tx_out_type::out_cash: @@ -2448,6 +3111,85 @@ output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint6 return ret; } + + + output_advanced_data_t BlockchainLMDB::get_output_advanced_data(const tx_out_type output_type, const uint64_t output_index) const + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + + if (!(output_type >= cryptonote::tx_out_type::out_advanced && output_type < cryptonote::tx_out_type::out_invalid)) + throw0(DB_ERROR("Unknown advanced output type")); + + uint64_t output_id; + + if( !get_output_id(output_type, output_index, output_id) ) + throw0(DB_ERROR("Output ID not found!")); + + check_open(); + + TXN_PREFIX_RDONLY(); + MDB_cursor *cur_output_advanced; + RCURSOR(output_advanced); + cur_output_advanced = m_cur_output_advanced; + + output_advanced_data_t output = AUTO_VAL_INIT(output); + + MDB_val_set(key, output_id); + blobdata blob; + MDB_val_set(value_blob, blob); + + auto result = mdb_cursor_get(cur_output_advanced, &key, &value_blob, MDB_SET); + if (result == MDB_SUCCESS) + { + output = parse_output_advanced_data_from_mdb(value_blob); + if(output.output_type != static_cast(output_type)) + throw0(DB_ERROR(lmdb_error("Attemting to get keys from output with ID " + std::to_string(output_id) + " for type "+ std::to_string(static_cast(output_type)) + " but not found: ", result).c_str())); + } + else if (result == MDB_NOTFOUND) + throw0(DB_ERROR(lmdb_error("Attemting to get keys from output with ID " + std::to_string(output_id) + " but not found: ", result).c_str())); + else + throw0(DB_ERROR(lmdb_error("DB error attempting to advanced output blob: ", result).c_str())); + + + TXN_POSTFIX_RDONLY(); + return output; + } + + bool BlockchainLMDB::get_output_id(const tx_out_type output_type, const uint64_t output_index, uint64_t& output_id) const + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + + if (!(output_type >= cryptonote::tx_out_type::out_advanced && output_type < cryptonote::tx_out_type::out_invalid)) + throw0(DB_ERROR("Unknown advanced output type")); + + check_open(); + + TXN_PREFIX_RDONLY(); + MDB_cursor *cur_output_advanced_type; + RCURSOR(output_advanced_type); + cur_output_advanced_type = m_cur_output_advanced_type; + + + const uint64_t out_type = static_cast(output_type); + MDB_val_set(key, out_type); + MDB_val_set(value, output_index); + + auto result = mdb_cursor_get(cur_output_advanced_type, &key, &value, MDB_GET_BOTH); + if (result == MDB_SUCCESS) + { + outkey_advanced *okadv = (outkey_advanced *)value.mv_data; + output_id = okadv->output_id; + } + else if (result == MDB_NOTFOUND) + return false; + else + throw0(DB_ERROR(lmdb_error("DB error attempting to advanced output blob: ", result).c_str())); + + + TXN_POSTFIX_RDONLY(); + return true; + } + tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t& output_id) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); @@ -2677,16 +3419,16 @@ bool BlockchainLMDB::for_all_outputs(std::function f, const tx_out_type output_type) const +{ + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + MDB_cursor *cur_output_advanced; + RCURSOR(output_advanced); + cur_output_advanced = m_cur_output_advanced; + + MDB_val k; + MDB_val v; + bool fret = true; + + MDB_cursor_op op = MDB_FIRST; + while (1) + { + int ret = mdb_cursor_get(cur_output_advanced, &k, &v, op); + op = MDB_NEXT; + if (ret == MDB_NOTFOUND) + break; + if (ret) + throw0(DB_ERROR("Failed to enumerate outputs")); + + output_advanced_data_t output = parse_output_advanced_data_from_mdb(v); + + txout_to_script txout = AUTO_VAL_INIT(txout); + txout.output_type = static_cast(output.output_type); + txout.key = output.pubkey; + + parse_and_validate_byte_array_from_blob(output.data, txout.data); + + + if (static_cast(txout.output_type) == output_type) { + tx_out_index toi = get_output_tx_and_index_from_global(output.output_id); + const uint64_t block_height = get_tx_block_height(toi.first); + if (!f(toi.first, block_height, output.output_id, txout)) { + fret = false; + break; + } + } + } + + TXN_POSTFIX_RDONLY(); + + return fret; + } +}; + bool BlockchainLMDB::for_all_outputs(uint64_t amount, const std::function &f, const tx_out_type output_type) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); @@ -2727,7 +3521,7 @@ bool BlockchainLMDB::for_all_outputs(uint64_t amount, const std::function &offsets, std::vector &outputs, const tx_out_type output_type, bool allow_partial) +void BlockchainLMDB::get_amount_output_key(const uint64_t &amount, const std::vector &offsets, + std::vector &outputs, const tx_out_type output_type, + bool allow_partial) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); - TIME_MEASURE_START(db3); check_open(); outputs.clear(); @@ -3173,17 +3968,19 @@ void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector &output_indexes, + std::vector &outputs, const tx_out_type output_type, + bool allow_partial) const + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + outputs.clear(); + + std::vector output_ids; + + for(const auto output_index: output_indexes){ + uint64_t output_id; + if(get_output_id(output_type, output_index, output_id)) + output_ids.push_back(output_id); + } + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_output_advanced; + RCURSOR(output_advanced); + cur_output_advanced = m_cur_output_advanced; + + TIME_MEASURE_START(db3); + + for (const uint64_t &output_id : output_ids) + { + output_advanced_data_t current = AUTO_VAL_INIT(current); + + MDB_val_set(key, output_id); + blobdata blob; + MDB_val_set(value_blob, blob); + + auto result = mdb_cursor_get(cur_output_advanced, &key, &value_blob, MDB_SET); + if (result == MDB_SUCCESS) + { + current = parse_output_advanced_data_from_mdb(value_blob); + outputs.push_back(current); + } + else if (result == MDB_NOTFOUND) + { + if (allow_partial) + { + MDEBUG("Partial result: " << outputs.size() << "/" << output_ids.size()); + break; + } + throw0(DB_ERROR(lmdb_error("Attemting to get keys from advanced output with current id " + std::to_string(output_id) + " but not found: ", result).c_str())); + } + else + throw0(DB_ERROR(lmdb_error("DB error attempting to get advanced output data: ", result).c_str())); + } + + TXN_POSTFIX_RDONLY(); + + TIME_MEASURE_FINISH(db3); + LOG_PRINT_L3("db3: " << db3); + } + + void BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices, const tx_out_type output_type) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); @@ -3348,7 +4204,8 @@ std::map> BlockchainLMDB::get while (num_elems > 0) { const tx_out_index toi = get_output_tx_and_index(amount, num_elems - 1, output_type); const uint64_t height = get_tx_block_height(toi.first); - if (height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= blockchain_height) + const uint64_t unlock_time = get_tx_unlock_time(toi.first); + if (blockchain_height - 1 + CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS >= unlock_time && height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= blockchain_height) break; --num_elems; } @@ -3473,563 +4330,1970 @@ void BlockchainLMDB::fixup() #define LOGIF(y) if (ELPP->vRegistry()->allowed(y, SAFEX_DEFAULT_LOG_CATEGORY)) -void BlockchainLMDB::migrate_0_1() +void BlockchainLMDB::migrate(const uint32_t oldversion) { - LOG_PRINT_L3("BlockchainLMDB::" << __func__); - uint64_t i, z, m_height; - int result; - mdb_txn_safe txn(false); - MDB_val k, v; - char *ptr; - - MLOG_YELLOW(el::Level::Info, "Migrating blockchain from DB version 0 to 1 - this may take a while:"); - MINFO("updating blocks, hf_versions, outputs, txs, and spent_keys tables..."); + //currently only version 1 is used + //for future use + switch(oldversion) { + default: + break; + } +} - do { - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); +bool BlockchainLMDB::is_valid_transaction_output_type(const txout_target_v &txout) +{ + // check if valid output type, txout_to_key, txout_token_to_key + if ((txout.type() == typeid(txout_to_key)) + || (txout.type() == typeid(txout_token_to_key)) + || (txout.type() == typeid(txout_to_script)) ) + { + return true; + } + + return false; +} + + +/* Keep the currently staked sum in interval 0 */ + uint64_t BlockchainLMDB::update_current_staked_token_sum(const uint64_t delta, int sign) + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + uint64_t m_height = height(); + + const uint64_t db_total_sum_position = 0; + + MDB_cursor *cur_token_staked_sum_total; + CURSOR(token_staked_sum_total); + cur_token_staked_sum_total = m_cur_token_staked_sum_total; + + uint64_t staked_tokens = 0; //staked tokens in interval + + MDB_val_set(k, db_total_sum_position); + MDB_val_set(v, staked_tokens); + + //get already staked tokens for this period + bool existing_interval = false; + auto result = mdb_cursor_get(cur_token_staked_sum_total, &k, &v, MDB_SET); + if (result == MDB_NOTFOUND) + { + staked_tokens = 0; + } + else if (result) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to fetch staked sum for interval: ", result).c_str())); + } + else if (result == MDB_SUCCESS) + { + uint64_t *ptr = (uint64_t *) v.mv_data; + staked_tokens = *ptr; + existing_interval = true; + } + + if (sign<0 && (staked_tokens - delta > staked_tokens)) + throw0(DB_ERROR(lmdb_error("Staked token sum could not be negative: ", result).c_str())); + + //check for overflow + if (sign>0 && staked_tokens + delta < staked_tokens) + throw0(DB_ERROR(lmdb_error("Token staked sum overflow: ", result).c_str())); + + uint64_t newly_staked_tokens = staked_tokens; + if (sign < 0) + newly_staked_tokens = newly_staked_tokens - delta; + else + newly_staked_tokens = newly_staked_tokens + delta; + + LOG_PRINT_L2("Current staked tokens is:" << staked_tokens << " newly staked tokens:" << newly_staked_tokens); + + const uint64_t db_total_sum_position2 = 0; + //update sum of staked tokens for interval + MDB_val_set(k2, db_total_sum_position2); + MDB_val_set(vupdate, newly_staked_tokens); + + if(newly_staked_tokens == 0 && existing_interval){ + if((result = mdb_cursor_del(cur_token_staked_sum_total, 0))) + throw0(DB_ERROR(lmdb_error("Failed to update token staked sum for interval: ", result).c_str())); + }else if ((result = mdb_cursor_put(cur_token_staked_sum_total, &k2, &vupdate, existing_interval ? (unsigned int) MDB_CURRENT : (unsigned int) MDB_APPEND))) + throw0(DB_ERROR(lmdb_error("Failed to update token staked sum for interval: ", result).c_str())); + + return newly_staked_tokens; + } + + + uint64_t BlockchainLMDB::update_staked_token_for_interval(const uint64_t interval, const uint64_t staked_tokens) + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + MDB_cursor *cur_token_staked_sum; + CURSOR(token_staked_sum); + cur_token_staked_sum = m_cur_token_staked_sum; + + + //Check if current interval already exists + uint64_t interval_staked_tokens = 0; //staked tokens in interval + //get already staked tokens for this period + bool existing_interval = false; + MDB_val_set(k, interval); + MDB_val_set(v, interval_staked_tokens); + auto result = mdb_cursor_get(cur_token_staked_sum, &k, &v, MDB_SET); + if (result == MDB_NOTFOUND) + { + interval_staked_tokens = 0; + } + else if (result) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to fetch staked sum for interval: ", result).c_str())); + } + else if (result == MDB_SUCCESS) + { + existing_interval = true; + } + + //update sum of staked tokens for interval + MDB_val_set(k2, interval); + MDB_val_set(vupdate, staked_tokens); + if ((result = mdb_cursor_put(cur_token_staked_sum, &k2, &vupdate, existing_interval ? (unsigned int) MDB_CURRENT : (unsigned int) MDB_APPEND))) + throw0(DB_ERROR(lmdb_error("Failed to update token staked sum for interval: ", result).c_str())); + + return staked_tokens; + } + + bool BlockchainLMDB::remove_staked_token_for_interval(const uint64_t interval){ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + MDB_cursor *cur_token_staked_sum; + CURSOR(token_staked_sum); + cur_token_staked_sum = m_cur_token_staked_sum; + + + //Check if current interval already exists + uint64_t interval_staked_tokens = 0; //staked tokens in interval + MDB_val_set(k, interval); + MDB_val_set(v, interval_staked_tokens); + auto result = mdb_cursor_get(cur_token_staked_sum, &k, &v, MDB_SET); + if (result != MDB_SUCCESS) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to fetch staked sum for interval: ", result).c_str())); + } + + if((result = mdb_cursor_del(cur_token_staked_sum, 0))) + throw0(DB_ERROR(lmdb_error("Failed to update token staked sum for interval: ", result).c_str())); + + return true; + } + + + uint64_t BlockchainLMDB::update_network_fee_sum_for_interval(const uint64_t interval_starting_block, const uint64_t collected_fee) + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + uint64_t m_height = height(); + + MDB_cursor *cur_network_fee_sum; + CURSOR(network_fee_sum); + cur_network_fee_sum = m_cur_network_fee_sum; + + uint64_t newtork_fee_sum = 0; //staked tokens in interval + + MDB_val_set(k, interval_starting_block); + MDB_val_set(v, newtork_fee_sum); + + //get already staked tokens for this period + bool existing_interval = false; + auto result = mdb_cursor_get(cur_network_fee_sum, &k, &v, MDB_SET); + if (result == MDB_NOTFOUND) + { + newtork_fee_sum = 0; + } + else if (result) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to fetch staked sum for interval: ", result).c_str())); + } + else if (result == MDB_SUCCESS) + { + uint64_t *ptr = (uint64_t *) v.mv_data; + newtork_fee_sum = *ptr; + existing_interval = true; + } + + if ((int64_t) newtork_fee_sum + collected_fee < newtork_fee_sum) + throw0(DB_ERROR(lmdb_error("Collected fee sum overflow: ", result).c_str())); + + + uint64_t new_network_fee_sum = newtork_fee_sum + collected_fee; + + LOG_PRINT_L2("Current staked tokens is:" << newtork_fee_sum << " newly staked tokens:" << new_network_fee_sum); + + //update sum of staked tokens for interval + MDB_val_set(k2, interval_starting_block); + MDB_val_set(vupdate, new_network_fee_sum); + if ((result = mdb_cursor_put(cur_network_fee_sum, &k2, &vupdate, existing_interval ? (unsigned int) MDB_CURRENT : (unsigned int) MDB_APPEND))) + throw0(DB_ERROR(lmdb_error("Failed to update network fee sum for interval: ", result).c_str())); + + return new_network_fee_sum; + } + + + + +/*****************************************************/ +/************ Safex related public functions *********/ +/*****************************************************/ + + /* Keep total sum in block 0 */ + uint64_t BlockchainLMDB::get_current_staked_token_sum() const + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_token_staked_sum_total; + RCURSOR(token_staked_sum_total); + cur_token_staked_sum_total = m_cur_token_staked_sum_total; + + uint64_t num_staked_tokens = 0; + + uint64_t key_value = 0; + + MDB_val_set(k, key_value); + MDB_val_set(v, num_staked_tokens); + auto get_result = mdb_cursor_get(cur_token_staked_sum_total, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + num_staked_tokens = 0; + } + else if (get_result) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to fetch staked sum for interval: ", get_result).c_str())); + } + else if (get_result == MDB_SUCCESS) + { + uint64_t *ptr = (uint64_t *) v.mv_data; + num_staked_tokens = *ptr; + } + + + TXN_POSTFIX_RDONLY(); + + return num_staked_tokens; + } + + + + uint64_t BlockchainLMDB::get_staked_token_sum_for_interval(const uint64_t interval) const + { + + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_token_staked_sum; + RCURSOR(token_staked_sum); + cur_token_staked_sum = m_cur_token_staked_sum; + + uint64_t num_staked_tokens = 0; + + const uint64_t previous_interval = interval > 0 ? interval - 1 : 0; //what is staked at the end of previous interval and not unlocked in this interval should receive interest + + MDB_val_set(k, previous_interval); + MDB_val_set(v, num_staked_tokens); + auto get_result = mdb_cursor_get(cur_token_staked_sum, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + num_staked_tokens = 0; + } + else if (get_result) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to fetch staked sum for interval: ", get_result).c_str())); + } + else if (get_result == MDB_SUCCESS) + { + uint64_t *ptr = (uint64_t *) v.mv_data; + num_staked_tokens = *ptr; + } + + + TXN_POSTFIX_RDONLY(); + + return num_staked_tokens; + } + + + + + uint64_t BlockchainLMDB::get_network_fee_sum_for_interval(const uint64_t interval) const + { + + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_network_fee_sum; + RCURSOR(network_fee_sum); + cur_network_fee_sum = m_cur_network_fee_sum; + + uint64_t network_fee_sum = 0; + + MDB_val_set(k, interval); + MDB_val_set(v, network_fee_sum); + auto get_result = mdb_cursor_get(cur_network_fee_sum, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + network_fee_sum = 0; + } + else if (get_result) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to fetch network fee sum for interval: ", get_result).c_str())); + } + else if (get_result == MDB_SUCCESS) + { + uint64_t *ptr = (uint64_t *) v.mv_data; + network_fee_sum = *ptr; + } + + + TXN_POSTFIX_RDONLY(); + + return network_fee_sum; + } + + + + std::vector BlockchainLMDB::get_token_stake_expiry_outputs(const uint64_t block_height) const + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_token_lock_expiry; + RCURSOR(token_lock_expiry); + cur_token_lock_expiry = m_cur_token_lock_expiry; + + std::vector data; + uint64_t buf = 0; + + MDB_val_set(k, block_height); + MDB_val_set(v, buf); + + mdb_size_t num_elems = 0; + + auto get_result = mdb_cursor_get(cur_token_lock_expiry, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + + } else if (get_result) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to fetch staked sum for interval: ", get_result).c_str())); + } + else if (get_result == MDB_SUCCESS) + { + uint64_t *ptr = (uint64_t *) v.mv_data; + data.push_back(*ptr); + + + get_result = mdb_cursor_count(cur_token_lock_expiry, &num_elems); + if (get_result) + throw0(DB_ERROR(std::string("Failed to get number staked epiry outputs: ").append(mdb_strerror(get_result)).c_str())); + } + + for (uint64_t i=0;i end_interval) { + return 0; + } + + safex::map_interval_interest interest_map; + if (!get_interval_interest_map(starting_interval, end_interval, interest_map)) { + MERROR("Could not get interval map"); + return 0; + } + + uint64_t interest = 0; + for (uint64_t i=starting_interval;i<=end_interval;++i) { + uint64_t add_interest = interest_map[i]*(txin.token_amount/SAFEX_TOKEN); + if(interest > interest + add_interest) + return 0; + interest += add_interest; + } + + return interest; + } + + + void BlockchainLMDB::add_safex_account(const safex::account_username &username, const blobdata &blob) { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + MDB_cursor *cur_safex_account; + CURSOR(safex_account) + cur_safex_account = m_cur_safex_account; + + + int result; + crypto::hash username_hash = username.hash(); + MDB_val_set(val_username, username_hash); + result = mdb_cursor_get(cur_safex_account, (MDB_val *)&val_username, NULL, MDB_SET); + if (result == 0) { + throw1(SAFEX_ACCOUNT_EXISTS(std::string("Attempting to add safex account that's already in the db (username ").append(username.c_str()).append(")").c_str())); + } else if (result != MDB_NOTFOUND) { + throw1(DB_ERROR(lmdb_error(std::string("Error checking if account exists for username ").append(username.c_str()) + ": ", result).c_str())); + } + + MDB_val_copy acc_info(blob); + result = mdb_cursor_put(cur_safex_account, (MDB_val *)&val_username, &acc_info, MDB_NOOVERWRITE); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to add account data to db transaction: ", result).c_str())); + + }; + + void BlockchainLMDB::edit_safex_account(const safex::account_username &username, const std::vector &new_data) { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + MDB_cursor *cur_safex_account; + CURSOR(safex_account); + cur_safex_account = m_cur_safex_account; + + crypto::hash username_hash = username.hash(); + + MDB_val_set(k, username_hash); + MDB_val v; + + //check if exists + auto result = mdb_cursor_get(cur_safex_account, &k, &v, MDB_SET); + if (result == MDB_SUCCESS) + { + + MDB_val_set(k2, username_hash); + safex::create_account_result sfx_account; + const cryptonote::blobdata accblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + cryptonote::parse_and_validate_from_blob(accblob, sfx_account); + + sfx_account.account_data = new_data; + + MDB_val_copy vupdate(t_serializable_object_to_blob(sfx_account)); + auto result2 = mdb_cursor_put(cur_safex_account, &k2, &vupdate, (unsigned int) MDB_CURRENT); + if (result2 != MDB_SUCCESS) + throw0(DB_ERROR(lmdb_error("Failed to update account data for username: "+boost::lexical_cast(username.c_str()), result2).c_str())); + } + else if (result == MDB_NOTFOUND) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to edit account, does not exists: ", result).c_str())); + } + else + { + throw0(DB_ERROR(lmdb_error("DB error attempting to edit account: ", result).c_str())); + } + }; + + + void BlockchainLMDB::remove_safex_account(const safex::account_username &username, const uint64_t& output_id) + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + CURSOR(safex_account); + + crypto::hash usename_hash = username.hash(); + MDB_val_set(k, usename_hash); + + auto result = mdb_cursor_get(m_cur_safex_account, &k, NULL, MDB_SET); + if (result != 0 && result != MDB_NOTFOUND) + throw1(DB_ERROR(lmdb_error("Error finding account to remove: ", result).c_str())); + if (!result) + { + remove_advanced_output(cryptonote::tx_out_type::out_safex_account, output_id); + //Then we remove safex account from DB + result = mdb_cursor_del(m_cur_safex_account, 0); + if (result) + throw1(DB_ERROR(lmdb_error("Error removing account: ", result).c_str())); + } + } + + void BlockchainLMDB::add_safex_offer(const crypto::hash &offer_id, const blobdata &blob) { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + MDB_cursor *cur_safex_offer; + CURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; + + + int result; + MDB_val_set(val_offer_id, offer_id); + result = mdb_cursor_get(cur_safex_offer, (MDB_val *)&val_offer_id, NULL, MDB_SET); + if (result == 0) { + throw1(SAFEX_ACCOUNT_EXISTS(std::string("Attempting to add safex offer that's already in the db (offerID ").append(offer_id.data).append(")").c_str())); + } else if (result != MDB_NOTFOUND) { + throw1(DB_ERROR(lmdb_error(std::string("Error checking if offer exists for offerID ").append(offer_id.data) + ": ", result).c_str())); + } + + MDB_val_copy offer_info(blob); + result = mdb_cursor_put(cur_safex_offer, (MDB_val *)&val_offer_id, &offer_info, MDB_NOOVERWRITE); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to add offer data to db transaction: ", result).c_str())); + } + + void BlockchainLMDB::edit_safex_offer(const crypto::hash &offer_id, bool active, uint64_t price, uint64_t quantity) { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + MDB_cursor *cur_safex_offer; + CURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; + + MDB_val_set(k, offer_id); + MDB_val v; + + auto result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_SET); + if (result == MDB_SUCCESS) + { + MDB_val_set(k2, offer_id); + safex::create_offer_result sfx_offer; + const cryptonote::blobdata offerblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + cryptonote::parse_and_validate_from_blob(offerblob, sfx_offer); + + sfx_offer.active = active; + sfx_offer.price = price; + sfx_offer.quantity = quantity; + sfx_offer.edited = true; + + MDB_val_copy vupdate(t_serializable_object_to_blob(sfx_offer)); + auto result2 = mdb_cursor_put(cur_safex_offer, &k2, &vupdate, (unsigned int) MDB_CURRENT); + if (result2 != MDB_SUCCESS) + throw0(DB_ERROR(lmdb_error("Failed to update offer data for offer id: "+boost::lexical_cast(offer_id), result2).c_str())); + } + else if (result == MDB_NOTFOUND) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to edit offer, does not exists: ", result).c_str())); + } + else + { + throw0(DB_ERROR(lmdb_error("DB error attempting to edit offer: ", result).c_str())); + } + } + + void BlockchainLMDB::remove_safex_offer(const crypto::hash& offer_id, const uint64_t& output_id) + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + CURSOR(safex_offer); + + MDB_val_set(k, offer_id); + + auto result = mdb_cursor_get(m_cur_safex_offer, &k, NULL, MDB_SET); + if (result != 0 && result != MDB_NOTFOUND) + throw1(DB_ERROR(lmdb_error("Error finding offer to remove: ", result).c_str())); + if (!result) + { + remove_advanced_output(cryptonote::tx_out_type::out_safex_offer, output_id); + //Then we remove safex offer from DB + result = mdb_cursor_del(m_cur_safex_offer, 0); + if (result) + throw1(DB_ERROR(lmdb_error("Error removing offer: ", result).c_str())); + } + } + + void BlockchainLMDB::remove_safex_offer_update(const crypto::hash& offer_id, const uint64_t& output_id) + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + CURSOR(safex_offer); + + MDB_val_set(k, offer_id); + MDB_val v; + auto result = mdb_cursor_get(m_cur_safex_offer, &k, &v, MDB_SET); + if (result != 0 && result != MDB_NOTFOUND) + throw1(DB_ERROR(lmdb_error("Error finding offer to remove: ", result).c_str())); + if (!result) + { + safex::create_offer_result sfx_offer; + const cryptonote::blobdata offerblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + cryptonote::parse_and_validate_from_blob(offerblob, sfx_offer); + + //First we must remove advanced output + remove_advanced_output(cryptonote::tx_out_type::out_safex_offer_update, output_id); + + restore_safex_offer_data(sfx_offer); + + //Then we update safex offer to DB + MDB_val_copy vupdate(t_serializable_object_to_blob(sfx_offer)); + auto result2 = mdb_cursor_put(m_cur_safex_offer, &k, &vupdate, (unsigned int) MDB_CURRENT); + if (result) + throw1(DB_ERROR(lmdb_error("Error removing offer: ", result).c_str())); + } + } + + void BlockchainLMDB::restore_safex_offer_data(safex::create_offer_result& sfx_offer){ + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + MDB_cursor *cur_output_advanced; + CURSOR(output_advanced); + cur_output_advanced = m_cur_output_advanced; + + uint64_t output_id = 0; + + MDB_val_set(key, output_id); + + blobdata blob; + MDB_val_set(value_blob, blob); + + output_advanced_data_t current = AUTO_VAL_INIT(current); + + auto get_result = mdb_cursor_get(cur_output_advanced, &key, &value_blob, MDB_LAST); + + while (get_result == MDB_SUCCESS) + { + safex::create_offer_data restored_sfx_offer_create; + safex::edit_offer_data restored_sfx_offer_update; + + current = parse_output_advanced_data_from_mdb(value_blob); + + if(current.output_type == static_cast(tx_out_type::out_safex_offer)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_offer_create); + + if(sfx_offer.offer_id == restored_sfx_offer_create.offer_id) { + sfx_offer.quantity = restored_sfx_offer_create.quantity; + sfx_offer.price = restored_sfx_offer_create.price; + sfx_offer.active = restored_sfx_offer_create.active; + sfx_offer.seller = restored_sfx_offer_create.seller; + sfx_offer.edited = false; + sfx_offer.output_id = current.type_index; + + return; + } + } + else if(current.output_type == static_cast(tx_out_type::out_safex_offer_update)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_offer_update); + + if(sfx_offer.offer_id == restored_sfx_offer_update.offer_id) { + sfx_offer.quantity = restored_sfx_offer_update.quantity; + sfx_offer.price = restored_sfx_offer_update.price; + sfx_offer.active = restored_sfx_offer_update.active; + sfx_offer.seller = restored_sfx_offer_update.seller; + + memcpy(&output_id, key.mv_data,sizeof(uint64_t)); + sfx_offer.output_id = current.type_index; + + return; + } + } + get_result = mdb_cursor_get(cur_output_advanced, &key, &value_blob, MDB_PREV); + + } + + throw0(DB_ERROR(lmdb_error("DB error attempting to restore safex offer: ", get_result).c_str())); + + } - MDB_stat db_stats; - if ((result = mdb_stat(txn, m_blocks, &db_stats))) - throw0(DB_ERROR(lmdb_error("Failed to query m_blocks: ", result).c_str())); - m_height = db_stats.ms_entries; - MINFO("Total number of blocks: " << m_height); - MINFO("block migration will update block_heights, block_info, and hf_versions..."); + void BlockchainLMDB::restore_safex_price_peg_data(safex::create_price_peg_result& sfx_price_peg){ + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + MDB_cursor *cur_output_advanced; + CURSOR(output_advanced); + cur_output_advanced = m_cur_output_advanced; + + uint64_t output_id = 0; + + MDB_val_set(key, output_id); + + blobdata blob; + MDB_val_set(value_blob, blob); + + output_advanced_data_t current = AUTO_VAL_INIT(current); + + auto get_result = mdb_cursor_get(cur_output_advanced, &key, &value_blob, MDB_LAST); + + while (get_result == MDB_SUCCESS) + { + safex::create_price_peg_data restored_sfx_price_peg_create; + safex::update_price_peg_data restored_sfx_price_peg_update; + + current = parse_output_advanced_data_from_mdb(value_blob); + + if(current.output_type == static_cast(tx_out_type::out_safex_price_peg)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_price_peg_create); + + if(sfx_price_peg.price_peg_id == restored_sfx_price_peg_create.price_peg_id) { + sfx_price_peg.creator = restored_sfx_price_peg_create.creator; + sfx_price_peg.rate = restored_sfx_price_peg_create.rate; + sfx_price_peg.currency = restored_sfx_price_peg_create.currency; + sfx_price_peg.title = restored_sfx_price_peg_create.title; + sfx_price_peg.description = restored_sfx_price_peg_create.description; + return; + } + } + else if(current.output_type == static_cast(tx_out_type::out_safex_price_peg_update)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_price_peg_update); + + if(sfx_price_peg.price_peg_id == restored_sfx_price_peg_update.price_peg_id) { + sfx_price_peg.rate = restored_sfx_price_peg_update.rate; + return; + } + } + get_result = mdb_cursor_get(cur_output_advanced, &key, &value_blob, MDB_PREV); + + } + + throw0(DB_ERROR(lmdb_error("DB error attempting to restore safex price_peg: ", get_result).c_str())); + + } + + void BlockchainLMDB::remove_safex_price_peg(const crypto::hash &price_peg_id, const uint64_t& output_id){ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + CURSOR(safex_price_peg); + + MDB_val_set(k, price_peg_id); + + auto result = mdb_cursor_get(m_cur_safex_price_peg, &k, NULL, MDB_SET); + if (result != 0 && result != MDB_NOTFOUND) + throw1(DB_ERROR(lmdb_error("Error finding price_peg to remove: ", result).c_str())); + if (!result) + { + remove_advanced_output(cryptonote::tx_out_type::out_safex_price_peg, output_id); + //Then we remove safex price_peg from DB + result = mdb_cursor_del(m_cur_safex_price_peg, 0); + if (result) + throw1(DB_ERROR(lmdb_error("Error removing price_peg: ", result).c_str())); + } + } + + void BlockchainLMDB::remove_safex_price_peg_update(const crypto::hash& price_peg_id, const uint64_t& output_id) + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + CURSOR(safex_price_peg); + + MDB_val_set(k, price_peg_id); + MDB_val v; + auto result = mdb_cursor_get(m_cur_safex_price_peg, &k, &v, MDB_SET); + if (result != 0 && result != MDB_NOTFOUND) + throw1(DB_ERROR(lmdb_error("Error finding price_peg to remove: ", result).c_str())); + if (!result) + { + safex::create_price_peg_result sfx_price_peg; + const cryptonote::blobdata pricepegblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + cryptonote::parse_and_validate_from_blob(pricepegblob, sfx_price_peg); + + //First we must remove advanced output + remove_advanced_output(cryptonote::tx_out_type::out_safex_price_peg_update, output_id); + + + restore_safex_price_peg_data(sfx_price_peg); + + //Then we update safex price_peg to DB + MDB_val_copy vupdate(t_serializable_object_to_blob(sfx_price_peg)); + auto result2 = mdb_cursor_put(m_cur_safex_price_peg, &k, &vupdate, (unsigned int) MDB_CURRENT); + if (result) + throw1(DB_ERROR(lmdb_error("Error removing safex price_peg: ", result).c_str())); + } + } + + void BlockchainLMDB::remove_safex_purchase(const crypto::hash& offer_id, const uint64_t quantity, const uint64_t& output_id) + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + MDB_cursor *cur_safex_offer; + CURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; + + uint8_t temp[SAFEX_OFFER_DATA_MAX_SIZE + sizeof(crypto::hash)]; + + MDB_val_set(k, offer_id); + MDB_val_set(v, temp); + + auto result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_SET); + if (result == MDB_SUCCESS) + { + remove_advanced_output(tx_out_type::out_safex_purchase, output_id); + safex::create_offer_result sfx_offer; + const cryptonote::blobdata offerblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + cryptonote::parse_and_validate_from_blob(offerblob, sfx_offer); + + sfx_offer.quantity += quantity; + + + MDB_val_copy vupdate(t_serializable_object_to_blob(sfx_offer)); + auto result2 = mdb_cursor_put(cur_safex_offer, &k, &vupdate, (unsigned int) MDB_CURRENT); + if (result2 != MDB_SUCCESS) + throw0(DB_ERROR(lmdb_error("Failed to remove purchase for offer id: "+boost::lexical_cast(offer_id), result2).c_str())); + } + else if (result == MDB_NOTFOUND) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to remove purchase: ", result).c_str())); + } + else + { + throw0(DB_ERROR(lmdb_error("DB error attempting to remove purchase: ", result).c_str())); + } + } + + void BlockchainLMDB::remove_safex_feedback(const crypto::hash& offer_id, safex::create_feedback_data& feedback_output_data, const uint64_t& output_id){ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + MDB_cursor *cur_safex_feedback; + CURSOR(safex_feedback) + cur_safex_feedback = m_cur_safex_feedback; + + std::string comment{feedback_output_data.comment.begin(),feedback_output_data.comment.end()}; + + safex::safex_feedback_db_data sfx_feedback_data{output_id, feedback_output_data.stars_given, comment}; + + MDB_val_set(k, offer_id); + MDB_val_copy v(t_serializable_object_to_blob(sfx_feedback_data)); + + auto result = mdb_cursor_get(cur_safex_feedback, &k, &v, MDB_GET_BOTH); + if (result == MDB_SUCCESS) + { + remove_advanced_output(tx_out_type::out_safex_feedback, output_id); + + if ((result = mdb_cursor_del(cur_safex_feedback, 0))) + throw1(DB_ERROR(lmdb_error("Failed to add removal of block info to db transaction: ", result).c_str())); + } + else + { + throw0(DB_ERROR(lmdb_error("DB error attempting to remove feedback: ", result).c_str())); + } + } + + void BlockchainLMDB::remove_network_fee_output(const uint64_t& amount, const uint64_t &output_id) + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + uint64_t m_height = height(); + + MDB_cursor *cur_network_fee_sum; + CURSOR(network_fee_sum); + cur_network_fee_sum = m_cur_network_fee_sum; + + + + uint64_t interval_starting_block = safex::calculate_interval_for_height(m_height, m_nettype); + uint64_t network_fee_sum = 0; + + MDB_val_set(k, interval_starting_block); + MDB_val_set(v, network_fee_sum); + + auto result = mdb_cursor_get(cur_network_fee_sum, &k, &v, MDB_SET); + if (result == MDB_SUCCESS) + { + remove_advanced_output(tx_out_type::out_network_fee, output_id); + + uint64_t *ptr = (uint64_t *) v.mv_data; + network_fee_sum = *ptr; + + network_fee_sum -= amount; + + MDB_val_set(k2, interval_starting_block); + MDB_val_set(vupdate, network_fee_sum); + + if(network_fee_sum == 0){ + if((result = mdb_cursor_del(cur_network_fee_sum, 0))) + throw0(DB_ERROR(lmdb_error("Failed to update network fee sum for interval: ", result).c_str())); + }else if ((result = mdb_cursor_put(cur_network_fee_sum, &k2, &vupdate, (unsigned int) MDB_CURRENT ))) + throw0(DB_ERROR(lmdb_error("Failed to update network fee sum for interval: ", result).c_str())); + } else{ + throw0(DB_ERROR(lmdb_error("DB error attempting to remove network fee output: ", result).c_str())); + } + } + + void BlockchainLMDB::remove_safex_account_update(const safex::account_username &username, const uint64_t& output_id) + { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + CURSOR(safex_account); + + crypto::hash usename_hash = username.hash(); + MDB_val_set(k, usename_hash); + MDB_val v; + auto result = mdb_cursor_get(m_cur_safex_account, &k, &v, MDB_SET); + if (result != 0 && result != MDB_NOTFOUND) + throw1(DB_ERROR(lmdb_error("Error finding account to remove: ", result).c_str())); + if (!result) + { + safex::create_account_result sfx_account; + const cryptonote::blobdata accblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + cryptonote::parse_and_validate_from_blob(accblob, sfx_account); + + //First we must remove advanced output + remove_advanced_output(cryptonote::tx_out_type::out_safex_account_update, output_id); + + + restore_safex_account_data(sfx_account); + + + //Then we update safex account to DB + MDB_val_copy vupdate(t_serializable_object_to_blob(sfx_account)); + auto result2 = mdb_cursor_put(m_cur_safex_account, &k, &vupdate, (unsigned int) MDB_CURRENT); + if (result) + throw1(DB_ERROR(lmdb_error("Error removing account: ", result).c_str())); + } + } + + void BlockchainLMDB::restore_safex_account_data(safex::create_account_result& sfx_account){ + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + MDB_cursor *cur_output_advanced; + CURSOR(output_advanced); + cur_output_advanced = m_cur_output_advanced; + + uint64_t output_id = 0; + + MDB_val_set(key, output_id); + + blobdata blob; + MDB_val_set(value_blob, blob); + + output_advanced_data_t current = AUTO_VAL_INIT(current); + + auto get_result = mdb_cursor_get(cur_output_advanced, &key, &value_blob, MDB_LAST); + + while (get_result == MDB_SUCCESS) + { + safex::create_account_data restored_sfx_account_create; + safex::edit_account_data restored_sfx_account_update; + + current = parse_output_advanced_data_from_mdb(value_blob); + + if(current.output_type == static_cast(tx_out_type::out_safex_account)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_account_create); + + if (sfx_account.username == restored_sfx_account_create.username) { + sfx_account.account_data = restored_sfx_account_create.account_data; + return; + } + } + else if(current.output_type == static_cast(tx_out_type::out_safex_account_update)){ + + parse_and_validate_object_from_blob(current.data, restored_sfx_account_update); + + sfx_account.account_data = restored_sfx_account_update.account_data; + return; + } + + get_result = mdb_cursor_get(cur_output_advanced, &key, &value_blob, MDB_PREV); + + } + throw0(DB_ERROR(lmdb_error("DB error attempting to restore safex account: ", get_result).c_str())); + + } + + + void BlockchainLMDB::remove_advanced_output(const tx_out_type& out_type, const uint64_t& output_index){ + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + + CURSOR(output_advanced); + CURSOR(output_txs); + CURSOR(output_advanced_type); + + uint64_t output_type = static_cast(out_type); + MDB_val_set(k_output_type, output_type); + MDB_val value = {sizeof(uint64_t), (void *)&output_index}; + + auto result = mdb_cursor_get(m_cur_output_advanced_type, &k_output_type, &value, MDB_GET_BOTH); + if(result != 0) + { + throw0(DB_ERROR("Unexpected: global output index not found for specified type in m_output_advanced_type")); + } + + outkey_advanced *okadv = (outkey_advanced *)value.mv_data; + uint64_t output_id = okadv->output_id; + + MDB_val_set(otxk, output_id); + + MDB_val_set(otxk2, output_id); + + result = mdb_cursor_get(m_cur_output_txs, (MDB_val *)&zerokval, &otxk, MDB_GET_BOTH); + if (result == MDB_NOTFOUND) + { + throw0(DB_ERROR("Unexpected: global output index not found in m_output_txs")); + } + else if (result) + { + throw1(DB_ERROR(lmdb_error("Error adding removal of output tx to db transaction", result).c_str())); + } + // We remove the output_tx from the outputs table + result = mdb_cursor_del(m_cur_output_txs, 0); + if (result) + throw0(DB_ERROR(lmdb_error(std::string("Error deleting output index ").c_str(), result).c_str())); + + result = mdb_cursor_get(m_cur_output_advanced, &otxk2, NULL, MDB_SET); + if (result != 0 && result != MDB_NOTFOUND) + throw1(DB_ERROR(lmdb_error("Error finding advanced output to remove: ", result).c_str())); + if (!result) + { + result = mdb_cursor_del(m_cur_output_advanced, 0); + if (result) + throw1(DB_ERROR(lmdb_error("Error removing advanced output: ", result).c_str())); + } + if ((result = mdb_cursor_del(m_cur_output_advanced_type, 0))) + throw0(DB_ERROR(lmdb_error("Failed to remove advanced output by type: ", result).c_str())); + } + + void BlockchainLMDB::create_safex_purchase(const safex::safex_purchase& purchase) { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + MDB_cursor *cur_safex_offer; + CURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; + + + int result; + MDB_val_set(k, purchase.offer_id); + MDB_val v; + + result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_SET); + if (result == MDB_SUCCESS) + { + safex::create_offer_result sfx_offer; + const cryptonote::blobdata accblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + cryptonote::parse_and_validate_from_blob(accblob, sfx_offer); + + if(sfx_offer.quantity - purchase.quantity > sfx_offer.quantity) + throw0(DB_ERROR("DB error attempting to create purchase: Not enough quantity of item")); + + sfx_offer.quantity -= purchase.quantity; + + + MDB_val_copy vupdate(t_serializable_object_to_blob(sfx_offer)); + auto result2 = mdb_cursor_put(cur_safex_offer, &k, &vupdate, (unsigned int) MDB_CURRENT); + if (result2 != MDB_SUCCESS) + throw0(DB_ERROR(lmdb_error("Failed to add purchase for offer id: "+boost::lexical_cast(purchase.offer_id), result2).c_str())); + } + else if (result == MDB_NOTFOUND) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to create purchase: ", result).c_str())); + } + else + { + throw0(DB_ERROR(lmdb_error("DB error attempting to create purchase: ", result).c_str())); + } + } + + void BlockchainLMDB::create_safex_feedback(const safex::safex_feedback& feedback) { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + MDB_cursor *cur_safex_feedback; + CURSOR(safex_feedback) + cur_safex_feedback = m_cur_safex_feedback; + + uint64_t output_index = get_num_outputs(tx_out_type::out_safex_feedback); + + safex::safex_feedback_db_data sfx_feedback_data{output_index, feedback.stars_given, feedback.comment}; + + + int result; + MDB_val_set(k, feedback.offer_id); + MDB_val_copy v(t_serializable_object_to_blob(sfx_feedback_data)); + + if ((result = mdb_cursor_put(cur_safex_feedback, &k, &v, MDB_APPENDDUP))) + throw0(DB_ERROR(lmdb_error("Failed to add feedback output index: ", result).c_str())); + } + + void BlockchainLMDB::add_safex_price_peg(const crypto::hash& price_peg_id, const blobdata &blob){ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + MDB_cursor *cur_safex_price_peg; + CURSOR(safex_price_peg) + cur_safex_price_peg = m_cur_safex_price_peg; + + int result; + MDB_val_set(val_price_peg_id, price_peg_id); + result = mdb_cursor_get(cur_safex_price_peg, (MDB_val *)&val_price_peg_id, NULL, MDB_SET); + if (result == 0) { + throw1(SAFEX_ACCOUNT_EXISTS(std::string("Attempting to add safex price peg that's already in the db (price peg ID ").append(price_peg_id.data).append(")").c_str())); + } else if (result != MDB_NOTFOUND) { + throw1(DB_ERROR(lmdb_error(std::string("Error checking if price peg exists for price peg ID ").append(price_peg_id.data) + ": ", result).c_str())); + } + + MDB_val_copy price_peg_info(blob); + result = mdb_cursor_put(cur_safex_price_peg, (MDB_val *)&val_price_peg_id, &price_peg_info, MDB_NOOVERWRITE); + if (result) + throw0(DB_ERROR(lmdb_error("Failed to add price peg data to db transaction: ", result).c_str())); + } + + void BlockchainLMDB::update_safex_price_peg(const crypto::hash& price_peg_id, const safex::update_price_peg_result& sfx_price_peg_update_result){ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + mdb_txn_cursors *m_cursors = &m_wcursors; + MDB_cursor *cur_safex_price_peg; + CURSOR(safex_price_peg) + cur_safex_price_peg = m_cur_safex_price_peg; + + int result; + MDB_val_set(val_price_peg_id, price_peg_id); + MDB_val v; + result = mdb_cursor_get(cur_safex_price_peg, (MDB_val *)&val_price_peg_id, &v, MDB_SET); + if (result == MDB_SUCCESS) { + MDB_val_set(k2, price_peg_id); + safex::create_price_peg_result sfx_price_peg; + const cryptonote::blobdata pricepegblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + cryptonote::parse_and_validate_from_blob(pricepegblob, sfx_price_peg); + + sfx_price_peg.rate = sfx_price_peg_update_result.rate; + + MDB_val_copy vupdate(t_serializable_object_to_blob(sfx_price_peg)); + auto result2 = mdb_cursor_put(cur_safex_price_peg, &k2, &vupdate, (unsigned int) MDB_CURRENT); + if (result2 != MDB_SUCCESS) + throw0(DB_ERROR(lmdb_error("Failed to update price peg data for price peg id: "+boost::lexical_cast(price_peg_id), result2).c_str())); } + else if (result == MDB_NOTFOUND) + { + throw0(DB_ERROR(lmdb_error("DB error attempting to update price peg, does not exists: ", result).c_str())); + } + else + { + throw0(DB_ERROR(lmdb_error("DB error attempting to update price peg: ", result).c_str())); + } + } + + bool BlockchainLMDB::get_account_key(const safex::account_username &username, crypto::public_key &pkey) const { + + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_account; + RCURSOR(safex_account); + cur_safex_account = m_cur_safex_account; + + crypto::hash username_hash = username.hash(); + + uint8_t temp[SAFEX_ACCOUNT_DATA_MAX_SIZE + sizeof(crypto::public_key)]; + + MDB_val_set(k, username_hash); + MDB_val_set(v, temp); + auto get_result = mdb_cursor_get(cur_safex_account, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + //throw0(DB_ERROR(lmdb_error(std::string("DB error account not found: ").append(username.c_str()), get_result).c_str())); + return false; + } + else if (get_result) + { + throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch account public key: ").append(username.c_str()), get_result).c_str())); + } + else if (get_result == MDB_SUCCESS) + { + safex::create_account_result sfx_account; + const cryptonote::blobdata accblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + cryptonote::parse_and_validate_from_blob(accblob, sfx_account); + + pkey = sfx_account.pkey; + } + + TXN_POSTFIX_RDONLY(); + + return true; + }; + + bool BlockchainLMDB::get_safex_accounts( std::vector> &safex_accounts) const{ + + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_account; + RCURSOR(safex_account); + cur_safex_account = m_cur_safex_account; + + crypto::hash username_hash{}; + uint8_t temp[sizeof(safex::create_account_data)]; + + MDB_val_set(k, username_hash); + MDB_val_set(v, temp); + + auto result = mdb_cursor_get(cur_safex_account, &k, &v, MDB_FIRST); + + while (result == MDB_SUCCESS) + { + safex::create_account_result sfx_account; + const cryptonote::blobdata accblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + + if(!cryptonote::parse_and_validate_from_blob(accblob, sfx_account)){ + result = mdb_cursor_get(cur_safex_account, &k, &v, MDB_NEXT); + continue; + } + + std::string str_username{sfx_account.username.begin(),sfx_account.username.end()}; + std::string str_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + + safex_accounts.emplace_back(std::make_pair(str_username,str_data)); + + result = mdb_cursor_get(cur_safex_account, &k, &v, MDB_NEXT); + } + + TXN_POSTFIX_RDONLY(); + + return true; + } + + bool BlockchainLMDB::get_safex_offer_height( crypto::hash &offer_id, uint64_t& height) const{ + + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_offer; + RCURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; + + uint64_t output_index{}; + bool edited = false; + + uint8_t temp[SAFEX_OFFER_DATA_MAX_SIZE + sizeof(crypto::hash)]; + + MDB_val_set(k, offer_id); + MDB_val_set(v, temp); + auto get_result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + return false; + } + else if (get_result) + { + throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch offer with id: ").append(offer_id.data), get_result).c_str())); + } + else if (get_result == MDB_SUCCESS) + { + safex::create_offer_result offer_result; + std::string tmp{(char*)v.mv_data, v.mv_size}; + parse_and_validate_object_from_blob(tmp,offer_result); + + output_index = offer_result.output_id; + edited = offer_result.edited; + } + + + tx_out_type out_type = edited ? tx_out_type::out_safex_offer_update : tx_out_type::out_safex_offer; + + output_advanced_data_t adv_data = get_output_advanced_data(out_type, output_index); + + height = adv_data.height; + + return true; + } + + + bool BlockchainLMDB::get_safex_offers( std::vector &safex_offers) const{ + + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_offer; + RCURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; + + crypto::hash offer_id{}; + uint8_t temp[sizeof(safex::create_offer_result)]; + + MDB_val_set(k, offer_id); + MDB_val_set(v, temp); + + auto result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_FIRST); + + while (result == MDB_SUCCESS) + { + safex::create_offer_result sfx_offer_result; + safex::safex_offer sfx_offer; + const cryptonote::blobdata offerblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + + if(!cryptonote::parse_and_validate_from_blob(offerblob, sfx_offer_result)){ + result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_NEXT); + continue; + } + + result = get_offer(sfx_offer_result.offer_id,sfx_offer); + if(!result) + return false; + sfx_offer.quantity = sfx_offer_result.quantity; + sfx_offer.price = sfx_offer_result.price; + sfx_offer.active = sfx_offer_result.active; + safex_offers.emplace_back(sfx_offer); + + result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_NEXT); + } - MINFO("migrating block_heights:"); - MDB_dbi o_heights; + TXN_POSTFIX_RDONLY(); - unsigned int flags; - result = mdb_dbi_flags(txn, m_block_heights, &flags); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to retrieve block_heights flags: ", result).c_str())); - /* if the flags are what we expect, this table has already been migrated */ - if ((flags & (MDB_INTEGERKEY|MDB_DUPSORT|MDB_DUPFIXED)) == (MDB_INTEGERKEY|MDB_DUPSORT|MDB_DUPFIXED)) { - txn.abort(); - LOG_PRINT_L1(" block_heights already migrated"); - break; + return true; } - /* the block_heights table name is the same but the old version and new version - * have incompatible DB flags. Create a new table with the right flags. We want - * the name to be similar to the old name so that it will occupy the same location - * in the DB. - */ - o_heights = m_block_heights; - lmdb_db_open(txn, "block_heightr", MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_block_heights, "Failed to open db handle for block_heightr"); - mdb_set_dupsort(txn, m_block_heights, compare_hash32); - - MDB_cursor *c_old, *c_cur; - blk_height bh; - MDB_val_set(nv, bh); - - /* old table was k(hash), v(height). - * new table is DUPFIXED, k(zeroval), v{hash, height}. - */ - i = 0; - z = m_height; - while(1) { - if (!(i % 2000)) { - if (i) { - LOGIF(el::Level::Info) { - std::cout << i << " / " << z << " \r" << std::flush; - } - txn.commit(); - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); - } - result = mdb_cursor_open(txn, m_block_heights, &c_cur); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_heightr: ", result).c_str())); - result = mdb_cursor_open(txn, o_heights, &c_old); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_heights: ", result).c_str())); - if (!i) { - MDB_stat ms; - mdb_stat(txn, m_block_heights, &ms); - i = ms.ms_entries; + uint64_t get_size(MDB_cursor *curr_cursor){ + + MDB_val k; + MDB_val v; + + uint64_t counter = 0; + + auto result = mdb_cursor_get(curr_cursor, &k, &v, MDB_FIRST); + + while(result==MDB_SUCCESS){ + result = mdb_cursor_get(curr_cursor, &k, &v, MDB_NEXT); + counter++; } + + + return counter; + } + + bool BlockchainLMDB::get_table_sizes( std::vector &table_sizes) const{ + check_open(); + + TXN_PREFIX_RDONLY(); + + RCURSOR(output_advanced); + RCURSOR(output_advanced_type); + RCURSOR(token_staked_sum); + RCURSOR(token_staked_sum_total); + RCURSOR(network_fee_sum); + RCURSOR(token_lock_expiry); + RCURSOR(safex_account); + RCURSOR(safex_offer); + RCURSOR(safex_feedback); + RCURSOR(safex_price_peg); + + table_sizes.push_back(get_size(m_cur_output_advanced)); + table_sizes.push_back(get_size(m_cur_output_advanced_type)); + table_sizes.push_back(get_size(m_cur_token_staked_sum)); + table_sizes.push_back(get_size(m_cur_token_staked_sum_total)); + table_sizes.push_back(get_size(m_cur_network_fee_sum)); + table_sizes.push_back(get_size(m_cur_token_lock_expiry)); + table_sizes.push_back(get_size(m_cur_safex_account)); + table_sizes.push_back(get_size(m_cur_safex_offer)); + table_sizes.push_back(get_size(m_cur_safex_feedback)); + table_sizes.push_back(get_size(m_cur_safex_price_peg)); + + TXN_POSTFIX_RDONLY(); + + return true; + } + + + + bool BlockchainLMDB::get_offer_stars_given(const crypto::hash offer_id, uint64_t &stars_received) const{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_feedback; + RCURSOR(safex_feedback) + cur_safex_feedback = m_cur_safex_feedback; + + + uint8_t temp[sizeof(uint64_t)+sizeof(SAFEX_FEEDBACK_DATA_MAX_SIZE)]; + + MDB_val_set(k, offer_id); + MDB_val_set(v, temp); + auto get_result = mdb_cursor_get(m_cur_safex_feedback, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + return false; } - result = mdb_cursor_get(c_old, &k, &v, MDB_NEXT); - if (result == MDB_NOTFOUND) { - txn.commit(); - break; + get_result = mdb_cursor_get(m_cur_safex_feedback, &k, &v, MDB_FIRST_DUP); + + if (get_result) + { + throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch rating for offer with id: ").append(offer_id.data), get_result).c_str())); } - else if (result) - throw0(DB_ERROR(lmdb_error("Failed to get a record from block_heights: ", result).c_str())); - bh.bh_hash = *(crypto::hash *)k.mv_data; - bh.bh_height = *(uint64_t *)v.mv_data; - result = mdb_cursor_put(c_cur, (MDB_val *)&zerokval, &nv, MDB_APPENDDUP); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to put a record into block_heightr: ", result).c_str())); - /* we delete the old records immediately, so the overall DB and mapsize should not grow. - * This is a little slower than just letting mdb_drop() delete it all at the end, but - * it saves a significant amount of disk space. - */ - result = mdb_cursor_del(c_old, 0); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete a record from block_heights: ", result).c_str())); - i++; - } - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); - /* Delete the old table */ - result = mdb_drop(txn, o_heights, 1); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete old block_heights table: ", result).c_str())); + stars_received = 0; + uint64_t feedbacks_count = 0; - RENAME_DB("block_heightr"); + while(get_result == MDB_SUCCESS){ - /* close and reopen to get old dbi slot back */ - mdb_dbi_close(m_env, m_block_heights); - lmdb_db_open(txn, "block_heights", MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED, m_block_heights, "Failed to open db handle for block_heights"); - mdb_set_dupsort(txn, m_block_heights, compare_hash32); - txn.commit(); + safex::safex_feedback_db_data sfx_feedback; + blobdata tmp{(char*)v.mv_data, v.mv_size}; + parse_and_validate_object_from_blob(tmp,sfx_feedback); + stars_received += sfx_feedback.stars_given; + feedbacks_count++; - } while(0); + get_result = mdb_cursor_get(cur_safex_feedback, &k, &v, MDB_NEXT_DUP); - /* old tables are k(height), v(value). - * new table is DUPFIXED, k(zeroval), v{height, values...}. - */ - do { - LOG_PRINT_L1("migrating block info:"); + } - MDB_dbi coins; - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); - result = mdb_dbi_open(txn, "block_coins", 0, &coins); - if (result == MDB_NOTFOUND) { - txn.abort(); - LOG_PRINT_L1(" block_info already migrated"); - break; + stars_received = (stars_received * COIN)/feedbacks_count; + + + TXN_POSTFIX_RDONLY(); + + return true; } - MDB_dbi diffs, hashes, sizes, timestamps; - mdb_block_info bi; - MDB_val_set(nv, bi); - - lmdb_db_open(txn, "block_diffs", 0, diffs, "Failed to open db handle for block_diffs"); - lmdb_db_open(txn, "block_hashes", 0, hashes, "Failed to open db handle for block_hashes"); - lmdb_db_open(txn, "block_sizes", 0, sizes, "Failed to open db handle for block_sizes"); - lmdb_db_open(txn, "block_timestamps", 0, timestamps, "Failed to open db handle for block_timestamps"); - MDB_cursor *c_cur, *c_coins, *c_diffs, *c_hashes, *c_sizes, *c_timestamps; - i = 0; - z = m_height; - while(1) { - MDB_val k, v; - if (!(i % 2000)) { - if (i) { - LOGIF(el::Level::Info) { - std::cout << i << " / " << z << " \r" << std::flush; - } - txn.commit(); - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); + + + bool BlockchainLMDB::get_account_data(const safex::account_username &username, std::vector &data) const { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_account; + RCURSOR(safex_account); + cur_safex_account = m_cur_safex_account; + + crypto::hash username_hash = username.hash(); + + uint8_t temp[SAFEX_ACCOUNT_DATA_MAX_SIZE + sizeof(crypto::public_key)]; + + MDB_val_set(k, username_hash); + MDB_val_set(v, temp); + auto get_result = mdb_cursor_get(cur_safex_account, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) { + //throw0(DB_ERROR(lmdb_error(std::string("DB error account not found: ").append(username.c_str()), get_result).c_str())); + return false; + } else if (get_result) { + throw0(DB_ERROR( + lmdb_error(std::string("DB error attempting to fetch account public key: ").append(username.c_str()), + get_result).c_str())); + } else if (get_result == MDB_SUCCESS) { + safex::create_account_result sfx_account; + const cryptonote::blobdata accblob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + cryptonote::parse_and_validate_from_blob(accblob, sfx_account); + + data = sfx_account.account_data; + } + + TXN_POSTFIX_RDONLY(); + + return true; + }; + + bool BlockchainLMDB::get_offer(const crypto::hash offer_id, safex::safex_offer &offer) const{ + + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_offer; + RCURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; + + uint64_t output_index{}; + uint64_t output_index_creation{}; + bool edited = false; + + uint8_t temp[SAFEX_OFFER_DATA_MAX_SIZE + sizeof(crypto::hash)]; + + MDB_val_set(k, offer_id); + MDB_val_set(v, temp); + auto get_result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + return false; } - result = mdb_cursor_open(txn, m_block_info, &c_cur); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_info: ", result).c_str())); - result = mdb_cursor_open(txn, coins, &c_coins); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_coins: ", result).c_str())); - result = mdb_cursor_open(txn, diffs, &c_diffs); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_diffs: ", result).c_str())); - result = mdb_cursor_open(txn, hashes, &c_hashes); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_hashes: ", result).c_str())); - result = mdb_cursor_open(txn, sizes, &c_sizes); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_coins: ", result).c_str())); - result = mdb_cursor_open(txn, timestamps, &c_timestamps); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for block_timestamps: ", result).c_str())); - if (!i) { - MDB_stat ms; - mdb_stat(txn, m_block_info, &ms); - i = ms.ms_entries; + else if (get_result) + { + throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch offer with id: ").append(offer_id.data), get_result).c_str())); } - } - result = mdb_cursor_get(c_coins, &k, &v, MDB_NEXT); - if (result == MDB_NOTFOUND) { - break; - } else if (result) - throw0(DB_ERROR(lmdb_error("Failed to get a record from block_coins: ", result).c_str())); - bi.bi_height = *(uint64_t *)k.mv_data; - bi.bi_coins = *(uint64_t *)v.mv_data; - result = mdb_cursor_get(c_diffs, &k, &v, MDB_NEXT); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to get a record from block_diffs: ", result).c_str())); - bi.bi_diff = *(uint64_t *)v.mv_data; - result = mdb_cursor_get(c_hashes, &k, &v, MDB_NEXT); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to get a record from block_hashes: ", result).c_str())); - bi.bi_hash = *(crypto::hash *)v.mv_data; - result = mdb_cursor_get(c_sizes, &k, &v, MDB_NEXT); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to get a record from block_sizes: ", result).c_str())); - if (v.mv_size == sizeof(uint32_t)) - bi.bi_size = *(uint32_t *)v.mv_data; - else - bi.bi_size = *(uint64_t *)v.mv_data; // this is a 32/64 compat bug in version 0 - result = mdb_cursor_get(c_timestamps, &k, &v, MDB_NEXT); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to get a record from block_timestamps: ", result).c_str())); - bi.bi_timestamp = *(uint64_t *)v.mv_data; - result = mdb_cursor_put(c_cur, (MDB_val *)&zerokval, &nv, MDB_APPENDDUP); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to put a record into block_info: ", result).c_str())); - result = mdb_cursor_del(c_coins, 0); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete a record from block_coins: ", result).c_str())); - result = mdb_cursor_del(c_diffs, 0); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete a record from block_diffs: ", result).c_str())); - result = mdb_cursor_del(c_hashes, 0); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete a record from block_hashes: ", result).c_str())); - result = mdb_cursor_del(c_sizes, 0); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete a record from block_sizes: ", result).c_str())); - result = mdb_cursor_del(c_timestamps, 0); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete a record from block_timestamps: ", result).c_str())); - i++; - } - mdb_cursor_close(c_timestamps); - mdb_cursor_close(c_sizes); - mdb_cursor_close(c_hashes); - mdb_cursor_close(c_diffs); - mdb_cursor_close(c_coins); - result = mdb_drop(txn, timestamps, 1); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete block_timestamps from the db: ", result).c_str())); - result = mdb_drop(txn, sizes, 1); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete block_sizes from the db: ", result).c_str())); - result = mdb_drop(txn, hashes, 1); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete block_hashes from the db: ", result).c_str())); - result = mdb_drop(txn, diffs, 1); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete block_diffs from the db: ", result).c_str())); - result = mdb_drop(txn, coins, 1); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete block_coins from the db: ", result).c_str())); - txn.commit(); - } while(0); + else if (get_result == MDB_SUCCESS) + { + safex::create_offer_result offer_result; + std::string tmp{(char*)v.mv_data, v.mv_size}; + parse_and_validate_object_from_blob(tmp,offer_result); - do { - LOG_PRINT_L1("migrating hf_versions:"); - MDB_dbi o_hfv; + offer.quantity = offer_result.quantity; - unsigned int flags; - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); - result = mdb_dbi_flags(txn, m_hf_versions, &flags); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to retrieve hf_versions flags: ", result).c_str())); - /* if the flags are what we expect, this table has already been migrated */ - if (flags & MDB_INTEGERKEY) { - txn.abort(); - LOG_PRINT_L1(" hf_versions already migrated"); - break; - } - /* the hf_versions table name is the same but the old version and new version - * have incompatible DB flags. Create a new table with the right flags. - */ - o_hfv = m_hf_versions; - lmdb_db_open(txn, "hf_versionr", MDB_INTEGERKEY | MDB_CREATE, m_hf_versions, "Failed to open db handle for hf_versionr"); + output_index = offer_result.output_id; + output_index_creation = offer_result.output_id_creation; + edited = offer_result.edited; + } - MDB_cursor *c_old, *c_cur; - i = 0; - z = m_height; - while(1) { - if (!(i % 2000)) { - if (i) { - LOGIF(el::Level::Info) { - std::cout << i << " / " << z << " \r" << std::flush; - } - txn.commit(); - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); + tx_out_type out_type = edited ? tx_out_type::out_safex_offer_update : tx_out_type::out_safex_offer; + uint64_t output_id; + if( !get_output_id(out_type, output_index, output_id)) + throw0(DB_ERROR("Output ID not found!")); + + MDB_cursor *cur_output_advanced; + RCURSOR(output_advanced); + cur_output_advanced = m_cur_output_advanced; + + //Get offer data + MDB_val_set(key, output_id); + blobdata blob; + MDB_val_set(value_blob, blob); + + output_advanced_data_t current = AUTO_VAL_INIT(current); + + get_result = mdb_cursor_get(cur_output_advanced, &key, &value_blob, MDB_SET); + + if (get_result == MDB_SUCCESS) + { + current = parse_output_advanced_data_from_mdb(value_blob); + + if( edited ){ + safex::edit_offer_data offer_result; + parse_and_validate_object_from_blob(current.data,offer_result); + + offer.description = offer_result.description; + offer.seller = std::string{offer_result.seller.begin(),offer_result.seller.end()}; + offer.price = offer_result.price; + offer.offer_id = offer_result.offer_id; + offer.active = offer_result.active; + offer.title = std::string{offer_result.title.begin(),offer_result.title.end()}; + offer.price_peg_id = offer_result.price_peg_id; + offer.price_peg_used = offer_result.price_peg_used; + offer.min_sfx_price = offer_result.min_sfx_price; + } + else { + safex::create_offer_data offer_result; + parse_and_validate_object_from_blob(current.data,offer_result); + + offer.description = offer_result.description; + offer.seller = std::string{offer_result.seller.begin(),offer_result.seller.end()}; + offer.price = offer_result.price; + offer.offer_id = offer_result.offer_id; + offer.active = offer_result.active; + offer.title = std::string{offer_result.title.begin(),offer_result.title.end()}; + offer.price_peg_id = offer_result.price_peg_id; + offer.price_peg_used = offer_result.price_peg_used; + offer.min_sfx_price = offer_result.min_sfx_price; + } + } - result = mdb_cursor_open(txn, m_hf_versions, &c_cur); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for spent_keyr: ", result).c_str())); - result = mdb_cursor_open(txn, o_hfv, &c_old); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for spent_keys: ", result).c_str())); - if (!i) { - MDB_stat ms; - mdb_stat(txn, m_hf_versions, &ms); - i = ms.ms_entries; + else if (get_result == MDB_NOTFOUND) + { + throw0(DB_ERROR(lmdb_error("Attemting to get offer from advanced output with current id " + std::to_string(output_id) + " but not found: ", get_result).c_str())); } + else + throw0(DB_ERROR(lmdb_error("DB error attempting to get advanced output data: ", get_result).c_str())); + + + uint64_t output_id_creation; + if(!get_output_id(tx_out_type::out_safex_offer, output_index_creation, output_id_creation)) + throw0(DB_ERROR("Output ID of offer creation not found!")); + //Get offer keys + MDB_val_set(k_creation, output_id_creation); + MDB_val_set(v_blob, blob); + + get_result = mdb_cursor_get(cur_output_advanced, &k_creation, &v_blob, MDB_SET); + + if (get_result == MDB_SUCCESS) + { + current = parse_output_advanced_data_from_mdb(v_blob); + safex::create_offer_data offer_result; + parse_and_validate_object_from_blob(current.data,offer_result); + + offer.seller_address = offer_result.seller_address; + offer.seller_private_view_key = offer_result.seller_private_view_key; } - result = mdb_cursor_get(c_old, &k, &v, MDB_NEXT); - if (result == MDB_NOTFOUND) { - txn.commit(); - break; + else if (get_result == MDB_NOTFOUND) + { + throw0(DB_ERROR(lmdb_error("Attemting to get offer from advanced output with current id " + std::to_string(output_index_creation) + " but not found: ", get_result).c_str())); } - else if (result) - throw0(DB_ERROR(lmdb_error("Failed to get a record from hf_versions: ", result).c_str())); - result = mdb_cursor_put(c_cur, &k, &v, MDB_APPEND); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to put a record into hf_versionr: ", result).c_str())); - result = mdb_cursor_del(c_old, 0); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete a record from hf_versions: ", result).c_str())); - i++; - } + else + throw0(DB_ERROR(lmdb_error("DB error attempting to get advanced output data: ", get_result).c_str())); - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); - /* Delete the old table */ - result = mdb_drop(txn, o_hfv, 1); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete old hf_versions table: ", result).c_str())); - RENAME_DB("hf_versionr"); - mdb_dbi_close(m_env, m_hf_versions); - lmdb_db_open(txn, "hf_versions", MDB_INTEGERKEY, m_hf_versions, "Failed to open db handle for hf_versions"); + TXN_POSTFIX_RDONLY(); - txn.commit(); - } while(0); + return true; + }; - do { - LOG_PRINT_L1("deleting old indices:"); + bool BlockchainLMDB::get_offer_seller(const crypto::hash offer_id, std::string &username) const{ - /* Delete all other tables, we're just going to recreate them */ - MDB_dbi dbi; - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); - result = mdb_dbi_open(txn, "tx_unlocks", 0, &dbi); - if (result == MDB_NOTFOUND) { - txn.abort(); - LOG_PRINT_L1(" old indices already deleted"); - break; + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_offer; + RCURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; + + + uint8_t temp[SAFEX_OFFER_DATA_MAX_SIZE + sizeof(crypto::hash)]; + + MDB_val_set(k, offer_id); + MDB_val_set(v, temp); + auto get_result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + //throw0(DB_ERROR(lmdb_error(std::string("DB error account not found: ").append(username.c_str()), get_result).c_str())); + return false; + } + else if (get_result) + { + throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch offer with id: ").append(offer_id.data), get_result).c_str())); + } + else if (get_result == MDB_SUCCESS) + { + safex::create_offer_result offer; + std::string tmp{(char*)v.mv_data, v.mv_size}; + parse_and_validate_object_from_blob(tmp,offer); + + username = std::string(offer.seller.begin(),offer.seller.end()); + } + + TXN_POSTFIX_RDONLY(); + + return true; + }; + + bool BlockchainLMDB::get_offer_price(const crypto::hash offer_id, uint64_t &price) const{ + + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_offer; + RCURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; + + + uint8_t temp[SAFEX_OFFER_DATA_MAX_SIZE + sizeof(crypto::hash)]; + + MDB_val_set(k, offer_id); + MDB_val_set(v, temp); + auto get_result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + //throw0(DB_ERROR(lmdb_error(std::string("DB error account not found: ").append(username.c_str()), get_result).c_str())); + return false; + } + else if (get_result) + { + throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch offer with id: ").append(offer_id.data), get_result).c_str())); + } + else if (get_result == MDB_SUCCESS) + { + safex::create_offer_result offer; + std::string tmp{(char*)v.mv_data, v.mv_size}; + parse_and_validate_object_from_blob(tmp,offer); + + price = offer.price; + } + + TXN_POSTFIX_RDONLY(); + + return true; } - txn.abort(); -#define DELETE_DB(x) do { \ - LOG_PRINT_L1(" " x ":"); \ - result = mdb_txn_begin(m_env, NULL, 0, txn); \ - if (result) \ - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); \ - result = mdb_dbi_open(txn, x, 0, &dbi); \ - if (!result) { \ - result = mdb_drop(txn, dbi, 1); \ - if (result) \ - throw0(DB_ERROR(lmdb_error("Failed to delete " x ": ", result).c_str())); \ - txn.commit(); \ - } } while(0) - - DELETE_DB("tx_heights"); - DELETE_DB("output_txs"); - DELETE_DB("output_indices"); - DELETE_DB("output_keys"); - DELETE_DB("spent_keys"); - DELETE_DB("output_amounts"); - DELETE_DB("tx_outputs"); - DELETE_DB("tx_unlocks"); - - /* reopen new DBs with correct flags */ - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); - lmdb_db_open(txn, LMDB_OUTPUT_TXS, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_output_txs, "Failed to open db handle for m_output_txs"); - mdb_set_dupsort(txn, m_output_txs, compare_uint64); - lmdb_db_open(txn, LMDB_TX_OUTPUTS, MDB_INTEGERKEY | MDB_CREATE, m_tx_outputs, "Failed to open db handle for m_tx_outputs"); - lmdb_db_open(txn, LMDB_SPENT_KEYS, MDB_INTEGERKEY | MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED, m_spent_keys, "Failed to open db handle for m_spent_keys"); - mdb_set_dupsort(txn, m_spent_keys, compare_hash32); - lmdb_db_open(txn, LMDB_OUTPUT_AMOUNTS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_output_amounts, "Failed to open db handle for m_output_amounts"); - mdb_set_dupsort(txn, m_output_amounts, compare_uint64); - lmdb_db_open(txn, LMDB_OUTPUT_TOKEN_AMOUNTS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_DUPFIXED | MDB_CREATE, m_output_token_amounts, "Failed to open db handle for m_output_token_amounts"); - mdb_set_dupsort(txn, m_output_token_amounts, compare_uint64); - txn.commit(); - } while(0); - - do { - LOG_PRINT_L1("migrating txs and outputs:"); - - unsigned int flags; - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); - result = mdb_dbi_flags(txn, m_txs, &flags); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to retrieve txs flags: ", result).c_str())); - /* if the flags are what we expect, this table has already been migrated */ - if (flags & MDB_INTEGERKEY) { - txn.abort(); - LOG_PRINT_L1(" txs already migrated"); - break; + bool BlockchainLMDB::get_offer_quantity(const crypto::hash offer_id, uint64_t &quantity) const{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_offer; + RCURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; + + + uint8_t temp[SAFEX_OFFER_DATA_MAX_SIZE + sizeof(crypto::hash)]; + + MDB_val_set(k, offer_id); + MDB_val_set(v, temp); + auto get_result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + //throw0(DB_ERROR(lmdb_error(std::string("DB error account not found: ").append(username.c_str()), get_result).c_str())); + return false; + } + else if (get_result) + { + throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch offer with id: ").append(offer_id.data), get_result).c_str())); + } + else if (get_result == MDB_SUCCESS) + { + safex::create_offer_result offer; + std::string tmp{(char*)v.mv_data, v.mv_size}; + parse_and_validate_object_from_blob(tmp,offer); + + quantity = offer.quantity; + } + + TXN_POSTFIX_RDONLY(); + + return true; } - MDB_dbi o_txs; - blobdata bd; - block b; - MDB_val hk; + bool BlockchainLMDB::get_offer_active_status(const crypto::hash offer_id, bool &active) const{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); - o_txs = m_txs; - mdb_set_compare(txn, o_txs, compare_hash32); - lmdb_db_open(txn, "txr", MDB_INTEGERKEY | MDB_CREATE, m_txs, "Failed to open db handle for txr"); + TXN_PREFIX_RDONLY(); - txn.commit(); + MDB_cursor *cur_safex_offer; + RCURSOR(safex_offer) + cur_safex_offer = m_cur_safex_offer; - MDB_cursor *c_blocks, *c_txs, *c_props, *c_cur; - i = 0; - z = m_height; - hk.mv_size = sizeof(crypto::hash); - set_batch_transactions(true); - batch_start(1000); - txn.m_txn = m_write_txn->m_txn; - m_height = 0; + uint8_t temp[SAFEX_OFFER_DATA_MAX_SIZE + sizeof(crypto::hash)]; - while(1) { - if (!(i % 1000)) { - if (i) { - LOGIF(el::Level::Info) { - std::cout << i << " / " << z << " \r" << std::flush; - } - MDB_val_set(pk, "txblk"); - MDB_val_set(pv, m_height); - result = mdb_cursor_put(c_props, &pk, &pv, 0); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to update txblk property: ", result).c_str())); - txn.commit(); - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); - m_write_txn->m_txn = txn.m_txn; - m_write_batch_txn->m_txn = txn.m_txn; - memset(&m_wcursors, 0, sizeof(m_wcursors)); + MDB_val_set(k, offer_id); + MDB_val_set(v, temp); + auto get_result = mdb_cursor_get(cur_safex_offer, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + //throw0(DB_ERROR(lmdb_error(std::string("DB error account not found: ").append(username.c_str()), get_result).c_str())); + return false; } - result = mdb_cursor_open(txn, m_blocks, &c_blocks); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for blocks: ", result).c_str())); - result = mdb_cursor_open(txn, m_properties, &c_props); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for properties: ", result).c_str())); - result = mdb_cursor_open(txn, o_txs, &c_txs); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to open a cursor for txs: ", result).c_str())); - if (!i) { - MDB_stat ms; - mdb_stat(txn, m_txs, &ms); - i = ms.ms_entries; - if (i) { - MDB_val_set(pk, "txblk"); - result = mdb_cursor_get(c_props, &pk, &k, MDB_SET); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to get a record from properties: ", result).c_str())); - m_height = *(uint64_t *)k.mv_data; - } + else if (get_result) + { + throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch offer with id: ").append(offer_id.data), get_result).c_str())); } - if (i) { - result = mdb_cursor_get(c_blocks, &k, &v, MDB_SET); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to get a record from blocks: ", result).c_str())); + else if (get_result == MDB_SUCCESS) + { + safex::create_offer_result offer; + std::string tmp{(char*)v.mv_data, v.mv_size}; + parse_and_validate_object_from_blob(tmp,offer); + + active = offer.active; } + + TXN_POSTFIX_RDONLY(); + + return true; + } + + bool BlockchainLMDB::get_safex_feedbacks( std::vector &safex_feedbacks, const crypto::hash& offer_id) const{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_feedback; + RCURSOR(safex_feedback) + cur_safex_feedback = m_cur_safex_feedback; + + + uint8_t temp[sizeof(uint64_t)+sizeof(SAFEX_FEEDBACK_DATA_MAX_SIZE)]; + + MDB_val_set(k, offer_id); + MDB_val_set(v, temp); + auto get_result = mdb_cursor_get(cur_safex_feedback, &k, &v, MDB_SET); + if (get_result == MDB_NOTFOUND) + { + return false; } - result = mdb_cursor_get(c_blocks, &k, &v, MDB_NEXT); - if (result == MDB_NOTFOUND) { - MDB_val_set(pk, "txblk"); - result = mdb_cursor_get(c_props, &pk, &v, MDB_SET); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to get a record from props: ", result).c_str())); - result = mdb_cursor_del(c_props, 0); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete a record from props: ", result).c_str())); - batch_stop(); - break; - } else if (result) - throw0(DB_ERROR(lmdb_error("Failed to get a record from blocks: ", result).c_str())); - - bd.assign(reinterpret_cast(v.mv_data), v.mv_size); - if (!parse_and_validate_block_from_blob(bd, b)) - throw0(DB_ERROR("Failed to parse block from blob retrieved from the db")); - - add_transaction(null_hash, b.miner_tx); - for (unsigned int j = 0; j(v.mv_data), v.mv_size); - if (!parse_and_validate_tx_from_blob(bd, tx)) - throw0(DB_ERROR("Failed to parse tx from blob retrieved from the db")); - add_transaction(null_hash, tx, &b.tx_hashes[j]); - result = mdb_cursor_del(c_txs, 0); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to get record from txs: ", result).c_str())); + + MDB_val_set(k2, offer_id); + MDB_val_set(v2, temp); + get_result = mdb_cursor_get(cur_safex_feedback, &k2, &v2, MDB_FIRST_DUP); + + while (get_result == MDB_SUCCESS) + { + safex::safex_feedback_db_data sfx_feedback; + const cryptonote::blobdata tmp((uint8_t*)v2.mv_data, (uint8_t*)v2.mv_data+v2.mv_size); + parse_and_validate_object_from_blob(tmp,sfx_feedback); + + std::string comment{sfx_feedback.comment.begin(),sfx_feedback.comment.end()}; + + get_result = mdb_cursor_get(cur_safex_feedback, &k2, &v2, MDB_NEXT_DUP); + safex_feedbacks.emplace_back(sfx_feedback.stars_given, comment, offer_id); } - i++; - m_height = i; + + TXN_POSTFIX_RDONLY(); + + return true; } + + + bool BlockchainLMDB::get_safex_price_pegs(std::vector &safex_price_pegs, + const std::string ¤cy) const { + + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + TXN_PREFIX_RDONLY(); + + MDB_cursor *cur_safex_price_peg; + RCURSOR(safex_price_peg) + cur_safex_price_peg = m_cur_safex_price_peg; + + crypto::hash price_peg_id{}; + uint8_t temp[sizeof(safex::create_price_peg_result)]; + + MDB_val_set(k, price_peg_id); + MDB_val_set(v, temp); + + bool currency_search = (currency != ""); + + auto result = mdb_cursor_get(cur_safex_price_peg, &k, &v, MDB_FIRST); + + while (result == MDB_SUCCESS) + { + safex::create_price_peg_result sfx_price_peg_result; + safex::safex_price_peg sfx_price_peg; + const cryptonote::blobdata price_peg_blob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + + if(!cryptonote::parse_and_validate_from_blob(price_peg_blob, sfx_price_peg_result)){ + result = mdb_cursor_get(cur_safex_price_peg, &k, &v, MDB_NEXT); + continue; + } + + if(currency_search){ + std::string db_currency{sfx_price_peg_result.currency.begin(),sfx_price_peg_result.currency.end()}; + if(currency == db_currency) + safex_price_pegs.emplace_back(sfx_price_peg_result.title,sfx_price_peg_result.creator,sfx_price_peg_result.currency,sfx_price_peg_result.description,sfx_price_peg_result.price_peg_id,sfx_price_peg_result.rate); + } + else + safex_price_pegs.emplace_back(sfx_price_peg_result.title,sfx_price_peg_result.creator,sfx_price_peg_result.currency,sfx_price_peg_result.description,sfx_price_peg_result.price_peg_id,sfx_price_peg_result.rate); + + result = mdb_cursor_get(cur_safex_price_peg, &k, &v, MDB_NEXT); + } + + TXN_POSTFIX_RDONLY(); + + return true; } - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); - result = mdb_drop(txn, o_txs, 1); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to delete txs from the db: ", result).c_str())); - RENAME_DB("txr"); - mdb_dbi_close(m_env, m_txs); + bool BlockchainLMDB::get_safex_price_peg( const crypto::hash& price_peg_id,safex::safex_price_peg &safex_price_peg) const { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); - lmdb_db_open(txn, "txs", MDB_INTEGERKEY, m_txs, "Failed to open db handle for txs"); + TXN_PREFIX_RDONLY(); - txn.commit(); - } while(0); + MDB_cursor *cur_safex_price_peg; + RCURSOR(safex_price_peg) + cur_safex_price_peg = m_cur_safex_price_peg; - uint32_t version = 1; - v.mv_data = (void *)&version; - v.mv_size = sizeof(version); - MDB_val_copy vk("version"); - result = mdb_txn_begin(m_env, NULL, 0, txn); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to create a transaction for the db: ", result).c_str())); - result = mdb_put(txn, m_properties, &vk, &v, 0); - if (result) - throw0(DB_ERROR(lmdb_error("Failed to update version for the db: ", result).c_str())); - txn.commit(); -} + uint8_t temp[sizeof(safex::create_price_peg_result)]; -void BlockchainLMDB::migrate(const uint32_t oldversion) -{ - switch(oldversion) { - case 0: - migrate_0_1(); /* FALLTHRU */ - default: - ; - } -} + MDB_val_set(k, price_peg_id); + MDB_val_set(v, temp); -bool BlockchainLMDB::is_valid_transaction_output_type(const txout_target_v &txout) -{ - // check if valid output type, txout_to_key, txout_token_to_key - if ((txout.type() == typeid(txout_to_key)) - || (txout.type() == typeid(txout_token_to_key)) - ) - { - return true; - } + auto result = mdb_cursor_get(cur_safex_price_peg, &k, &v, MDB_SET); + + if (result == MDB_SUCCESS) + { + safex::create_price_peg_result sfx_price_peg_result; + safex::safex_price_peg sfx_price_peg; + const cryptonote::blobdata price_peg_blob((uint8_t*)v.mv_data, (uint8_t*)v.mv_data+v.mv_size); + + if(!cryptonote::parse_and_validate_from_blob(price_peg_blob, sfx_price_peg_result)){ + throw0(DB_ERROR(lmdb_error(std::string("Error parsing price peg from DB with id: ").append(price_peg_id.data), result).c_str())); + } + + safex_price_peg = safex::safex_price_peg{sfx_price_peg_result.title,sfx_price_peg_result.creator,sfx_price_peg_result.currency, + sfx_price_peg_result.description,sfx_price_peg_result.price_peg_id,sfx_price_peg_result.rate}; + + + + } + else if (result == MDB_NOTFOUND) + { + return false; + } + else if (result) + { + throw0(DB_ERROR(lmdb_error(std::string("DB error attempting to fetch price peg with id: ").append(price_peg_id.data), result).c_str())); + } + + TXN_POSTFIX_RDONLY(); + + return true; + } - return false; -} } // namespace cryptonote diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index 2ac7d70d5..c7f37f4e9 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -36,6 +36,11 @@ #include #include +#include +#include +#include +#include +#include #define ENABLE_AUTO_RESIZE @@ -62,6 +67,18 @@ typedef struct mdb_txn_cursors MDB_cursor *m_txc_txpool_blob; MDB_cursor *m_txc_hf_versions; + + MDB_cursor *m_txc_output_advanced; + MDB_cursor *m_txc_output_advanced_type; + MDB_cursor *m_txc_token_locked_sum; + MDB_cursor *m_txc_token_locked_sum_total; + MDB_cursor *m_txc_network_fee_sum; + MDB_cursor *m_txc_token_lock_expiry; + MDB_cursor *m_txc_safex_account; + MDB_cursor *m_txc_safex_offer; + MDB_cursor *m_txc_safex_feedback; + MDB_cursor *m_txc_safex_price_peg; + } mdb_txn_cursors; #define m_cur_blocks m_cursors->m_txc_blocks @@ -77,6 +94,16 @@ typedef struct mdb_txn_cursors #define m_cur_txpool_meta m_cursors->m_txc_txpool_meta #define m_cur_txpool_blob m_cursors->m_txc_txpool_blob #define m_cur_hf_versions m_cursors->m_txc_hf_versions +#define m_cur_output_advanced m_cursors->m_txc_output_advanced +#define m_cur_output_advanced_type m_cursors->m_txc_output_advanced_type +#define m_cur_token_staked_sum m_cursors->m_txc_token_locked_sum +#define m_cur_token_staked_sum_total m_cursors->m_txc_token_locked_sum_total +#define m_cur_network_fee_sum m_cursors->m_txc_network_fee_sum +#define m_cur_token_lock_expiry m_cursors->m_txc_token_lock_expiry +#define m_cur_safex_account m_cursors->m_txc_safex_account +#define m_cur_safex_offer m_cursors->m_txc_safex_offer +#define m_cur_safex_feedback m_cursors->m_txc_safex_feedback +#define m_cur_safex_price_peg m_cursors->m_txc_safex_price_peg typedef struct mdb_rflags { @@ -94,6 +121,16 @@ typedef struct mdb_rflags bool m_rf_txpool_meta; bool m_rf_txpool_blob; bool m_rf_hf_versions; + bool m_rf_output_advanced; + bool m_rf_output_advanced_type; + bool m_rf_token_staked_sum; + bool m_rf_token_staked_sum_total; + bool m_rf_network_fee_sum; + bool m_rf_token_lock_expiry; + bool m_rf_safex_account; + bool m_rf_safex_offer; + bool m_rf_safex_feedback; + bool m_rf_safex_price_peg; } mdb_rflags; typedef struct mdb_threadinfo @@ -162,134 +199,170 @@ struct mdb_txn_safe class BlockchainLMDB : public BlockchainDB { public: - BlockchainLMDB(bool batch_transactions=false); + BlockchainLMDB(bool batch_transactions=false, cryptonote::network_type nettype = cryptonote::network_type::MAINNET); ~BlockchainLMDB(); - virtual void open(const std::string& filename, const int mdb_flags=0); + virtual void open(const std::string& filename, const int mdb_flags=0) override; - virtual void close(); + virtual void close() override; - virtual void sync(); + virtual void sync() override; - virtual void safesyncmode(const bool onoff); + virtual void safesyncmode(const bool onoff) override; - virtual void reset(); + virtual void reset() override; - virtual std::vector get_filenames() const; + virtual std::vector get_filenames() const override; - virtual std::string get_db_name() const; + virtual std::string get_db_name() const override; - virtual bool lock(); + virtual bool lock() override; - virtual void unlock(); + virtual void unlock() override; - virtual bool block_exists(const crypto::hash& h, uint64_t *height = NULL) const; + virtual bool block_exists(const crypto::hash& h, uint64_t *height = NULL) const override; - virtual uint64_t get_block_height(const crypto::hash& h) const; + virtual uint64_t get_block_height(const crypto::hash& h) const override; - virtual block_header get_block_header(const crypto::hash& h) const; + virtual block_header get_block_header(const crypto::hash& h) const override; - virtual cryptonote::blobdata get_block_blob(const crypto::hash& h) const; + virtual cryptonote::blobdata get_block_blob(const crypto::hash& h) const override; - virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t& height) const; + virtual cryptonote::blobdata get_block_blob_from_height(const uint64_t& height) const override; - virtual uint64_t get_block_timestamp(const uint64_t& height) const; + virtual uint64_t get_block_timestamp(const uint64_t& height) const override; - virtual uint64_t get_top_block_timestamp() const; + virtual uint64_t get_top_block_timestamp() const override; - virtual size_t get_block_size(const uint64_t& height) const; + virtual size_t get_block_size(const uint64_t& height) const override; - virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const; + virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const override; - virtual difficulty_type get_block_difficulty(const uint64_t& height) const; + virtual difficulty_type get_block_difficulty(const uint64_t& height) const override; - virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const; + virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const override; - virtual uint64_t get_block_already_migrated_tokens(const uint64_t& height) const; + virtual uint64_t get_block_already_migrated_tokens(const uint64_t& height) const override; - virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const; + virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const override; - virtual std::vector get_blocks_range(const uint64_t& h1, const uint64_t& h2) const; + virtual std::vector get_blocks_range(const uint64_t& h1, const uint64_t& h2) const override; - virtual std::vector get_hashes_range(const uint64_t& h1, const uint64_t& h2) const; + virtual std::vector get_hashes_range(const uint64_t& h1, const uint64_t& h2) const override; - virtual crypto::hash top_block_hash() const; + virtual crypto::hash top_block_hash() const override; - virtual block get_top_block() const; + virtual block get_top_block() const override; - virtual uint64_t height() const; + virtual uint64_t height() const override; virtual bool getpwned(output_data_t& dat) const; - virtual bool tx_exists(const crypto::hash& h) const; - virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const; - - virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const; - - virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const; + virtual bool tx_exists(const crypto::hash& h) const override; + virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const override; - virtual uint64_t get_tx_count() const; + virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const override; - virtual std::vector get_tx_list(const std::vector& hlist) const; + virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override; - virtual uint64_t get_tx_block_height(const crypto::hash& h) const; + virtual uint64_t get_tx_count() const override; - virtual uint64_t get_num_outputs(const uint64_t& amount, const tx_out_type output_type) const; + virtual std::vector get_tx_list(const std::vector& hlist) const override; - virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type); - virtual output_data_t get_output_key(const uint64_t& global_index) const; - virtual void get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs, const tx_out_type output_type, bool allow_partial = false); - - virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const; - virtual void get_output_tx_and_index_from_global(const std::vector &global_indices, - std::vector &tx_out_indices) const; + virtual uint64_t get_tx_block_height(const crypto::hash& h) const override; - virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const; - virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices, const tx_out_type output_type) const; + virtual uint64_t get_num_outputs(const uint64_t& amount, const tx_out_type output_type) const override; + virtual uint64_t get_num_outputs(const tx_out_type output_type) const override; - virtual std::vector get_tx_amount_output_indices(const uint64_t tx_id) const; + virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const override; + virtual void get_amount_output_key(const uint64_t &amount, const std::vector &offsets, + std::vector &outputs, const tx_out_type output_type, + bool allow_partial = false) const override; - virtual bool has_key_image(const crypto::key_image& img) const; + virtual void get_advanced_output_key(const std::vector &output_indexes, + std::vector &outputs, const tx_out_type output_type, + bool allow_partial = false) const override; - virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t& meta); - virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& meta); - virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const; - virtual bool txpool_has_tx(const crypto::hash &txid) const; - virtual void remove_txpool_tx(const crypto::hash& txid); - virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const; - virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const; - virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const; - virtual bool for_all_txpool_txes(std::function f, bool include_blob = false, bool include_unrelayed_txes = true) const; + virtual output_advanced_data_t get_output_advanced_data(const tx_out_type output_type, const uint64_t output_index) const override; + virtual bool get_output_id(const tx_out_type output_type, const uint64_t output_index, uint64_t& output_id) const override; - virtual bool for_all_key_images(std::function) const; - virtual bool for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::function) const; - virtual bool for_all_transactions(std::function) const; - virtual bool for_all_outputs(std::function f, const tx_out_type output_type) const; - virtual bool for_all_outputs(uint64_t amount, const std::function &f, const tx_out_type output_type) const; + virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& output_id) const override; + virtual void get_output_tx_and_index_from_global(const std::vector &global_indices, + std::vector &tx_out_indices) const; - virtual uint64_t add_block( const block& blk + virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const override; + virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices, const tx_out_type output_type) const override; + + + virtual std::vector get_tx_amount_output_indices(const uint64_t tx_id) const override; + + virtual bool has_key_image(const crypto::key_image& img) const override; + + virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t& meta) override; + virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& meta) override; + virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const override; + virtual bool txpool_has_tx(const crypto::hash &txid) const override; + virtual void remove_txpool_tx(const crypto::hash& txid) override; + virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const override; + virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const override; + virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const override; + virtual bool for_all_txpool_txes(std::function f, bool include_blob = false, bool include_unrelayed_txes = true) const override; + + virtual bool for_all_key_images(std::function) const override; + virtual bool for_blocks_range(const uint64_t& h1, const uint64_t& h2, std::function) const override; + virtual bool for_all_transactions(std::function) const override; + virtual bool for_all_outputs(std::function f, const tx_out_type output_type) const override; + virtual bool for_all_outputs(uint64_t amount, const std::function &f, const tx_out_type output_type) const override; + virtual bool for_all_advanced_outputs(std::function f, const tx_out_type output_type) const override; + + virtual uint64_t get_current_staked_token_sum() const override; + virtual uint64_t get_staked_token_sum_for_interval(const uint64_t interval) const override; + virtual uint64_t get_network_fee_sum_for_interval(const uint64_t interval) const override; + virtual std::vector get_token_stake_expiry_outputs(const uint64_t block_height) const override; + virtual bool get_interval_interest_map(const uint64_t start_interval, const uint64_t end_interval, safex::map_interval_interest &map) const override; + virtual uint64_t calculate_staked_token_interest_for_output(const txin_to_script &txin, const uint64_t unlock_height) const override; + virtual bool get_account_key(const safex::account_username &username, crypto::public_key &pkey) const override; + virtual bool get_account_data(const safex::account_username &username, std::vector &data) const override; + virtual bool get_offer(const crypto::hash offer_id, safex::safex_offer &offer) const override; + virtual bool get_offer_seller(const crypto::hash offer_id, std::string &username) const override; + virtual bool get_offer_price(const crypto::hash offer_id, uint64_t &price) const override; + virtual bool get_offer_quantity(const crypto::hash offer_id, uint64_t &quantity) const override; + virtual bool get_offer_active_status(const crypto::hash offer_id, bool &active) const override; + + virtual bool get_safex_accounts( std::vector> &safex_accounts) const override; + virtual bool get_safex_offers(std::vector &offers) const override; + virtual bool get_safex_offer_height( crypto::hash &offer_id, uint64_t& height) const override; + virtual bool get_offer_stars_given(const crypto::hash offer_id, uint64_t &stars_received) const override; + virtual bool get_safex_feedbacks( std::vector &safex_feedbacks, const crypto::hash& offer_id) const override; + virtual bool get_safex_price_pegs( std::vector &safex_price_pegs, const std::string& currency) const override; + virtual bool get_safex_price_peg( const crypto::hash& price_peg_id,safex::safex_price_peg &safex_price_peg) const override; + + virtual bool get_table_sizes( std::vector &table_sizes) const override; + + + virtual uint64_t add_block( const block& blk , const size_t& block_size , const difficulty_type& cumulative_difficulty , const uint64_t& coins_generated , const uint64_t& tokens_migrated , const std::vector& txs - ); + ) override; - virtual void set_batch_transactions(bool batch_transactions); - virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0); + virtual void set_batch_transactions(bool batch_transactions) override; + virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) override; virtual void batch_commit(); - virtual void batch_stop(); - virtual void batch_abort(); + virtual void batch_stop() override; + virtual void batch_abort() override; - virtual void block_txn_start(bool readonly); - virtual void block_txn_stop(); - virtual void block_txn_abort(); + virtual void block_txn_start(bool readonly) override; + virtual void block_txn_stop() override; + virtual void block_txn_abort() override; virtual bool block_rtxn_start(MDB_txn **mtxn, mdb_txn_cursors **mcur) const; virtual void block_rtxn_stop() const; - virtual void pop_block(block& blk, std::vector& txs); + virtual void pop_block(block& blk, std::vector& txs) override; - virtual bool can_thread_bulk_indices() const { return true; } + virtual bool can_thread_bulk_indices() const override { return true; } /** * @brief return a histogram of outputs on the blockchain @@ -300,7 +373,7 @@ class BlockchainLMDB : public BlockchainDB * * @return a set of amount/instances */ - std::map> get_output_histogram(const std::vector &amounts, bool unlocked, uint64_t recent_cutoff, const tx_out_type output_type) const; + std::map> get_output_histogram(const std::vector &amounts, bool unlocked, uint64_t recent_cutoff, const tx_out_type output_type) const override; private: void do_resize(uint64_t size_increase=0); @@ -315,40 +388,49 @@ class BlockchainLMDB : public BlockchainDB , const uint64_t& coins_generated , const uint64_t& tokens_migrated , const crypto::hash& block_hash - ); + ) override; + + virtual void remove_block() override; - virtual void remove_block(); + virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) override; - virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash); + virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) override; - virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx); + virtual void remove_unstake_token(const crypto::hash& tx_hash, const transaction& tx) override; virtual uint64_t add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment - ); + ) override; virtual void add_tx_amount_output_indices(const uint64_t tx_id, const std::vector& amount_output_indices - ); + ) override; void remove_tx_outputs(const uint64_t tx_id, const transaction& tx); void remove_output(const uint64_t amount, const uint64_t& out_index, tx_out_type output_type); - virtual void add_spent_key(const crypto::key_image& k_image); + virtual void add_spent_key(const crypto::key_image& k_image) override; - virtual void remove_spent_key(const crypto::key_image& k_image); + virtual void remove_spent_key(const crypto::key_image& k_image) override; + + /** + * Process command input for db related changes + * + * @param txin advanced input with command + */ + virtual void process_command_input(const cryptonote::txin_to_script &txin) override; uint64_t num_outputs() const; // Hard fork - virtual void set_hard_fork_version(uint64_t height, uint8_t version); - virtual uint8_t get_hard_fork_version(uint64_t height) const; - virtual void check_hard_fork_info(); - virtual void drop_hard_fork_info(); + virtual void set_hard_fork_version(uint64_t height, uint8_t version) override; + virtual uint8_t get_hard_fork_version(uint64_t height) const override; + virtual void check_hard_fork_info() override; + virtual void drop_hard_fork_info() override; /** * @brief convert a tx output to a blob for storage @@ -370,21 +452,260 @@ class BlockchainLMDB : public BlockchainDB void check_open() const; - virtual bool is_read_only() const; + virtual bool is_read_only() const override; // fix up anything that may be wrong due to past bugs - virtual void fixup(); + virtual void fixup() override; // migrate from older DB version to current void migrate(const uint32_t oldversion); - // migrate from DB version 0 to 1 - void migrate_0_1(); - void cleanup_batch(); virtual bool is_valid_transaction_output_type(const txout_target_v &txout); + uint64_t add_token_output(const tx_out& tx_output, const uint64_t unlock_time, const uint64_t num_outputs); + + uint64_t add_cash_output(const tx_out& tx_output, const uint64_t unlock_time, const uint64_t num_outputs); + + uint64_t add_advanced_output(const tx_out& tx_output, const uint64_t unlock_time, const uint64_t output_id, const tx_out_type out_type); + + void process_advanced_output(const tx_out& tx_output, const uint64_t output_id, const uint8_t output_type); + + void process_advanced_input(const cryptonote::txin_to_script &txin); + + + uint64_t update_current_staked_token_sum(const uint64_t delta, int sign); + uint64_t update_network_fee_sum_for_interval(const uint64_t interval_starting_block, const uint64_t collected_fee) override; + + /** + * Add new account to database + * + * @param username safex account username + * @param pkey safex account public key + * @param data account desitription data + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + * + */ + void add_safex_account(const safex::account_username &username, const blobdata &blob); + + /** + * Edit account data + * + * @param username safex account username + * @param new_data account desitription data + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void edit_safex_account(const safex::account_username &username, const std::vector &new_data); + + /** + * Remove safex account from database + * + * @param username safex account username + * @param output_id id of the account creation output + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void remove_safex_account(const safex::account_username &username, const uint64_t& output_id); + + /** + * Add new offer to database + * + * @param offer_id safex offer id + * @param blob offer data + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + * + */ + void add_safex_offer(const crypto::hash &offer_id, const blobdata &blob); + + + /** + * Edit offer in database + * + * @param offer_id safex offer id + * @param blob offer data + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + * + */ + void edit_safex_offer(const crypto::hash &offer_id, bool active, uint64_t price, uint64_t quantity); + + /** + * Remove safex offer from database + * + * @param offer_id safex offer id + * @param output_id id of the offer creation output + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void remove_safex_offer(const crypto::hash &offer_id, const uint64_t& output_id); + + /** + * Remove safex offer update from database + * + * @param offer_id safex offer id + * @param output_id id of the offer edit output + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void remove_safex_offer_update(const crypto::hash &offer_id, const uint64_t& output_id); + + /** + * Remove safex price_peg from database + * + * @param price_peg_id safex price_peg id + * @param output_id id of the price peg creation output + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void remove_safex_price_peg(const crypto::hash &price_peg_id, const uint64_t& output_id); + + /** + * Remove safex price_peg update from database + * + * @param price_peg_id safex price_peg id + * @param output_id id of the price peg update output + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void remove_safex_price_peg_update(const crypto::hash &price_peg_id, const uint64_t& output_id); + /** + * Create purchase in database + * + * @param purchase safex purchase data + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + * + */ + void create_safex_purchase(const safex::safex_purchase& purchase); + + /** + * Create price peg in database + * + * @param price_peg_id Unique ID of price peg + * @param blob safex price peg data + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + * + */ + void add_safex_price_peg(const crypto::hash& price_peg_id, const blobdata &blob); + + /** + * Update price peg in database + * + * @param price_peg_id ID of price peg to be updated + * @param sfx_price_peg_update_result safex price peg data + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + * + */ + void update_safex_price_peg(const crypto::hash& price_peg_id, const safex::update_price_peg_result& sfx_price_peg_update_result); + /** + * Create feedback in database + * + * @param feedback safex feedback data + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + * + */ + void create_safex_feedback(const safex::safex_feedback& feedback); + /** + * Remove advanced output from DB + * + * @param out_type Type of the advanced output + * @param Output index of the advanced output to be deleted + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + * + */ + void remove_advanced_output(const tx_out_type& out_type, const uint64_t& output_index); + + /** + * Remove last safex account update from database + * + * @param username safex account username + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void remove_safex_account_update(const safex::account_username &username, const uint64_t& output_id); + + /** + * Remove last staked tokens from database + * + * @param token_amount amount of tokens sent + * @param Output id of the stake token output to be deleted + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void remove_staked_token(const uint64_t token_amount, const uint64_t& output_id); + + /** + * Remove safex purchase advanced output and update offer quantity from database + * + * @param offer_id ID of purchased offer to update + * @param quantity Quantity of product purchased + * @param output_id Output ID of the purchase output to be deleted + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void remove_safex_purchase(const crypto::hash& offer_id, const uint64_t quantity, const uint64_t& output_id); + + /** + * Remove safex feedback advanced output and update offer quantity from database + * + * @param offer_id ID of offer where feedback is given + * @param feedback_output_data Data of feedback to be removed + * @param output_id Output ID of the feedback output to be deleted + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void remove_safex_feedback(const crypto::hash& offer_id, safex::create_feedback_data& feedback_output_data, const uint64_t& output_id); + + /** + * Remove network fee output and update total network fee from database + * + * @param offer_id ID of offer where feedback is given + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void remove_network_fee_output(const uint64_t& amount, const uint64_t& output_id); + + /** + * Restore safex account data by getting it from advanced output table + * + * @param sfx_account safex account that needs to be updated + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void restore_safex_account_data(safex::create_account_result& sfx_account); + + /** + * Restore safex offer data by getting it from advanced output table + * + * @param sfx_offer safex offer that needs to be updated + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void restore_safex_offer_data(safex::create_offer_result& sfx_offer); + + /** + * Restore safex price_peg data by getting it from advanced output table + * + * @param sfx_price_peg safex price_peg that needs to be updated + * + * If any of this cannot be done, it throw the corresponding subclass of DB_EXCEPTION + */ + void restore_safex_price_peg_data(safex::create_price_peg_result& sfx_price_peg); + +protected: + + uint64_t update_staked_token_for_interval(const uint64_t interval, const uint64_t staked_tokens) override; + + bool remove_staked_token_for_interval(const uint64_t interval) override; + private: MDB_env* m_env; @@ -411,6 +732,18 @@ class BlockchainLMDB : public BlockchainDB MDB_dbi m_properties; + //Safex related + MDB_dbi m_output_advanced; + MDB_dbi m_output_advanced_type; + MDB_dbi m_token_staked_sum; + MDB_dbi m_token_staked_sum_total; + MDB_dbi m_network_fee_sum; + MDB_dbi m_token_lock_expiry; + MDB_dbi m_safex_account; + MDB_dbi m_safex_offer; + MDB_dbi m_safex_feedback; + MDB_dbi m_safex_price_peg; + mutable uint64_t m_cum_size; // used in batch size estimation mutable unsigned int m_cum_count; std::string m_folder; @@ -424,6 +757,7 @@ class BlockchainLMDB : public BlockchainDB mdb_txn_cursors m_wcursors; mutable boost::thread_specific_ptr m_tinfo; + #if defined(__arm__) // force a value so it can compile with 32-bit ARM constexpr static uint64_t DEFAULT_MAPSIZE = 1LL << 31; diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp index e2bc055e4..c1acdd72c 100644 --- a/src/blockchain_utilities/blockchain_export.cpp +++ b/src/blockchain_utilities/blockchain_export.cpp @@ -155,7 +155,9 @@ int main(int argc, char* argv[]) tx_memory_pool m_mempool(*core_storage); core_storage = new Blockchain(m_mempool); - BlockchainDB* db = new_db(db_type); + cryptonote::network_type nettype = opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET; + + BlockchainDB* db = new_db(db_type, nettype); if (db == NULL) { LOG_ERROR("Attempted to use non-existent database type: " << db_type); @@ -177,7 +179,7 @@ int main(int argc, char* argv[]) LOG_PRINT_L0("Error opening database: " << e.what()); return 1; } - r = core_storage->init(db, opt_testnet ? cryptonote::TESTNET : opt_stagenet ? cryptonote::STAGENET : cryptonote::MAINNET); + r = core_storage->init(db, nettype); CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize source blockchain storage"); LOG_PRINT_L0("Source blockchain storage initialized OK"); diff --git a/src/blockchain_utilities/blockchain_usage.cpp b/src/blockchain_utilities/blockchain_usage.cpp index a0a492392..4790e836a 100644 --- a/src/blockchain_utilities/blockchain_usage.cpp +++ b/src/blockchain_utilities/blockchain_usage.cpp @@ -172,7 +172,7 @@ int main(int argc, char* argv[]) std::unique_ptr core_storage; tx_memory_pool m_mempool(*core_storage); core_storage.reset(new Blockchain(m_mempool)); - BlockchainDB* db = new_db(db_type); + BlockchainDB* db = new_db(db_type, net_type); if (db == NULL) { LOG_ERROR("Attempted to use non-existent database type: " << db_type); diff --git a/src/checkpoints/checkpoints.cpp b/src/checkpoints/checkpoints.cpp index e4ed8867d..a16d255f1 100644 --- a/src/checkpoints/checkpoints.cpp +++ b/src/checkpoints/checkpoints.cpp @@ -165,12 +165,15 @@ namespace cryptonote if (nettype == TESTNET) { ADD_CHECKPOINT(1, "753e1454ebc44ffb18d7b390f7393a66ce7f3a8aaaf1e4e857af9df4e80d5784"); + ADD_CHECKPOINT(100000,"94b27cd801da1cbbe886e5ac8e98d3147a555923050a526f0d4754ef31416d54"); return true; } if (nettype == STAGENET) { + ADD_CHECKPOINT(1, "fb37e7df933669b58e3d946fd555c3dd3b830156b15ba25a6d8bc300c4ada10a"); + ADD_CHECKPOINT(90000, "8252181f588b5760fbc5dee91eaeaf304878ae385413aa0eef600cd8210019e9"); return true; } diff --git a/src/common/util.cpp b/src/common/util.cpp index 41486f3d4..4df0c7f38 100644 --- a/src/common/util.cpp +++ b/src/common/util.cpp @@ -752,9 +752,9 @@ std::string get_nix_version_display_string() return true; } - bool is_whole_coin_amount(uint64_t amount) + bool is_whole_token_amount(uint64_t token_amount) { - return amount % SAFEX_CASH_COIN == 0; + return token_amount % SAFEX_TOKEN == 0; } } diff --git a/src/common/util.h b/src/common/util.h index ecd365e4c..7f7c50caf 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -213,5 +213,5 @@ namespace tools bool sha256sum(const uint8_t *data, size_t len, crypto::hash &hash); bool sha256sum(const std::string &filename, crypto::hash &hash); - bool is_whole_coin_amount(uint64_t amount); + bool is_whole_token_amount(uint64_t amount); } diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index f08e1d12f..419f44110 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -251,11 +251,18 @@ namespace crypto { #endif buf.h = prefix_hash; buf.key = pub; + try_again: random_scalar(k); + if (((const uint32_t*)(&k))[7] == 0) // we don't want tiny numbers here + goto try_again; ge_scalarmult_base(&tmp3, &k); ge_p3_tobytes(&buf.comm, &tmp3); hash_to_scalar(&buf, sizeof(s_comm), sig.c); + if (!sc_isnonzero((const unsigned char*)sig.c.data)) + goto try_again; sc_mulsub(&sig.r, &sig.c, &unwrap(sec), &k); + if (!sc_isnonzero((const unsigned char*)sig.r.data)) + goto try_again; } bool crypto_ops::check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) { @@ -269,11 +276,14 @@ namespace crypto { if (ge_frombytes_vartime(&tmp3, &pub) != 0) { return false; } - if (sc_check(&sig.c) != 0 || sc_check(&sig.r) != 0) { + if (sc_check(&sig.c) != 0 || sc_check(&sig.r) != 0 || !sc_isnonzero(&sig.c)) { return false; } ge_double_scalarmult_base_vartime(&tmp2, &sig.c, &tmp3, &sig.r); ge_tobytes(&buf.comm, &tmp2); + static const ec_point infinity = {{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}; + if (memcmp(&buf.comm, &infinity, 32) == 0) + return false; hash_to_scalar(&buf, sizeof(s_comm), c); sc_sub(&c, &c, &sig.c); return sc_isnonzero(&c) == 0; diff --git a/src/cryptonote_basic/cryptonote_basic.h b/src/cryptonote_basic/cryptonote_basic.h index ae2a3207d..6f902b33a 100644 --- a/src/cryptonote_basic/cryptonote_basic.h +++ b/src/cryptonote_basic/cryptonote_basic.h @@ -52,6 +52,7 @@ #include "tx_extra.h" #include "ringct/rctTypes.h" #include "device/device.hpp" +#include "safex/safex_core.h" namespace cryptonote { @@ -62,12 +63,15 @@ namespace cryptonote struct txout_to_script { - std::vector keys; - std::vector script; + crypto::public_key key; + std::vector data; //Local output data and state + uint8_t output_type{0}; + BEGIN_SERIALIZE_OBJECT() - FIELD(keys) - FIELD(script) + VARINT_FIELD(output_type) + FIELD(key) + FIELD(data) END_SERIALIZE() }; @@ -111,7 +115,7 @@ namespace cryptonote boost::optional operator()(const cryptonote::txout_to_script &txout) const { - return {}; + return txout.key; } }; @@ -129,14 +133,21 @@ namespace cryptonote struct txin_to_script { - crypto::hash prev; - size_t prevout; - std::vector sigset; + std::vector key_offsets = AUTO_VAL_INIT(key_offsets); //offsets of previous inputs that should be spent + crypto::key_image k_image = AUTO_VAL_INIT(k_image); // double spending protection, only owner of previous txout_to_script can use it + uint64_t amount = 0; //Safex Cash amount as input + uint64_t token_amount = 0; //Safex Token amount as input + safex::command_t command_type = safex::command_t::nop; //Command type, to ease processing of input + std::vector script; //Contains Safex protocol layer commands executed on txout_to_script state + BEGIN_SERIALIZE_OBJECT() - FIELD(prev) - VARINT_FIELD(prevout) - FIELD(sigset) + VARINT_FIELD(amount) + VARINT_FIELD(token_amount) + VARINT_FIELD(*(reinterpret_cast(&command_type))) + FIELD(key_offsets) + FIELD(k_image) + FIELD(script) END_SERIALIZE() }; @@ -209,6 +220,18 @@ namespace cryptonote out_cash = 0, out_token = 1, out_bitcoin_migration = 2, + out_advanced = 10, //generic advanced utxo + out_staked_token = 11, + out_network_fee = 12, //safex cash collected as network trading fee + out_safex_account = 15, //safex account output + out_safex_account_update = 16, //safex account output update + out_safex_offer = 20, + out_safex_offer_update = 21, + out_safex_purchase = 30, + out_safex_feedback_token = 40, + out_safex_feedback = 41, + out_safex_price_peg = 50, + out_safex_price_peg_update = 51, out_invalid = 100 }; @@ -238,7 +261,7 @@ namespace cryptonote boost::optional operator()(const cryptonote::txin_to_script &txin) const { - return {}; + return txin.k_image; } boost::optional operator()(const cryptonote::txin_gen &txin) const @@ -273,7 +296,7 @@ namespace cryptonote boost::optional &> operator()(const cryptonote::txin_to_script &txin) const { - return {}; + return txin.key_offsets; } boost::optional &> operator()(const cryptonote::txin_gen &txin) const @@ -282,7 +305,7 @@ namespace cryptonote } }; - //For easier retrieval of input/output cash or token amount from variant + //For easier retrieval of input mixed cash or token amount from variant class amount_visitor : public boost::static_visitor> { public: @@ -308,7 +331,7 @@ namespace cryptonote boost::optional operator()(const cryptonote::txin_to_script &txin) const { - return {}; + return txin.amount; } boost::optional operator()(const cryptonote::txin_gen &txin) const @@ -317,25 +340,146 @@ namespace cryptonote } }; - //Gets cash or token amount, depending of tx input type - template - inline uint64_t get_tx_input_amount(const TxInput &txin) + + //For easier retrieval of input token amount from variant + class token_amount_visitor : public boost::static_visitor> { + public: + boost::optional operator()(const cryptonote::txin_to_key &txin) const + { + return 0; + } + + boost::optional operator()(const cryptonote::txin_token_migration &txin) const + { + return txin.token_amount; + } + + boost::optional operator()(const cryptonote::txin_token_to_key &txin) const + { + return txin.token_amount; + } + + boost::optional operator()(const cryptonote::txin_to_scripthash &txin) const + { + return 0; + } + + boost::optional operator()(const cryptonote::txin_to_script &txin) const + { + return txin.token_amount; + } + + boost::optional operator()(const cryptonote::txin_gen &txin) const + { + return 0; + } + }; + + //For easier retrieval of input cash amount from variant + class cash_amount_visitor : public boost::static_visitor> + { + public: + boost::optional operator()(const cryptonote::txin_to_key &txin) const + { + return txin.amount; + } + + boost::optional operator()(const cryptonote::txin_token_migration &txin) const + { + return 0; + } + + boost::optional operator()(const cryptonote::txin_token_to_key &txin) const + { + return 0; + } + + boost::optional operator()(const cryptonote::txin_to_scripthash &txin) const + { + return 0; + } + + boost::optional operator()(const cryptonote::txin_to_script &txin) const + { + return txin.amount; + } + + boost::optional operator()(const cryptonote::txin_gen &txin) const + { + return 0; + } + }; + + //Gets cash or token amount, what is relevant for that input + template + inline uint64_t get_tx_input_value_amount(const TXInput &txin) { + return 0; + } + + + template <> + inline uint64_t get_tx_input_value_amount(const txin_to_key &txin) { return txin.amount; } - template<> - inline uint64_t get_tx_input_amount(const txin_token_to_key &txin) - { + template <> + inline uint64_t get_tx_input_value_amount(const txin_token_to_key &txin) { + return txin.token_amount; + } + + template <> + inline uint64_t get_tx_input_value_amount(const txin_token_migration &txin) { + return txin.token_amount; + } + + //Gets cash input amount, depending of tx input type + template + inline uint64_t get_tx_input_cash_amount(const TXInput &txin) { + return 0; + } + + template <> + inline uint64_t get_tx_input_cash_amount(const txin_v &txin) { + return *boost::apply_visitor(cash_amount_visitor(), txin); + } + + template <> + inline uint64_t get_tx_input_cash_amount(const txin_to_key &txin) { + return txin.amount; + } + + template <> + inline uint64_t get_tx_input_cash_amount(const txin_to_script &txin) { + return txin.amount; + } + + //Gets token input amount, depending of tx input type + template + inline uint64_t get_tx_input_token_amount(const TXInput &txin) { + return 0; + } + + template <> + inline uint64_t get_tx_input_token_amount(const txin_v &txin) { + return *boost::apply_visitor(token_amount_visitor(), txin); + } + + template <> + inline uint64_t get_tx_input_token_amount(const txin_token_to_key &txin) { return txin.token_amount; } - template<> - inline uint64_t get_tx_input_amount(const txin_token_migration &txin) - { + template <> + inline uint64_t get_tx_input_token_amount(const txin_token_migration &txin) { return txin.token_amount; } + template <> + inline uint64_t get_tx_input_token_amount(const txin_to_script &txin) { + return txin.token_amount; + } + /** * @brief check if transaction output is of valid type * @@ -348,6 +492,7 @@ namespace cryptonote // check if valid output type, txout_to_key, txout_token_to_key if ((txout.type() == typeid(txout_to_key)) || (txout.type() == typeid(txout_token_to_key)) + || (txout.type() == typeid(txout_to_script)) ) { return true; @@ -364,21 +509,22 @@ namespace cryptonote * other checks for specialized types * */ - inline bool is_valid_transaction_input_type(const txin_v &txin) + inline bool is_valid_transaction_input_type(const txin_v &txin, const int tx_version) { // check if valid input type , txin_token_migration, txin_token_to_key - if ((txin.type() == typeid(txin_to_key)) - || (txin.type() == typeid(txin_token_to_key)) - || (txin.type() == typeid(txin_token_migration)) - ) + if (tx_version == 1 && ((txin.type() == typeid(txin_to_key)) || (txin.type() == typeid(txin_token_to_key)) || (txin.type() == typeid(txin_token_migration)))) { return true; } + else if (tx_version == 2 && ((txin.type() == typeid(txin_to_key)) || (txin.type() == typeid(txin_token_to_key)) + || (txin.type() == typeid(txin_to_script)))) { + return true; + } return false; } - //For easier retrieval of input/output cash or token amount from variant + //Gives output type for output that is referenced from intput class tx_output_type_visitor : public boost::static_visitor { public: @@ -404,7 +550,31 @@ namespace cryptonote tx_out_type operator()(const cryptonote::txin_to_script &txin) const { - return tx_out_type::out_invalid; + switch (txin.command_type) { + case safex::command_t::donate_network_fee: + case safex::command_t::simple_purchase: + return tx_out_type::out_cash; + case safex::command_t::token_stake: + return tx_out_type::out_token; + case safex::command_t::token_unstake: + return tx_out_type::out_staked_token; + case safex::command_t::create_account: + return tx_out_type::out_token; + case safex::command_t::edit_account: + case safex::command_t::create_offer: + case safex::command_t::create_price_peg: + return tx_out_type::out_safex_account; + case safex::command_t::edit_offer: + return tx_out_type::out_safex_offer; + case safex::command_t::update_price_peg: + return tx_out_type::out_safex_price_peg; + case safex::command_t::create_feedback: + return tx_out_type::out_safex_feedback_token; + case safex::command_t::nop: + default: + return tx_out_type::out_invalid; + } + } tx_out_type operator()(const cryptonote::txin_gen &txin) const @@ -419,6 +589,8 @@ namespace cryptonote return tx_out_type::out_cash; } else if (txout.type() == typeid(txout_token_to_key)) { return tx_out_type::out_token; + } else if (txout.type() == typeid(txout_to_script)) { + return static_cast((boost::get(txout)).output_type); } else { return tx_out_type::out_invalid; } @@ -432,7 +604,7 @@ namespace cryptonote * @param transaction input varible */ template - inline tx_out_type get_tx_out_type_from_input(const TxInput &txin) + inline tx_out_type derive_tx_out_type_from_input(const TxInput &txin) { if (typeid(txin) == typeid(txin_to_key)) { return tx_out_type::out_cash; @@ -491,6 +663,37 @@ namespace cryptonote }; + + inline tx_out_type get_tx_type(const std::vector& vout) + { + tx_out_type tx_type = tx_out_type::out_invalid; + bool token_seen = false; + bool advanced_seen = false; + for(auto it: vout){ + auto curr_tx_out_type = get_tx_out_type(it.target); + switch(curr_tx_out_type){ + case tx_out_type::out_cash: + if(!token_seen && !advanced_seen) + tx_type = tx_out_type::out_cash; + break; + case tx_out_type::out_token: + if(!advanced_seen){ + token_seen = true; + tx_type = tx_out_type::out_token; + } + break; + default: + if(curr_tx_out_type >= tx_out_type::out_advanced && curr_tx_out_type < tx_out_type::out_invalid + && ((tx_type < curr_tx_out_type && tx_type != tx_out_type::out_safex_purchase) || curr_tx_out_type == tx_out_type::out_safex_purchase + || tx_type == tx_out_type::out_invalid)){ + tx_type = get_tx_out_type(it.target); + advanced_seen = true; + } + } + } + return tx_type; + } + class transaction_prefix { @@ -506,7 +709,7 @@ namespace cryptonote BEGIN_SERIALIZE() VARINT_FIELD(version) - if(version == 0 || CURRENT_TRANSACTION_VERSION < version) return false; + if(version == 0 || version > MAX_SUPPORTED_TX_VERSION) return false; VARINT_FIELD(unlock_time) FIELD(vin) FIELD(vout) @@ -526,7 +729,7 @@ namespace cryptonote public: std::vector > signatures; //count signatures always the same as inputs count - rct::rctSig rct_signatures; + rct::rctSig rct_signatures; //for RingCT and Booletproofs // hash cash mutable crypto::hash hash; @@ -551,58 +754,34 @@ namespace cryptonote } FIELDS(*static_cast(this)) - - if (version == 1) + ar.tag("signatures"); + ar.begin_array(); + PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures); + bool signatures_not_expected = signatures.empty(); + if (!signatures_not_expected && vin.size() != signatures.size()) + return false; + + for (size_t i = 0; i < vin.size(); ++i) { - ar.tag("signatures"); - ar.begin_array(); - PREPARE_CUSTOM_VECTOR_SERIALIZATION(vin.size(), signatures); - bool signatures_not_expected = signatures.empty(); - if (!signatures_not_expected && vin.size() != signatures.size()) - return false; - - for (size_t i = 0; i < vin.size(); ++i) + size_t signature_size = get_signature_size(vin[i]); + if (signatures_not_expected) { - size_t signature_size = get_signature_size(vin[i]); - if (signatures_not_expected) - { - if (0 == signature_size) - continue; - else - return false; - } - - PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]); - if (signature_size != signatures[i].size()) + if (0 == signature_size) + continue; + else return false; + } - FIELDS(signatures[i]); + PREPARE_CUSTOM_VECTOR_SERIALIZATION(signature_size, signatures[i]); + if (signature_size != signatures[i].size()) + return false; - if (vin.size() - i > 1) - ar.delimit_array(); - } - ar.end_array(); - } - else - { - ar.tag("rct_signatures"); - if (!vin.empty()) - { - ar.begin_object(); - bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size()); - if (!r || !ar.stream().good()) return false; - ar.end_object(); - if (rct_signatures.type != rct::RCTTypeNull) - { - ar.tag("rctsig_prunable"); - ar.begin_object(); - r = rct_signatures.p.serialize_rctsig_prunable(ar, rct_signatures.type, vin.size(), vout.size(), - vin.size() > 0 && vin[0].type() == typeid(txin_to_key) ? boost::get(vin[0]).key_offsets.size() - 1 : 0); - if (!r || !ar.stream().good()) return false; - ar.end_object(); - } - } + FIELDS(signatures[i]); + + if (vin.size() - i > 1) + ar.delimit_array(); } + ar.end_array(); END_SERIALIZE() template class Archive> @@ -610,20 +789,6 @@ namespace cryptonote { FIELDS(*static_cast(this)) - if (version == 1) - { - } - else - { - ar.tag("rct_signatures"); - if (!vin.empty()) - { - ar.begin_object(); - bool r = rct_signatures.serialize_rctsig_base(ar, vin.size(), vout.size()); - if (!r || !ar.stream().good()) return false; - ar.end_object(); - } - } return true; } @@ -673,7 +838,7 @@ namespace cryptonote struct txin_signature_size_visitor : public boost::static_visitor { size_t operator()(const txin_gen& txin) const{return 0;} - size_t operator()(const txin_to_script& txin) const{return 0;} + size_t operator()(const txin_to_script& txin) const{return txin.key_offsets.size();} size_t operator()(const txin_to_scripthash& txin) const{return 0;} size_t operator()(const txin_to_key& txin) const {return txin.key_offsets.size();} size_t operator()(const txin_token_migration& txin) const {return 1;} diff --git a/src/cryptonote_basic/cryptonote_boost_serialization.h b/src/cryptonote_basic/cryptonote_boost_serialization.h index 78dd45cba..465615dc0 100644 --- a/src/cryptonote_basic/cryptonote_boost_serialization.h +++ b/src/cryptonote_basic/cryptonote_boost_serialization.h @@ -93,8 +93,9 @@ namespace boost template inline void serialize(Archive &a, cryptonote::txout_to_script &x, const boost::serialization::version_type ver) { - a & x.keys; - a & x.script; + a & x.output_type; + a & x.key; + a & x.data; } @@ -125,9 +126,11 @@ namespace boost template inline void serialize(Archive &a, cryptonote::txin_to_script &x, const boost::serialization::version_type ver) { - a & x.prev; - a & x.prevout; - a & x.sigset; + a & x.key_offsets; + a & x.k_image; + a & x.amount; + a & x.token_amount; + a & x.script; } template @@ -190,16 +193,7 @@ namespace boost a & x.vin; a & x.vout; a & x.extra; - if (x.version == 1) - { - a & x.signatures; - } - else - { - a & (rct::rctSigBase&)x.rct_signatures; - if (x.rct_signatures.type != rct::RCTTypeNull) - a & x.rct_signatures.p; - } + a & x.signatures; } template diff --git a/src/cryptonote_basic/cryptonote_format_utils.cpp b/src/cryptonote_basic/cryptonote_format_utils.cpp index 54a6ee8fe..3477883cd 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.cpp +++ b/src/cryptonote_basic/cryptonote_format_utils.cpp @@ -42,6 +42,7 @@ using namespace epee; #include "crypto/crypto.h" #include "crypto/hash.h" #include "ringct/rctSigs.h" +#include "safex/command.h" #undef SAFEX_DEFAULT_LOG_CATEGORY #define SAFEX_DEFAULT_LOG_CATEGORY "cn" @@ -127,35 +128,16 @@ namespace cryptonote //--------------------------------------------------------------- bool expand_transaction_1(transaction &tx, bool base_only) { - if (tx.version >= 2 && !is_coinbase(tx)) - { - rct::rctSig &rv = tx.rct_signatures; - if (rv.outPk.size() != tx.vout.size()) - { - LOG_PRINT_L1("Failed to parse transaction from blob, bad outPk size in tx " << get_transaction_hash(tx)); - return false; - } - for (size_t n = 0; n < tx.rct_signatures.outPk.size(); ++n) - rv.outPk[n].dest = rct::pk2rct(boost::get(tx.vout[n].target).key); - - if (!base_only) - { - const bool bulletproof = rv.type == rct::RCTTypeFullBulletproof || rv.type == rct::RCTTypeSimpleBulletproof; - if (bulletproof) - { - if (rv.p.bulletproofs.size() != tx.vout.size()) - { - LOG_PRINT_L1("Failed to parse transaction from blob, bad bulletproofs size in tx " << get_transaction_hash(tx)); - return false; - } - for (size_t n = 0; n < rv.outPk.size(); ++n) - { - rv.p.bulletproofs[n].V.resize(1); - rv.p.bulletproofs[n].V[0] = rv.outPk[n].mask; - } - } - } - } + return true; + } + //--------------------------------------------------------------- + bool parse_and_validate_byte_array_from_blob(const blobdata& bytes_blob, std::vector &data) + { + std::stringstream ss; + ss << bytes_blob; + binary_archive ba(ss); + bool r = ::serialization::serialize(ba, data); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse byte array from blob"); return true; } //--------------------------------------------------------------- @@ -198,6 +180,16 @@ namespace cryptonote return true; } //--------------------------------------------------------------- + bool parse_and_validate_txout_to_script_from_blob(const blobdata& tx_blob, txout_to_script& txout) + { + std::stringstream ss; + ss << tx_blob; + binary_archive ba(ss); + bool r = ::serialization::serialize(ba, txout); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse txout_to_script from blob"); + return true; + } + //--------------------------------------------------------------- bool generate_key_image_helper(const account_keys& ack, const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev) { crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation); @@ -213,7 +205,7 @@ namespace cryptonote additional_recv_derivations.push_back(additional_recv_derivation); } - boost::optional subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index,hwdev); + boost::optional subaddr_recv_info = is_out_to_acc_precomp(subaddresses, out_key, recv_derivation, additional_recv_derivations, real_output_index, hwdev); CHECK_AND_ASSERT_MES(subaddr_recv_info, false, "key image helper: given output pubkey doesn't seem to belong to this address"); return generate_key_image_helper_precomp(ack, out_key, subaddr_recv_info->derivation, real_output_index, subaddr_recv_info->index, in_ephemeral, ki, hwdev); @@ -321,21 +313,16 @@ namespace cryptonote //--------------------------------------------------------------- bool get_tx_fee(const transaction& tx, uint64_t & fee) { - if (tx.version > 1) - { - fee = tx.rct_signatures.txnFee; - return true; - } uint64_t amount_in = 0; uint64_t amount_out = 0; + for(auto& in: tx.vin) { - if (in.type() != typeid(txin_to_key)) - { - continue; //skip non safex cash inputs when calculating fee - } - amount_in += boost::get(in).amount; + auto cash_amount_opt = boost::apply_visitor(cash_amount_visitor(), in); + if (!cash_amount_opt) continue; + amount_in += *cash_amount_opt; } + for(auto& o: tx.vout) amount_out += o.amount; @@ -457,7 +444,7 @@ namespace cryptonote return migration_pub_keys.data; } - crypto::public_key get_migration_pub_key_from_extra(const std::vector& tx_extra, const int index) + crypto::public_key get_migration_pub_key_from_extra(const std::vector& tx_extra, const int index) { return get_migration_pub_keys_from_extra(tx_extra)[index]; } @@ -579,16 +566,13 @@ namespace cryptonote return true; } //--------------------------------------------------------------- - bool get_inputs_money_amount(const transaction& tx, uint64_t& money) + bool get_inputs_cash_amount(const transaction &tx, uint64_t &money) { money = 0; for(const auto& in: tx.vin) { - if (in.type() == typeid(const txin_to_key)) { - uint64_t amount = *boost::apply_visitor(amount_visitor(), in); + uint64_t amount = *boost::apply_visitor(cash_amount_visitor(), in); money += amount; - } - } return true; } @@ -598,11 +582,8 @@ namespace cryptonote tokens = 0; for(const auto& in: tx.vin) { - if ((in.type() == typeid(const txin_token_to_key)) || (in.type() == typeid(const txin_token_migration))) { - uint64_t amount = *boost::apply_visitor(amount_visitor(), in); - tokens += amount; - } - + uint64_t token_amount = *boost::apply_visitor(token_amount_visitor(), in); + tokens += token_amount; } return true; } @@ -620,6 +601,74 @@ namespace cryptonote return migrated_tokens; } //--------------------------------------------------------------- + int64_t get_token_staked_amount(const transaction &tx) + { + int64_t staked_tokens = 0; + //count unstaked tokens + for (const auto &vin: tx.vin) + { + if (vin.type() == typeid(txin_to_script)) + { + const txin_to_script& in = boost::get(vin); + if (in.command_type == safex::command_t::token_unstake) { + staked_tokens -= in.token_amount; + } + } + } + + //count staked tokens + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_staked_token) + { + const txout_to_script& out = boost::get(vout.target); + if (out.output_type == static_cast(tx_out_type::out_staked_token)) { + staked_tokens += vout.token_amount; + } + } + } + + + return staked_tokens; + } + //--------------------------------------------------------------- + uint64_t get_collected_network_fee_amount(const transaction &tx) + { + uint64_t network_fee = 0; + + //count collected fee + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_network_fee) + { + const txout_to_script& out = boost::get(vout.target); + if (out.output_type == static_cast(tx_out_type::out_network_fee)) { + network_fee += vout.amount; + } + } + } + + return network_fee; + } + //--------------------------------------------------------------- + uint64_t get_network_distributed_fee_amount(const transaction &tx) + { + uint64_t network_fee = 0; + //count distributed network fee + for (const auto &vin: tx.vin) + { + if (vin.type() == typeid(txin_to_script)) + { + const txin_to_script& in = boost::get(vin); + if (in.command_type == safex::command_t::token_unstake) { + network_fee += in.amount; + } + } + } + + return network_fee; + } + //--------------------------------------------------------------- uint64_t get_block_height(const block& b) { CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, 0, "wrong miner tx in block: " << get_block_hash(b) << ", b.miner_tx.vin.size() != 1"); @@ -631,34 +680,53 @@ namespace cryptonote { for(const auto& in: tx.vin) { - CHECK_AND_ASSERT_MES((in.type() == typeid(txin_to_key)) || (in.type() == typeid(txin_token_migration)) - || (in.type() == typeid(txin_token_to_key)), false, "wrong variant type: " - << in.type().name() << ", expected " << typeid(txin_to_key).name() - << ", in transaction id=" << get_transaction_hash(tx)); - + if (tx.version == 1) { + CHECK_AND_ASSERT_MES((in.type() == typeid(txin_to_key)) + || (in.type() == typeid(txin_token_migration)) || (in.type() == typeid(txin_token_to_key)), + false, "wrong variant type: " << in.type().name() << ", expected " << typeid(txin_to_key).name() << ", in transaction id=" << get_transaction_hash(tx)); + } else if (tx.version == 2) { + CHECK_AND_ASSERT_MES((in.type() == typeid(txin_to_script)) || (in.type() == typeid(txin_to_key)) + || (in.type() == typeid(txin_token_migration)) || (in.type() == typeid(txin_token_to_key)), + false, "wrong variant type: " << in.type().name() << ", expected " << typeid(txin_to_key).name() + << " or " << typeid(txin_token_to_key).name() << " or " << typeid(txin_token_migration).name() + << " or " << typeid(txin_to_script).name() << ", in transaction id=" << get_transaction_hash(tx)); + } } return true; } //----------------------------------------------------------------------------------------------- - bool check_outs_valid(const transaction& tx) - { - for(const tx_out& out: tx.vout) - { - CHECK_AND_ASSERT_MES((out.target.type() == typeid(txout_to_key) || - (out.target.type() == typeid(txout_token_to_key))), false, "wrong variant type: " - << out.target.type().name() << ", expected " << typeid(txout_to_key).name() << " or " << typeid(txout_token_to_key).name() - << ", in transaction id=" << get_transaction_hash(tx)); + bool check_outs_valid(const transaction &tx) { + for (const tx_out &out: tx.vout) { - if (tx.version == 1) - { - CHECK_AND_NO_ASSERT_MES(0 < out.amount || 0 < out.token_amount , false, "zero amount output in transaction id=" << get_transaction_hash(tx)); - } + if (tx.version == 1) { + CHECK_AND_ASSERT_MES(((out.target.type() == typeid(txout_to_key)) || (out.target.type() == typeid(txout_token_to_key))), + false, "wrong variant type: " << out.target.type().name() << ", expected " << typeid(txout_to_key).name() + << " or " << typeid(txout_token_to_key).name() << ", in transaction id=" << get_transaction_hash(tx)); + } else if (tx.version == 2) { + CHECK_AND_ASSERT_MES(((out.target.type() == typeid(txout_to_key)) || + (out.target.type() == typeid(txout_token_to_key)) || + (out.target.type() == typeid(txout_to_script))), + false, "wrong variant type for advanced transaction: " << out.target.type().name() << ", expected " << typeid(txout_to_key).name() + << " or " << typeid(txout_token_to_key).name() << " or " << typeid(txout_to_script).name() << ", in transaction id=" + << get_transaction_hash(tx)); - const crypto::public_key &pkey = *boost::apply_visitor(destination_public_key_visitor(), out.target); - if(!check_key(pkey)) - return false; - } - return true; + } + + + CHECK_AND_NO_ASSERT_MES((0 < out.amount || 0 < out.token_amount || (out.target.type() == typeid(txout_to_script))), false, + "zero amount output in transaction id=" << get_transaction_hash(tx)); + + + + + auto pkey_opt = boost::apply_visitor(destination_public_key_visitor(), out.target); + if (!pkey_opt) + return false; + + if (!check_key(*pkey_opt)) + return false; + } + return true; } //----------------------------------------------------------------------------------------------- bool check_money_overflow(const transaction& tx) @@ -668,54 +736,53 @@ namespace cryptonote //--------------------------------------------------------------- bool check_inputs_overflow(const transaction& tx) { - uint64_t money = 0; - uint64_t tokens = 0; + uint64_t total_cash = 0; + uint64_t total_tokens = 0; for(const auto& in: tx.vin) { - uint64_t amount = *boost::apply_visitor(amount_visitor(), in); + uint64_t cash_amount = *boost::apply_visitor(cash_amount_visitor(), in); + uint64_t token_amount = *boost::apply_visitor(token_amount_visitor(), in); - if (in.type() == typeid(const txin_to_key)) { - if(money > amount + money) - return false; - money += amount; - } else if ((in.type() == typeid(const txin_token_migration)) - || (in.type() == typeid(const txin_token_to_key))) { - if(tokens > amount + tokens) - return false; - if(amount >= 100000000*SAFEX_TOKEN) - return false; - tokens += amount; - } + if(total_cash > cash_amount + total_cash) + return false; + + if(total_tokens > token_amount + total_tokens) + return false; + if(token_amount >= 100000000*SAFEX_TOKEN) + return false; + + total_cash += cash_amount; + total_tokens += token_amount; } + return true; } //--------------------------------------------------------------- bool check_outs_overflow(const transaction& tx) { - uint64_t cash_amount = 0; - uint64_t token_amount = 0; - + uint64_t total_cash = 0; + uint64_t total_tokens = 0; for(const auto& o: tx.vout) { - if(cash_amount > o.amount + cash_amount) + if(total_cash > o.amount + total_cash) return false; - cash_amount += o.amount; + total_cash += o.amount; - if(token_amount > o.token_amount + token_amount) + if(total_tokens > o.token_amount + total_tokens) return false; if(o.token_amount >= 100000000*SAFEX_TOKEN) return false; - token_amount += o.token_amount; + total_tokens += o.token_amount; } return true; } //--------------------------------------------------------------- - uint64_t get_outs_money_amount(const transaction& tx) + uint64_t get_outs_cash_amount(const transaction &tx) { - uint64_t outputs_amount = 0; + uint64_t outputs_cash = 0; for(const auto& o: tx.vout) - outputs_amount += o.amount; - return outputs_amount; + outputs_cash += o.amount; + return outputs_cash; } //--------------------------------------------------------------- uint64_t get_outs_token_amount(const transaction& tx) @@ -758,6 +825,39 @@ namespace cryptonote return false; } //--------------------------------------------------------------- + bool is_safex_out_to_acc(const crypto::public_key& safex_acc_pkey, const crypto::public_key& out_key) + { + if (safex_acc_pkey == out_key) + return true; + + return false; + } + //--------------------------------------------------------------- + + bool is_create_safex_account_token_fee(const std::vector& vout, const crypto::public_key& output_token_pubkey) + { + bool is_token_fee = true; + bool is_create_account = false; + std::array iterator_pubkey; + std::array token_pubkey; + std::copy(std::begin(output_token_pubkey.data), std::end(output_token_pubkey.data), std::begin(token_pubkey)); + for(auto tx_output: vout){ + // Only one output with SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE token amount is the actual fee. We search for first isntance + if(tx_output.target.type() == typeid(txout_token_to_key) && tx_output.token_amount == SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE){ + const txout_token_to_key &out = boost::get(tx_output.target); + std::copy(std::begin(out.key.data), std::end(out.key.data), std::begin(iterator_pubkey)); + + if(iterator_pubkey < token_pubkey) + is_token_fee = false; + } + + + if(tx_output.target.type() == typeid(txout_to_script) && get_tx_out_type(tx_output.target) == cryptonote::tx_out_type::out_safex_account) + is_create_account = true; + } + return is_token_fee && is_create_account; + } + //--------------------------------------------------------------- boost::optional is_out_to_acc_precomp(const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector& additional_derivations, size_t output_index, hw::device &hwdev) { // try the shared tx pubkey @@ -778,6 +878,16 @@ namespace cryptonote return boost::none; } //--------------------------------------------------------------- + boost::optional is_safex_output_to_acc_precomp(const safex::safex_account_keys& acc, const std::unordered_map& subaddresses, const crypto::public_key& out_key, size_t output_index, hw::device &hwdev) + { + if (acc.m_public_key == out_key) { + //my account output + return subaddress_receive_info{subaddress_index{0,0}, crypto::key_derivation{}}; + } + + return boost::none; + } + //--------------------------------------------------------------- bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered) { crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); @@ -887,59 +997,11 @@ namespace cryptonote return get_transaction_hash(t, res, NULL); } //--------------------------------------------------------------- - bool calculate_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size) + bool calculate_transaction_hash(const transaction &t, crypto::hash &res, size_t *blob_size) { - // v1 transactions hash the entire blob - if (t.version == 1) - { - size_t ignored_blob_size, &blob_size_ref = blob_size ? *blob_size : ignored_blob_size; - return get_object_hash(t, res, blob_size_ref); - } - - // v2 transactions hash different parts together, than hash the set of those hashes - crypto::hash hashes[3]; - - // prefix - get_transaction_prefix_hash(t, hashes[0]); + size_t ignored_blob_size, &blob_size_ref = blob_size ? *blob_size : ignored_blob_size; + return get_object_hash(t, res, blob_size_ref); - transaction &tt = const_cast(t); - - // base rct - { - std::stringstream ss; - binary_archive ba(ss); - const size_t inputs = t.vin.size(); - const size_t outputs = t.vout.size(); - bool r = tt.rct_signatures.serialize_rctsig_base(ba, inputs, outputs); - CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures base"); - cryptonote::get_blob_hash(ss.str(), hashes[1]); - } - - // prunable rct - if (t.rct_signatures.type == rct::RCTTypeNull) - { - hashes[2] = crypto::null_hash; - } - else - { - std::stringstream ss; - binary_archive ba(ss); - const size_t inputs = t.vin.size(); - const size_t outputs = t.vout.size(); - const size_t mixin = t.vin.empty() ? 0 : t.vin[0].type() == typeid(txin_to_key) ? boost::get(t.vin[0]).key_offsets.size() - 1 : 0; - bool r = tt.rct_signatures.p.serialize_rctsig_prunable(ba, t.rct_signatures.type, inputs, outputs, mixin); - CHECK_AND_ASSERT_MES(r, false, "Failed to serialize rct signatures prunable"); - cryptonote::get_blob_hash(ss.str(), hashes[2]); - } - - // the tx hash is the hash of the 3 hashes - res = cn_fast_hash(hashes, sizeof(hashes)); - - // we still need the size - if (blob_size) - *blob_size = get_object_blobsize(t); - - return true; } //--------------------------------------------------------------- bool get_transaction_hash(const transaction& t, crypto::hash& res, size_t* blob_size) @@ -1075,6 +1137,11 @@ namespace cryptonote return t_serializable_object_to_blob(tx, b_blob); } //--------------------------------------------------------------- + blobdata txout_script_to_blob(const txout_to_script& txout) + { + return t_serializable_object_to_blob(txout); + } + //--------------------------------------------------------------- void get_tx_tree_hash(const std::vector& tx_hashes, crypto::hash& h) { tree_hash(tx_hashes.data(), tx_hashes.size(), h); diff --git a/src/cryptonote_basic/cryptonote_format_utils.h b/src/cryptonote_basic/cryptonote_format_utils.h index 000e1f481..d9e8f79b7 100644 --- a/src/cryptonote_basic/cryptonote_format_utils.h +++ b/src/cryptonote_basic/cryptonote_format_utils.h @@ -38,6 +38,7 @@ #include "crypto/crypto.h" #include "crypto/hash.h" #include +#include namespace epee { @@ -49,6 +50,18 @@ namespace cryptonote //--------------------------------------------------------------- void get_transaction_prefix_hash(const transaction_prefix& tx, crypto::hash& h); crypto::hash get_transaction_prefix_hash(const transaction_prefix& tx); + + template + bool parse_and_validate_object_from_blob(const blobdata& bytes_blob, T &data) { + std::stringstream ss; + ss << bytes_blob; + binary_archive ba(ss); + bool r = ::serialization::serialize(ba, data); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse byte array from blob"); + return true; + } + + bool parse_and_validate_byte_array_from_blob (const blobdata& bytes_blob, std::vector &data); bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash); bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx); bool parse_and_validate_tx_base_from_blob(const blobdata& tx_blob, transaction& tx); @@ -85,16 +98,33 @@ namespace cryptonote bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id); bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id); bool is_out_to_acc(const account_keys& acc, const crypto::public_key& out_key, const crypto::public_key& tx_pub_key, const std::vector& additional_tx_public_keys, size_t output_index); + bool is_safex_out_to_acc(const safex::safex_account_keys& acc, const crypto::public_key& out_key); + bool is_safex_out_to_acc(const crypto::public_key& safex_acc_pkey, const crypto::public_key& out_key); struct subaddress_receive_info { subaddress_index index; crypto::key_derivation derivation; }; + bool is_create_safex_account_token_fee(const std::vector& vout, const crypto::public_key& output_token_pubkey); boost::optional is_out_to_acc_precomp(const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::key_derivation& derivation, const std::vector& additional_derivations, size_t output_index, hw::device &hwdev); + boost::optional is_safex_output_to_acc_precomp(const safex::safex_account_keys& acc, const std::unordered_map& subaddresses, const crypto::public_key& out_key, size_t output_index, hw::device &hwdev); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, const std::vector& additional_tx_public_keys, std::vector& outs, uint64_t& money_transfered); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered); bool get_tx_fee(const transaction& tx, uint64_t & fee); uint64_t get_tx_fee(const transaction& tx); + bool parse_and_validate_txout_to_script_from_blob(const blobdata& tx_blob, txout_to_script& txout); + + template + bool parse_and_validate_from_blob(const blobdata& tx_blob, T& object) + { + std::stringstream ss; + ss << tx_blob; + binary_archive ba(ss); + bool r = ::serialization::serialize(ba, object); + CHECK_AND_ASSERT_MES(r, false, "Failed to parse txout_to_script from blob"); + return true; + } + bool generate_key_image_helper(const account_keys& ack, const std::unordered_map& subaddresses, const crypto::public_key& out_key, const crypto::public_key& tx_public_key, const std::vector& additional_tx_public_keys, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); bool generate_key_image_helper_precomp(const account_keys& ack, const crypto::public_key& out_key, const crypto::key_derivation& recv_derivation, size_t real_output_index, const subaddress_index& received_index, keypair& in_ephemeral, crypto::key_image& ki, hw::device &hwdev); void get_blob_hash(const blobdata& blob, crypto::hash& res); @@ -111,10 +141,13 @@ namespace cryptonote bool get_block_hash(const block& b, crypto::hash& res); crypto::hash get_block_hash(const block& b); bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); - bool get_inputs_money_amount(const transaction& tx, uint64_t& money); + bool get_inputs_cash_amount(const transaction &tx, uint64_t &money); bool get_inputs_token_amount(const transaction& tx, uint64_t& tokens); uint64_t get_input_token_migration_amount(const transaction& tx); - uint64_t get_outs_money_amount(const transaction& tx); + int64_t get_token_staked_amount(const transaction &tx); + uint64_t get_collected_network_fee_amount(const transaction &tx); + uint64_t get_network_distributed_fee_amount(const transaction &tx); + uint64_t get_outs_cash_amount(const transaction &tx); uint64_t get_outs_token_amount(const transaction& tx); bool check_inputs_types_supported(const transaction& tx); bool check_outs_valid(const transaction& tx); @@ -234,6 +267,8 @@ namespace cryptonote bool is_valid_decomposed_amount(uint64_t amount); void get_hash_stats(uint64_t &tx_hashes_calculated, uint64_t &tx_hashes_cached, uint64_t &block_hashes_calculated, uint64_t & block_hashes_cached); + blobdata txout_script_to_blob(const txout_to_script& txout); + crypto::secret_key encrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase); crypto::secret_key decrypt_key(crypto::secret_key key, const epee::wipeable_string &passphrase); #define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \ diff --git a/src/cryptonote_basic/miner.cpp b/src/cryptonote_basic/miner.cpp index e2eabef09..382a66660 100644 --- a/src/cryptonote_basic/miner.cpp +++ b/src/cryptonote_basic/miner.cpp @@ -98,13 +98,13 @@ namespace cryptonote } - miner::miner(i_miner_handler* phandler, Blockchain* pbc):m_stop(1), + miner::miner(i_miner_handler* phandler, const get_block_hash_t &gbh):m_stop(1), m_template(boost::value_initialized()), m_template_no(0), m_diffic(0), m_thread_index(0), m_phandler(phandler), - m_pbc(pbc), + m_gbh(gbh), m_height(0), m_pausers_count(0), m_threads_total(0), @@ -382,12 +382,12 @@ namespace cryptonote return true; } //----------------------------------------------------------------------------------------------------- - bool miner::find_nonce_for_given_block(const Blockchain *pbc, block& bl, const difficulty_type& diffic, uint64_t height) + bool miner::find_nonce_for_given_block(const get_block_hash_t &gbh, block& bl, const difficulty_type& diffic, uint64_t height) { for(; bl.nonce != std::numeric_limits::max(); bl.nonce++) { crypto::hash h; - get_block_longhash(pbc, bl, h, height, tools::get_max_concurrency()); + gbh(bl, height, tools::get_max_concurrency(), h); if(check_hash(h, diffic)) { @@ -485,7 +485,7 @@ namespace cryptonote b.nonce = nonce; crypto::hash h; - get_block_longhash(m_pbc, b, h, height, tools::get_max_concurrency()); + m_gbh(b, height, tools::get_max_concurrency(), h); if(check_hash(h, local_diff)) { diff --git a/src/cryptonote_basic/miner.h b/src/cryptonote_basic/miner.h index ff9fae291..2b956751f 100644 --- a/src/cryptonote_basic/miner.h +++ b/src/cryptonote_basic/miner.h @@ -57,7 +57,7 @@ namespace cryptonote ~i_miner_handler(){}; }; - class Blockchain; + typedef std::function get_block_hash_t; /************************************************************************/ /* */ @@ -65,7 +65,7 @@ namespace cryptonote class miner { public: - miner(i_miner_handler* phandler, Blockchain* pbc); + miner(i_miner_handler* phandler, const get_block_hash_t& gbh); ~miner(); bool init(const boost::program_options::variables_map& vm, network_type nettype); static void init_options(boost::program_options::options_description& desc); @@ -81,7 +81,7 @@ namespace cryptonote bool on_idle(); void on_synchronized(); //synchronous analog (for fast calls) - static bool find_nonce_for_given_block(const Blockchain *pbc, block& bl, const difficulty_type& diffic, uint64_t height); + static bool find_nonce_for_given_block(const get_block_hash_t &gbh, block& bl, const difficulty_type& diffic, uint64_t height); void pause(); void resume(); void do_print_hashrate(bool do_hr); @@ -137,7 +137,7 @@ namespace cryptonote std::list m_threads; epee::critical_section m_threads_lock; i_miner_handler* m_phandler; - Blockchain* m_pbc; + get_block_hash_t m_gbh; account_public_address m_mine_address; epee::math_helper::once_a_time_seconds<5> m_update_block_template_interval; epee::math_helper::once_a_time_seconds<2> m_update_merge_hr_interval; diff --git a/src/cryptonote_basic/verification_context.h b/src/cryptonote_basic/verification_context.h index 00e872582..cf1acbd3b 100644 --- a/src/cryptonote_basic/verification_context.h +++ b/src/cryptonote_basic/verification_context.h @@ -48,7 +48,12 @@ namespace cryptonote bool m_too_big; bool m_overspend; bool m_fee_too_low; - bool m_not_rct; + bool m_non_supported_version; + bool m_safex_verification_failed; + bool m_safex_invalid_command; + bool m_safex_invalid_command_params; + bool m_safex_invalid_input; + bool m_safex_command_execution_failed; }; struct block_verification_context diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 4e69aa7f2..517827328 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -43,7 +43,6 @@ #define CRYPTONOTE_MAX_TX_SIZE 1000000000 #define CRYPTONOTE_PUBLIC_ADDRESS_TEXTBLOB_VER 0 #define CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW 60 -#define CURRENT_TRANSACTION_VERSION 1 //do not use ringct #define CURRENT_BLOCK_MAJOR_VERSION 1 #define CURRENT_BLOCK_MINOR_VERSION 0 #define CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT 60*60*2 @@ -114,6 +113,7 @@ #define CRYPTONOTE_MEMPOOL_TX_LIVETIME (86400*3) //seconds, three days #define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME 604800 //seconds, one week +#define CRYPTONOTE_MEMPOOL_SAFEX_TX_LIVETIME 3600 //seconds, 1 hour #define COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT 1000 @@ -160,14 +160,63 @@ #define HF_VERSION_FORBID_DUST HF_VERSION_TBD //forbid dust and compound outputs #define HF_VERSION_ALLOW_BULLETPROOFS HF_VERSION_TBD #define HF_VERSION_DIFFICULTY_V2 3 -#define HF_VERSION_MAX_SUPPORTED_TX_VERSION 1 #define HF_VERSION_VALID_DECOMPOSED_MINER_TX_1 3 #define HF_VERSION_VALID_DECOMPOSED_MINER_TX_2 4 #define HF_VERSION_ALLOW_LESS_BLOCK_REWARD 2 #define HF_VERSION_MINER_TX_MAX_OUTS 11 #define HF_VERSION_CHANGE_MINER_DUST_HANDLING 5 + #define HF_VERSION_STOP_COUNTERFEIT_TOKENS 6 +#define HF_VERSION_ALLOW_TX_VERSION_2 7 +#define HF_VERSION_MINER_DUST_HANDLE_DIGIT 7 + +constexpr uint8_t MIN_SUPPORTED_TX_VERSION = 1; +constexpr uint8_t MAX_SUPPORTED_TX_VERSION = 2; + +//Safex related constants +constexpr uint64_t SAFEX_COMMAND_PROTOCOL_VERSION = 1; + +//Safex token stake constants +constexpr uint64_t SAFEX_MINIMUM_TOKEN_STAKE_AMOUNT = 10000 * SAFEX_TOKEN; +constexpr uint64_t SAFEX_DEFAULT_TOKEN_STAKE_EXPIRY_PERIOD = 500000; +constexpr uint64_t SAFEX_DEFAULT_INTERVAL_PERIOD_FAKECHAIN = 10; //blocks +constexpr uint64_t SAFEX_DEFAULT_INTERVAL_PERIOD_TESTNET = 10; //blocks +constexpr uint64_t SAFEX_DEFAULT_INTERVAL_PERIOD_STAGENET = 100; //blocks +constexpr uint64_t SAFEX_DEFAULT_INTERVAL_PERIOD = 1000; //blocks +constexpr uint64_t SAFEX_DEFAULT_MINUMUM_TOKEN_STAKE_PERIOD_FAKECHAIN = SAFEX_DEFAULT_INTERVAL_PERIOD_FAKECHAIN*3; //blocks +constexpr uint64_t SAFEX_DEFAULT_MINUMUM_TOKEN_STAKE_PERIOD_TESTNET = SAFEX_DEFAULT_INTERVAL_PERIOD_TESTNET*1; //blocks +constexpr uint64_t SAFEX_DEFAULT_MINUMUM_TOKEN_STAKE_PERIOD_STAGENET = SAFEX_DEFAULT_INTERVAL_PERIOD_STAGENET*10; //blocks +constexpr uint64_t SAFEX_DEFAULT_MINUMUM_TOKEN_STAKE_PERIOD = SAFEX_DEFAULT_INTERVAL_PERIOD*10; //blocks + +//Safex network fee constants +constexpr uint64_t SAFEX_DEFAULT_NETWORK_FEE_PERCENTAGE = 5; + +//Safex create account token lock constants +constexpr uint64_t SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE = 1000*SAFEX_TOKEN; +constexpr uint64_t SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN = 1; +constexpr uint64_t SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_TESTNET = 10; +constexpr uint64_t SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_STAGENET = 300; +constexpr uint64_t SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD = 1500;// TBD + +//Safex account constants +constexpr uint64_t SAFEX_ACCOUNT_USERNAME_MAX_SIZE = 32; +constexpr uint64_t SAFEX_ACCOUNT_DATA_MAX_SIZE = 2048; + +//Safex offer constants +constexpr uint64_t SAFEX_OFFER_NAME_MAX_SIZE = 80; +constexpr uint64_t SAFEX_OFFER_DATA_MAX_SIZE = 2048; +constexpr uint64_t SAFEX_OFFER_MINIMUM_PRICE = SAFEX_CASH_COIN/10000; // 0.0001 SFX + +//Safex price peg constants +constexpr uint64_t SAFEX_PRICE_PEG_NAME_MAX_SIZE = 60; +constexpr uint64_t SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE = 8; +constexpr uint64_t SAFEX_PRICE_PEG_DATA_MAX_SIZE = 2048; + +//Safex feedback constants +constexpr uint64_t SAFEX_FEEDBACK_MAX_RATING = 3; +constexpr uint64_t SAFEX_FEEDBACK_DATA_MAX_SIZE = 2048; + #define DEFAULT_MIX 6 //default wallet mix for transactions #define PER_KB_FEE_QUANTIZATION_DECIMALS 6 @@ -199,7 +248,6 @@ namespace config } }; std::string const GENESIS_TX = "013c01ff00018080a8ec85afd1b10100028ff33b5dc7640ad6333405a875f9a92cd69e99fc15d208ea2eb990203d1348dc8301011d22a19d7aa99b11c1143fd40e200760de6caa90eab16bd12d0188d6db8537611103c23aed713351b8b88e15bb213983aa03f26aca95da4e77384654153d50a55fc78dcc65a751789b60e816e3710d448b05f56777e66aff4c6228472e6a41e122dc9ab470e5997573adea910e70c4c3a04e3957e33c099848f0fd2d12dc6b84eca3"; uint32_t const GENESIS_NONCE = 10000; - //TODO: Set to other values when activating new hard fork uint64_t const HARDFORK_V4_INIT_DIFF = 330000000; uint64_t const HARDFORK_V4_START_HEIGHT = 330000; @@ -274,8 +322,8 @@ namespace config } }; std::string const GENESIS_TX = "013c01ff00018080a8ec85afd1b1010002d4372ec2272690ccd59880807d1fa00f7bd2fa67f7abb350cafbdc24a4ba372c8301011a1ca7d7e74037e4d000a0fc2cc61389ac7d8b0a6b600c62e77374477c4c414d1103a83b4a507df5b0dc5af701078828a1372d77761339a28a7ebb1ff450622f7456d1083f35430eba3353a9e42514480a0cbccbda5ee6abb2d856f8a9aae056a92a6ece1020496a36a4b68341e3b401653139683f8dc27d76ff9eb9c26c2528c26a"; uint32_t const GENESIS_NONCE = 10003; - uint64_t const HARDFORK_V4_INIT_DIFF = 6000; - uint64_t const HARDFORK_V4_START_HEIGHT = 308450; + uint64_t const HARDFORK_V4_INIT_DIFF = 1; + uint64_t const HARDFORK_V4_START_HEIGHT = 1260; } namespace stagenet @@ -292,9 +340,8 @@ namespace config } }; std::string const GENESIS_TX = "013c01ff00018080a8ec85afd1b1010002cd3249adde7fce93280c3a87db72648b7e47eeb08a5e6ff8e926f86e4aa9ffa283010126cb71e5ddd6461fea5d5b00644c5fb9711a2951e1345ba95c648b00ca08e23d1103ab3e85348739c5348f5dd7a61de6e1d30c0a81389ba9ce533da1e65df03f6a71f2df17d26217fb61bd2e8bc65197bf535904d9f5d75e531712f7fd3e255c5ad5308d1ee2cc4166b8effafd2f75d9c8483bb264ed7539cbc2921c580b40b1218b"; uint32_t const GENESIS_NONCE = 10002; - //TODO: Set to other values when activating new hard fork - uint64_t const HARDFORK_V4_INIT_DIFF = 100; - uint64_t const HARDFORK_V4_START_HEIGHT = 241847; + uint64_t const HARDFORK_V4_INIT_DIFF = 1000; + uint64_t const HARDFORK_V4_START_HEIGHT = 87200; } } diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index 843371a6d..7e0139c8d 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -99,7 +99,7 @@ endif() safex_private_headers(cryptonote_core ${cryptonote_core_private_headers}) - + if(BUILD_SAFEX_PROTOBUF_RPC) safex_add_library(cryptonote_core @@ -112,6 +112,7 @@ if(BUILD_SAFEX_PROTOBUF_RPC) common cncrypto blockchain_db + safex_core multisig ringct device @@ -136,6 +137,7 @@ else() common cncrypto blockchain_db + safex_core multisig ringct device diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index 1df4ba2c1..488b6cd06 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -62,6 +62,8 @@ #if defined(PER_BLOCK_CHECKPOINT) #include "blocks/blocks.h" #endif +#include "safex/command.h" +#include "safex/safex_account.h" #undef SAFEX_DEFAULT_LOG_CATEGORY #define SAFEX_DEFAULT_LOG_CATEGORY "blockchain" @@ -118,11 +120,13 @@ static const struct { } testnet_hard_forks[] = { // version 1 from the start of the blockchain { 1, 1, 0, 1514764801 }, - { 2, 33407, 0, 1541066055}, - { 3, 78500, 0, 1546512073}, //184650 - { 4, config::testnet::HARDFORK_V4_START_HEIGHT, 0, 1565962165}, + { 2, 1250, 0, 1541066055}, + { 3, 1260, 0, 1605355986}, //184650 + { 4, config::testnet::HARDFORK_V4_START_HEIGHT, 0, 1605455986}, //TODO: Update when preapring HF5 for testnet - { 5, config::testnet::HARDFORK_V4_START_HEIGHT, 0, 1565962165} + { 5, config::testnet::HARDFORK_V4_START_HEIGHT, 0, 1605555986}, + { 6, config::testnet::HARDFORK_V4_START_HEIGHT, 0, 1605655986}, + { 7, config::testnet::HARDFORK_V4_START_HEIGHT, 0, 1605755986} }; static const uint64_t testnet_hard_fork_version_1_till = 33406; @@ -137,15 +141,16 @@ static const struct { { 2, 100, 0, 1561283500}, { 3, 200, 0, 1562283500}, { 4, config::stagenet::HARDFORK_V4_START_HEIGHT, 0, 1565962165}, - //TODO: Update when preapring HF5 for stagenet - { 5, config::stagenet::HARDFORK_V4_START_HEIGHT, 0, 1565962165} + { 5, config::stagenet::HARDFORK_V4_START_HEIGHT + 1, 0, 1565962166}, + { 6, config::stagenet::HARDFORK_V4_START_HEIGHT + 2, 0, 1592478292}, + { 7, 91020, 0, 1605691874} }; //------------------------------------------------------------------ Blockchain::Blockchain(tx_memory_pool& tx_pool) : m_db(), m_tx_pool(tx_pool), m_hardfork(NULL), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_current_block_cumul_sz_median(0), m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_db_default_sync(false), - m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false), m_prepare_height(0) + m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_cancel(false), m_prepare_height(0), m_batch_success(true) { LOG_PRINT_L3("Blockchain::" << __func__); } @@ -174,7 +179,8 @@ bool Blockchain::have_tx_keyimg_as_spent(const crypto::key_image &key_im) const // and collects the public key for each from the transaction it was included in // via the visitor passed to it. template -bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const TxInput& txin, visitor_t &vis, const crypto::hash &tx_prefix_hash, uint64_t* pmax_related_block_height) const +bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const TxInput& txin, visitor_t &vis, + const crypto::hash &tx_prefix_hash, uint64_t* pmax_related_block_height) const { LOG_PRINT_L3("Blockchain::" << __func__); @@ -192,8 +198,7 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const TxInput& t std::vector absolute_offsets = relative_output_offsets_to_absolute(txin.key_offsets); std::vector outputs; - uint64_t value_amount = get_tx_input_amount(txin); //token or cash amount depending of input type - //todo ATANA double check token vs cash amount differentiation + uint64_t value_amount = get_tx_input_value_amount(txin); //token or cash amount depending of input type bool found = false; auto it = m_scan_table.find(tx_prefix_hash); @@ -211,8 +216,8 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const TxInput& t { try { - tx_out_type txout_type = cryptonote::get_tx_out_type_from_input(txin); - m_db->get_output_key(value_amount, absolute_offsets, outputs, txout_type, true); + tx_out_type txout_type = cryptonote::derive_tx_out_type_from_input(txin); + m_db->get_amount_output_key(value_amount, absolute_offsets, outputs, txout_type, true); if (absolute_offsets.size() != outputs.size()) { MERROR_VER("Output does not exist! amount = " << value_amount); @@ -237,8 +242,8 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const TxInput& t add_offsets.push_back(absolute_offsets[i]); try { - tx_out_type txout_type = cryptonote::get_tx_out_type_from_input(txin); - m_db->get_output_key(value_amount, add_offsets, add_outputs, txout_type, true); + tx_out_type txout_type = cryptonote::derive_tx_out_type_from_input(txin); + m_db->get_amount_output_key(value_amount, add_offsets, add_outputs, txout_type, true); if (add_offsets.size() != add_outputs.size()) { MERROR_VER("Output does not exist! amount = " << value_amount); @@ -262,7 +267,7 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const TxInput& t output_data_t output_index; try { - tx_out_type txout_type = cryptonote::get_tx_out_type_from_input(txin); + tx_out_type txout_type = cryptonote::derive_tx_out_type_from_input(txin); // get tx hash and output index for output if (count < outputs.size()) @@ -311,6 +316,340 @@ bool Blockchain::scan_outputkeys_for_indexes(size_t tx_version, const TxInput& t return true; } //------------------------------------------------------------------ +//Template specialization for script inputs, where it depends which outputs we shold take +template<> +bool Blockchain::scan_outputkeys_for_indexes + (size_t tx_version, const txin_to_script &txin, Blockchain::outputs_generic_visitor &vis, + const crypto::hash &tx_prefix_hash, uint64_t *pmax_related_block_height) const +{ + LOG_PRINT_L3("Blockchain::" << __func__); + + // ND: Disable locking and make method private. + //CRITICAL_REGION_LOCAL(m_blockchain_lock); + + tx_out_type output_type{tx_out_type::out_invalid}; //type which the input is referencing + + //check command type + switch (txin.command_type) + { + case safex::command_t::token_stake: + output_type = tx_out_type::out_token; + break; + case safex::command_t::token_unstake: + output_type = tx_out_type::out_staked_token; + break; + case safex::command_t::donate_network_fee: + output_type = tx_out_type::out_cash; + break; + case safex::command_t::create_account: + output_type = tx_out_type::out_token; + break; + case safex::command_t::edit_account: + output_type = tx_out_type::out_safex_account; + break; + case safex::command_t::create_offer: + output_type = tx_out_type::out_safex_account; + break; + case safex::command_t::edit_offer: + output_type = tx_out_type::out_safex_offer; + break; + case safex::command_t::simple_purchase: + output_type = tx_out_type::out_cash; + break; + case safex::command_t::create_feedback: + output_type = tx_out_type::out_safex_feedback_token; + break; + case safex::command_t::create_price_peg: + output_type = tx_out_type::out_safex_account; + break; + case safex::command_t::update_price_peg: + output_type = tx_out_type::out_safex_price_peg; + break; + default: + MERROR_VER("Unknown command type"); + return false; + break; + } + + if (!txin.key_offsets.size()) + return false; + + if(!safex::is_safex_key_image_verification_needed(txin.command_type) && txin.key_offsets.size() != 1){ + MERROR_VER("Commands that don't have key image verification must have only 1 key offset"); + return false; + } + + + std::vector absolute_offsets; + uint64_t value_amount = 0; + switch (output_type) + { + case tx_out_type::out_staked_token: + case tx_out_type::out_safex_account: + case tx_out_type::out_safex_feedback_token: + case tx_out_type::out_safex_offer: + case tx_out_type::out_safex_price_peg: + { + absolute_offsets = txin.key_offsets; + break; + } + case tx_out_type::out_token: + { + absolute_offsets = relative_output_offsets_to_absolute(txin.key_offsets); + value_amount = get_tx_input_token_amount(txin); + break; + } + + case tx_out_type::out_cash: + case tx_out_type::out_network_fee: + { + absolute_offsets = relative_output_offsets_to_absolute(txin.key_offsets); + value_amount = get_tx_input_cash_amount(txin); + break; + } + default: + MERROR_VER("Unknown output type"); + return false; + } + + if (output_type == tx_out_type::out_token || output_type == tx_out_type::out_cash) + { + std::vector outputs; + bool found = false; + auto it = m_scan_table.find(tx_prefix_hash); + if (it != m_scan_table.end()) + { + auto its = it->second.find(txin.k_image); + if (its != it->second.end()) + { + outputs = its->second; + found = true; + } + } + + if (!found) + { + try + { + m_db->get_amount_output_key(value_amount, absolute_offsets, outputs, output_type, true); + if (absolute_offsets.size() != outputs.size()) + { + MERROR_VER("Output does not exist! amount = " << value_amount); + return false; + } + } + catch (...) + { + MERROR_VER("Output does not exist! amount = " << value_amount); + return false; + } + } + else + { + // check for partial results and add the rest if needed; + if (outputs.size() < absolute_offsets.size() && outputs.size() > 0) + { + MDEBUG("Additional outputs needed: " << absolute_offsets.size() - outputs.size()); + std::vector add_offsets; + std::vector add_outputs; + for (size_t i = outputs.size(); i < absolute_offsets.size(); i++) + add_offsets.push_back(absolute_offsets[i]); + try + { + m_db->get_amount_output_key(value_amount, add_offsets, add_outputs, output_type, true); + if (add_offsets.size() != add_outputs.size()) + { + MERROR_VER("Output does not exist! amount = " << value_amount); + return false; + } + } + catch (...) + { + MERROR_VER("Output does not exist! amount = " << value_amount); + return false; + } + outputs.insert(outputs.end(), add_outputs.begin(), add_outputs.end()); + } + } + + size_t count = 0; + for (const uint64_t &i : absolute_offsets) + { + try + { + output_data_t output_index; + try + { + // get tx hash and output index for output + if (count < outputs.size()) + output_index = outputs.at(count); + else + output_index = m_db->get_output_key(value_amount, i, output_type); + + // call to the passed boost visitor to grab the public key for the output + if (!vis.handle_output(output_index.unlock_time, output_index.pubkey, output_index.commitment)) + { + MERROR_VER("Failed to handle_output for output no = " << count << ", with absolute offset " << i); + return false; + } + } + catch (...) + { + MERROR_VER("Output does not exist! amount = " << value_amount << ", absolute_offset = " << i); + return false; + } + + // if on last output and pmax_related_block_height not null pointer + if (++count == absolute_offsets.size() && pmax_related_block_height) + { + // set *pmax_related_block_height to tx block height for this output + auto h = output_index.height; + if (*pmax_related_block_height < h) + { + *pmax_related_block_height = h; + } + } + } + catch (const OUTPUT_DNE &e) + { + MERROR_VER("Output does not exist: " << e.what()); + return false; + } + catch (const TX_DNE &e) + { + MERROR_VER("Transaction does not exist: " << e.what()); + return false; + } + + } + } +/* Handle advanced outputs that should be spend in the transaction */ + else if ((output_type == tx_out_type::out_staked_token) + || (output_type == tx_out_type::out_network_fee) + || (output_type == tx_out_type::out_safex_account) + || (output_type == tx_out_type::out_safex_feedback_token) + || (output_type == tx_out_type::out_safex_offer) + || (output_type == tx_out_type::out_safex_price_peg)) { + + std::vector outputs; + bool found = false; + auto it = m_scan_table_adv.find(tx_prefix_hash); + if (it != m_scan_table_adv.end()) + { + auto its = it->second.find(txin.k_image); + if (its != it->second.end()) + { + outputs = its->second; + found = true; + } + } + + if (!found) + { + try + { + m_db->get_advanced_output_key(absolute_offsets, outputs, output_type, true); + if (absolute_offsets.size() != outputs.size()) + { + MERROR_VER("Advanced outputs do not exist!"); + return false; + } + } + catch (...) + { + MERROR_VER("Advanced outputs do not exist"); + return false; + } + } + else + { + // check for partial results and add the rest if needed; + if (outputs.size() < absolute_offsets.size() && outputs.size() > 0) + { + MDEBUG("Additional advanced outputs needed: " << absolute_offsets.size() - outputs.size()); + std::vector add_offsets; + std::vector add_outputs; + for (size_t i = outputs.size(); i < absolute_offsets.size(); i++) + add_offsets.push_back(absolute_offsets[i]); + try + { + m_db->get_advanced_output_key(add_offsets, add_outputs, output_type, true); + if (add_offsets.size() != add_outputs.size()) + { + MERROR_VER("Advanced outputs do not exist"); + return false; + } + } + catch (...) + { + MERROR_VER("Advanced output does not exist!"); + return false; + } + outputs.insert(outputs.end(), add_outputs.begin(), add_outputs.end()); + } + } + + size_t count = 0; + for (const uint64_t &i : absolute_offsets) + { + try + { + output_advanced_data_t output_data; + try + { + // get tx hash and output index for output + if (count < outputs.size()) + output_data = outputs.at(count); + else + output_data = m_db->get_output_advanced_data(output_type, i); + + // call to the passed boost visitor to grab the public key for the output + if (!vis.handle_output(output_data.unlock_time, output_data.pubkey, rct::key{0})) + { + MERROR_VER("Failed to handle_output for output no = " << count << ", with absolute offset " << i); + return false; + } + } + catch (...) + { + MERROR_VER("Output does not exist! amount = " << value_amount << ", absolute_offset = " << i); + return false; + } + + // if on last output and pmax_related_block_height not null pointer + if (++count == absolute_offsets.size() && pmax_related_block_height) + { + // set *pmax_related_block_height to tx block height for this output + auto h = output_data.height; + if (*pmax_related_block_height < h) + { + *pmax_related_block_height = h; + } + } + + } + catch (const OUTPUT_DNE &e) + { + MERROR_VER("Output does not exist: " << e.what()); + return false; + } + catch (const TX_DNE &e) + { + MERROR_VER("Transaction does not exist: " << e.what()); + return false; + } + + } + + } + else { + MERROR_VER("Unknown output type."); + return false; + } + + return true; +} +//------------------------------------------------------------------ uint64_t Blockchain::get_current_blockchain_height() const { LOG_PRINT_L3("Blockchain::" << __func__); @@ -611,16 +950,16 @@ block Blockchain::pop_block_from_blockchain() // // FIXME: HardFork // This is not quite correct, as we really want to add the txes - // to the pool based on the version determined after all blocks + // to the pool based on the hf_version determined after all blocks // are popped. - uint8_t version = get_current_hard_fork_version(); + uint8_t hf_version = get_current_hard_fork_version(); // We assume that if they were in a block, the transactions are already // known to the network as a whole. However, if we had mined that block, // that might not be always true. Unlikely though, and always relaying // these again might cause a spike of traffic as many nodes re-relay // all the transactions in a popped block when a reorg happens. - bool r = m_tx_pool.add_tx(tx, tvc, true, true, false, version); + bool r = m_tx_pool.add_tx(tx, tvc, true, true, false, hf_version); if (!r) { LOG_ERROR("Error returning transaction to tx_pool"); @@ -630,6 +969,7 @@ block Blockchain::pop_block_from_blockchain() m_blocks_longhash_table.clear(); m_scan_table.clear(); + m_scan_table_adv.clear(); m_blocks_txs_check.clear(); m_check_txin_table.clear(); @@ -1161,7 +1501,7 @@ bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height) } //------------------------------------------------------------------ // This function validates the miner transaction reward -bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version) +bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t hf_version) { LOG_PRINT_L3("Blockchain::" << __func__); //validate reward @@ -1170,7 +1510,8 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl money_in_use += o.amount; partial_block_reward = false; - if (version == HF_VERSION_VALID_DECOMPOSED_MINER_TX_1 || version == HF_VERSION_VALID_DECOMPOSED_MINER_TX_2) { + + if (hf_version == HF_VERSION_VALID_DECOMPOSED_MINER_TX_1 || hf_version == HF_VERSION_VALID_DECOMPOSED_MINER_TX_2) { for (auto &o: b.miner_tx.vout) { if (!is_valid_decomposed_amount(o.amount)) { MERROR_VER("miner tx output " << print_money(o.amount) << " is not a valid decomposed amount"); @@ -1181,7 +1522,7 @@ bool Blockchain::validate_miner_transaction(const block& b, size_t cumulative_bl std::vector last_blocks_sizes; get_last_n_blocks_sizes(last_blocks_sizes, CRYPTONOTE_REWARD_BLOCKS_WINDOW); - if (!get_block_reward(epee::misc_utils::median(last_blocks_sizes), cumulative_block_size, already_generated_coins, base_reward, version, m_db->height())) + if (!get_block_reward(epee::misc_utils::median(last_blocks_sizes), cumulative_block_size, already_generated_coins, base_reward, hf_version, m_db->height())) { MERROR_VER("block size " << cumulative_block_size << " is bigger than allowed for this blockchain"); return false; @@ -1324,10 +1665,8 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m } else { - if (cur_tx.fee != cur_tx.tx.rct_signatures.txnFee) - { - LOG_ERROR("Creating block template: error: invalid fee"); - } + //todo ATANA implement tx version 2 checks + LOG_ERROR("Transacdtion version 2 not yet supported"); } } if (txs_size != real_txs_size) @@ -1352,7 +1691,7 @@ bool Blockchain::create_block_template(block& b, const account_public_address& m */ //make blocks coin-base tx looks close to real coinbase tx to get truthful blob size uint8_t hf_version = m_hardfork->get_current_version(); - size_t max_outs = hf_version >= HF_VERSION_CHANGE_MINER_DUST_HANDLING ? 1 : HF_VERSION_MINER_TX_MAX_OUTS; + size_t max_outs = hf_version >= HF_VERSION_CHANGE_MINER_DUST_HANDLING && hf_version <= HF_VERSION_MINER_DUST_HANDLE_DIGIT ? 1 : HF_VERSION_MINER_TX_MAX_OUTS; bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, max_outs, hf_version); CHECK_AND_ASSERT_MES(r, false, "Failed to construct miner tx, first chance"); size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx); @@ -2049,6 +2388,11 @@ bool Blockchain::get_outs(const COMMAND_RPC_GET_OUTPUTS_BIN::request& req, COMMA const output_data_t od = m_db->get_output_key(i.amount, i.index, req.out_type); tx_out_index toi = m_db->get_output_tx_and_index(i.amount, i.index, req.out_type); bool unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first)); + if(req.out_type == cryptonote::tx_out_type::out_token){ + cryptonote::transaction tx = m_db->get_tx(toi.first); + if(is_create_safex_account_token_fee(tx.vout, od.pubkey)) + unlocked &= od.height + safex::get_safex_minumum_account_create_token_lock_period(m_nettype) <= m_db->height(); + } res.outs.push_back({od.pubkey, od.commitment, unlocked, od.height, toi.first}); } @@ -2062,12 +2406,19 @@ bool Blockchain::get_outs_proto(const COMMAND_RPC_GET_OUTPUTS_PROTOBUF::request& #ifdef SAFEX_PROTOBUF_RPC CRITICAL_REGION_LOCAL(m_blockchain_lock); + auto out_type = static_cast(req.out_type); + for (const auto &i: req.outputs) { // get tx_hash, tx_out_index from DB - const output_data_t od = m_db->get_output_key(i.amount, i.index, static_cast(req.out_type)); - tx_out_index toi = m_db->get_output_tx_and_index(i.amount, i.index, static_cast(req.out_type)); + const output_data_t od = m_db->get_output_key(i.amount, i.index, out_type); + tx_out_index toi = m_db->get_output_tx_and_index(i.amount, i.index, out_type); bool unlocked = is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first)); + if(out_type == cryptonote::tx_out_type::out_token){ + cryptonote::transaction tx = m_db->get_tx(toi.first); + if(is_create_safex_account_token_fee(tx.vout, od.pubkey)) + unlocked &= od.height + safex::get_safex_minumum_account_create_token_lock_period(m_nettype) <= m_db->height(); + } proto.add_out_entry(od.pubkey, unlocked, od.height, toi.first); } @@ -2201,94 +2552,6 @@ uint64_t Blockchain::block_difficulty(uint64_t i) const return 0; } //------------------------------------------------------------------ -//TODO: return type should be void, throw on exception -// alternatively, return true only if no blocks missed -template -bool Blockchain::get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const -{ - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - - for (const auto& block_hash : block_ids) - { - try - { - blocks.push_back(std::make_pair(m_db->get_block_blob(block_hash), block())); - if (!parse_and_validate_block_from_blob(blocks.back().first, blocks.back().second)) - { - LOG_ERROR("Invalid block"); - return false; - } - } - catch (const BLOCK_DNE& e) - { - missed_bs.push_back(block_hash); - } - catch (const std::exception& e) - { - return false; - } - } - return true; -} -//------------------------------------------------------------------ -//TODO: return type should be void, throw on exception -// alternatively, return true only if no transactions missed -template -bool Blockchain::get_transactions_blobs(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const -{ - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - - for (const auto& tx_hash : txs_ids) - { - try - { - cryptonote::blobdata tx = AUTO_VAL_INIT(tx); - if (m_db->get_tx_blob(tx_hash, tx)) - txs.push_back(std::move(tx)); - else - missed_txs.push_back(tx_hash); - } - catch (const std::exception& e) - { - return false; - } - } - return true; -} -//------------------------------------------------------------------ -template -bool Blockchain::get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const -{ - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - - for (const auto& tx_hash : txs_ids) - { - try - { - cryptonote::blobdata tx = AUTO_VAL_INIT(tx); - if (m_db->get_tx_blob(tx_hash, tx)) - { - txs.push_back(transaction()); - if (!parse_and_validate_tx_from_blob(tx, txs.back())) - { - LOG_ERROR("Invalid transaction"); - return false; - } - } - else - missed_txs.push_back(tx_hash); - } - catch (const std::exception& e) - { - return false; - } - } - return true; -} -//------------------------------------------------------------------ // Find the split point between us and foreign blockchain and return // (by reference) the most recent common block hash along with up to // BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes. @@ -2621,38 +2884,23 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context { for (auto &o: tx.vout) { - if (tx.version == 1) + if (!is_valid_decomposed_amount(o.amount) && !is_valid_decomposed_amount(o.token_amount)) { - if (!is_valid_decomposed_amount(o.amount) && !is_valid_decomposed_amount(o.token_amount)) - { - tvc.m_invalid_output = true; - return false; - } + tvc.m_invalid_output = true; + return false; } } } // check that the outputs are whole amounts for token transfers - if (tx.version == 1) { - for (auto &o: tx.vout) { - if ((o.target.type() == typeid(txout_token_to_key))) { - if (!tools::is_whole_coin_amount(o.token_amount)) { - tvc.m_invalid_output = true; - return false; - } - } - } - } - - - // in a v2 tx, all outputs must have 0 amount - if (hf_version >= HF_VERSION_ENFORCE_RCT) { - if (tx.version >= 2) { - for (auto &o: tx.vout) { - if (o.amount != 0) { - tvc.m_invalid_output = true; - return false; - } + for (auto &o: tx.vout) + { + if ((o.target.type() == typeid(txout_token_to_key))) + { + if (!tools::is_whole_token_amount(o.token_amount)) + { + tvc.m_invalid_output = true; + return false; } } } @@ -2685,17 +2933,632 @@ bool Blockchain::check_tx_outputs(const transaction& tx, tx_verification_context return true; } //------------------------------------------------------------------ +bool Blockchain::check_safex_tx(const transaction &tx, tx_verification_context &tvc) +{ + + if (tx.version == 1) return true; + + std::vector input_commands_to_execute; + safex::command_t input_command_to_check; + + bool only_donate_seen = true; + bool only_stake_seen = true; + + for (auto txin: tx.vin) + { + if ((txin.type() == typeid(txin_to_script))) + { + const txin_to_script &txin_script = boost::get(txin); + + if(txin_script.command_type != safex::command_t::donate_network_fee) + only_donate_seen = false; + + if(txin_script.command_type != safex::command_t::token_stake) + only_stake_seen = false; + + input_commands_to_execute.push_back(txin_script); + input_command_to_check = txin_script.command_type; + } + } + + // Per TX there can be : + // * 1 command for all types + // * >1 commands if they are all stake token or donate_network_fee + if (!(input_commands_to_execute.size() == 1 + || (input_commands_to_execute.size() > 1 && (only_donate_seen || only_stake_seen)))) { + tvc.m_safex_invalid_command = true; + return false; + } + + + std::vector advanced_outputs; + bool network_fee_out = false; + bool purchase_out = false; + bool feedback_token_out = false; + + for (auto txout: tx.vout) + { + if ((txout.target.type() == typeid(txout_to_script))) + { + auto txout_type = get_tx_out_type(txout.target); + advanced_outputs.push_back(txout_type); + if(txout_type == cryptonote::tx_out_type::out_safex_purchase) + purchase_out = true; + if(txout_type == cryptonote::tx_out_type::out_safex_feedback_token) + feedback_token_out = true; + if(txout_type == cryptonote::tx_out_type::out_network_fee) + network_fee_out = true; + } + } + + // Per TX there can be : + // * 1 advanced output for all types + // * 3 outputs if tx is safex_purchase + // * 0 outputs if tx is token_unstake + if (!(advanced_outputs.size() == 1 + || (advanced_outputs.size() == 3 && network_fee_out && purchase_out && feedback_token_out) + || (advanced_outputs.size() == 0 && input_command_to_check== safex::command_t::token_unstake))) { + tvc.m_safex_invalid_command = true; + return false; + } + + //validate all command logic + for (const txin_to_script& cmd: input_commands_to_execute) + if (!safex::validate_safex_command(*m_db, cmd)) { + tvc.m_safex_command_execution_failed = true; + return false; + } + + //check all commands tx restrictions + if (!check_safex_tx_command(tx, input_command_to_check)){ + tvc.m_safex_invalid_input = true; + return false; + } + + return true; +} +//------------------------------------------------------------------ +bool Blockchain::check_safex_tx_command(const transaction &tx, const safex::command_t &command_type){ + + if (command_type == safex::command_t::token_stake) + { + /* Find amount of input staked tokens */ + uint64_t inputs_staked_token_amount = 0; + for(const auto &vin: tx.vin) + if ((vin.type() == typeid(txin_to_script))){ + const txin_to_script &txin_script = boost::get(vin); + if(txin_script.command_type == safex::command_t::token_stake) + inputs_staked_token_amount += txin_script.token_amount; + } + + /* Find amount of output staked tokens */ + uint64_t outputs_staked_token_amount = 0; + for (const auto &vout: tx.vout) + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_staked_token) + { + const txout_to_script &out = boost::get(vout.target); + if (out.output_type == static_cast(tx_out_type::out_staked_token)) + outputs_staked_token_amount += vout.token_amount; + } + + /* Check if minumum amount of tokens is staked */ + if (outputs_staked_token_amount < safex::get_minimum_token_stake_amount(m_nettype)) + { + MERROR("Safex token stake amount too small, must be at least "<< cryptonote::print_money(safex::get_minimum_token_stake_amount(m_nettype))); + return false; + } + /* Check if amount of staked tokens in the output is less or equal to the amount in the input*/ + if (inputs_staked_token_amount < outputs_staked_token_amount) + { + MERROR("Safex token stake output amount higher than input amount"); + return false; + } + } + else if (command_type == safex::command_t::token_unstake) + { + + } + else if (command_type == safex::command_t::donate_network_fee) + { + /* Find cash amount on output that is donated */ + uint64_t outputs_donated_cash_amount = 0; + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_network_fee) + { + const txout_to_script &out = boost::get(vout.target); + if (out.output_type == static_cast(tx_out_type::out_network_fee)) + outputs_donated_cash_amount += vout.amount; + } + } + + uint64_t input_cash_amount = 0; + for (const auto &txin: tx.vin) + { + input_cash_amount += get_tx_input_cash_amount(txin); + } + + /* Check if donated cash amount matches */ + if (outputs_donated_cash_amount >= input_cash_amount || outputs_donated_cash_amount == 0) + { + MERROR("Invalid safex cash input amount"); + return false; + } + } + else if (command_type == safex::command_t::create_account) + { + + uint64_t total_locked_tokens = 0; + bool create_account_seen = false; + txin_to_script command; + for(auto txin: tx.vin){ + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &stxin = boost::get(txin); + if (stxin.command_type == safex::command_t::create_account) + { + command = stxin; + } + } + } + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(command.script); + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account) + { + if(create_account_seen) + { + MERROR("Multiple Safex account creation outputs"); + return false; + } + create_account_seen = true; + + const txout_to_script &out = boost::get(vout.target); + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string account_username(std::begin(account.username), std::end(account.username)); + + + if(cmd->get_username() != account_username || cmd->get_account_key() != account.pkey || cmd->get_account_data() != account.account_data){ + MERROR("Output data not matching input command data"); + return false; + } + + } + if (vout.target.type() == typeid(txout_token_to_key) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_token && vout.token_amount == SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE) + { + total_locked_tokens += vout.token_amount; + } + + } + + if(!create_account_seen){ + MERROR("Create account output not found"); + return false; + } + + if(total_locked_tokens < SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE){ + MERROR("Not enough tokens given as output. Needed: " + std::to_string(SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE) + ", actual sent: "+std::to_string(total_locked_tokens) ); + return false; + } + + } + else if (command_type == safex::command_t::edit_account) + { + bool edit_account_seen = false; + txin_to_script command; + for(auto txin: tx.vin){ + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &stxin = boost::get(txin); + if (stxin.command_type == safex::command_t::edit_account) + { + command = stxin; + } + } + } + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(command.script); + + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account_update) + { + if(edit_account_seen) + { + MERROR("Multiple Safex account edit outputs"); + return false; + } + edit_account_seen = true; + + const txout_to_script &out = boost::get(vout.target); + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string account_username(std::begin(account.username), std::end(account.username)); + + + if(cmd->get_username() != account_username || cmd->get_new_account_data() != account.account_data){ + MERROR("Output data not matching input command data"); + return false; + } + + } + } + + if(!edit_account_seen){ + MERROR("Edit account output not found"); + return false; + } + } + else if (command_type == safex::command_t::create_offer) + { + bool create_offer_seen = false; + txin_to_script command; + for(auto txin: tx.vin){ + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &stxin = boost::get(txin); + if (stxin.command_type == safex::command_t::create_offer) + { + command = stxin; + } + } + } + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(command.script); + + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer) + { + if(create_offer_seen) + { + MERROR("Multiple Safex offer create outputs"); + return false; + } + create_offer_seen = true; + + const txout_to_script &out = boost::get(vout.target); + safex::create_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + + if(cmd->get_offerid() != offer.offer_id || cmd->get_price_peg_id() != offer.price_peg_id || cmd->get_seller() != offer.seller + || cmd->get_title() != offer.title || cmd->get_price() != offer.price || cmd->get_min_sfx_price() != offer.min_sfx_price + || cmd->get_quantity() != offer.quantity || cmd->get_active() != offer.active || cmd->get_price_peg_used() != offer.price_peg_used + || cmd->get_description() != offer.description || cmd->get_seller_private_view_key() != offer.seller_private_view_key + || cmd->get_seller_address() != offer.seller_address){ + MERROR("Output data not matching input command data"); + return false; + } + + } + } + + if(!create_offer_seen){ + MERROR("Create offer output not found"); + return false; + } + } + else if (command_type == safex::command_t::edit_offer) + { + bool edit_offer_seen = false; + txin_to_script command; + for(auto txin: tx.vin){ + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &stxin = boost::get(txin); + if (stxin.command_type == safex::command_t::edit_offer) + { + command = stxin; + } + } + } + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(command.script); + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer_update) + { + if(edit_offer_seen) + { + MERROR("Multiple Safex offer edit outputs"); + return false; + } + edit_offer_seen = true; + + const txout_to_script &out = boost::get(vout.target); + safex::edit_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + + if(cmd->get_offerid() != offer.offer_id || cmd->get_price_peg_id() != offer.price_peg_id || cmd->get_seller() != offer.seller + || cmd->get_title() != offer.title || cmd->get_price() != offer.price || cmd->get_min_sfx_price() != offer.min_sfx_price + || cmd->get_quantity() != offer.quantity || cmd->get_active() != offer.active || cmd->get_price_peg_used() != offer.price_peg_used + || cmd->get_description() != offer.description){ + MERROR("Output data not matching input command data"); + return false; + } + } + } + if(!edit_offer_seen){ + MERROR("Edit offer output not found"); + return false; + } + } + else if (command_type == safex::command_t::simple_purchase) + { + uint64_t network_fee = 0; + uint64_t product_payment = 0; + uint64_t total_payment = 0; + crypto::secret_key secret_seller_view_key; + crypto::public_key public_seller_spend_key; + bool purchase_seen = false; + txin_to_script command; + for(auto txin: tx.vin){ + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &stxin = boost::get(txin); + if (stxin.command_type == safex::command_t::simple_purchase) + { + command = stxin; + } + } + } + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(command.script); + + + if (tx.unlock_time > m_db->height()) + { + MERROR("Purchase TX should not be locked"); + return false; + } + + for (const auto &vout: tx.vout) { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_purchase) + { + if(purchase_seen) + { + MERROR("Multiple Safex purchase outputs"); + return false; + } + purchase_seen = true; + + const txout_to_script &out = boost::get(vout.target); + safex::safex_offer offer_to_purchase; + safex::create_purchase_data purchase; + const cryptonote::blobdata purchaseblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(purchaseblob, purchase); + + if(cmd->get_offerid() != purchase.offer_id + || cmd->get_price() != purchase.price + || cmd->get_quantity() != purchase.quantity + || cmd->get_shipping() != purchase.shipping){ + MERROR("Output data not matching input command data"); + return false; + } + + total_payment = purchase.price; + get_safex_offer(purchase.offer_id, offer_to_purchase); + + secret_seller_view_key = offer_to_purchase.seller_private_view_key; + public_seller_spend_key = offer_to_purchase.seller_address.m_spend_public_key; + + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_feedback_token) + { + + const txout_to_script &out = boost::get(vout.target); + safex::create_feedback_token_data feedback_token; + const cryptonote::blobdata feedbacktokenblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(feedbacktokenblob, feedback_token); + + + if(cmd->get_offerid() != feedback_token.offer_id){ + MERROR("Output data not matching input command data"); + return false; + } + } + } + + std::vector seller_outs= is_safex_purchase_right_address(secret_seller_view_key, public_seller_spend_key, tx); + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_network_fee) + { + network_fee += vout.amount; + } + else if (vout.target.type() == typeid(txout_to_key) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_cash) + { + const crypto::public_key &out = *boost::apply_visitor(destination_public_key_visitor(), vout.target); + auto it = std::find(seller_outs.begin(),seller_outs.end(),out); + if(it!=seller_outs.end()) + product_payment += vout.amount; + } + } + + uint64_t calculated_network_fee = calculate_safex_network_fee(total_payment, m_nettype, command_type); + //check network fee payment + if (calculated_network_fee > network_fee) + { + MERROR("Not enough cash given for network fee"); + return false; + } + //check purchase cash payment + if (total_payment - calculated_network_fee > product_payment) + { + MERROR("Not enough cash given for product payment"); + return false; + } + } + else if (command_type == safex::command_t::create_feedback) + { + bool feedback_seen = false; + txin_to_script command; + for(auto txin: tx.vin){ + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &stxin = boost::get(txin); + if (stxin.command_type == safex::command_t::create_feedback) + { + command = stxin; + } + } + } + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(command.script); + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_feedback) + { + if(feedback_seen) + { + MERROR("Multiple Safex feedback outputs"); + return false; + } + feedback_seen = true; + + const txout_to_script &out = boost::get(vout.target); + safex::create_feedback_data feedback; + const cryptonote::blobdata feedbackblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(feedbackblob, feedback); + + if(cmd->get_offerid() != feedback.offer_id + || cmd->get_stars_given() != feedback.stars_given + || cmd->get_comment() != feedback.comment){ + MERROR("Output data not matching input command data"); + return false; + } + } + } + if(!feedback_seen){ + MERROR("Create feedback output not found"); + return false; + } + } + else if (command_type == safex::command_t::create_price_peg) + { + bool create_price_peg_seen = false; + txin_to_script command; + for(auto txin: tx.vin){ + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &stxin = boost::get(txin); + if (stxin.command_type == safex::command_t::create_price_peg) + { + command = stxin; + } + } + } + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(command.script); + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg) + { + if(create_price_peg_seen) + { + MERROR("Multiple Safex create price peg outputs"); + return false; + } + create_price_peg_seen = true; + + const txout_to_script &out = boost::get(vout.target); + safex::create_price_peg_data price_peg; + const cryptonote::blobdata price_peg_blob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(price_peg_blob, price_peg); + + if(cmd->get_title() != price_peg.title + || cmd->get_price_peg_id() != price_peg.price_peg_id + || cmd->get_creator() != price_peg.creator + || cmd->get_description() != price_peg.description + || cmd->get_currency() != price_peg.currency + || cmd->get_rate() != price_peg.rate){ + MERROR("Output data not matching input command data"); + return false; + } + } + } + if(!create_price_peg_seen){ + MERROR("Create price peg output not found"); + return false; + } + } + else if (command_type == safex::command_t::update_price_peg) + { + bool update_price_peg_seen = false; + txin_to_script command; + for(auto txin: tx.vin){ + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &stxin = boost::get(txin); + if (stxin.command_type == safex::command_t::update_price_peg) + { + command = stxin; + } + } + } + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(command.script); + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg_update) + { + if(update_price_peg_seen) + { + MERROR("Multiple Safex update price peg outputs"); + return false; + } + update_price_peg_seen = true; + + const txout_to_script &out = boost::get(vout.target); + safex::update_price_peg_data price_peg; + const cryptonote::blobdata price_peg_blob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(price_peg_blob, price_peg); + + if(cmd->get_price_peg_id() != price_peg.price_peg_id + || cmd->get_rate() != price_peg.rate){ + MERROR("Output data not matching input command data"); + return false; + } + + } + } + if(!update_price_peg_seen){ + MERROR("Update price peg output not found"); + return false; + } + } + else + { + MERROR("Unsupported safex command"); + return false; + } + + return true; +} +//------------------------------------------------------------------ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const { LOG_PRINT_L3("Blockchain::" << __func__); for (const txin_v& in: tx.vin) { //CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, in_to_key, true); - if (cryptonote::is_valid_transaction_input_type(in)) { + if (cryptonote::is_valid_transaction_input_type(in, tx.version)) { auto k_image_opt = boost::apply_visitor(key_image_visitor(), in); //key image boost optional of currently checked input CHECK_AND_ASSERT_MES(k_image_opt, true, "key image is not available in input"); const crypto::key_image &k_image = *k_image_opt; + if (in.type() == typeid(txin_to_script)) + { + const txin_to_script& in_to_script = boost::get(in); + if(!safex::is_safex_key_image_verification_needed(in_to_script.command_type)) + continue; + } + if(have_tx_keyimg_as_spent(k_image)) return true; } else { @@ -2709,7 +3572,7 @@ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_prefix_hash, const std::vector> &pubkeys) { PERF_TIMER(expand_transaction_2); - CHECK_AND_ASSERT_MES(tx.version == 2, false, "Transaction version is not 2"); + CHECK_AND_ASSERT_MES(tx.version >= 2, false, "Transaction version is not 2"); rct::rctSig &rv = tx.rct_signatures; @@ -2776,7 +3639,76 @@ bool Blockchain::expand_transaction_2(transaction &tx, const crypto::hash &tx_pr return true; } -//------------------------------------------------------------------ +//------------------------------------------------------------------. + + +bool Blockchain::check_advanced_tx_input(const txin_to_script &txin, tx_verification_context &tvc) +{ + + if (txin.command_type == safex::command_t::token_stake) + { + if (txin.amount > 0 || txin.token_amount == 0) + return false; + } + else if (txin.command_type == safex::command_t::token_unstake) + { + if (txin.token_amount == 0) + return false; + } + else if (txin.command_type == safex::command_t::donate_network_fee) + { + if (txin.amount == 0 || txin.token_amount > 0) + return false; + } + else if (txin.command_type == safex::command_t::create_account) + { + if (txin.amount != 0 || txin.token_amount == 0) //create account input references (spends some of token outputs), in total SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE + return false; + } + else if (txin.command_type == safex::command_t::edit_account) + { + if (txin.amount > 0 || txin.token_amount > 0) + return false; + } + else if (txin.command_type == safex::command_t::create_offer) + { + if (txin.amount > 0 || txin.token_amount > 0) + return false; + } + else if (txin.command_type == safex::command_t::edit_offer) + { + if (txin.amount > 0 || txin.token_amount > 0) + return false; + } + else if (txin.command_type == safex::command_t::simple_purchase) + { + if (txin.amount == 0 || txin.token_amount > 0) + return false; + } + else if (txin.command_type == safex::command_t::create_feedback) + { + if (txin.amount > 0 || txin.token_amount > 0) + return false; + } + else if (txin.command_type == safex::command_t::create_price_peg) + { + if (txin.amount > 0 || txin.token_amount > 0) + return false; + } + else if (txin.command_type == safex::command_t::update_price_peg) + { + if (txin.amount > 0 || txin.token_amount > 0) + return false; + } + else + { + MERROR_VER("Unknown input command type"); + return false; + } + + return true; +} +//------------------------------------------------------------------. // This function validates transaction inputs and their keys. // FIXME: consider moving functionality specific to one input into // check_tx_input() rather than here, and use this function simply @@ -2844,22 +3776,6 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, return false; } } - - // min/max tx version based on HF, and we accept v1 txes if having a non mixable - const size_t max_tx_version = (hf_version < HF_VERSION_ENFORCE_RCT) ? 1 : 2; - if (tx.version > max_tx_version) - { - MERROR_VER("transaction version " << (unsigned)tx.version << " is higher than max accepted version " << max_tx_version); - tvc.m_verifivation_failed = true; - return false; - } - const size_t min_tx_version = (n_unmixable > 0 ? 1 : (hf_version >= HF_VERSION_ENFORCE_RCT) ? 2 : 1); - if (tx.version < min_tx_version) - { - MERROR_VER("transaction version " << (unsigned)tx.version << " is lower than min accepted version " << min_tx_version); - tvc.m_verifivation_failed = true; - return false; - } } //sorted ins @@ -2867,7 +3783,7 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, for (size_t n = 0; n < tx.vin.size(); ++n) { const txin_v &txin = tx.vin[n]; - if (is_valid_transaction_input_type(txin)) + if (is_valid_transaction_input_type(txin, tx.version)) { const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), txin); if ((last_key_image != boost::value_initialized()) && (memcmp(&k_image, &last_key_image, sizeof(last_key_image)) >= 0)) @@ -2899,73 +3815,89 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, uint64_t already_migrated_tokens = m_db->height() ? m_db->get_block_already_migrated_tokens(m_db->height() - 1) : 0; //whole number of tokens, without decimals CHECK_AND_ASSERT_MES((already_migrated_tokens <= TOKEN_TOTAL_SUPPLY), false, "wrong number of migrated tokens, please purge and rebuild database"); - MDEBUG("already_migrated_tokens: " << already_migrated_tokens); uint64_t newly_migrated_tokens = 0; - - - - for (const auto& txin : tx.vin) { // make sure output being spent is of allow input type (txin_to_key,txin_token_to_key) ... - CHECK_AND_ASSERT_MES(is_valid_transaction_input_type(txin), false, "wrong type id in tx input at Blockchain::check_tx_inputs"); + CHECK_AND_ASSERT_MES(is_valid_transaction_input_type(txin, tx.version), false, "wrong type id in tx input at Blockchain::check_tx_inputs"); // make sure that the input amount is a while number - if (tx.version == 1 && ((txin.type() == typeid(txin_token_to_key)) || (txin.type() == typeid(txin_token_migration)))) + if ((txin.type() == typeid(txin_token_to_key)) || (txin.type() == typeid(txin_token_migration))) { - auto amount = boost::apply_visitor(amount_visitor(), txin); - CHECK_AND_ASSERT_MES(tools::is_whole_coin_amount(*amount), false, "token amount not a whole number"); + auto token_amount = boost::apply_visitor(token_amount_visitor(), txin); + CHECK_AND_ASSERT_MES(tools::is_whole_token_amount(*token_amount), false, "token amount not a whole number"); //Check for maximum of migrated tokens if (txin.type() == typeid(txin_token_migration)) { - newly_migrated_tokens += *amount/SAFEX_TOKEN; //don't keep decimals + newly_migrated_tokens += *token_amount/SAFEX_TOKEN; //don't keep decimals //note: we are duing calculations with whole number of tokens. Database keeps whole number of tokens CHECK_AND_ASSERT_MES((already_migrated_tokens+newly_migrated_tokens <= TOKEN_TOTAL_SUPPLY), false, "max number of migrated tokens exceeded"); - } } + /* Check advaced command intput validity */ + if ((txin.type() == typeid(txin_to_script)) && !check_advanced_tx_input(boost::get(txin), tvc)) + { + MERROR_VER("Error in advanced input"); + tvc.m_safex_invalid_input = true; + return false; + } + + // make sure tx output has key offset(s) (is signed to be used) CHECK_AND_ASSERT_MES(is_valid_txin_key_offsets(txin), false, "empty in_to_key.key_offsets in transaction with id " << get_transaction_hash(tx)); const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), txin); //key image of currently checked input - if (have_tx_keyimg_as_spent(k_image)) + if (txin.type() == typeid(txin_to_script)) { - MERROR_VER("Key image already spent in blockchain: " << epee::string_tools::pod_to_hex(k_image)); - tvc.m_double_spend = true; - return false; + const txin_to_script& in_to_script = boost::get(txin); + if(safex::is_safex_key_image_verification_needed(in_to_script.command_type)){ + if (have_tx_keyimg_as_spent(k_image)) + { + MERROR_VER("Key image already spent in blockchain: " << epee::string_tools::pod_to_hex(k_image)); + tvc.m_double_spend = true; + return false; + } + } + } else { + if (have_tx_keyimg_as_spent(k_image)) + { + MERROR_VER("Key image already spent in blockchain: " << epee::string_tools::pod_to_hex(k_image)); + tvc.m_double_spend = true; + return false; + } } - if (tx.version == 1) - { - // basically, make sure number of inputs == number of signatures - CHECK_AND_ASSERT_MES(sig_index < tx.signatures.size(), false, "wrong transaction: not signature entry for input with index= " << sig_index); + + // basically, make sure number of inputs == number of signatures + CHECK_AND_ASSERT_MES(sig_index < tx.signatures.size(), false, "wrong transaction: not signature entry for input with index= " << sig_index); + #if defined(CACHE_VIN_RESULTS) - auto itk = it->second.find(k_image); - if(itk != it->second.end()) + auto itk = it->second.find(k_image); + if(itk != it->second.end()) + { + if(!itk->second) { - if(!itk->second) - { - MERROR_VER("Failed ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << k_image << " sig_index: " << sig_index); - return false; - } - - // txin has been verified already, skip - sig_index++; - continue; + MERROR_VER("Failed ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << k_image << " sig_index: " << sig_index); + return false; } -#endif + + // txin has been verified already, skip + sig_index++; + continue; } +#endif + // make sure that output being spent matches up correctly with the // signature spending it. - if (!check_tx_input(tx.version, txin, tx_prefix_hash, tx.version == 1 ? tx.signatures[sig_index] : std::vector(), tx.rct_signatures, pubkeys[sig_index], pmax_used_block_height)) + if (!check_tx_input(tx.version, txin, tx_prefix_hash, tx.signatures[sig_index], pubkeys[sig_index], pmax_used_block_height)) { it->second[k_image] = false; MERROR_VER("Failed to check ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << k_image << " sig_index: " << sig_index); @@ -2977,15 +3909,56 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, return false; } - if (tx.version == 1) - { if (threads > 1) { // ND: Speedup // 1. Thread ring signature verification if possible. if (txin.type() == typeid(txin_token_migration)) { tpool.submit(&waiter, boost::bind(&Blockchain::check_migration_signature, this, std::cref(tx_prefix_hash), std::cref(tx.signatures[sig_index][0]), std::ref(results[sig_index]))); - } else { + } + else if ((txin.type() == typeid(txin_to_script)) && (boost::get(txin).command_type == safex::command_t::edit_account)) { + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(boost::get(txin).script); + crypto::public_key account_pkey{}; + get_safex_account_public_key(cmd->get_username(), account_pkey); + tpool.submit(&waiter, boost::bind(&Blockchain::check_safex_account_signature, this, std::cref(tx_prefix_hash), std::cref(account_pkey), + std::cref(tx.signatures[sig_index][0]), std::ref(results[sig_index])) + ); + } + else if ((txin.type() == typeid(txin_to_script)) && (boost::get(txin).command_type == safex::command_t::create_offer)) { + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(boost::get(txin).script); + crypto::public_key account_pkey{}; + get_safex_account_public_key(cmd->get_seller(), account_pkey); + tpool.submit(&waiter, boost::bind(&Blockchain::check_safex_account_signature, this, std::cref(tx_prefix_hash), std::cref(account_pkey), + std::cref(tx.signatures[sig_index][0]), std::ref(results[sig_index])) + ); + } + else if ((txin.type() == typeid(txin_to_script)) && (boost::get(txin).command_type == safex::command_t::edit_offer)) { + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(boost::get(txin).script); + crypto::public_key account_pkey{}; + get_safex_account_public_key(cmd->get_seller(), account_pkey); + tpool.submit(&waiter, boost::bind(&Blockchain::check_safex_account_signature, this, std::cref(tx_prefix_hash), std::cref(account_pkey), + std::cref(tx.signatures[sig_index][0]), std::ref(results[sig_index])) + ); + } + else if ((txin.type() == typeid(txin_to_script)) && (boost::get(txin).command_type == safex::command_t::create_price_peg)) { + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(boost::get(txin).script); + crypto::public_key account_pkey{}; + get_safex_account_public_key(cmd->get_creator(), account_pkey); + tpool.submit(&waiter, boost::bind(&Blockchain::check_safex_account_signature, this, std::cref(tx_prefix_hash), std::cref(account_pkey), + std::cref(tx.signatures[sig_index][0]), std::ref(results[sig_index])) + ); + } + else if ((txin.type() == typeid(txin_to_script)) && (boost::get(txin).command_type == safex::command_t::update_price_peg)) { + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(boost::get(txin).script); + crypto::public_key account_pkey{}; + safex::safex_price_peg sfx_price_peg; + get_safex_price_peg(cmd->get_price_peg_id(),sfx_price_peg); + get_safex_account_public_key(sfx_price_peg.creator, account_pkey); + tpool.submit(&waiter, boost::bind(&Blockchain::check_safex_account_signature, this, std::cref(tx_prefix_hash), std::cref(account_pkey), + std::cref(tx.signatures[sig_index][0]), std::ref(results[sig_index])) + ); + } + else { tpool.submit(&waiter, boost::bind(&Blockchain::check_ring_signature, this, std::cref(tx_prefix_hash), std::cref(k_image), std::cref(pubkeys[sig_index]), std::cref(tx.signatures[sig_index]), std::ref(results[sig_index]))); } } @@ -2993,7 +3966,39 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, { if (txin.type() == typeid(txin_token_migration)) { check_migration_signature(tx_prefix_hash, tx.signatures[sig_index][0], results[sig_index]); - } else { + } else if ((txin.type() == typeid(txin_to_script)) && (boost::get(txin).command_type == safex::command_t::edit_account)) { + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(boost::get(txin).script); + crypto::public_key account_pkey{}; + get_safex_account_public_key(cmd->get_username(), account_pkey); + check_safex_account_signature(tx_prefix_hash,account_pkey,tx.signatures[sig_index][0],results[sig_index]); + } + else if ((txin.type() == typeid(txin_to_script)) && (boost::get(txin).command_type == safex::command_t::create_offer)) { + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(boost::get(txin).script); + crypto::public_key account_pkey{}; + get_safex_account_public_key(cmd->get_seller(), account_pkey); + check_safex_account_signature( tx_prefix_hash, account_pkey,tx.signatures[sig_index][0], results[sig_index]); + } + else if ((txin.type() == typeid(txin_to_script)) && (boost::get(txin).command_type == safex::command_t::edit_offer)) { + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(boost::get(txin).script); + crypto::public_key account_pkey{}; + get_safex_account_public_key(cmd->get_seller(), account_pkey); + check_safex_account_signature( tx_prefix_hash, account_pkey,tx.signatures[sig_index][0], results[sig_index]); + } + else if ((txin.type() == typeid(txin_to_script)) && (boost::get(txin).command_type == safex::command_t::create_price_peg)) { + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(boost::get(txin).script); + crypto::public_key account_pkey{}; + get_safex_account_public_key(cmd->get_creator(), account_pkey); + check_safex_account_signature( tx_prefix_hash, account_pkey,tx.signatures[sig_index][0], results[sig_index]); + } + else if ((txin.type() == typeid(txin_to_script)) && (boost::get(txin).command_type == safex::command_t::update_price_peg)) { + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(boost::get(txin).script); + crypto::public_key account_pkey{}; + safex::safex_price_peg sfx_price_peg; + get_safex_price_peg(cmd->get_price_peg_id(),sfx_price_peg); + get_safex_account_public_key(sfx_price_peg.creator, account_pkey); + check_safex_account_signature( tx_prefix_hash, account_pkey,tx.signatures[sig_index][0], results[sig_index]); + } + else { check_ring_signature(tx_prefix_hash, k_image, pubkeys[sig_index], tx.signatures[sig_index], results[sig_index]); } @@ -3011,17 +4016,13 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, } it->second[k_image] = true; } - } sig_index++; } - if (tx.version == 1 && threads > 1) - waiter.wait(); - if (tx.version == 1) - { if (threads > 1) { + waiter.wait(); // save results to table, passed or otherwise bool failed = false; for (size_t i = 0; i < tx.vin.size(); i++) @@ -3040,150 +4041,13 @@ bool Blockchain::check_tx_inputs(transaction& tx, tx_verification_context &tvc, return false; } } - } - else - { - //for RingCT - if (!expand_transaction_2(tx, tx_prefix_hash, pubkeys)) - { - MERROR_VER("Failed to expand rct signatures!"); - return false; - } - - // from version 2, check ringct signatures - // obviously, the original and simple rct APIs use a mixRing that's indexes - // in opposite orders, because it'd be too simple otherwise... - const rct::rctSig &rv = tx.rct_signatures; - switch (rv.type) - { - case rct::RCTTypeNull: { - // we only accept no signatures for coinbase txes - MERROR_VER("Null rct signature on non-coinbase tx"); - return false; - } - case rct::RCTTypeSimple: - case rct::RCTTypeSimpleBulletproof: - { - // check all this, either reconstructed (so should really pass), or not - { - if (pubkeys.size() != rv.mixRing.size()) - { - MERROR_VER("Failed to check ringct signatures: mismatched pubkeys/mixRing size"); - return false; - } - for (size_t i = 0; i < pubkeys.size(); ++i) - { - if (pubkeys[i].size() != rv.mixRing[i].size()) - { - MERROR_VER("Failed to check ringct signatures: mismatched pubkeys/mixRing size"); - return false; - } - } - - for (size_t n = 0; n < pubkeys.size(); ++n) - { - for (size_t m = 0; m < pubkeys[n].size(); ++m) - { - if (pubkeys[n][m].dest != rct::rct2pk(rv.mixRing[n][m].dest)) - { - MERROR_VER("Failed to check ringct signatures: mismatched pubkey at vin " << n << ", index " << m); - return false; - } - if (pubkeys[n][m].mask != rct::rct2pk(rv.mixRing[n][m].mask)) - { - MERROR_VER("Failed to check ringct signatures: mismatched commitment at vin " << n << ", index " << m); - return false; - } - } - } - } - - if (rv.p.MGs.size() != tx.vin.size()) - { - MERROR_VER("Failed to check ringct signatures: mismatched MGs/vin sizes"); - return false; - } - for (size_t n = 0; n < tx.vin.size(); ++n) - { - if (rv.p.MGs[n].II.empty() || memcmp(&boost::get(tx.vin[n]).k_image, &rv.p.MGs[n].II[0], 32)) - { - MERROR_VER("Failed to check ringct signatures: mismatched key image"); - return false; - } - } - - if (!rct::verRctSimple(rv, false)) - { - MERROR_VER("Failed to check ringct signatures!"); - return false; - } - break; - } - case rct::RCTTypeFull: - case rct::RCTTypeFullBulletproof: - { - // check all this, either reconstructed (so should really pass), or not - { - bool size_matches = true; - for (size_t i = 0; i < pubkeys.size(); ++i) - size_matches &= pubkeys[i].size() == rv.mixRing.size(); - for (size_t i = 0; i < rv.mixRing.size(); ++i) - size_matches &= pubkeys.size() == rv.mixRing[i].size(); - if (!size_matches) - { - MERROR_VER("Failed to check ringct signatures: mismatched pubkeys/mixRing size"); - return false; - } - for (size_t n = 0; n < pubkeys.size(); ++n) - { - for (size_t m = 0; m < pubkeys[n].size(); ++m) - { - if (pubkeys[n][m].dest != rct::rct2pk(rv.mixRing[m][n].dest)) - { - MERROR_VER("Failed to check ringct signatures: mismatched pubkey at vin " << n << ", index " << m); - return false; - } - if (pubkeys[n][m].mask != rct::rct2pk(rv.mixRing[m][n].mask)) - { - MERROR_VER("Failed to check ringct signatures: mismatched commitment at vin " << n << ", index " << m); - return false; - } - } - } - } - - if (rv.p.MGs.size() != 1) - { - MERROR_VER("Failed to check ringct signatures: Bad MGs size"); - return false; - } - if (rv.p.MGs.empty() || rv.p.MGs[0].II.size() != tx.vin.size()) - { - MERROR_VER("Failed to check ringct signatures: mismatched II/vin sizes"); - return false; - } - for (size_t n = 0; n < tx.vin.size(); ++n) - { - if (memcmp(&boost::get(tx.vin[n]).k_image, &rv.p.MGs[0].II[n], 32)) - { - MERROR_VER("Failed to check ringct signatures: mismatched II/vin sizes"); - return false; - } - } - - if (!rct::verRct(rv, false)) - { - MERROR_VER("Failed to check ringct signatures!"); - return false; - } - break; - } - default: - MERROR_VER("Unsupported rct type: " << rv.type); + if(!check_safex_tx(tx,tvc)){ + tvc.m_verifivation_failed = true; + tvc.m_safex_verification_failed = true; return false; - } } + return true; } @@ -3207,6 +4071,15 @@ void Blockchain::check_migration_signature(const crypto::hash &tx_prefix_hash, get_migration_verification_public_key(m_nettype, sender_public_key); result = crypto::check_signature(tx_prefix_hash, sender_public_key, signature) ? 1 : 0; } +//------------------------------------------------------------------ +void Blockchain::check_safex_account_signature(const crypto::hash &tx_prefix_hash, const crypto::public_key &sender_safex_account_key, + const crypto::signature &signature, uint64_t &result) +{ + + result = safex::check_safex_account_signature(tx_prefix_hash, sender_safex_account_key, signature) ? 1 : 0; +} + + //------------------------------------------------------------------ static uint64_t get_fee_quantization_mask() { @@ -3250,10 +4123,10 @@ uint64_t Blockchain::get_dynamic_per_kb_fee(uint64_t block_reward, size_t median //------------------------------------------------------------------ bool Blockchain::check_fee(size_t blob_size, uint64_t fee) const { - const uint8_t version = get_current_hard_fork_version(); + const uint8_t hf_version = get_current_hard_fork_version(); uint64_t fee_per_kb; - if (version < HF_VERSION_DYNAMIC_FEE) + if (hf_version < HF_VERSION_DYNAMIC_FEE) { fee_per_kb = FEE_PER_KB; } @@ -3262,9 +4135,9 @@ bool Blockchain::check_fee(size_t blob_size, uint64_t fee) const uint64_t median = m_current_block_cumul_sz_limit / 2; uint64_t already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0; uint64_t base_reward; - if (!get_block_reward(median, 1, already_generated_coins, base_reward, version, m_db->height())) + if (!get_block_reward(median, 1, already_generated_coins, base_reward, hf_version, m_db->height())) return false; - fee_per_kb = get_dynamic_per_kb_fee(base_reward, median, version); + fee_per_kb = get_dynamic_per_kb_fee(base_reward, median, hf_version); } MDEBUG("Using " << print_money(fee_per_kb) << "/kB fee"); @@ -3283,15 +4156,15 @@ bool Blockchain::check_fee(size_t blob_size, uint64_t fee) const //------------------------------------------------------------------ uint64_t Blockchain::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks) const { - const uint8_t version = get_current_hard_fork_version(); + const uint8_t hf_version = get_current_hard_fork_version(); - if (version < HF_VERSION_DYNAMIC_FEE) + if (hf_version < HF_VERSION_DYNAMIC_FEE) return FEE_PER_KB; if (grace_blocks >= CRYPTONOTE_REWARD_BLOCKS_WINDOW) grace_blocks = CRYPTONOTE_REWARD_BLOCKS_WINDOW - 1; - const uint64_t min_block_size = get_min_block_size(version); + const uint64_t min_block_size = get_min_block_size(hf_version); std::vector sz; get_last_n_blocks_sizes(sz, CRYPTONOTE_REWARD_BLOCKS_WINDOW - grace_blocks); for (size_t i = 0; i < grace_blocks; ++i) @@ -3303,13 +4176,13 @@ uint64_t Blockchain::get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks) cons uint64_t already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0; uint64_t base_reward; - if (!get_block_reward(median, 1, already_generated_coins, base_reward, version, m_db->height())) + if (!get_block_reward(median, 1, already_generated_coins, base_reward, hf_version, m_db->height())) { MERROR("Failed to determine block reward, using placeholder " << print_money(BLOCK_REWARD_OVERESTIMATE) << " as a high bound"); base_reward = BLOCK_REWARD_OVERESTIMATE; } - uint64_t fee = get_dynamic_per_kb_fee(base_reward, median, version); + uint64_t fee = get_dynamic_per_kb_fee(base_reward, median, hf_version); MDEBUG("Estimating " << grace_blocks << "-block fee at " << print_money(fee) << "/kB"); return fee; } @@ -3345,7 +4218,7 @@ bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time) const // and validates that they exist and are usable. It also checks the ring // signature for each input. template -bool Blockchain::check_tx_input_generic(size_t tx_version, const T& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const rct::rctSig &rct_signatures, std::vector &output_keys, uint64_t* pmax_related_block_height) +bool Blockchain::check_tx_input_generic(size_t tx_version, const T& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, std::vector &output_keys, uint64_t* pmax_related_block_height) { LOG_PRINT_L3("Blockchain::" << __func__); @@ -3362,104 +4235,96 @@ bool Blockchain::check_tx_input_generic(size_t tx_version, const T& txin, const { } - bool get_pwned(const public_key &key) - { - uint8_t version = m_bch.get_current_hard_fork_version(); - if(version < HF_VERSION_STOP_COUNTERFEIT_TOKENS) - return false; - - for(const auto& it: config::PROBLEMATIC_TOKEN_OUTPUTS) { - crypto::public_key problematic_key; - - epee::string_tools::hex_to_pod(it, problematic_key); - - if(problematic_key==key){ - LOG_ERROR("I'm sorry Dave, I'm afraid I can't do that."); - return true; - } + }; - } - return false; - } + output_keys.clear(); - bool handle_output(uint64_t unlock_time, const crypto::public_key &pubkey, const rct::key &commitment) - { - //check tx unlock time - if (!m_bch.is_tx_spendtime_unlocked(unlock_time)) - { - MERROR_VER("One of outputs for one of inputs has wrong tx.unlock_time = " << unlock_time); - return false; - } + uint64_t cash_amount = get_tx_input_cash_amount(txin); + uint64_t token_amount = get_tx_input_token_amount(txin); + // collect output keys + Blockchain::outputs_generic_visitor vi(output_keys, *this); + if (!scan_outputkeys_for_indexes(tx_version, txin, vi, tx_prefix_hash, pmax_related_block_height)) + { + MERROR_VER("Failed to get output keys for tx with cash amount = " << print_money(cash_amount) << " token amount=" << token_amount << " and count indexes " << txin.key_offsets.size()); + return false; + } + if(txin.key_offsets.size() != output_keys.size()) + { + MERROR_VER("Output keys for tx with amount= " << cash_amount<< " token amount=" << token_amount << " and count indexes " << txin.key_offsets.size() << " returned wrong keys count " << output_keys.size()); + return false; + } - if(get_pwned(pubkey)) - { - MERROR_VER("One of outputs has a problematic history: " << pubkey); - return false; - } - // The original code includes a check for the output corresponding to this input - // to be a txout_to_key. This is removed, as the database does not store this info, - // but only txout_to_key outputs are stored in the DB in the first place, done in - // Blockchain*::add_output + CHECK_AND_ASSERT_MES(sig.size() == output_keys.size(), false, "internal error: tx signatures count=" << sig.size() << " mismatch with outputs keys count for inputs=" << output_keys.size()); + return true; +} - m_output_keys.push_back(rct::ctkey({rct::pk2rct(pubkey), commitment})); - return true; - } - }; +//------------------------------------------------------------------ +// This function locates all outputs associated with a given input (mixins) +// and validates that they exist and are usable for advanced inputs +// with comamnds. It also checks the ring +// signature for each input. +bool Blockchain::check_tx_input_script(size_t tx_version, const txin_to_script& txin, const crypto::hash& tx_prefix_hash, + const std::vector& sig, std::vector &output_keys, + uint64_t* pmax_related_block_height) +{ + LOG_PRINT_L3("Blockchain::" << __func__); + + //CRITICAL_REGION_LOCAL(m_blockchain_lock); output_keys.clear(); - uint64_t value_amount = get_tx_input_amount(txin); + + uint64_t cash_amount = get_tx_input_cash_amount(txin); + uint64_t token_amount = get_tx_input_token_amount(txin); // collect output keys - outputs_visitor vi(output_keys, *this); + Blockchain::outputs_generic_visitor vi(output_keys, *this); if (!scan_outputkeys_for_indexes(tx_version, txin, vi, tx_prefix_hash, pmax_related_block_height)) { - MERROR_VER("Failed to get output keys for tx with amount = " << print_money(value_amount) << " and count indexes " << txin.key_offsets.size()); + MERROR_VER("Failed to get advanced output keys for tx with cash amount = " << print_money(cash_amount) << " token amount=" << token_amount << " and count indexes " << txin.key_offsets.size()); return false; } if(txin.key_offsets.size() != output_keys.size()) { - MERROR_VER("Output keys for tx with amount = " << value_amount << " and count indexes " << txin.key_offsets.size() << " returned wrong keys count " << output_keys.size()); + MERROR_VER("Advanced output keys for tx with amount= " << cash_amount<< " token amount=" << token_amount << " and count indexes " << txin.key_offsets.size() << " returned wrong keys count " << output_keys.size()); return false; } - if (tx_version == 1) { - CHECK_AND_ASSERT_MES(sig.size() == output_keys.size(), false, "internal error: tx signatures count=" << sig.size() << " mismatch with outputs keys count for inputs=" << output_keys.size()); - } - // rct_signatures will be expanded after this + + CHECK_AND_ASSERT_MES(sig.size() == output_keys.size(), false, "internal error: tx signatures count=" << sig.size() << " mismatch with outputs keys count for inputs=" << output_keys.size()); + return true; } //------------------------------------------------------------------ // Call particular specialized function to check various input types -bool Blockchain::check_tx_input(size_t tx_version, const txin_v& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const rct::rctSig &rct_signatures, std::vector &output_keys, uint64_t* pmax_related_block_height) +bool Blockchain::check_tx_input(size_t tx_version, const txin_v& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, std::vector &output_keys, uint64_t* pmax_related_block_height) { struct txin_visitor : public boost::static_visitor { size_t tx_version; const crypto::hash& tx_prefix_hash; const std::vector& sig; - const rct::rctSig &rct_signatures; std::vector &output_keys; uint64_t* pmax_related_block_height; Blockchain *const that; txin_visitor(Blockchain *const _that, size_t _tx_version, const crypto::hash& _tx_prefix_hash, const std::vector& _sig, - const rct::rctSig &_rct_signatures, std::vector &_output_keys, uint64_t* _pmax_related_block_height): - that(_that), tx_version(_tx_version), tx_prefix_hash(_tx_prefix_hash), sig(_sig),rct_signatures(_rct_signatures),output_keys(_output_keys), + std::vector &_output_keys, uint64_t* _pmax_related_block_height): + that(_that), tx_version(_tx_version), tx_prefix_hash(_tx_prefix_hash), sig(_sig), output_keys(_output_keys), pmax_related_block_height(_pmax_related_block_height) {} bool operator()(const cryptonote::txin_gen & _txin) const {return false;} - bool operator()(const txin_to_key & _txin) const {return that->check_tx_input_generic(tx_version, _txin, tx_prefix_hash, sig, rct_signatures, output_keys, pmax_related_block_height);} - bool operator()(const txin_token_to_key & _txin) const {return that->check_tx_input_generic(tx_version, _txin, tx_prefix_hash, sig, rct_signatures, output_keys, pmax_related_block_height);} + bool operator()(const txin_to_key & _txin) const {return that->check_tx_input_generic(tx_version, _txin, tx_prefix_hash, sig, output_keys, pmax_related_block_height);} + bool operator()(const txin_token_to_key & _txin) const {return that->check_tx_input_generic(tx_version, _txin, tx_prefix_hash, sig, output_keys, pmax_related_block_height);} bool operator()(const txin_token_migration & _txin) const {return that->check_tx_input_migration(tx_version, _txin, tx_prefix_hash, sig, output_keys, pmax_related_block_height);} - bool operator()(const txin_to_script & _txin) const {return false;} + bool operator()(const txin_to_script & _txin) const {return that->check_tx_input_script(tx_version, _txin, tx_prefix_hash, sig, output_keys, pmax_related_block_height);} bool operator()(const txin_to_scripthash & _txin) const {return false;} }; - return boost::apply_visitor(txin_visitor(this, tx_version, tx_prefix_hash, sig, rct_signatures, output_keys, pmax_related_block_height), txin); + return boost::apply_visitor(txin_visitor(this, tx_version, tx_prefix_hash, sig, output_keys, pmax_related_block_height), txin); } //------------------------------------------------------------------ // Verify migration transaction @@ -3551,7 +4416,7 @@ bool Blockchain::check_block_timestamp(const block& b, uint64_t& median_ts) cons //------------------------------------------------------------------ void Blockchain::return_tx_to_pool(std::vector &txs) { - uint8_t version = get_current_hard_fork_version(); + uint8_t hf_version = get_current_hard_fork_version(); for (auto& tx : txs) { cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc); @@ -3560,7 +4425,7 @@ void Blockchain::return_tx_to_pool(std::vector &txs) // that might not be always true. Unlikely though, and always relaying // these again might cause a spike of traffic as many nodes re-relay // all the transactions in a popped block when a reorg happens. - if (!m_tx_pool.add_tx(tx, tvc, true, true, false, version)) + if (!m_tx_pool.add_tx(tx, tvc, true, true, false, hf_version)) { MERROR("Failed to return taken transaction with hash: " << get_transaction_hash(tx) << " to tx_pool"); } @@ -3901,14 +4766,27 @@ bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash& catch (const KEY_IMAGE_EXISTS& e) { LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what()); + m_batch_success = false; bvc.m_verifivation_failed = true; return_tx_to_pool(txs); return false; } + catch (const SAFEX_TX_CONFLICT& e) + { + LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what()); + m_batch_success = false; + bvc.m_verifivation_failed = true; +// auto it = find_if(txs.begin(),txs.end(),[e](transaction& tx){ return tx.hash == e.tx_hash; }); +// txs.erase(it); + return_tx_to_pool(txs); + return false; + } catch (const std::exception& e) { //TODO: figure out the best way to deal with this failure LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what()); + m_batch_success = false; + bvc.m_verifivation_failed = true; return_tx_to_pool(txs); return false; } @@ -4102,7 +4980,10 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) try { - m_db->batch_stop(); + if (m_batch_success) + m_db->batch_stop(); + else + m_db->batch_abort(); success = true; } catch (const std::exception &e) @@ -4139,6 +5020,7 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) TIME_MEASURE_FINISH(t1); m_blocks_longhash_table.clear(); m_scan_table.clear(); + m_scan_table_adv.clear(); m_blocks_txs_check.clear(); m_check_txin_table.clear(); @@ -4157,12 +5039,27 @@ bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) } //------------------------------------------------------------------ -//FIXME: unused parameter txs -void Blockchain::output_scan_worker(const uint64_t amount, const tx_out_type output_type, const std::vector &offsets, std::vector &outputs, std::unordered_map &txs) const +void Blockchain::output_scan_worker(const uint64_t amount, const tx_out_type output_type, const std::vector &offsets, std::vector &outputs) const +{ + try + { + m_db->get_amount_output_key(amount, offsets, outputs, output_type, true); + } + catch (const std::exception& e) + { + MERROR_VER("EXCEPTION: " << e.what()); + } + catch (...) + { + + } +} +//------------------------------------------------------------------ +void Blockchain::output_advanced_scan_worker(const tx_out_type output_type, const std::vector &output_ids, std::vector &outputs) const { try { - m_db->get_output_key(amount, offsets, outputs, output_type, true); + m_db->get_advanced_output_key(output_ids, outputs, output_type, true); } catch (const std::exception& e) { @@ -4319,6 +5216,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::listheight() + blocks_entry.size()) < m_blocks_hash_check.size()) return true; @@ -4437,6 +5335,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list, std::vector> tx_map; + std::set types; + + // [input] store all found advanced output types and vector of their output ids + std::map> advanced_output_ids_map; + // [output] stores all output_advanced_data_t for each tx_out_type + std::map> tx_advanced_map; + #define SCAN_TABLE_QUIT(m) \ do { \ MERROR_VER(m) ;\ m_scan_table.clear(); \ + m_scan_table_adv.clear(); \ return false; \ } while(0); \ @@ -4484,6 +5391,15 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list>()); + its_advanced = m_scan_table_adv.find(tx_prefix_hash); + assert(its_advanced != m_scan_table_adv.end()); + + // get all amounts from tx.vin(s) for (const auto &txin : tx.vin) { @@ -4494,9 +5410,21 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::listsecond.end()) SCAN_TABLE_QUIT("Duplicate key_image found from incoming blocks."); + auto it_advanced = its_advanced->second.find(k_image); + if (it_advanced != its_advanced->second.end()) + SCAN_TABLE_QUIT("Duplicate advanced key_image found from incoming blocks."); + const tx_out_type output_type = boost::apply_visitor(tx_output_type_visitor(), txin); - const uint64_t amount = *boost::apply_visitor(amount_visitor(), txin); - amounts.push_back(std::pair{output_type, amount}); + if (output_type == tx_out_type::out_cash || output_type == tx_out_type::out_token) + { + const uint64_t amount = *boost::apply_visitor(amount_visitor(), txin); + amounts.push_back(std::pair{output_type, amount}); + } + else + { + types.insert(output_type); + + } } // sort and remove duplicate amounts from amounts list @@ -4505,7 +5433,7 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list &amount : amounts) + for (const std::pair &amount : amounts) { if (offset_map.find(amount) == offset_map.end()) offset_map.emplace(amount, std::vector()); @@ -4514,20 +5442,39 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list()); } + for(auto type: types) + { + if(tx_advanced_map.find(type)== tx_advanced_map.end()) + tx_advanced_map.emplace(type, std::vector()); + } + // add new absolute_offsets to offset_map for (const auto &txin : tx.vin) { - if ((txin.type() == typeid(const txin_to_key)) || (txin.type() == typeid(const txin_token_to_key))) { + const tx_out_type output_presumed_type = boost::apply_visitor(tx_output_type_visitor(), txin); + + if ((txin.type() == typeid(const txin_to_key)) || (txin.type() == typeid(const txin_token_to_key)) + || (txin.type() == typeid(const txin_to_script) && (output_presumed_type == tx_out_type::out_cash || output_presumed_type == tx_out_type::out_token)) + ) + { // no need to check for duplicate here. const std::vector &key_offsets = *boost::apply_visitor(key_offset_visitor(), txin); const uint64_t amount = *boost::apply_visitor(amount_visitor(), txin); - const tx_out_type output_presumed_type = boost::apply_visitor(tx_output_type_visitor(), txin); + auto absolute_offsets = relative_output_offsets_to_absolute(key_offsets); - for (const auto & offset : absolute_offsets) + for (const auto &offset : absolute_offsets) offset_map[std::pair{output_presumed_type, amount}].push_back(offset); } + else if (txin.type() == typeid(const txin_to_script)) + { + const std::vector &output_ids = *boost::apply_visitor(key_offset_visitor(), txin); + + for (uint64_t output_id: output_ids) + advanced_output_ids_map[output_presumed_type].push_back(output_id); + + } } } } @@ -4540,9 +5487,6 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list> transactions(amounts.size()); - threads = tpool.get_max_concurrency(); if (!m_db->can_thread_bulk_indices()) threads = 1; @@ -4559,9 +5503,14 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::list &key_offsets = *boost::apply_visitor(key_offset_visitor(), txin); const uint64_t output_value_amount = *boost::apply_visitor(amount_visitor(), txin); - const tx_out_type output_presumed_type = boost::apply_visitor(tx_output_type_visitor(), txin); auto needed_offsets = relative_output_offsets_to_absolute(key_offsets); @@ -4640,7 +5601,40 @@ bool Blockchain::prepare_handle_incoming_blocks(const std::listsecond.emplace(k_image, outputs); - } else if (txin.type() == typeid(txin_token_migration)) { + } + else if (txin.type() == typeid(const txin_to_script)) + { + const std::vector &needed_output_ids = *boost::apply_visitor(key_offset_visitor(), txin); + + + std::vector advanced_outputs; + for (const uint64_t & needed_output_id : needed_output_ids) + { + size_t pos = 0; + bool found = false; + + for (const output_advanced_data_t &output_found : tx_advanced_map[output_presumed_type]) + { + if (needed_output_id == output_found.output_id) + { + found = true; + break; + } + + ++pos; + } + + if (found && pos < tx_advanced_map[output_presumed_type].size()) + advanced_outputs.push_back(tx_advanced_map[output_presumed_type].at(pos)); + else + break; + } + + const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), txin); + its_advanced->second.emplace(k_image, advanced_outputs); + + } + else if (txin.type() == typeid(txin_token_migration)) { const txin_token_migration &in_token_migration = boost::get < txin_token_migration > (txin); std::vector outputs; @@ -4949,3 +5943,343 @@ uint64_t Blockchain::count_new_migration_tokens(const std::vector& return ret; } + +uint64_t Blockchain::get_current_staked_token_sum() const +{ + return m_db->get_current_staked_token_sum(); +} + +uint64_t Blockchain::get_staked_token_sum_for_interval(const uint64_t &interval) const +{ + return m_db->get_staked_token_sum_for_interval(interval); +} + +uint64_t Blockchain::get_network_fee_sum_for_interval(const uint64_t& interval) const +{ + return m_db->get_network_fee_sum_for_interval(interval); +} + + +/* Returns token stake interest */ +uint64_t Blockchain::calculate_staked_token_interest(const uint64_t token_amount, const uint64_t start_block, const uint64_t end_block) const +{ + uint64_t ret = 0; + + + return ret; +} + +uint64_t Blockchain::calculate_staked_token_interest_for_output(const txin_to_script &txin, const uint64_t unlock_height) const +{ + return m_db->calculate_staked_token_interest_for_output(txin, unlock_height); +} + +std::map Blockchain::get_interest_map(uint64_t begin_interval, uint64_t end_interval) +{ + safex::map_interval_interest interest_map; + if (!m_db->get_interval_interest_map(begin_interval, end_interval, interest_map)) { + MERROR("Could not get interval map"); + return interest_map; + } + + return interest_map; +} + + +bool Blockchain::get_safex_account_public_key(const safex::account_username &username, crypto::public_key &pkey) const +{ + + try { + bool result = m_db->get_account_key(username, pkey); + return result; + } + catch (std::exception &ex) { + //MERROR("Error fetching account public key: "+std::string(ex.what())); + return false; + } +} + +bool Blockchain::get_safex_account_data(const safex::account_username &username, std::vector &data) const +{ + + try { + bool result = m_db->get_account_data(username, data); + return result; + } + catch (std::exception &ex) { + MERROR("Error fetching account data: "+std::string(ex.what())); + return false; + } +} + +bool Blockchain::get_safex_offer_seller(const crypto::hash &offerID, std::string &seller) const +{ + try { + bool result = m_db->get_offer_seller(offerID, seller); + return result; + } + catch (std::exception &ex) { + MERROR("Error fetching offer seller username: "+std::string(ex.what())); + return false; + } +} + +bool Blockchain::get_safex_offer(const crypto::hash &offerID, safex::safex_offer &offer) const +{ + try { + bool result = m_db->get_offer(offerID, offer); + return result; + } + catch (std::exception &ex) { + MERROR("Error fetching offer: "+std::string(ex.what())); + return false; + } +} + +bool Blockchain::get_safex_offer_price(const crypto::hash &offerID, uint64_t &price) const +{ + try { + bool result = m_db->get_offer_price(offerID, price); + return result; + } + catch (std::exception &ex) { + MERROR("Error fetching offer price: "+std::string(ex.what())); + return false; + } +} + +bool Blockchain::get_safex_offer_quantity(const crypto::hash &offerID, uint64_t &quantity) const +{ + try { + bool result = m_db->get_offer_quantity(offerID, quantity); + return result; + } + catch (std::exception &ex) { + MERROR("Error fetching offer quantity: "+std::string(ex.what())); + return false; + } +} + +bool Blockchain::get_safex_offer_active_status(const crypto::hash &offerID, bool &active) const +{ + try { + bool result = m_db->get_offer_active_status(offerID, active); + return result; + } + catch (std::exception &ex) { + MERROR("Error fetching offer active status: "+std::string(ex.what())); + return false; + } +} + +bool Blockchain::get_safex_offer_rating(const crypto::hash &offerID, uint64_t &rating) const +{ + try { + bool result = m_db->get_offer_stars_given(offerID, rating); + return result; + } + catch (std::exception &ex) { + MERROR("Error fetching offer active status: "+std::string(ex.what())); + return false; + } +} + +bool Blockchain::get_safex_accounts( std::vector> &safex_accounts) const +{ + LOG_PRINT_L3("Blockchain::" << __func__); + + return m_db->get_safex_accounts(safex_accounts); +} + +bool Blockchain::get_table_sizes( std::vector &table_sizes) const +{ + LOG_PRINT_L3("Blockchain::" << __func__); + + return m_db->get_table_sizes(table_sizes); +} + +bool Blockchain::get_safex_offer_height( crypto::hash &offer_id, uint64_t &height) const +{ + LOG_PRINT_L3("Blockchain::" << __func__); + + return m_db->get_safex_offer_height(offer_id, height); +} + +bool Blockchain::get_safex_offers( std::vector &safex_offers) const +{ + LOG_PRINT_L3("Blockchain::" << __func__); + + return m_db->get_safex_offers(safex_offers); +} + +bool Blockchain::get_safex_feedbacks(std::vector& safex_feedbacks, const crypto::hash& offer_id) const +{ + LOG_PRINT_L3("Blockchain::" << __func__); + + return m_db->get_safex_feedbacks(safex_feedbacks, offer_id); +} + +bool Blockchain::get_safex_price_pegs( std::vector &safex_price_pegs, const std::string& currency) const +{ + LOG_PRINT_L3("Blockchain::" << __func__); + + return m_db->get_safex_price_pegs(safex_price_pegs, currency); +} + +bool Blockchain::get_safex_price_peg( const crypto::hash& price_peg_id, safex::safex_price_peg& sfx_price_peg) const +{ + LOG_PRINT_L3("Blockchain::" << __func__); + + return m_db->get_safex_price_peg(price_peg_id,sfx_price_peg); +} + +std::vector Blockchain::is_safex_purchase_right_address(const crypto::secret_key& seller_secret_view_key, const crypto::public_key& public_seller_spend_key, const cryptonote::transaction& tx) { + + crypto::public_key pkey; + if (!crypto::secret_key_to_public_key(seller_secret_view_key, pkey)) { + return {}; + } + + hw::device &hwdev = hw::get_device("default"); + + boost::unique_lock hwdev_lock (hwdev); + hw::reset_mode rst(hwdev); + hwdev_lock.unlock(); + + + std::vector seller_outputs{}; + + std::vector tx_extra_fields; + if(!parse_tx_extra(tx.extra, tx_extra_fields)) + { + return seller_outputs; + } + size_t pk_index = 0; + tx_extra_pub_key pub_key_field; + if(!find_tx_extra_field_by_type(tx_extra_fields, pub_key_field, pk_index++)) + { + if (pk_index > 1) + return seller_outputs; + return seller_outputs; + } + + crypto::public_key tx_pub_key = pub_key_field.pub_key; + crypto::key_derivation derivation; + hwdev_lock.lock(); + hwdev.set_mode(hw::device::TRANSACTION_PARSE); + if (!hwdev.generate_key_derivation(tx_pub_key, seller_secret_view_key, derivation)) + { + MWARNING("Failed to generate key derivation from tx pubkey, skipping"); + static_assert(sizeof(derivation) == sizeof(rct::key), "Mismatched sizes of key_derivation and rct::key"); + memcpy(&derivation, rct::identity().bytes, sizeof(derivation)); + } + + // additional tx pubkeys and derivations for multi-destination transfers involving one or more subaddresses + std::vector additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(tx); + std::vector additional_derivations; + for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i) + { + additional_derivations.push_back({}); + if (!hwdev.generate_key_derivation(additional_tx_pub_keys[i], seller_secret_view_key, additional_derivations.back())) + { + MWARNING("Failed to generate key derivation from tx pubkey, skipping"); + additional_derivations.pop_back(); + } + } + hwdev_lock.unlock(); + + + + for (size_t i = 0; i < tx.vout.size(); ++i) + { + + auto o = tx.vout[i]; + boost::optional received; + + hwdev_lock.lock(); + hwdev.set_mode(hw::device::TRANSACTION_PARSE); + if (!cryptonote::is_valid_transaction_output_type(o.target)) + { + hwdev_lock.unlock(); + continue; + } + + const crypto::public_key &out_key = *boost::apply_visitor(destination_public_key_visitor(), o.target); + + std::unordered_map m_subaddresses; + cryptonote::subaddress_index sub_index{}; + m_subaddresses[public_seller_spend_key] = sub_index; + + received = is_out_to_acc_precomp(m_subaddresses, out_key, derivation, additional_derivations, i, hwdev); + + if(received) + { + seller_outputs.push_back(out_key); + } + hwdev_lock.unlock(); + } + + return seller_outputs; +} + +bool Blockchain::are_safex_tokens_unlocked(const std::vector &tx_vin) { + + //We search the inputs for tokens + for (const txin_v &txin: tx_vin) + { + if (txin.type() == typeid(txin_token_to_key)) + { + const txin_token_to_key &in = boost::get(txin); + if(in.token_amount != SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE) + continue; + const std::vector absolute = cryptonote::relative_output_offsets_to_absolute(in.key_offsets); + + // Now we search the offsets and find their txs + for (auto index: absolute) { + tx_out_index toi = this->m_db->get_output_tx_and_index(in.token_amount, index, tx_out_type::out_token); + auto output_token_fee = this->m_db->get_output_key(in.token_amount, index, tx_out_type::out_token); + cryptonote::transaction tx = m_db->get_tx(toi.first); + //Now we search for script input + if(is_create_safex_account_token_fee(tx.vout,output_token_fee.pubkey) && + output_token_fee.height + safex::get_safex_minumum_account_create_token_lock_period(m_nettype) > m_db->height()) + return false; + } + } else if ((txin.type() == typeid(txin_to_script)) && (boost::get(txin).command_type == safex::command_t::create_account)) + { + const txin_to_script &in = boost::get(txin); + if(in.token_amount != SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE) + continue; + const std::vector absolute = cryptonote::relative_output_offsets_to_absolute(in.key_offsets); + + // Now we search the offsets and find their txs + for (auto index: absolute) { + tx_out_index toi = this->m_db->get_output_tx_and_index(in.token_amount, index, tx_out_type::out_token); + auto output_token_fee = this->m_db->get_output_key(in.token_amount, index, tx_out_type::out_token); + cryptonote::transaction tx = m_db->get_tx(toi.first); + //Now we search for script input + if(is_create_safex_account_token_fee(tx.vout,output_token_fee.pubkey) && + output_token_fee.height + safex::get_safex_minumum_account_create_token_lock_period(m_nettype) > m_db->height()) + return false; + } + } + + } + return true; +} + +uint8_t Blockchain::get_maximum_tx_version_supported(uint8_t hf_version) const +{ + + switch (m_nettype) { + case cryptonote::network_type::FAKECHAIN: + case cryptonote::network_type::TESTNET: + return MAX_SUPPORTED_TX_VERSION; + case cryptonote::network_type::STAGENET: + return hf_version < HF_VERSION_ALLOW_TX_VERSION_2 ? MIN_SUPPORTED_TX_VERSION : MAX_SUPPORTED_TX_VERSION; + default: + return hf_version < HF_VERSION_ALLOW_TX_VERSION_2 ? MIN_SUPPORTED_TX_VERSION : MAX_SUPPORTED_TX_VERSION; + } + + return hf_version < HF_VERSION_ALLOW_TX_VERSION_2 ? MIN_SUPPORTED_TX_VERSION : MAX_SUPPORTED_TX_VERSION; +} + diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 9df36fe4c..9445ec9e9 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -612,6 +612,36 @@ namespace cryptonote */ bool check_tx_inputs(transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, tx_verification_context &tvc, bool kept_by_block = false); + + /** + * @brief check transaction safex related invariants + * + * @param tx the transaction to validate + * @param tvc transaction verification context + * + * @return returns false if tx does not hold safex related invariants, otherwise true + */ + bool check_safex_tx(const transaction &tx, tx_verification_context &tvc); + + /** + * @brief check if transaction outputs and inputs satisfy command type restrictions + * + * @param tx the transaction to validate + * @param command_type command type that is being checked + * + * @return returns false if tx does not hold safex related restrictions, otherwise true + */ + bool check_safex_tx_command(const transaction &tx, const safex::command_t& command_type); + + bool are_safex_tokens_unlocked(const std::vector &tx_vin); + + /** + * @brief Get maximum tx version in the blockchain + * + * @return return max tx_version that is supported for current hardfork + */ + uint8_t get_maximum_tx_version_supported(uint8_t hf_version) const; + /** * @brief get dynamic per kB fee for a given block size * @@ -704,8 +734,37 @@ namespace cryptonote * * @return false if an unexpected exception occurs, else true */ + //------------------------------------------------------------------ + //TODO: return type should be void, throw on exception + // alternatively, return true only if no blocks missed template - bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const; + bool get_blocks(const t_ids_container& block_ids, t_blocks_container& blocks, t_missed_container& missed_bs) const + { + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + + for (const auto& block_hash : block_ids) + { + try + { + blocks.push_back(std::make_pair(m_db->get_block_blob(block_hash), block())); + if (!parse_and_validate_block_from_blob(blocks.back().first, blocks.back().second)) + { + LOG_ERROR("Invalid block"); + return false; + } + } + catch (const BLOCK_DNE& e) + { + missed_bs.push_back(block_hash); + } + catch (const std::exception& e) + { + return false; + } + } + return true; + } /** * @brief gets transactions based on a list of transaction hashes @@ -719,10 +778,62 @@ namespace cryptonote * * @return false if an unexpected exception occurs, else true */ + //TODO: return type should be void, throw on exception + // alternatively, return true only if no transactions missed template - bool get_transactions_blobs(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const; + bool get_transactions_blobs(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const + { + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + + for (const auto& tx_hash : txs_ids) + { + try + { + cryptonote::blobdata tx = AUTO_VAL_INIT(tx); + if (m_db->get_tx_blob(tx_hash, tx)) + txs.push_back(std::move(tx)); + else + missed_txs.push_back(tx_hash); + } + catch (const std::exception& e) + { + return false; + } + } + return true; + } + //------------------------------------------------------------------ template - bool get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const; + bool get_transactions(const t_ids_container& txs_ids, t_tx_container& txs, t_missed_container& missed_txs) const + { + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + + for (const auto& tx_hash : txs_ids) + { + try + { + cryptonote::blobdata tx = AUTO_VAL_INIT(tx); + if (m_db->get_tx_blob(tx_hash, tx)) + { + txs.push_back(transaction()); + if (!parse_and_validate_tx_from_blob(tx, txs.back())) + { + LOG_ERROR("Invalid transaction"); + return false; + } + } + else + missed_txs.push_back(tx_hash); + } + catch (const std::exception& e) + { + return false; + } + } + return true; + } //debug functions @@ -950,11 +1061,18 @@ namespace cryptonote * @param output_type type of output (cash, token...) * @param offsets the indices (indexed to the amount) of the outputs * @param outputs return-by-reference the outputs collected - * @param txs unused, candidate for removal */ void output_scan_worker(const uint64_t amount, const tx_out_type output_type, const std::vector &offsets, - std::vector &outputs, std::unordered_map &txs) const; + std::vector &outputs) const; + + /** + * @brief get a number of advanced outputs with their ids + * + * @param output_type - type of output (locked token...) + * @param output_ids - output ids of outputs that should be retrieved + * @param outputs return-by-reference the advanced outputs collected + */ + void output_advanced_scan_worker(const tx_out_type output_type, const std::vector &output_ids, std::vector &outputs) const; /** * @brief computes the "short" and "long" hashes for a set of blocks @@ -998,8 +1116,72 @@ namespace cryptonote */ void on_new_tx_from_block(const cryptonote::transaction &tx); + /** + * @brief Returns last known staked token sum + * + * @return locked token amount + */ + uint64_t get_current_staked_token_sum() const; + + uint64_t get_staked_token_sum_for_interval(const uint64_t &interval) const; + + uint64_t get_network_fee_sum_for_interval(const uint64_t& interval) const; + + uint64_t calculate_staked_token_interest(const uint64_t token_amount, const uint64_t start_block, const uint64_t end_block) const; + + uint64_t calculate_staked_token_interest_for_output(const txin_to_script &txin, const uint64_t unlock_height) const; + + std::map get_interest_map(uint64_t begin_interval, uint64_t end_interval); + + bool get_safex_account_public_key(const safex::account_username &username, crypto::public_key &pkey) const; + bool get_safex_account_data(const safex::account_username &username, std::vector &data) const; + + bool get_safex_offer_seller(const crypto::hash &offerID, std::string &seller) const; + bool get_safex_offer(const crypto::hash &offerID, safex::safex_offer &offer) const; + bool get_safex_offer_price(const crypto::hash &offerID, uint64_t &price) const; + bool get_safex_offer_quantity(const crypto::hash &offerID, uint64_t &quantity) const; + bool get_safex_offer_active_status(const crypto::hash &offerID, bool &active) const; + bool get_safex_offer_rating(const crypto::hash &offerID, uint64_t &rating) const; + bool get_safex_price_peg( const crypto::hash& price_peg_id, safex::safex_price_peg& sfx_price_peg) const; + + bool get_safex_accounts( std::vector> &safex_accounts) const; + bool get_safex_offer_height( crypto::hash &offer_id, uint64_t& height) const; + bool get_safex_offers(std::vector &safex_offers) const; + bool get_safex_feedbacks(std::vector& safex_feedbacks, const crypto::hash& offer_id) const; + bool get_safex_price_pegs(std::vector &safex_price_pegs, const std::string& currency) const; + + bool get_table_sizes( std::vector &table_sizes) const; + private: + struct outputs_generic_visitor + { + std::vector& m_output_keys; + const Blockchain& m_bch; + outputs_generic_visitor(std::vector& output_keys, const Blockchain& bch) : + m_output_keys(output_keys), m_bch(bch) + { + } + + bool handle_output(uint64_t unlock_time, const crypto::public_key &pubkey, const rct::key &commitment) + { + //check tx unlock time + if (!m_bch.is_tx_spendtime_unlocked(unlock_time)) + { + MCERROR("verify", "One of outputs for one of inputs has wrong tx.unlock_time = " << unlock_time); + return false; + } + + // The original code includes a check for the output corresponding to this input + // to be a txout_to_key. This is removed, as the database does not store this info, + // but only txout_to_key outputs are stored in the DB in the first place, done in + // Blockchain*::add_output + + m_output_keys.push_back(rct::ctkey({rct::pk2rct(pubkey), commitment})); + return true; + } + }; + // TODO: evaluate whether or not each of these typedefs are left over from blockchain_storage typedef std::unordered_map blocks_by_id_index; @@ -1029,6 +1211,7 @@ namespace cryptonote // metadata containers std::unordered_map>> m_scan_table; + std::unordered_map>> m_scan_table_adv; std::unordered_map m_blocks_longhash_table; std::unordered_map> m_check_txin_table; @@ -1071,6 +1254,8 @@ namespace cryptonote std::atomic m_cancel; + bool m_batch_success; + // for prepare_handle_incoming_blocks uint64_t m_prepare_height; uint64_t m_prepare_nblocks; @@ -1113,18 +1298,29 @@ namespace cryptonote * @param tx_prefix_hash the transaction prefix hash, for caching organization * @param sig the input signature * @param output_keys return-by-reference the public keys of the outputs in the input set - * @param rct_signatures the ringCT signatures, which are only valid if tx version > 1 * @param pmax_related_block_height return-by-pointer the height of the most recent block in the input set * * @return false if any output is not yet unlocked, or is missing, otherwise true */ template - bool check_tx_input_generic(size_t tx_version, const T& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const rct::rctSig &rct_signatures, std::vector &output_keys, uint64_t* pmax_related_block_height); + bool check_tx_input_generic(size_t tx_version, const T& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, std::vector &output_keys, uint64_t* pmax_related_block_height); - bool check_tx_input(size_t tx_version, const txin_v& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const rct::rctSig &rct_signatures, std::vector &output_keys, uint64_t* pmax_related_block_height); + bool check_tx_input(size_t tx_version, const txin_v& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, std::vector &output_keys, uint64_t* pmax_related_block_height); bool check_tx_input_migration(size_t tx_version, const txin_token_migration& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, std::vector &output_keys, uint64_t* pmax_related_block_height); + bool check_tx_input_script(size_t tx_version, const txin_to_script& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, std::vector &output_keys, uint64_t* pmax_related_block_height); + + /** + * @brief validates one safex input + * + * + * @param txin input + * @param tvc returned information about tx verification + * + * @return false if any validation step fails, otherwise true + */ + bool check_advanced_tx_input(const txin_to_script &txin, tx_verification_context &tvc); /** * @brief validate a transaction's inputs and their keys @@ -1248,11 +1444,11 @@ namespace cryptonote * @param base_reward return-by-reference the new block's generated coins * @param already_generated_coins the amount of currency generated prior to this block * @param partial_block_reward return-by-reference true if miner accepted only partial reward - * @param version hard fork version for that transaction + * @param hf_version hard fork version for that transaction * * @return false if anything is found wrong with the miner transaction, otherwise true */ - bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t version); + bool validate_miner_transaction(const block& b, size_t cumulative_block_size, uint64_t fee, uint64_t& base_reward, uint64_t already_generated_coins, bool &partial_block_reward, uint8_t hf_version); /** * @brief reverts the blockchain to its previous state following a failed switch @@ -1430,6 +1626,16 @@ namespace cryptonote void check_migration_signature(const crypto::hash &tx_prefix_hash, const crypto::signature &signature, uint64_t &result); + /** + * @brief validates a safex account transaction input signature + * + * @param tx_prefix_hash the transaction prefix' hash + * @param sender_safex_account_key safex account public key + * @param sig the signature generated for every command input account initiated + * @param result false if the account signature is invalid, otherwise true + */ + void check_safex_account_signature(const crypto::hash &tx_prefix_hash, const crypto::public_key &sender_safex_account_key, + const crypto::signature &signature, uint64_t &result); /** * @brief loads block hashes from compiled-in data set * @@ -1466,5 +1672,29 @@ namespace cryptonote * */ uint64_t count_new_migration_tokens(const std::vector& txs) const; + + /** + * @brief Calculates cash amount that token holder receives when unlocking + * tokens that are locked at start_block until the end block + * + * @param token_amount token amount that is locked + * @param start block height, where tokens are locked + * @end_block last known end block, where token unlock operation is set + * + */ + + + /** + * @brief Checks if the amount needed for purchase + * is sent to seller + * + * @param seller_secret_view_key secret view key of seller + * @param tx transaction for checking + * @param out transaction_output that we are checking + * + */ + + std::vector is_safex_purchase_right_address(const crypto::secret_key& seller_secret_view_key, const crypto::public_key& public_seller_spend_key, const cryptonote::transaction& tx); + }; } // namespace cryptonote diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index a891736a0..1ca6d3813 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -55,6 +55,7 @@ using namespace epee; #include "blockchain_db/blockchain_db.h" #include "ringct/rctSigs.h" #include "version.h" +#include "safex/command.h" #ifdef SAFEX_PROTOBUF_RPC #include "protobuf/cryptonote_to_protobuf.h" @@ -167,7 +168,9 @@ namespace cryptonote core::core(i_cryptonote_protocol* pprotocol): m_mempool(m_blockchain_storage), m_blockchain_storage(m_mempool), - m_miner(this, &m_blockchain_storage), + m_miner(this, [this](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash) { + return cryptonote::get_block_longhash(&m_blockchain_storage, b, hash, height, threads); + }), m_miner_address(boost::value_initialized()), m_starter_message_showed(false), m_target_blockchain_height(0), @@ -287,7 +290,7 @@ namespace cryptonote auto data_dir = boost::filesystem::path(m_config_folder); - if (m_nettype == MAINNET) + if (m_nettype != FAKECHAIN) { cryptonote::checkpoints checkpoints; if (!checkpoints.init_default_checkpoints(m_nettype)) @@ -323,7 +326,44 @@ namespace cryptonote { return m_blockchain_storage.get_current_blockchain_height(); } - //----------------------------------------------------------------------------------------------- + + bool core::get_safex_accounts( std::vector> &safex_accounts) const + { + return m_blockchain_storage.get_safex_accounts(safex_accounts); + }; + + bool core::get_table_sizes( std::vector &table_sizes) const + { + return m_blockchain_storage.get_table_sizes(table_sizes); + } + //----------------------------------------------------------------------------------------------- + bool core::get_safex_offer_height( crypto::hash &offer_id, uint64_t &height) const + { + return m_blockchain_storage.get_safex_offer_height(offer_id, height); + } + bool core::get_safex_offers( std::vector &safex_offers) const + { + return m_blockchain_storage.get_safex_offers(safex_offers); + } + + bool core::get_safex_feedbacks( std::vector &safex_feedbacks, const crypto::hash& offer_id) const + { + return m_blockchain_storage.get_safex_feedbacks(safex_feedbacks,offer_id); + } + + bool core::get_safex_price_pegs(std::vector &safex_price_pegs, const std::string& currency) const + { + return m_blockchain_storage.get_safex_price_pegs(safex_price_pegs, currency); + } + + bool core::get_safex_price_peg( const crypto::hash& price_peg_id, safex::safex_price_peg& sfx_price_peg) const + { + return m_blockchain_storage.get_safex_price_peg(price_peg_id,sfx_price_peg); + + } + + + //----------------------------------------------------------------------------------------------- void core::get_blockchain_top(uint64_t& height, crypto::hash& top_id) const { top_id = m_blockchain_storage.get_tail_id(height); @@ -421,7 +461,7 @@ namespace cryptonote // folder might not be a directory, etc, etc catch (...) { } - std::unique_ptr db(new_db(db_type)); + std::unique_ptr db(new_db(db_type, m_nettype)); if (db == NULL) { LOG_ERROR("Attempted to use non-existent database type"); @@ -637,14 +677,6 @@ namespace cryptonote } bad_semantics_txes_lock.unlock(); - if (tx.version == 0 || tx.version > HF_VERSION_MAX_SUPPORTED_TX_VERSION) - { - // HF_VERSION_MAX_SUPPORTED_TX_VERSION is the latest transaction version - // we know in the current protocol version - tvc.m_verifivation_failed = true; - return false; - } - return true; } //----------------------------------------------------------------------------------------------- @@ -775,6 +807,17 @@ namespace cryptonote return true; } + bool check_advanced_tx_semantic(const transaction& tx) + { + //todo atana implement for various usecases + + //todo atana implement check for token unlock interest validity + + + return true; + } + + //----------------------------------------------------------------------------------------------- bool core::check_tx_semantic(const transaction& tx, bool keeped_by_block) const { @@ -798,18 +841,11 @@ namespace cryptonote MERROR_VER("tx with invalid outputs, rejected for tx id= " << get_transaction_hash(tx)); return false; } - if (tx.version > 1) - { - if (tx.rct_signatures.outPk.size() != tx.vout.size()) - { - MERROR_VER("tx with mismatched vout/outPk count, rejected for tx id= " << get_transaction_hash(tx)); - return false; - } - } + + const uint8_t version = m_blockchain_storage.get_current_hard_fork_version(); if(!check_money_overflow(tx)) { - const uint8_t version = m_blockchain_storage.get_current_hard_fork_version(); bool known_problem = false; if(version < HF_VERSION_STOP_COUNTERFEIT_TOKENS) { @@ -832,13 +868,13 @@ namespace cryptonote } } - if (tx.version == 1) + if (tx.version >= MIN_SUPPORTED_TX_VERSION && tx.version <= m_blockchain_storage.get_maximum_tx_version_supported(version)) { uint64_t amount_in = 0; - get_inputs_money_amount(tx, amount_in); - uint64_t amount_out = get_outs_money_amount(tx); + get_inputs_cash_amount(tx, amount_in); + uint64_t amount_out = get_outs_cash_amount(tx); - if(amount_in <= amount_out) + if (amount_in <= amount_out) { MERROR_VER("tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << get_transaction_hash(tx)); return false; @@ -848,13 +884,17 @@ namespace cryptonote get_inputs_token_amount(tx, tokens_in); uint64_t tokens_out = get_outs_token_amount(tx); - if(tokens_in < tokens_out) + if (tokens_in < tokens_out) { MERROR_VER("tx with wrong token amounts: ins " << tokens_in << ", outs " << tokens_out << ", rejected for tx id= " << get_transaction_hash(tx)); return false; } } - // for version > 1, ringct signatures check verifies amounts match + else + { + MERROR_VER("Unsuported transaction version"); + return false; + } if(!keeped_by_block && get_object_blobsize(tx) >= m_blockchain_storage.get_current_cumulative_blocksize_limit() - CRYPTONOTE_COINBASE_BLOB_RESERVED_SIZE) { @@ -881,36 +921,14 @@ namespace cryptonote return false; } - if (tx.version >= 2) + //check tx version 2 semantics + if (!check_advanced_tx_semantic(tx)) { - const rct::rctSig &rv = tx.rct_signatures; - switch (rv.type) { - case rct::RCTTypeNull: - // coinbase should not come here, so we reject for all other types - MERROR_VER("Unexpected Null rctSig type"); - return false; - case rct::RCTTypeSimple: - case rct::RCTTypeSimpleBulletproof: - if (!rct::verRctSimple(rv, true)) - { - MERROR_VER("rct signature semantics check failed"); - return false; - } - break; - case rct::RCTTypeFull: - case rct::RCTTypeFullBulletproof: - if (!rct::verRct(rv, true)) - { - MERROR_VER("rct signature semantics check failed"); - return false; - } - break; - default: - MERROR_VER("Unknown rct type: " << rv.type); - return false; - } + MERROR_VER("Advanced transaction is not valid"); + return false; } + return true; } //----------------------------------------------------------------------------------------------- @@ -956,14 +974,14 @@ namespace cryptonote [this, &emission_amount, &total_fee_amount](uint64_t, const crypto::hash& hash, const block& b){ std::list txs; std::list missed_txs; - uint64_t coinbase_amount = get_outs_money_amount(b.miner_tx); - this->get_transactions(b.tx_hashes, txs, missed_txs); + uint64_t coinbase_amount = get_outs_cash_amount(b.miner_tx); + this->get_transactions(b.tx_hashes, txs, missed_txs); uint64_t tx_fee_amount = 0; for(const auto& tx: txs) { tx_fee_amount += get_tx_fee(tx); } - + emission_amount += coinbase_amount - tx_fee_amount; total_fee_amount += tx_fee_amount; return true; @@ -995,13 +1013,123 @@ namespace cryptonote return total_migrated_tokens_amount; } + //----------------------------------------------------------------------------------------------- + int64_t core::get_staked_tokens(const uint64_t start_offset, const size_t count) + { + int64_t total_staked_tokens_amount = 0; + if (count) + { + const uint64_t end = start_offset + count - 1; + m_blockchain_storage.for_blocks_range(start_offset, end, + [this, &total_staked_tokens_amount](uint64_t, const crypto::hash& hash, const block& b) { + std::list txs; + std::list missed_txs; + this->get_transactions(b.tx_hashes, txs, missed_txs); + for(const auto& tx: txs) + { + total_staked_tokens_amount += get_token_staked_amount(tx); + } + + return true; + }); + } + + return total_staked_tokens_amount; + } + //----------------------------------------------------------------------------------------------- + uint64_t core::get_staked_tokens() const + { + return this->m_blockchain_storage.get_current_staked_token_sum(); + } + + uint64_t core::get_locked_tokens_for_interval(const uint64_t& interval) const + { + return this->m_blockchain_storage.get_staked_token_sum_for_interval(interval); + } + + uint64_t core::get_current_interval() const { + return safex::calculate_interval_for_height(this->get_current_blockchain_height(), m_nettype); + } + + + //----------------------------------------------------------------------------------------------- + uint64_t core::get_collected_network_fee(const uint64_t start_offset, const size_t count) const + { + uint64_t total_network_fee_amount = 0; + if (count) + { + const uint64_t end = start_offset + count - 1; + m_blockchain_storage.for_blocks_range(start_offset, end, + [this, &total_network_fee_amount](uint64_t, const crypto::hash& hash, const block& b) { + std::list txs; + std::list missed_txs; + this->get_transactions(b.tx_hashes, txs, missed_txs); + for(const auto& tx: txs) + { + total_network_fee_amount += get_collected_network_fee_amount(tx); + } + + return true; + }); + } + + return total_network_fee_amount; + } + //----------------------------------------------------------------------------------------------- + uint64_t core::get_distributed_network_fee(const uint64_t start_offset, const size_t count) const + { + uint64_t total_network_fee_amount = 0; + if (count) + { + const uint64_t end = start_offset + count - 1; + m_blockchain_storage.for_blocks_range(start_offset, end, + [this, &total_network_fee_amount](uint64_t, const crypto::hash& hash, const block& b) { + std::list txs; + std::list missed_txs; + this->get_transactions(b.tx_hashes, txs, missed_txs); + for(const auto& tx: txs) + { + total_network_fee_amount += get_network_distributed_fee_amount(tx); + } + + return true; + }); + } + + return total_network_fee_amount; + } + //----------------------------------------------------------------------------------------------- + uint64_t core::get_network_fee_for_interval(const uint64_t& interval) const + { + return static_cast(this->m_blockchain_storage.get_network_fee_sum_for_interval(interval)); + } + + //----------------------------------------------------------------------------------------------- + bool core::get_safex_account_info(const std::string& username, safex::safex_account& account) const + { + std::vector accdata; + if (!this->m_blockchain_storage.get_safex_account_data(username, accdata)) { + MERROR_VER("Unable to get safex account data for username " << username); + return false; + } + crypto::public_key pkey; + if (!this->m_blockchain_storage.get_safex_account_public_key(username, pkey)) { + MERROR_VER("Unable to get safex account pkey for username " << username); + return false; + } + + account = safex::safex_account{username, pkey, accdata}; + return true; + } + + //----------------------------------------------------------------------------------------------- bool core::check_tx_inputs_keyimages_diff(const transaction& tx) const { std::unordered_set ki; for(const auto& in: tx.vin) { - if (cryptonote::is_valid_transaction_input_type(in)) { + if (cryptonote::is_valid_transaction_input_type(in, tx.version)) { const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), in); if(!ki.insert(k_image).second) return false; @@ -1017,6 +1145,7 @@ namespace cryptonote const uint8_t version = m_blockchain_storage.get_current_hard_fork_version(); if (version >= HF_VERSION_TBD) { + //TODO: GRKI Check if this should be added in the next hardfork for(const auto& in: tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false); @@ -1038,7 +1167,17 @@ namespace cryptonote // invalid key_image if (!(rct::scalarmultKey(rct::ki2rct(k_image), rct::curveOrder()) == rct::identity())) return false; - } else if ((in.type() == typeid(const txin_token_migration))) { + } else if (in.type() == typeid(const txin_to_script)) { + + const txin_to_script &txin = boost::get(in); + if (safex::is_safex_key_image_verification_needed(txin.command_type)){ + const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), in); + // invalid key_image + if (!(rct::scalarmultKey(rct::ki2rct(k_image), rct::curveOrder()) == rct::identity())) + return false; + } + } + else if (in.type() == typeid(const txin_token_migration)) { // todo igor: check if this is necessary } else { CHECK_AND_ASSERT_MES(false, false, "wrong variant type: " << in.type().name() << ", expected " << typeid(txin_to_key).name() << ", " << typeid(txin_token_to_key).name() << @@ -1079,8 +1218,8 @@ namespace cryptonote return true; } - uint8_t version = m_blockchain_storage.get_current_hard_fork_version(); - return m_mempool.add_tx(tx, tx_hash, blob_size, tvc, keeped_by_block, relayed, do_not_relay, version); + uint8_t hf_version = m_blockchain_storage.get_current_hard_fork_version(); + return m_mempool.add_tx(tx, tx_hash, blob_size, tvc, keeped_by_block, relayed, do_not_relay, hf_version); } //----------------------------------------------------------------------------------------------- bool core::relay_txpool_transactions() @@ -1202,7 +1341,12 @@ namespace cryptonote m_miner.resume(); return false; } - prepare_handle_incoming_blocks(blocks); + if (!prepare_handle_incoming_blocks(blocks)) + { + MERROR("Block found, but failed to prepare to add"); + m_miner.resume(); + return false; + } m_blockchain_storage.add_new_block(b, bvc); cleanup_handle_incoming_blocks(true); //anyway - update miner template @@ -1256,7 +1400,11 @@ namespace cryptonote bool core::prepare_handle_incoming_blocks(const std::list &blocks) { m_incoming_tx_lock.lock(); - m_blockchain_storage.prepare_handle_incoming_blocks(blocks); + if (!m_blockchain_storage.prepare_handle_incoming_blocks(blocks)) + { + cleanup_handle_incoming_blocks(false); + return false; + } return true; } @@ -1367,7 +1515,7 @@ namespace cryptonote bool core::get_pool_transaction(const crypto::hash &id, cryptonote::blobdata& tx) const { return m_mempool.get_transaction(id, tx); - } + } //----------------------------------------------------------------------------------------------- bool core::pool_has_tx(const crypto::hash &id) const { @@ -1645,4 +1793,10 @@ namespace cryptonote { raise(SIGTERM); } + + std::map core::get_interest_map(uint64_t begin_interval, uint64_t end_interval) + { + return m_blockchain_storage.get_interest_map(begin_interval, end_interval); + } + } diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 5b97dc8a0..0035880bf 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -50,6 +50,8 @@ #include "warnings.h" #include "crypto/hash.h" +#include "safex/safex_account.h" + PUSH_WARNINGS DISABLE_VS_WARNINGS(4355) @@ -749,7 +751,99 @@ namespace cryptonote * @return number of migrated tokens in the range of blocks */ uint64_t get_migrated_tokens(const uint64_t start_offset, const size_t count); + + /** + * @brief get the delta of staked and unstaked tokens in block range + * + * @return if >0, number of newly staked tokens, if <0, number of unstaked tokens in total for range of blocks + */ + int64_t get_staked_tokens(const uint64_t start_offset, const size_t count); + + uint64_t get_current_interval() const; + + /** + * @brief get last known token locked sum + * + * @return amount of locked tokens + */ + uint64_t get_staked_tokens() const; + + /** + * @brief get last known token locked sum + * @param interval + * + * @return amount of locked tokens + */ + uint64_t get_locked_tokens_for_interval(const uint64_t& interval) const; + + /** + * @brief get the delta of network fee in block range + * + * @return if >0, number of newly collected netowork fee, if <0, amount of distributed network fee to tokenholders + */ + uint64_t get_collected_network_fee(const uint64_t start_offset, const size_t count) const; + + + /** + * @brief get the delta of network fee in block range + * + * @return if >0, number of newly collected netowork fee, if <0, amount of distributed network fee to tokenholders + */ + uint64_t get_distributed_network_fee(const uint64_t start_offset, const size_t count) const; + uint64_t get_network_fee_for_interval(const uint64_t& interval) const; + + //----------------------------------------------------------------------------------------------- + /** + * @brief get safex account info + * + * @return structure with account info + */ + bool get_safex_account_info(const std::string& username, safex::safex_account& account) const; + + /** + * @brief gets pair of elements + * + * @return True if we get the elements from Blockchain + */ + bool get_safex_accounts( std::vector> &safex_accounts) const; + + bool get_table_sizes( std::vector &table_sizes) const; + + /** + * @brief gets height of the last time offer was edited(or created) + * + * @return True if we get the height from Blockchain + */ + bool get_safex_offer_height( crypto::hash &offer_id, uint64_t& height) const; + + /** + * @brief gets all offers inside the Blockchain + * + * @return True if we get the elements from Blockchain + */ + bool get_safex_offers( std::vector &safex_offers) const; + + /** + * @brief gets all price pegs inside the Blockchain for given currency + * + * @return True if we get the elements from Blockchain + */ + bool get_safex_price_pegs( std::vector &safex_price_pegs, const std::string& currency = "") const; + + /** + * @brief gets price peg inside the Blockchain for given ID + * + * @return True if we get the elements from Blockchain + */ + bool get_safex_price_peg( const crypto::hash& price_peg_id, safex::safex_price_peg& sfx_price_peg) const; + /** + * @brief gets feedbacks for given offer_id + * + * @return True if we get the elements from Blockchain + */ + bool get_safex_feedbacks( std::vector &safex_feedbacks, const crypto::hash& offer_id) const; + /** * @brief get the network type we're on * @@ -784,6 +878,7 @@ namespace cryptonote * @return whether the core is running offline */ bool offline() const { return m_offline; } + std::map get_interest_map(uint64_t begin_interval, uint64_t end_interval); private: diff --git a/src/cryptonote_core/cryptonote_tx_utils.cpp b/src/cryptonote_core/cryptonote_tx_utils.cpp index e33ab7d82..7c456fdf8 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.cpp +++ b/src/cryptonote_core/cryptonote_tx_utils.cpp @@ -43,7 +43,7 @@ using namespace epee; #include "crypto/crypto.h" #include "crypto/hash.h" #include "ringct/rctSigs.h" -#include "multisig/multisig.h" +#include "safex/command.h" using namespace crypto; @@ -76,6 +76,10 @@ namespace cryptonote LOG_PRINT_L2("destinations include " << num_stdaddresses << " standard addresses and " << num_subaddresses << " subaddresses"); } //--------------------------------------------------------------- + bool is_advanced_transaction(const std::vector& sources) { + return std::any_of(sources.begin(), sources.end(), [](const tx_source_entry &sr) {return sr.command_type != safex::command_t::nop;}); + } + //--------------------------------------------------------------- bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce, size_t max_outs, uint8_t hard_fork_version) { tx.vin.clear(); tx.vout.clear(); @@ -113,7 +117,6 @@ namespace cryptonote block_reward = block_reward - block_reward % ::config::BASE_REWARD_CLAMP_THRESHOLD; } - std::vector out_amounts; decompose_amount_into_digits(block_reward, hard_fork_version >= 2 ? 0 : ::config::DEFAULT_DUST_THRESHOLD, [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, @@ -195,14 +198,13 @@ namespace cryptonote return addr.m_view_public_key; } //--------------------------------------------------------------- - bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, std::vector extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout, bool shuffle_outs) + bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, + std::vector& sources, std::vector& destinations, const boost::optional& change_addr, + std::vector extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, + const std::vector &additional_tx_keys, bool shuffle_outs) { hw::device &hwdev = sender_account_keys.get_device(); -#if (CURRENT_TRANSACTION_VERSION < 2) - CHECK_AND_ASSERT_MES((!rct), false, "Error, transaction version is 2, ringCt is not used"); -#endif - if (sources.empty()) { LOG_ERROR("Empty sources"); @@ -212,12 +214,8 @@ namespace cryptonote std::vector amount_keys; tx.set_null(); amount_keys.clear(); - if (msout) - { - msout->c.clear(); - } - tx.version = rct ? 2 : 1; + tx.version = 1; tx.unlock_time = unlock_time; tx.extra = extra; @@ -289,9 +287,9 @@ namespace cryptonote for(const tx_source_entry &src_entr : sources) { ++idx; - const bool migration_input = src_entr.migration; - const bool token_transaction = src_entr.token_transaction; - if (migration_input) + const bool migration_input = (src_entr.referenced_output_type == tx_out_type::out_bitcoin_migration); + const bool token_transaction = (src_entr.referenced_output_type == tx_out_type::out_token) || (src_entr.referenced_output_type == tx_out_type::out_bitcoin_migration); + if (migration_input) { txin_token_migration input_token_migration = AUTO_VAL_INIT(input_token_migration); input_token_migration.token_amount = src_entr.token_amount; @@ -326,13 +324,13 @@ namespace cryptonote return false; } - //check that derivated key is equal with real output key (if non multisig) - if(!migration_input && !msout && !(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) ) + //check that derivated key is equal with real output key + if(!migration_input && !(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest) ) { LOG_ERROR("derived public key mismatch with output public key at index " << idx << ", real out " << src_entr.real_output << "! "<< ENDL << "derived_key:" << string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:" << string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second.dest) ); - LOG_ERROR("token_amount " << src_entr.token_amount << ", amount " << src_entr.amount << ", rct " << src_entr.rct); + LOG_ERROR("token_amount " << src_entr.token_amount << ", amount " << src_entr.amount); LOG_ERROR("tx pubkey " << src_entr.real_out_tx_key << ", real_output_in_tx_index " << src_entr.real_output_in_tx_index); return false; } @@ -341,7 +339,7 @@ namespace cryptonote { txin_token_to_key input_token_to_key = AUTO_VAL_INIT(input_token_to_key); input_token_to_key.token_amount = src_entr.token_amount; - input_token_to_key.k_image = msout ? rct::rct2ki(src_entr.multisig_kLRki.ki) : img; + input_token_to_key.k_image = img; //fill outputs array and use relative offsets for(const tx_source_entry::output_entry& out_entry: src_entr.outputs) @@ -355,7 +353,7 @@ namespace cryptonote //put key image into tx input txin_to_key input_to_key = AUTO_VAL_INIT(input_to_key); input_to_key.amount = src_entr.amount; - input_to_key.k_image = msout ? rct::rct2ki(src_entr.multisig_kLRki.ki) : img; + input_to_key.k_image = img; //fill outputs array and use relative offsets for(const tx_source_entry::output_entry& out_entry: src_entr.outputs) @@ -421,7 +419,8 @@ namespace cryptonote size_t output_index = 0; for(const tx_destination_entry& dst_entr: destinations) { - CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || dst_entr.token_amount > 0 || tx.version > 1, false, "Destination with wrong amount: " << dst_entr.amount << " or token amount " << dst_entr.token_amount); + CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || dst_entr.token_amount > 0 || tx.version > 1, false, + "Destination with wrong amount: " << dst_entr.amount << " or token amount " << dst_entr.token_amount); crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); @@ -455,12 +454,6 @@ namespace cryptonote additional_tx_public_keys.push_back(additional_txkey.pub); } - if (tx.version > 1) - { - crypto::secret_key scalar1 = AUTO_VAL_INIT(scalar1); - hwdev.derivation_to_scalar(derivation, output_index, scalar1); - amount_keys.push_back(rct::sk2rct(scalar1)); - } r = hwdev.derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key); CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to derive_public_key(" << derivation << ", " << output_index << ", "<< dst_entr.addr.m_spend_public_key << ")"); @@ -551,7 +544,7 @@ namespace cryptonote sigs.resize(src_entr.outputs.size()); if (!zero_secret_key) { const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), tx.vin[i]); - if (src_entr.migration) { + if (src_entr.referenced_output_type == tx_out_type::out_bitcoin_migration) { public_key spend_public_key = AUTO_VAL_INIT(spend_public_key); CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(sender_account_keys.m_spend_secret_key, spend_public_key), false, "Could not create public_key from private_key"); crypto::generate_signature(tx_prefix_hash, spend_public_key, sender_account_keys.m_spend_secret_key, sigs[0]); @@ -569,289 +562,1382 @@ namespace cryptonote } else { - size_t n_total_outs = sources[0].outputs.size(); // only for non-simple rct - - // the non-simple version is slightly smaller, but assumes all real inputs - // are on the same index, so can only be used if there just one ring. - bool use_simple_rct = sources.size() > 1; + LOG_ERROR("Transaction version>=2 not supported"); + return false; - if (!use_simple_rct) - { - // non simple ringct requires all real inputs to be at the same index for all inputs - for(const tx_source_entry& src_entr: sources) - { - if(src_entr.real_output != sources.begin()->real_output) - { - LOG_ERROR("All inputs must have the same index for non-simple ringct"); - return false; - } - } + } - // enforce same mixin for all outputs - for (size_t i = 1; i < sources.size(); ++i) { - if (n_total_outs != sources[i].outputs.size()) { - LOG_ERROR("Non-simple ringct transaction has varying ring size"); - return false; - } - } - } + tx.invalidate_hashes(); - uint64_t amount_in = 0, amount_out = 0; - rct::ctkeyV inSk; - // mixRing indexing is done the other way round for simple - rct::ctkeyM mixRing(use_simple_rct ? sources.size() : n_total_outs); - rct::keyV destinations; - std::vector inamounts, outamounts; - std::vector index; - std::vector kLRki; - for (size_t i = 0; i < sources.size(); ++i) - { - rct::ctkey ctkey; - amount_in += sources[i].amount; - inamounts.push_back(sources[i].amount); - index.push_back(sources[i].real_output); - // inSk: (secret key, mask) - ctkey.dest = rct::sk2rct(in_contexts[i].in_ephemeral.sec); - ctkey.mask = sources[i].mask; - inSk.push_back(ctkey); - // inPk: (public key, commitment) - // will be done when filling in mixRing - if (msout) - { - kLRki.push_back(sources[i].multisig_kLRki); - } - } - for (size_t i = 0; i < tx.vout.size(); ++i) - { - destinations.push_back(rct::pk2rct(boost::get(tx.vout[i].target).key)); - outamounts.push_back(tx.vout[i].amount); - amount_out += tx.vout[i].amount; - } + return true; + } - if (use_simple_rct) - { - // mixRing indexing is done the other way round for simple - for (size_t i = 0; i < sources.size(); ++i) - { - mixRing[i].resize(sources[i].outputs.size()); - for (size_t n = 0; n < sources[i].outputs.size(); ++n) - { - mixRing[i][n] = sources[i].outputs[n].second; - } - } - } - else - { - for (size_t i = 0; i < n_total_outs; ++i) // same index assumption - { - mixRing[i].resize(sources.size()); - for (size_t n = 0; n < sources.size(); ++n) - { - mixRing[i][n] = sources[n].outputs[i].second; - } - } - } + /** + * + * @param unstaked_token_destination - destination that receives unstaked tokens related to this interest + * @param interest_amount - calculated interest amount + * @return new interest destination that matches destination found in array + */ + tx_destination_entry create_interest_destination(const cryptonote::tx_destination_entry &unstaked_token_destination, const uint64_t interest_amount) + { + return tx_destination_entry{interest_amount, unstaked_token_destination.addr, unstaked_token_destination.is_subaddress, tx_out_type::out_cash}; + } - // fee - if (!use_simple_rct && amount_in > amount_out) - outamounts.push_back(amount_in - amount_out); + txin_to_script prepare_advanced_input(const tx_source_entry &src_entr, const crypto::key_image &img) + { + txin_to_script input = AUTO_VAL_INIT(input); + input.command_type = src_entr.command_type; + input.token_amount = src_entr.token_amount; + input.amount = src_entr.amount; - // zero out all amounts to mask rct outputs, real amounts are now encrypted - for (size_t i = 0; i < tx.vin.size(); ++i) - { - if (sources[i].rct) - boost::get(tx.vin[i]).amount = 0; - } - for (size_t i = 0; i < tx.vout.size(); ++i) - tx.vout[i].amount = 0; + if (src_entr.command_type == safex::command_t::token_stake) + { + input.k_image = img; - crypto::hash tx_prefix_hash; - get_transaction_prefix_hash(tx, tx_prefix_hash); - rct::ctkeyV outSk; - if (use_simple_rct) - tx.rct_signatures = rct::genRctSimple(rct::hash2rct(tx_prefix_hash), inSk, destinations, inamounts, outamounts, amount_in - amount_out, mixRing, amount_keys, msout ? &kLRki : NULL, msout, index, outSk, bulletproof, hwdev); - else - tx.rct_signatures = rct::genRct(rct::hash2rct(tx_prefix_hash), inSk, destinations, outamounts, mixRing, amount_keys, msout ? &kLRki[0] : NULL, msout, sources[0].real_output, outSk, bulletproof, hwdev); // same index assumption + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input.key_offsets.push_back(out_entry.first); - CHECK_AND_ASSERT_MES(tx.vout.size() == outSk.size(), false, "outSk size does not match vout"); + input.key_offsets = absolute_output_offsets_to_relative(input.key_offsets); - MCINFO("construct_tx", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL); + //here, prepare data of transaction command execution and serialize command + safex::token_stake cmd{SAFEX_COMMAND_PROTOCOL_VERSION, src_entr.token_amount}; + safex::safex_command_serializer::serialize_safex_object(cmd, input.script); } + else if (src_entr.command_type == safex::command_t::token_unstake) + { + input.k_image = img; - tx.invalidate_hashes(); + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input.key_offsets.push_back(out_entry.first); - return true; - } - //--------------------------------------------------------------- - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, std::vector extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, bool rct, bool bulletproof, rct::multisig_out *msout) - { - hw::device &hwdev = sender_account_keys.get_device(); - hwdev.open_tx(tx_key); + input.key_offsets = absolute_output_offsets_to_relative(input.key_offsets); - // figure out if we need to make additional tx pubkeys - size_t num_stdaddresses = 0; - size_t num_subaddresses = 0; - account_public_address single_dest_subaddress = AUTO_VAL_INIT(single_dest_subaddress); - classify_addresses(destinations, change_addr, num_stdaddresses, num_subaddresses, single_dest_subaddress); - bool need_additional_txkeys = num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1); - if (need_additional_txkeys) + //here, prepare data of transaction command execution and serialize command + + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(src_entr.outputs.size() > 0, "Invalid staked token output id", safex::command_t::token_unstake); + + safex::token_unstake cmd{SAFEX_COMMAND_PROTOCOL_VERSION, src_entr.outputs[0].first}; + safex::safex_command_serializer::serialize_safex_object(cmd, input.script); + } + else if (src_entr.command_type == safex::command_t::donate_network_fee) { - additional_tx_keys.clear(); - for (const auto &d: destinations) - additional_tx_keys.push_back(keypair::generate(sender_account_keys.get_device()).sec); + input.k_image = img; + + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input.key_offsets.push_back(out_entry.first); + + input.key_offsets = absolute_output_offsets_to_relative(input.key_offsets); + + //here, prepare data of transaction command execution and serialize command + safex::donate_fee cmd{SAFEX_COMMAND_PROTOCOL_VERSION, src_entr.amount}; + safex::safex_command_serializer::serialize_safex_object(cmd, input.script); } + else if (src_entr.command_type == safex::command_t::create_account) + { + input.k_image = img; - 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, bulletproof, msout); - hwdev.close_tx(); - return r; - } - //--------------------------------------------------------------- - bool construct_tx(const account_keys& sender_account_keys, std::vector& sources, const std::vector& destinations, const boost::optional& change_addr, std::vector extra, transaction& tx, uint64_t unlock_time) - { - std::unordered_map subaddresses; - subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0}; - crypto::secret_key tx_key; - std::vector additional_tx_keys; - std::vector 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, false, NULL); - } - //--------------------------------------------------------------- - bool generate_genesis_block( - block& bl - , std::string const & genesis_tx - , uint32_t nonce - ) - { - //genesis block - bl = boost::value_initialized(); + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input.key_offsets.push_back(out_entry.first); - blobdata tx_bl; - bool r = string_tools::parse_hexstr_to_binbuff(genesis_tx, tx_bl); - CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); - r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx); - CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); - bl.major_version = CURRENT_BLOCK_MAJOR_VERSION; - bl.minor_version = CURRENT_BLOCK_MINOR_VERSION; - bl.invalidate_hashes(); - bl.timestamp = 0; - bl.nonce = nonce; - miner::find_nonce_for_given_block(NULL, bl, 1, 0); - return true; - } - //--------------------------------------------------------------- - void get_altblock_longhash(const block& b, crypto::hash& res, const uint64_t main_height, const uint64_t height, const uint64_t seed_height, const crypto::hash& seed_hash) - { - blobdata bd = get_block_hashing_blob(b); - rx_slow_hash(main_height, seed_height, seed_hash.data, bd.data(), bd.size(), res.data, 0, 1); - } + input.key_offsets = absolute_output_offsets_to_relative(input.key_offsets); - bool get_block_longhash(const Blockchain *pbc, const block& b, crypto::hash& res, const uint64_t height, const int miners) - { - blobdata bd = get_block_hashing_blob(b); - if (b.major_version >= RX_BLOCK_VERSION) + safex::create_account_data account; + parse_and_validate_from_blob(src_entr.command_safex_data, account); + + + //todo get username, pkey and data create way to pass data in source entry + safex::create_account cmd(SAFEX_COMMAND_PROTOCOL_VERSION, account.username, account.pkey, account.account_data); + safex::safex_command_serializer::serialize_safex_object(cmd, input.script); + } + else if (src_entr.command_type == safex::command_t::edit_account) { - uint64_t seed_height, main_height; - crypto::hash hash; - if (pbc != NULL) - { - seed_height = rx_seedheight(height); - hash = pbc->get_pending_block_id_by_height(seed_height); - main_height = pbc->get_current_blockchain_height(); - } - else - { - memset(&hash, 0, sizeof(hash)); // only happens when generating genesis block - seed_height = 0; - main_height = 0; - } - rx_slow_hash(main_height, seed_height, hash.data, bd.data(), bd.size(), res.data, miners, 0); + input.k_image = img; + + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input.key_offsets.push_back(out_entry.first); + + input.key_offsets = absolute_output_offsets_to_relative(input.key_offsets); + + safex::edit_account_data account; + parse_and_validate_from_blob(src_entr.command_safex_data, account); + + + safex::edit_account cmd(SAFEX_COMMAND_PROTOCOL_VERSION, account.username, account.account_data); + safex::safex_command_serializer::serialize_safex_object(cmd, input.script); } - else + else if (src_entr.command_type == safex::command_t::create_offer) { - const int pow_variant = b.major_version < HF_VERSION_DIFFICULTY_V2 ? b.major_version: HF_VERSION_DIFFICULTY_V2; - crypto::cn_slow_hash(bd.data(), bd.size(), res, pow_variant); + input.k_image = img; + + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input.key_offsets.push_back(out_entry.first); + + input.key_offsets = absolute_output_offsets_to_relative(input.key_offsets); + + safex::create_offer_data offer; + parse_and_validate_from_blob(src_entr.command_safex_data, offer); + + safex::create_offer cmd(SAFEX_COMMAND_PROTOCOL_VERSION, offer); + + safex::safex_command_serializer::serialize_safex_object(cmd, input.script); + + } - return true; - } + else if (src_entr.command_type == safex::command_t::edit_offer) + { + input.k_image = img; - crypto::hash get_block_longhash(const Blockchain *pbc, const block& b, const uint64_t height, const int miners) - { - crypto::hash p = crypto::null_hash; - get_block_longhash(pbc, b, p, height, miners); - return p; - } + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input.key_offsets.push_back(out_entry.first); - void get_block_longhash_reorg(const uint64_t split_height) - { - rx_reorg(split_height); - } - //--------------------------------------------------------------- - cryptonote::tx_source_entry::output_entry generate_migration_bitcoin_transaction_output(const account_keys& sender_account_keys, const crypto::hash bitcoin_tx_hash, uint64_t token_amount) - { - cryptonote::tx_source_entry::output_entry bitcoin_output{0u, rct::ctkey( - {rct::pk2rct(sender_account_keys.m_account_address.m_spend_public_key), - rct::zeroCommit(token_amount)})}; - return bitcoin_output; - } + input.key_offsets = absolute_output_offsets_to_relative(input.key_offsets); - bool generate_migration_key_image(const crypto::hash &bitcoin_transaction_hash, crypto::key_image &key_image) - { - // todo igor for now just place the transaction hash into key_image it should be enough - CHECK_AND_ASSERT_MES(sizeof(key_image.data) == sizeof(bitcoin_transaction_hash.data), false, "key_image and bitcoin_hash do not have the same size."); - memcpy(key_image.data, bitcoin_transaction_hash.data, sizeof(key_image.data)); - return true; - } + safex::edit_offer_data offer; + parse_and_validate_from_blob(src_entr.command_safex_data, offer); - namespace fakechain //for token core tests. Not nice, but only possible without much refactoring - { - static crypto::public_key MIGRATION_FAKECHAIN_VALIDATION_PUBLIC_KEY; + safex::edit_offer cmd(SAFEX_COMMAND_PROTOCOL_VERSION, offer); - void set_core_tests_public_key(const crypto::public_key& publicKey) + safex::safex_command_serializer::serialize_safex_object(cmd, input.script); + + + } + else if (src_entr.command_type == safex::command_t::simple_purchase) { - MIGRATION_FAKECHAIN_VALIDATION_PUBLIC_KEY = publicKey; + input.k_image = img; + + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input.key_offsets.push_back(out_entry.first); + + input.key_offsets = absolute_output_offsets_to_relative(input.key_offsets); + + safex::create_purchase_data purchase; + parse_and_validate_from_blob(src_entr.command_safex_data, purchase); + + safex::simple_purchase cmd(SAFEX_COMMAND_PROTOCOL_VERSION, purchase); + + safex::safex_command_serializer::serialize_safex_object(cmd, input.script); + + } + else if (src_entr.command_type == safex::command_t::create_feedback) + { + input.k_image = img; - const crypto::public_key& get_core_tests_public_key() + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input.key_offsets.push_back(out_entry.first); + + input.key_offsets = absolute_output_offsets_to_relative(input.key_offsets); + + safex::create_feedback_data feedback; + parse_and_validate_from_blob(src_entr.command_safex_data, feedback); + + safex::create_feedback cmd(SAFEX_COMMAND_PROTOCOL_VERSION, feedback); + + safex::safex_command_serializer::serialize_safex_object(cmd, input.script); + + + } + else if (src_entr.command_type == safex::command_t::create_price_peg) { - return MIGRATION_FAKECHAIN_VALIDATION_PUBLIC_KEY; + input.k_image = img; + + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input.key_offsets.push_back(out_entry.first); + + input.key_offsets = absolute_output_offsets_to_relative(input.key_offsets); + + safex::create_price_peg_data price_peg; + parse_and_validate_from_blob(src_entr.command_safex_data, price_peg); + + safex::create_price_peg cmd(SAFEX_COMMAND_PROTOCOL_VERSION, price_peg); + + safex::safex_command_serializer::serialize_safex_object(cmd, input.script); + + } - } + else if (src_entr.command_type == safex::command_t::update_price_peg) + { + input.k_image = img; - const std::string get_genesis_tx_as_str(cryptonote::network_type nettype) - { - switch (nettype) + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input.key_offsets.push_back(out_entry.first); + + input.key_offsets = absolute_output_offsets_to_relative(input.key_offsets); + + safex::update_price_peg_data price_peg; + parse_and_validate_from_blob(src_entr.command_safex_data, price_peg); + + safex::update_price_peg cmd(SAFEX_COMMAND_PROTOCOL_VERSION, price_peg); + + safex::safex_command_serializer::serialize_safex_object(cmd, input.script); + + + } + else { - case cryptonote::network_type::MAINNET: return config::GENESIS_TX;break; - case cryptonote::network_type::STAGENET: return config::stagenet::GENESIS_TX;break; - case cryptonote::network_type::TESTNET: return config::testnet::GENESIS_TX;break; - default: - return ""; + SAFEX_COMMAND_ASSERT_MES_AND_THROW("Unknown safex command type", safex::command_t::invalid_command); } + + return input; } - bool extract_migration_pubkey_from_genesis_transaction(cryptonote::network_type nettype, crypto::public_key& migration_key) + //Based on advanced inputs, create additional outputs + std::vector adjust_advanced_outputs(const std::vector& sources, const tx_source_entry &src_entr, const txin_to_script& input_txin_to_script, + const std::vector& destinations) { - //genesis block - cryptonote::transaction genesis_tx; - std::string const & genesis_tx_str = get_genesis_tx_as_str(nettype); - blobdata tx_bl; + tx_destination_entry dst_entr{}; + std::vector splitted_dsts; + + //add interest output for fee distribution + if (input_txin_to_script.command_type == safex::command_t::token_unstake) { + //find staked token amount matching to this interest + uint64_t input_token_staked_amount = 0; + uint64_t output_token_amount = 0; + for (uint64_t i = 0; i < sources.size(); i++) + if (sources[i].referenced_output_type == tx_out_type::out_staked_token && sources[i].real_output == src_entr.real_output) + input_token_staked_amount = sources[i].token_amount; + + if (input_token_staked_amount == 0) + { + LOG_ERROR("Could not match staked token input with calculated interest input"); + return std::vector{}; + } - bool r = string_tools::parse_hexstr_to_binbuff(genesis_tx_str, tx_bl); - CHECK_AND_ASSERT_MES(r, false, "failed to parse genesis tx from hard coded blob"); - r = parse_and_validate_tx_from_blob(tx_bl, genesis_tx); - CHECK_AND_ASSERT_MES(r, false, "failed to parse genesis tx from hard coded blob"); + for (const tx_destination_entry& dt: destinations) { + if (dt.output_type == tx_out_type::out_token && dt.amount == 0) { + output_token_amount += dt.token_amount; + } - int migration_key_index = 0; - switch (nettype) - { - case cryptonote::network_type::MAINNET: migration_key_index = config::MIGRATION_GENESIS_PUBKEY_INDEX; break; - case cryptonote::network_type::STAGENET: migration_key_index = config::stagenet::MIGRATION_GENESIS_PUBKEY_INDEX; break; - case cryptonote::network_type::TESTNET: migration_key_index = config::testnet::MIGRATION_GENESIS_PUBKEY_INDEX; break; - default: migration_key_index = 0; break; + if (output_token_amount == input_token_staked_amount) { + dst_entr = create_interest_destination(dt, input_txin_to_script.amount); + } + } + cryptonote::decompose_amount_into_digits(dst_entr.amount, ::config::DEFAULT_DUST_THRESHOLD, + [&](uint64_t chunk) + { splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, dst_entr.addr, dst_entr.is_subaddress, cryptonote::tx_out_type::out_cash)); }, + [&](uint64_t a_dust) + { splitted_dsts.push_back(cryptonote::tx_destination_entry(a_dust, dst_entr.addr, dst_entr.is_subaddress, cryptonote::tx_out_type::out_cash)); }); } - migration_key = get_migration_pub_key_from_extra(genesis_tx.extra, migration_key_index); - return true; + + return splitted_dsts; + } + + /** + * Based on ouput, check if matching source entry logic applies (command that produces output), and return command input + * @param dst_entr - destination output for which input should be founded + * @param sources - vector of source entries + * @param inputs - vector of transaction inputs created based on source entries + * @return pointer to input matching output or nullptr + */ + const std::vector match_inputs(const tx_destination_entry &dst_entr, const std::vector &sources, const std::vector& inputs) + { + + int counter=0; + std::vector matched_inputs; + + switch (dst_entr.output_type) + { + case tx_out_type::out_staked_token: + { + counter = std::count_if(sources.begin(), sources.end(), [](const tx_source_entry &entry) + { return entry.command_type == safex::command_t::token_stake; }); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(counter > 0, "Must be at least one tocken lock command per transaction", safex::command_t::token_stake); + + std::for_each(inputs.begin(), inputs.end(), [&](const txin_v &txin) + { + if ((txin.type() == typeid(txin_to_script)) + && (boost::get(txin).command_type == safex::command_t::token_stake)) + { + matched_inputs.push_back(&boost::get(txin)); + }; + + + }); + + //count tokens to lock + uint64_t tokens_to_lock = 0; + for (auto txin: matched_inputs) + { + tokens_to_lock += txin->token_amount; + } + + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(tokens_to_lock >= dst_entr.token_amount, "Not enough tokens to lock at input", safex::command_t::token_stake); + + return matched_inputs; + + } + case tx_out_type::out_network_fee: + { + counter = std::count_if(sources.begin(), sources.end(), [](const tx_source_entry &entry) + { return (entry.command_type == safex::command_t::donate_network_fee || entry.command_type == safex::command_t::simple_purchase); }); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(counter > 0, "There must be donate fee command for this output", safex::command_t::donate_network_fee) ; + + std::for_each(inputs.begin(), inputs.end(), [&](const txin_v &txin) + { + if (txin.type() == typeid(txin_to_script) + && (boost::get(txin).command_type == safex::command_t::donate_network_fee + || boost::get(txin).command_type == safex::command_t::simple_purchase )) + { + matched_inputs.push_back(&boost::get(txin)); + }; + + + }); + + //count amount to donate + uint64_t amount_to_donate = 0; + for (auto txin: matched_inputs) + { + if(txin->command_type == safex::command_t::donate_network_fee) + amount_to_donate += txin->amount; + if(txin->command_type == safex::command_t::simple_purchase) + amount_to_donate += calculate_safex_network_fee(txin->amount, network_type::MAINNET, txin->command_type); + } + +// SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(amount_to_donate >= dst_entr.amount, "Not enough safex cash to donate", safex::command_t::donate_network_fee); + + return matched_inputs; + + } + case tx_out_type::out_safex_account: + { + counter = std::count_if(sources.begin(), sources.end(), [](const tx_source_entry &entry) + { return entry.command_type == safex::command_t::create_account; }); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(counter == 1, "Must be one create account command per transaction", safex::command_t::create_account); + + std::for_each(inputs.begin(), inputs.end(), [&](const txin_v &txin) + { + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &cmd = boost::get(txin); + if (cmd.command_type == safex::command_t::create_account) + { + matched_inputs.push_back(&cmd); + }; + } + }); + + return matched_inputs; + + } + case tx_out_type::out_safex_account_update: + { + counter = std::count_if(sources.begin(), sources.end(), [](const tx_source_entry &entry) + { return entry.command_type == safex::command_t::edit_account; }); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(counter == 1, "Must be one edit account command per transaction", safex::command_t::edit_account); + + std::for_each(inputs.begin(), inputs.end(), [&](const txin_v &txin) + { + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &cmd = boost::get(txin); + if (cmd.command_type == safex::command_t::edit_account) + { + matched_inputs.push_back(&cmd); + }; + } + }); + + return matched_inputs; + + } + case tx_out_type::out_safex_offer: + { + counter = std::count_if(sources.begin(), sources.end(), [](const tx_source_entry &entry) + { return entry.command_type == safex::command_t::create_offer; }); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(counter == 1, "Must be one create offer command per transaction", safex::command_t::create_offer); + + std::for_each(inputs.begin(), inputs.end(), [&](const txin_v &txin) + { + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &cmd = boost::get(txin); + if (cmd.command_type == safex::command_t::create_offer) + { + matched_inputs.push_back(&cmd); + }; + } + }); + + return matched_inputs; + + } + case tx_out_type::out_safex_offer_update: + { + counter = std::count_if(sources.begin(), sources.end(), [](const tx_source_entry &entry) + { return entry.command_type == safex::command_t::edit_offer; }); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(counter == 1, "Must be one edit offer command per transaction", safex::command_t::edit_offer); + + std::for_each(inputs.begin(), inputs.end(), [&](const txin_v &txin) + { + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &cmd = boost::get(txin); + if (cmd.command_type == safex::command_t::edit_offer) + { + matched_inputs.push_back(&cmd); + }; + } + }); + + return matched_inputs; + + } + case tx_out_type::out_safex_purchase: + { + counter = std::count_if(sources.begin(), sources.end(), [](const tx_source_entry &entry) + { return entry.command_type == safex::command_t::simple_purchase; }); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(counter == 1, "Must be one purchase command per transaction", safex::command_t::simple_purchase); + + std::for_each(inputs.begin(), inputs.end(), [&](const txin_v &txin) + { + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &cmd = boost::get(txin); + if (cmd.command_type == safex::command_t::simple_purchase) + { + matched_inputs.push_back(&cmd); + }; + } + }); + + return matched_inputs; + + } + case tx_out_type::out_safex_feedback_token: + { + counter = std::count_if(sources.begin(), sources.end(), [](const tx_source_entry &entry) + { return entry.command_type == safex::command_t::simple_purchase; }); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(counter == 1, "Must be one purchase command per transaction", safex::command_t::simple_purchase); + + std::for_each(inputs.begin(), inputs.end(), [&](const txin_v &txin) + { + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &cmd = boost::get(txin); + if (cmd.command_type == safex::command_t::simple_purchase) + { + matched_inputs.push_back(&cmd); + }; + } + }); + + return matched_inputs; + + } + case tx_out_type::out_safex_feedback: + { + counter = std::count_if(sources.begin(), sources.end(), [](const tx_source_entry &entry) + { return entry.command_type == safex::command_t::create_feedback; }); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(counter == 1, "Must be one purchase command per transaction", safex::command_t::create_feedback); + + std::for_each(inputs.begin(), inputs.end(), [&](const txin_v &txin) + { + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &cmd = boost::get(txin); + if (cmd.command_type == safex::command_t::create_feedback) + { + matched_inputs.push_back(&cmd); + }; + } + }); + + return matched_inputs; + + } + case tx_out_type::out_safex_price_peg: + { + counter = std::count_if(sources.begin(), sources.end(), [](const tx_source_entry &entry) + { return entry.command_type == safex::command_t::create_price_peg; }); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(counter == 1, "Must be one create price_peg command per transaction", safex::command_t::create_price_peg); + + std::for_each(inputs.begin(), inputs.end(), [&](const txin_v &txin) + { + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &cmd = boost::get(txin); + if (cmd.command_type == safex::command_t::create_price_peg) + { + matched_inputs.push_back(&cmd); + }; + } + }); + + return matched_inputs; + + } + case tx_out_type::out_safex_price_peg_update: + { + counter = std::count_if(sources.begin(), sources.end(), [](const tx_source_entry &entry) + { return entry.command_type == safex::command_t::update_price_peg; }); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(counter == 1, "Must be one update price_peg command per transaction", safex::command_t::update_price_peg); + + std::for_each(inputs.begin(), inputs.end(), [&](const txin_v &txin) + { + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script &cmd = boost::get(txin); + if (cmd.command_type == safex::command_t::update_price_peg) + { + matched_inputs.push_back(&cmd); + }; + } + }); + + return matched_inputs; + + } + default: + SAFEX_COMMAND_ASSERT_MES_AND_THROW("Unknown safex output type", safex::command_t::invalid_command); + } + + + } + + //--------------------------------------------------------------- + bool construct_advanced_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, + std::vector& sources, std::vector& destinations, const boost::optional& change_addr, + std::vector extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, + const std::vector &additional_tx_keys, const safex::safex_account_keys &sfx_acc_keys, bool shuffle_outs) + { + hw::device &hwdev = sender_account_keys.get_device(); + + if (sources.empty()) + { + LOG_ERROR("Empty sources"); + return false; + } + + std::vector amount_keys; + tx.set_null(); + amount_keys.clear(); + + tx.version = 2; + tx.unlock_time = unlock_time; + + tx.extra = extra; + crypto::public_key txkey_pub = AUTO_VAL_INIT(txkey_pub); + + // if we have a stealth payment id, find it and encrypt it with the tx key now + std::vector tx_extra_fields; + if (parse_tx_extra(tx.extra, tx_extra_fields)) + { + tx_extra_nonce extra_nonce = AUTO_VAL_INIT(extra_nonce); + if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) + { + crypto::hash8 payment_id = null_hash8; + if (get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) + { + LOG_PRINT_L2("Encrypting payment id " << payment_id); + crypto::public_key view_key_pub = get_destination_view_key_pub(destinations, change_addr); + if (view_key_pub == null_pkey) + { + LOG_ERROR("Destinations have to have exactly one output to support encrypted payment ids"); + return false; + } + + if (!hwdev.encrypt_payment_id(payment_id, view_key_pub, tx_key)) + { + LOG_ERROR("Failed to encrypt payment id"); + return false; + } + + std::string extra_nonce; + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id); + remove_field_from_tx_extra(tx.extra, typeid(tx_extra_nonce)); + if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) + { + LOG_ERROR("Failed to add encrypted payment id to tx extra"); + return false; + } + LOG_PRINT_L1("Encrypted payment ID: " << payment_id); + } + + } + } + else + { + LOG_ERROR("Failed to parse tx extra"); + return false; + } + + struct input_generation_context_data + { + keypair in_ephemeral = AUTO_VAL_INIT(in_ephemeral); + }; + std::vector in_contexts; + + uint64_t summary_inputs_money = 0; + uint64_t summary_inputs_tokens = 0; + + //fill inputs + int idx = -1; + for(const tx_source_entry &src_entr : sources) + { + ++idx; + + if (src_entr.real_output >= src_entr.outputs.size()) + { + LOG_ERROR("real_output index (" << src_entr.real_output << ")bigger than output_keys.size()=" << src_entr.outputs.size()); + return false; + } + summary_inputs_money += src_entr.amount; + summary_inputs_tokens += src_entr.token_amount; + + //key_derivation recv_derivation; + in_contexts.push_back(input_generation_context_data()); + keypair &in_ephemeral = in_contexts.back().in_ephemeral; + crypto::key_image img{}; + const auto &out_key = reinterpret_cast(src_entr.outputs[src_entr.real_output].second.dest); + if (!safex::is_safex_key_image_verification_needed(src_entr.command_type)) + { + if (!crypto::check_key(out_key)) + { + LOG_ERROR("Invalid safex account public key!"); + return false; + } + + crypto::hash cmd_hash{}; + memcpy(img.data, cmd_hash.data, sizeof(img.data)); + + } else { + if (!generate_key_image_helper(sender_account_keys, subaddresses, out_key, src_entr.real_out_tx_key, + src_entr.real_out_additional_tx_keys, src_entr.real_output_in_tx_index, + in_ephemeral, img, hwdev)) { + LOG_ERROR("Key image generation failed!"); + return false; + } + } + + //check that derivated key is equal with real output key + if (src_entr.referenced_output_type == tx_out_type::out_safex_account || src_entr.referenced_output_type == tx_out_type::out_safex_offer + || src_entr.referenced_output_type == tx_out_type::out_safex_price_peg) { + //check that account passed secret key is matching the public key + if (!sfx_acc_keys.valid()) { + LOG_ERROR("Safex account keys invalid"); + return false; + } + const crypto::secret_key &acc_secret_key = sfx_acc_keys.m_secret_key; + crypto::public_key acc_public_key{}; + CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(acc_secret_key, acc_public_key), false, "Could not create safex account public_key from private_key"); + if (!(acc_public_key == out_key)) { + LOG_ERROR("Safex account private key not matching output account key!"); + return false; + } + } + else if (!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second.dest)) + { + //check that derivated key is equal with real output key + LOG_ERROR("derived public key mismatch with output public key at index " << idx << ", real out " << src_entr.real_output << "! " << ENDL << "derived_key:" + << string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:" + << string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second.dest)); + LOG_ERROR("token_amount " << src_entr.token_amount << ", amount " << src_entr.amount); + LOG_ERROR("tx pubkey " << src_entr.real_out_tx_key << ", real_output_in_tx_index " << src_entr.real_output_in_tx_index); + return false; + } + + if (src_entr.command_type != safex::command_t::nop) + { + txin_to_script input_txin_to_script = prepare_advanced_input(src_entr, img); + tx.vin.push_back(input_txin_to_script); + + //adhoc add destination for interest based on input distribute newtork fee command + if (input_txin_to_script.command_type == safex::command_t::token_unstake) { + std::vector dsts_interest = adjust_advanced_outputs(sources, src_entr, input_txin_to_script, destinations); + for(auto dst: dsts_interest) + if(dst.amount > 0) + destinations.push_back(dst); + } + + } + else if (src_entr.referenced_output_type == tx_out_type::out_token) + { + txin_token_to_key input_token_to_key = AUTO_VAL_INIT(input_token_to_key); + input_token_to_key.token_amount = src_entr.token_amount; + input_token_to_key.k_image = img; + + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input_token_to_key.key_offsets.push_back(out_entry.first); + + input_token_to_key.key_offsets = absolute_output_offsets_to_relative(input_token_to_key.key_offsets); + tx.vin.push_back(input_token_to_key); + } + else if (src_entr.referenced_output_type == tx_out_type::out_cash) + { + //put key image into tx input + txin_to_key input_to_key = AUTO_VAL_INIT(input_to_key); + input_to_key.amount = src_entr.amount; + input_to_key.k_image = img; + + //fill outputs array and use relative offsets + for (const tx_source_entry::output_entry &out_entry: src_entr.outputs) + input_to_key.key_offsets.push_back(out_entry.first); + + input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets); + tx.vin.push_back(input_to_key); + } + else + { + LOG_ERROR("Unsuported input!!"); + return false; + } + + + } + + if (shuffle_outs) + { + std::shuffle(destinations.begin(), destinations.end(), std::default_random_engine(crypto::rand())); + } + + // sort ins by their key image + std::vector ins_order(sources.size()); + for (size_t n = 0; n < sources.size(); ++n) + ins_order[n] = n; + std::sort(ins_order.begin(), ins_order.end(), [&](const size_t i0, const size_t i1) { + const crypto::key_image &tk0_key_image = *boost::apply_visitor(key_image_visitor(), tx.vin[i0]); + const crypto::key_image &tk1_key_image = *boost::apply_visitor(key_image_visitor(), tx.vin[i1]); + return memcmp(&tk0_key_image, &tk1_key_image, sizeof(tk1_key_image)) > 0; + }); + tools::apply_permutation(ins_order, [&] (size_t i0, size_t i1) { + std::swap(tx.vin[i0], tx.vin[i1]); + std::swap(in_contexts[i0], in_contexts[i1]); + std::swap(sources[i0], sources[i1]); + }); + + // figure out if we need to make additional tx pubkeys + size_t num_stdaddresses = 0; + size_t num_subaddresses = 0; + account_public_address single_dest_subaddress = AUTO_VAL_INIT(single_dest_subaddress); + classify_addresses(destinations, change_addr, num_stdaddresses, num_subaddresses, single_dest_subaddress); + + // if this is a single-destination transfer to a subaddress, we set the tx pubkey to R=s*D + if (num_stdaddresses == 0 && num_subaddresses == 1) + { + txkey_pub = rct::rct2pk(hwdev.scalarmultKey(rct::pk2rct(single_dest_subaddress.m_spend_public_key), rct::sk2rct(tx_key))); + } + else + { + txkey_pub = rct::rct2pk(hwdev.scalarmultBase(rct::sk2rct(tx_key))); + } + remove_field_from_tx_extra(tx.extra, typeid(tx_extra_pub_key)); + add_tx_pub_key_to_extra(tx, txkey_pub); + + std::vector additional_tx_public_keys; + + // we don't need to include additional tx keys if: + // - all the destinations are standard addresses + // - there's only one destination which is a subaddress + bool need_additional_txkeys = num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1); + if (need_additional_txkeys) + CHECK_AND_ASSERT_MES(destinations.size() == additional_tx_keys.size(), false, "Wrong amount of additional tx keys"); + + uint64_t summary_outs_money = 0; + uint64_t summary_outs_tokens = 0; + //fill outputs + size_t output_index = 0; + for(const tx_destination_entry& dst_entr: destinations) + { + CHECK_AND_ASSERT_MES(dst_entr.amount > 0 || dst_entr.token_amount > 0 || dst_entr.output_type > tx_out_type::out_advanced, false, "Destination with wrong amount: " << dst_entr.amount << " or token amount " << dst_entr.token_amount); + crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); + crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); + + // make additional tx pubkey if necessary + keypair additional_txkey = AUTO_VAL_INIT(additional_txkey); + if (need_additional_txkeys) + { + additional_txkey.sec = additional_tx_keys[output_index]; + if (dst_entr.is_subaddress) + additional_txkey.pub = rct::rct2pk(hwdev.scalarmultKey(rct::pk2rct(dst_entr.addr.m_spend_public_key), rct::sk2rct(additional_txkey.sec))); + else + additional_txkey.pub = rct::rct2pk(hwdev.scalarmultBase(rct::sk2rct(additional_txkey.sec))); + } + + bool r; + if (change_addr && dst_entr.addr == *change_addr) + { + // sending change to yourself; derivation = a*R + r = hwdev.generate_key_derivation(txkey_pub, sender_account_keys.m_view_secret_key, derivation); + CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << txkey_pub << ", " << sender_account_keys.m_view_secret_key << ")"); + } + else + { + // sending to the recipient; derivation = r*A (or s*C in the subaddress scheme) + r = hwdev.generate_key_derivation(dst_entr.addr.m_view_public_key, dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key, derivation); + CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << dst_entr.addr.m_view_public_key << ", " << (dst_entr.is_subaddress && need_additional_txkeys ? additional_txkey.sec : tx_key) << ")"); + } + + if (need_additional_txkeys) + { + additional_tx_public_keys.push_back(additional_txkey.pub); + } + + r = hwdev.derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key); + CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to derive_public_key(" << derivation << ", " << output_index << ", "<< dst_entr.addr.m_spend_public_key << ")"); + + hwdev.add_output_key_mapping(dst_entr.addr.m_view_public_key, dst_entr.addr.m_spend_public_key, dst_entr.is_subaddress, output_index, amount_keys.back(), out_eph_public_key); + + tx_out out = AUTO_VAL_INIT(out); + + if (dst_entr.output_type == tx_out_type::out_token) + { + out.token_amount = dst_entr.token_amount; + out.amount = 0; + txout_token_to_key ttk = AUTO_VAL_INIT(ttk); + ttk.key = out_eph_public_key; + out.target = ttk; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_cash) + { + out.amount = dst_entr.amount; + out.token_amount = 0; + txout_to_key tk = AUTO_VAL_INIT(tk); + tk.key = out_eph_public_key; + out.target = tk; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_staked_token) + { + out.token_amount = dst_entr.token_amount; + out.amount = 0; + + txout_to_script txs = AUTO_VAL_INIT(txs); + txs.output_type = static_cast(cryptonote::tx_out_type::out_staked_token); + txs.key = out_eph_public_key; + //find matching script input + const std::vector matched_inputs = match_inputs(dst_entr, sources, tx.vin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(matched_inputs.size() > 0, "Missing command on inputs to create token stake output", safex::command_t::token_stake); + //nothing else to do with matched inputs, create txout data field + safex::safex_command_serializer::serialize_safex_object(safex::token_stake_data{}, txs.data); + + out.target = txs; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_network_fee) + { + out.amount = dst_entr.amount; + out.token_amount = 0; + + txout_to_script txs = AUTO_VAL_INIT(txs); + txs.output_type = static_cast(tx_out_type::out_network_fee); + txs.key = out_eph_public_key; + //find matching script input + const std::vector matched_inputs = match_inputs(dst_entr, sources, tx.vin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(matched_inputs.size() > 0, "Missing command on inputs to create network fee output", safex::command_t::donate_network_fee); + + //nothing else to do with matched inputs, create txout data field + safex::safex_command_serializer::serialize_safex_object(safex::donate_fee_data{}, txs.data); + + out.target = txs; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_safex_account) + { + out.amount = dst_entr.amount; + out.token_amount = dst_entr.token_amount; + + txout_to_script txs = AUTO_VAL_INIT(txs); + txs.output_type = static_cast(tx_out_type::out_safex_account); + txs.key = sfx_acc_keys.m_public_key; + txs.data = std::vector(std::begin(dst_entr.output_data), std::end(dst_entr.output_data)); + + //find matching script input + const std::vector matched_inputs = match_inputs(dst_entr, sources, tx.vin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(matched_inputs.size() > 0, "Missing command on inputs to create account", safex::command_t::create_account); + + out.target = txs; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_safex_account_update) + { + txout_to_script txs = AUTO_VAL_INIT(txs); + txs.output_type = static_cast(tx_out_type::out_safex_account_update); + txs.key = sfx_acc_keys.m_public_key; + txs.data = std::vector(std::begin(dst_entr.output_data), std::end(dst_entr.output_data)); + + //find matching script input + const std::vector matched_inputs = match_inputs(dst_entr, sources, tx.vin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(matched_inputs.size() > 0, "Missing command on inputs to edit account", safex::command_t::edit_account); + + out.target = txs; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_safex_offer) + { + txout_to_script txs = AUTO_VAL_INIT(txs); + txs.output_type = static_cast(tx_out_type::out_safex_offer); + txs.key = sfx_acc_keys.m_public_key; + txs.data = std::vector(std::begin(dst_entr.output_data), std::end(dst_entr.output_data)); + + //find matching script input + const std::vector matched_inputs = match_inputs(dst_entr, sources, tx.vin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(matched_inputs.size() > 0, "Missing command on inputs to create offer", safex::command_t::create_offer); + + out.target = txs; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_safex_offer_update) + { + txout_to_script txs = AUTO_VAL_INIT(txs); + txs.output_type = static_cast(tx_out_type::out_safex_offer_update); + txs.key = sfx_acc_keys.m_public_key; + txs.data = std::vector(std::begin(dst_entr.output_data), std::end(dst_entr.output_data)); + + //find matching script input + const std::vector matched_inputs = match_inputs(dst_entr, sources, tx.vin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(matched_inputs.size() > 0, "Missing command on inputs to edit offer", safex::command_t::edit_offer); + + out.target = txs; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_safex_purchase) + { + out.token_amount = 0; + txout_to_script txs = AUTO_VAL_INIT(txs); + txs.output_type = static_cast(tx_out_type::out_safex_purchase); + txs.key = out_eph_public_key; + txs.data = std::vector(std::begin(dst_entr.output_data), std::end(dst_entr.output_data)); + + //find matching script input + const std::vector matched_inputs = match_inputs(dst_entr, sources, tx.vin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(matched_inputs.size() > 0, "Missing command on inputs to create purchase", safex::command_t::simple_purchase); + + out.target = txs; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_safex_feedback_token) + { + out.token_amount = 0; + txout_to_script txs = AUTO_VAL_INIT(txs); + txs.output_type = static_cast(tx_out_type::out_safex_feedback_token); + txs.key = out_eph_public_key; + txs.data = std::vector(std::begin(dst_entr.output_data), std::end(dst_entr.output_data)); + + //find matching script input + const std::vector matched_inputs = match_inputs(dst_entr, sources, tx.vin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(matched_inputs.size() > 0, "Missing command on inputs to create feedback token", safex::command_t::simple_purchase); + + out.target = txs; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_safex_feedback) + { + out.token_amount = 0; + txout_to_script txs = AUTO_VAL_INIT(txs); + txs.output_type = static_cast(tx_out_type::out_safex_feedback); + txs.key = out_eph_public_key; + txs.data = std::vector(std::begin(dst_entr.output_data), std::end(dst_entr.output_data)); + + //find matching script input + const std::vector matched_inputs = match_inputs(dst_entr, sources, tx.vin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(matched_inputs.size() > 0, "Missing command on inputs to create feedback", safex::command_t::create_feedback); + + out.target = txs; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_safex_price_peg) + { + txout_to_script txs = AUTO_VAL_INIT(txs); + txs.output_type = static_cast(tx_out_type::out_safex_price_peg); + txs.key = sfx_acc_keys.m_public_key; + txs.data = std::vector(std::begin(dst_entr.output_data), std::end(dst_entr.output_data)); + + //find matching script input + const std::vector matched_inputs = match_inputs(dst_entr, sources, tx.vin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(matched_inputs.size() > 0, "Missing command on inputs to create price peg", safex::command_t::create_price_peg); + + out.target = txs; + tx.vout.push_back(out); + } + else if (dst_entr.output_type == tx_out_type::out_safex_price_peg_update) + { + txout_to_script txs = AUTO_VAL_INIT(txs); + txs.output_type = static_cast(tx_out_type::out_safex_price_peg_update); + txs.key = sfx_acc_keys.m_public_key; + txs.data = std::vector(std::begin(dst_entr.output_data), std::end(dst_entr.output_data)); + + //find matching script input + const std::vector matched_inputs = match_inputs(dst_entr, sources, tx.vin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(matched_inputs.size() > 0, "Missing command on inputs to create price peg", safex::command_t::update_price_peg); + + out.target = txs; + tx.vout.push_back(out); + } + else + { + LOG_ERROR("Wrong transaction output type"); + return false; + } + + output_index++; + summary_outs_money += dst_entr.amount; + summary_outs_tokens += dst_entr.token_amount; + } + CHECK_AND_ASSERT_MES(additional_tx_public_keys.size() == additional_tx_keys.size(), false, "Internal error creating additional public keys"); + + remove_field_from_tx_extra(tx.extra, typeid(tx_extra_additional_pub_keys)); + + LOG_PRINT_L2("tx pubkey: " << txkey_pub); + if (need_additional_txkeys) + { + LOG_PRINT_L2("additional tx pubkeys: "); + for (size_t i = 0; i < additional_tx_public_keys.size(); ++i) + LOG_PRINT_L2(additional_tx_public_keys[i]); + add_additional_tx_pub_keys_to_extra(tx.extra, additional_tx_public_keys); + } + + //check money + if(summary_outs_money > summary_inputs_money ) + { + LOG_ERROR("Transaction inputs money ("<< summary_inputs_money << ") less than outputs money (" << summary_outs_money << ")"); + return false; + } + + //check tokens + if(summary_outs_tokens > summary_inputs_tokens ) + { + LOG_ERROR("Transaction inputs tokens ("<< summary_inputs_tokens << ") less than outputs tokens (" << summary_outs_tokens << ")"); + return false; + } + + // check for watch only wallet + bool zero_secret_key = true; + for (size_t i = 0; i < sizeof(sender_account_keys.m_spend_secret_key); ++i) + zero_secret_key &= (sender_account_keys.m_spend_secret_key.data[i] == 0); + if (zero_secret_key) + { + MDEBUG("Null secret key, skipping signatures"); + } + + if (tx.version == 2) //transaction with safex entities + { + //generate ring signatures + crypto::hash tx_prefix_hash = AUTO_VAL_INIT(tx_prefix_hash); + get_transaction_prefix_hash(tx, tx_prefix_hash); + + std::stringstream ss_ring_s; + size_t i = 0; + for(const tx_source_entry& src_entr: sources) + { + ss_ring_s << "pub_keys:" << ENDL; + std::vector keys_ptrs; + std::vector keys(src_entr.outputs.size()); + size_t ii = 0; + + for(const tx_source_entry::output_entry& o: src_entr.outputs) + { + keys[ii] = rct2pk(o.second.dest); + keys_ptrs.push_back(&keys[ii]); + ss_ring_s << o.second.dest << ENDL; + ++ii; + } + tx.signatures.push_back(std::vector()); + std::vector& sigs = tx.signatures.back(); + sigs.resize(src_entr.outputs.size()); + if (!zero_secret_key) { + const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), tx.vin[i]); + if (src_entr.referenced_output_type == tx_out_type::out_bitcoin_migration) { + public_key spend_public_key = AUTO_VAL_INIT(spend_public_key); + CHECK_AND_ASSERT_MES(crypto::secret_key_to_public_key(sender_account_keys.m_spend_secret_key, spend_public_key), false, "Could not create public_key from private_key"); + crypto::generate_signature(tx_prefix_hash, spend_public_key, sender_account_keys.m_spend_secret_key, sigs[0]); + } + else if (src_entr.referenced_output_type == tx_out_type::out_safex_account || src_entr.referenced_output_type == tx_out_type::out_safex_offer + || src_entr.referenced_output_type == tx_out_type::out_safex_price_peg) { + crypto::generate_signature(tx_prefix_hash, sfx_acc_keys.m_public_key, sfx_acc_keys.m_secret_key, *sigs.data()); + MCINFO("construct_tx", "sfx account advanced_output_id="<< src_entr.real_output); + } + else { + crypto::generate_ring_signature(tx_prefix_hash, k_image, keys_ptrs, in_contexts[i].in_ephemeral.sec, src_entr.real_output, sigs.data()); + } + } + ss_ring_s << "signatures:" << ENDL; + std::for_each(sigs.begin(), sigs.end(), [&](const crypto::signature& s){ss_ring_s << s << ENDL;}); + ss_ring_s << "prefix_hash:" << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[i].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL; + i++; + } + + MCINFO("construct_tx", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL << ss_ring_s.str()); + } + else + { + LOG_ERROR("Advanced transaction must be version >1"); + return false; + + } + + tx.invalidate_hashes(); + + return true; + } + + tx_destination_entry create_safex_account_destination(const account_public_address &to, const std::string &username, const crypto::public_key &pkey, + const std::vector &account_data) + { + safex::create_account_data acc_output_data{username, pkey, account_data}; + blobdata blobdata = cryptonote::t_serializable_object_to_blob(acc_output_data); + return tx_destination_entry{0, to, false, tx_out_type::out_safex_account, blobdata}; + } + + tx_destination_entry edit_safex_account_destination(const account_public_address &to, const std::string &username, const std::vector &account_data) + { + safex::edit_account_data acc_output_data{username, account_data}; + blobdata blobdata = cryptonote::t_serializable_object_to_blob(acc_output_data); + return tx_destination_entry{0, to, false, tx_out_type::out_safex_account_update, blobdata}; + } + + tx_destination_entry create_safex_offer_destination(const account_public_address &to, const safex::safex_offer &sfx_offer) + { + safex::create_offer_data offer_output_data{sfx_offer}; + blobdata blobdata = cryptonote::t_serializable_object_to_blob(offer_output_data); + return tx_destination_entry{0, to, false, tx_out_type::out_safex_offer, blobdata}; + } + + tx_destination_entry edit_safex_offer_destination(const account_public_address &to, const safex::safex_offer &sfx_offer) + { + safex::edit_offer_data offer_output_data{sfx_offer}; + blobdata blobdata = cryptonote::t_serializable_object_to_blob(offer_output_data); + return tx_destination_entry{0, to, false, tx_out_type::out_safex_offer_update, blobdata}; + } + + tx_destination_entry create_safex_purchase_destination(const cryptonote::account_public_address &to, const safex::safex_purchase &sfx_purchase) + { + safex::create_purchase_data safex_purchase_output_data{sfx_purchase}; + blobdata blobdata = cryptonote::t_serializable_object_to_blob(safex_purchase_output_data); + return tx_destination_entry{0, to, false, tx_out_type::out_safex_purchase, blobdata}; + } + + tx_destination_entry create_safex_feedback_token_destination(const cryptonote::account_public_address &to, const safex::safex_feedback_token &sfx_feedback_token) + { + safex::create_feedback_token_data safex_feedback_token_output_data{sfx_feedback_token}; + blobdata blobdata = cryptonote::t_serializable_object_to_blob(safex_feedback_token_output_data); + return tx_destination_entry{0, to, false, tx_out_type::out_safex_feedback_token,blobdata}; + } + + tx_destination_entry create_safex_feedback_destination(const cryptonote::account_public_address &to, const safex::safex_feedback &sfx_feedback) + { + safex::create_feedback_data safex_feedback_output_data{sfx_feedback}; + blobdata blobdata = cryptonote::t_serializable_object_to_blob(safex_feedback_output_data); + return tx_destination_entry{0, to, false, tx_out_type::out_safex_feedback,blobdata}; + } + + tx_destination_entry create_safex_price_peg_destination(const cryptonote::account_public_address &to, const safex::safex_price_peg &sfx_price_peg) + { + safex::create_price_peg_data safex_price_peg_output_data{sfx_price_peg}; + blobdata blobdata = cryptonote::t_serializable_object_to_blob(safex_price_peg_output_data); + return tx_destination_entry{0, to, false, tx_out_type::out_safex_price_peg,blobdata}; + } + + tx_destination_entry update_safex_price_peg_destination(const cryptonote::account_public_address &to, const safex::safex_price_peg &sfx_price_peg) + { + safex::update_price_peg_data safex_price_peg_output_data{sfx_price_peg}; + blobdata blobdata = cryptonote::t_serializable_object_to_blob(safex_price_peg_output_data); + return tx_destination_entry{0, to, false, tx_out_type::out_safex_price_peg_update,blobdata}; + } + //--------------------------------------------------------------- + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, + std::vector& destinations, const boost::optional& change_addr, std::vector extra, + transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, const safex::safex_account_keys &sfx_acc_keys) + { + hw::device &hwdev = sender_account_keys.get_device(); + hwdev.open_tx(tx_key); + + // figure out if we need to make additional tx pubkeys + size_t num_stdaddresses = 0; + size_t num_subaddresses = 0; + account_public_address single_dest_subaddress = AUTO_VAL_INIT(single_dest_subaddress); + classify_addresses(destinations, change_addr, num_stdaddresses, num_subaddresses, single_dest_subaddress); + bool need_additional_txkeys = num_subaddresses > 0 && (num_stdaddresses > 0 || num_subaddresses > 1); + if (need_additional_txkeys) + { + additional_tx_keys.clear(); + for (const auto &d: destinations) + additional_tx_keys.push_back(keypair::generate(sender_account_keys.get_device()).sec); + } + + bool r; + if (is_advanced_transaction(sources)) + { + try + { + r = construct_advanced_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys, sfx_acc_keys); + } + catch (safex::command_exception &exception) + { + LOG_ERROR("Error constructing advanced transaction: " << exception.what()); + r = false; + } + } + else + r = construct_tx_with_tx_key(sender_account_keys, subaddresses, sources, destinations, change_addr, extra, tx, unlock_time, tx_key, additional_tx_keys); + + hwdev.close_tx(); + return r; + } + //--------------------------------------------------------------- + bool construct_tx(const account_keys& sender_account_keys, std::vector& sources, const std::vector& destinations, const boost::optional& change_addr, + std::vector extra, transaction& tx, uint64_t unlock_time, const safex::safex_account_keys &sfx_acc_keys) + { + std::unordered_map subaddresses; + subaddresses[sender_account_keys.m_account_address.m_spend_public_key] = {0,0}; + crypto::secret_key tx_key; + std::vector additional_tx_keys; + std::vector 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, sfx_acc_keys); + } + //--------------------------------------------------------------- + bool generate_genesis_block( + block& bl + , std::string const & genesis_tx + , uint32_t nonce + ) + { + //genesis block + bl = boost::value_initialized(); + + blobdata tx_bl; + bool r = string_tools::parse_hexstr_to_binbuff(genesis_tx, tx_bl); + CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); + r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx); + CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); + bl.major_version = CURRENT_BLOCK_MAJOR_VERSION; + bl.minor_version = CURRENT_BLOCK_MINOR_VERSION; + bl.invalidate_hashes(); + bl.timestamp = 0; + bl.nonce = nonce; + miner::find_nonce_for_given_block([](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash){ + return cryptonote::get_block_longhash(NULL, b, hash, height, threads); + }, bl, 1, 0); + return true; + } + //--------------------------------------------------------------- + void get_altblock_longhash(const block& b, crypto::hash& res, const uint64_t main_height, const uint64_t height, const uint64_t seed_height, const crypto::hash& seed_hash) + { + blobdata bd = get_block_hashing_blob(b); + rx_slow_hash(main_height, seed_height, seed_hash.data, bd.data(), bd.size(), res.data, 0, 1); + } + + bool get_block_longhash(const Blockchain *pbc, const block& b, crypto::hash& res, const uint64_t height, const int miners) + { + blobdata bd = get_block_hashing_blob(b); + if (b.major_version >= RX_BLOCK_VERSION) + { + uint64_t seed_height, main_height; + crypto::hash hash; + if (pbc != NULL) + { + seed_height = rx_seedheight(height); + hash = pbc->get_pending_block_id_by_height(seed_height); + main_height = pbc->get_current_blockchain_height(); + } + else + { + memset(&hash, 0, sizeof(hash)); // only happens when generating genesis block + seed_height = 0; + main_height = 0; + } + rx_slow_hash(main_height, seed_height, hash.data, bd.data(), bd.size(), res.data, miners, 0); + } + else + { + const int pow_variant = b.major_version < HF_VERSION_DIFFICULTY_V2 ? b.major_version: HF_VERSION_DIFFICULTY_V2; + crypto::cn_slow_hash(bd.data(), bd.size(), res, pow_variant); + } + return true; + } + + crypto::hash get_block_longhash(const Blockchain *pbc, const block& b, const uint64_t height, const int miners) + { + crypto::hash p = crypto::null_hash; + get_block_longhash(pbc, b, p, height, miners); + return p; + } + + void get_block_longhash_reorg(const uint64_t split_height) + { + rx_reorg(split_height); + } + //--------------------------------------------------------------- + cryptonote::tx_source_entry::output_entry generate_migration_bitcoin_transaction_output(const account_keys& sender_account_keys, const crypto::hash bitcoin_tx_hash, uint64_t token_amount) + { + cryptonote::tx_source_entry::output_entry bitcoin_output{0u, rct::ctkey( + {rct::pk2rct(sender_account_keys.m_account_address.m_spend_public_key), + rct::zeroCommit(token_amount)})}; + return bitcoin_output; + } + + bool generate_migration_key_image(const crypto::hash &bitcoin_transaction_hash, crypto::key_image &key_image) + { + // todo igor for now just place the transaction hash into key_image it should be enough + CHECK_AND_ASSERT_MES(sizeof(key_image.data) == sizeof(bitcoin_transaction_hash.data), false, "key_image and bitcoin_hash do not have the same size."); + memcpy(key_image.data, bitcoin_transaction_hash.data, sizeof(key_image.data)); + return true; + } + + namespace fakechain //for token core tests. Not nice, but only possible without much refactoring + { + static crypto::public_key MIGRATION_FAKECHAIN_VALIDATION_PUBLIC_KEY; + + void set_core_tests_public_key(const crypto::public_key& publicKey) + { + MIGRATION_FAKECHAIN_VALIDATION_PUBLIC_KEY = publicKey; + } + + const crypto::public_key& get_core_tests_public_key() + { + return MIGRATION_FAKECHAIN_VALIDATION_PUBLIC_KEY; + } + } + + const std::string get_genesis_tx_as_str(cryptonote::network_type nettype) + { + switch (nettype) + { + case cryptonote::network_type::MAINNET: return config::GENESIS_TX;break; + case cryptonote::network_type::STAGENET: return config::stagenet::GENESIS_TX;break; + case cryptonote::network_type::TESTNET: return config::testnet::GENESIS_TX;break; + default: + return ""; + } + } + + bool extract_migration_pubkey_from_genesis_transaction(cryptonote::network_type nettype, crypto::public_key& migration_key) + { + //genesis block + cryptonote::transaction genesis_tx; + std::string const & genesis_tx_str = get_genesis_tx_as_str(nettype); + blobdata tx_bl; + + bool r = string_tools::parse_hexstr_to_binbuff(genesis_tx_str, tx_bl); + CHECK_AND_ASSERT_MES(r, false, "failed to parse genesis tx from hard coded blob"); + + r = parse_and_validate_tx_from_blob(tx_bl, genesis_tx); + CHECK_AND_ASSERT_MES(r, false, "failed to parse genesis tx from hard coded blob"); + + int migration_key_index = 0; + switch (nettype) + { + case cryptonote::network_type::MAINNET: migration_key_index = config::MIGRATION_GENESIS_PUBKEY_INDEX; break; + case cryptonote::network_type::STAGENET: migration_key_index = config::stagenet::MIGRATION_GENESIS_PUBKEY_INDEX; break; + case cryptonote::network_type::TESTNET: migration_key_index = config::testnet::MIGRATION_GENESIS_PUBKEY_INDEX; break; + default: migration_key_index = 0; break; + } + migration_key = get_migration_pub_key_from_extra(genesis_tx.extra, migration_key_index); + return true; } @@ -872,5 +1958,142 @@ namespace cryptonote } return true; } + + /** + * @brief Add safex related data from the tx and check if new data is in conflict with other transactions + * + * @param tx Transaction that is being inserted + * @param safex_accounts_in_use vector of safex account usernames that are used in other transactions from the same block + * @param safex_offers_in_use vector of safex offer IDs that are used in other transactions from the same block + * @param safex_offers_purchase_in_progress vector of safex offer IDs that are being purchased in other transactions from the same block + * @param safex_price_peg_update_in_progress vector of safex price peg IDs that are used in other transactions from the same block + * + * @return true if tx is ok to be in the block, return false if tx is in conflict with some other tx + */ + bool insert_and_check_safex_restrictions(const transaction &tx, std::vector &safex_accounts_in_use, std::vector &safex_offers_in_use, + std::vector &safex_offers_purchase_in_progress, std::vector &safex_price_peg_update_in_progress) + { + + if(tx.version < 2) + return true; + + // Here we check for Safex related data and check if it is already added in the vectors. + // If data already exists, then this tx is in conflict with some other tx and block cannot be added. + + for (const auto &vout: tx.vout) + { + + if(vout.target.type() != typeid(txout_to_script)) + continue; + + if (get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + + auto it = std::find_if(safex_accounts_in_use.begin(),safex_accounts_in_use.end(), [&username](const std::string& it_username){ return it_username == username;}); + + if(it == safex_accounts_in_use.end()) + safex_accounts_in_use.push_back(username); + else + return false; + + } else if (get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + + auto it = std::find_if(safex_accounts_in_use.begin(),safex_accounts_in_use.end(), [&username](const std::string& it_username){ return it_username == username;}); + + if(it == safex_accounts_in_use.end()) + safex_accounts_in_use.push_back(username); + else + return false; + + } else if (get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + + auto it = std::find_if(safex_offers_in_use.begin(),safex_offers_in_use.end(), [&offer](const crypto::hash& item){ return offer.offer_id == item;}); + + if(it == safex_offers_in_use.end()) + safex_offers_in_use.push_back(offer.offer_id); + else + return false; + + } else if (get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + + auto it = std::find_if(safex_offers_in_use.begin(),safex_offers_in_use.end(), [&offer](const crypto::hash& item){ return offer.offer_id == item;}); + + if(it == safex_offers_in_use.end()) + safex_offers_in_use.push_back(offer.offer_id); + else + return false; + + it = std::find_if(safex_offers_purchase_in_progress.begin(),safex_offers_purchase_in_progress.end(), [&offer](const crypto::hash& item){ return offer.offer_id == item;}); + + if(it != safex_offers_purchase_in_progress.end()) + return false; + + } else if (get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_price_peg_data price_peg; + const cryptonote::blobdata pricepegblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(pricepegblob, price_peg); + + auto it = std::find_if(safex_price_peg_update_in_progress.begin(),safex_price_peg_update_in_progress.end(), [&price_peg](const crypto::hash& it_pirce_peg_id){ return price_peg.price_peg_id == it_pirce_peg_id;}); + + if(it == safex_price_peg_update_in_progress.end()) + safex_price_peg_update_in_progress.push_back(price_peg.price_peg_id); + else + return false; + + } else if (get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::update_price_peg_data price_peg; + const cryptonote::blobdata pricepegblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(pricepegblob, price_peg); + + auto it = std::find_if(safex_price_peg_update_in_progress.begin(),safex_price_peg_update_in_progress.end(), [&price_peg](const crypto::hash& it_pirce_peg_id){ return price_peg.price_peg_id == it_pirce_peg_id;}); + + if(it == safex_price_peg_update_in_progress.end()) + safex_price_peg_update_in_progress.push_back(price_peg.price_peg_id); + else + return false; + + } else if(get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_purchase) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_purchase_data purchase; + const cryptonote::blobdata purchaseblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(purchaseblob, purchase); + + auto it = std::find_if(safex_offers_in_use.begin(),safex_offers_in_use.end(), [&purchase](const crypto::hash& item){ return purchase.offer_id == item;}); + if( it != safex_offers_in_use.end()){ + return false; + } + else{ + safex_offers_purchase_in_progress.push_back(purchase.offer_id); + } + } + } + return true; + } //--------------------------------------------------------------- } diff --git a/src/cryptonote_core/cryptonote_tx_utils.h b/src/cryptonote_core/cryptonote_tx_utils.h index 2155e8ec8..a85746ca7 100644 --- a/src/cryptonote_core/cryptonote_tx_utils.h +++ b/src/cryptonote_core/cryptonote_tx_utils.h @@ -34,6 +34,12 @@ #include #include #include "ringct/rctOps.h" +#include "safex/safex_core.h" +#include "safex/safex_account.h" +#include "safex/safex_offer.h" +#include "safex/safex_purchase.h" +#include "safex/safex_feedback_token.h" +#include "safex/safex_feedback.h" namespace cryptonote { @@ -44,23 +50,25 @@ namespace cryptonote bool get_migration_verification_public_key(cryptonote::network_type nettype, crypto::public_key &public_key); + bool insert_and_check_safex_restrictions(const transaction &tx, std::vector &safex_accounts_in_use, std::vector &safex_offers_in_use, + std::vector &safex_offers_purchase_in_progress, std::vector &safex_price_peg_update_in_progress); + struct tx_source_entry { typedef std::pair output_entry; - std::vector outputs; //index + key + optional ringct commitment + std::vector outputs; //index + key size_t real_output = 0; //index in outputs vector of real output_entry crypto::public_key real_out_tx_key = AUTO_VAL_INIT(real_out_tx_key); //incoming real tx public key std::vector real_out_additional_tx_keys; //incoming real tx additional public keys size_t real_output_in_tx_index = 0; //index in transaction outputs vector - uint64_t amount = 0; //money - bool rct = false; //true if the output is rct - rct::key mask = AUTO_VAL_INIT(mask);//ringct amount mask - rct::multisig_kLRki multisig_kLRki = AUTO_VAL_INIT(multisig_kLRki); //multisig info + uint64_t amount = 0; //cash uint64_t token_amount = 0; //tokens - bool token_transaction = false; //source with safex tokens, not safex cash - bool migration = false; //this transaction is migration from bitcoin network + cryptonote::tx_out_type referenced_output_type = tx_out_type::out_cash; + safex::command_t command_type = safex::command_t::nop; + cryptonote::blobdata command_safex_data; + void push_output(uint64_t idx, const crypto::public_key &k, uint64_t amount) { outputs.push_back(std::make_pair(idx, rct::ctkey({rct::pk2rct(k), rct::zeroCommit(amount)}))); } @@ -71,12 +79,11 @@ namespace cryptonote FIELD(real_out_additional_tx_keys) FIELD(real_output_in_tx_index) FIELD(amount) - FIELD(rct) - FIELD(mask) - FIELD(multisig_kLRki) FIELD(token_amount) - FIELD(token_transaction) - FIELD(migration) + FIELD(referenced_output_type) + FIELD(command_type) + FIELD(command_safex_data) + if (real_output >= outputs.size()) return false; @@ -90,30 +97,66 @@ namespace cryptonote account_public_address addr; //destination address bool is_subaddress; bool token_transaction; //output is safex tokens, not safex cash + bool script_output; // if this is advanced output + tx_out_type output_type; //type of the output + cryptonote::blobdata output_data; //output safex data + + tx_destination_entry() : amount(0), token_amount(0), addr(AUTO_VAL_INIT(addr)), is_subaddress(false), + token_transaction(false), script_output(false), output_type{tx_out_type::out_cash} { + + } - tx_destination_entry() : amount(0), token_amount(0), addr(AUTO_VAL_INIT(addr)), is_subaddress(false), token_transaction(false) { } - tx_destination_entry(uint64_t a, const account_public_address &ad, bool is_subaddress, bool is_token_transaction = false) : amount(0), token_amount(0), addr(ad), is_subaddress(is_subaddress), token_transaction(is_token_transaction) + + + tx_destination_entry(uint64_t a, const account_public_address &ad, bool is_subaddress, tx_out_type _out_type = tx_out_type::out_cash, cryptonote::blobdata _output_data={}) : + amount(0), token_amount(0), addr(ad), is_subaddress(is_subaddress), token_transaction(is_token_output(_out_type)), script_output(is_script_output(_out_type)), + output_type(_out_type), output_data{_output_data} { - if (is_token_transaction) + if ((_out_type == tx_out_type::out_token) + || (_out_type == tx_out_type::out_staked_token)) + { token_amount = a; - else + } else { amount = a; + } + } + constexpr bool is_token_output(tx_out_type _out_type) const { return _out_type == tx_out_type::out_token;} + constexpr bool is_cash_output(tx_out_type _out_type) const { return _out_type == tx_out_type::out_cash;} + constexpr bool is_script_output(tx_out_type _out_type) const { return (_out_type >= tx_out_type::out_advanced && _out_type < tx_out_type::out_invalid );} + + BEGIN_SERIALIZE_OBJECT() VARINT_FIELD(amount) VARINT_FIELD(token_amount) FIELD(addr) FIELD(is_subaddress) FIELD(token_transaction) + FIELD(script_output) + FIELD(output_type) + FIELD(output_data) END_SERIALIZE() }; //--------------------------------------------------------------- crypto::public_key get_destination_view_key_pub(const std::vector &destinations, const boost::optional& change_addr); - bool construct_tx(const account_keys& sender_account_keys, std::vector &sources, const std::vector& destinations, const boost::optional& change_addr, std::vector extra, transaction& tx, uint64_t unlock_time); - bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, std::vector extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector &additional_tx_keys, bool rct = false, bool bulletproof = false, rct::multisig_out *msout = NULL, bool shuffle_outs = true); - bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, std::vector extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, bool rct = false, bool bulletproof = false, rct::multisig_out *msout = NULL); + bool construct_tx(const account_keys& sender_account_keys, std::vector &sources, const std::vector& destinations, const boost::optional& change_addr, std::vector extra, transaction& tx, uint64_t unlock_time, const safex::safex_account_keys &sfx_account_keys={}); + bool construct_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, std::vector extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector &additional_tx_keys, bool shuffle_outs = true); + bool construct_advanced_tx_with_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, std::vector extra, transaction& tx, uint64_t unlock_time, const crypto::secret_key &tx_key, const std::vector &additional_tx_keys, const safex::safex_account_keys &sfx_acc_keys, bool shuffle_outs = true); + bool construct_tx_and_get_tx_key(const account_keys& sender_account_keys, const std::unordered_map& subaddresses, std::vector& sources, std::vector& destinations, const boost::optional& change_addr, std::vector extra, transaction& tx, uint64_t unlock_time, crypto::secret_key &tx_key, std::vector &additional_tx_keys, const safex::safex_account_keys &sfx_acc_keys = safex::safex_account_keys{}); + + tx_destination_entry create_safex_account_destination(const account_public_address &to, const std::string &username, const crypto::public_key &pkey, const std::vector &account_data); + tx_destination_entry edit_safex_account_destination(const account_public_address &to, const std::string &username, const std::vector &account_data); + tx_destination_entry create_safex_offer_destination(const account_public_address &to, const safex::safex_offer &sfx_offer); + tx_destination_entry edit_safex_offer_destination(const account_public_address &to, const safex::safex_offer &sfx_offer); + tx_destination_entry create_safex_purchase_destination(const cryptonote::account_public_address &to, const safex::safex_purchase &sfx_purchase); + tx_destination_entry create_safex_feedback_token_destination(const cryptonote::account_public_address &to, const safex::safex_feedback_token &sfx_feedback_token); + tx_destination_entry create_safex_feedback_destination(const cryptonote::account_public_address &to, const safex::safex_feedback &sfx_feedback); + tx_destination_entry create_safex_price_peg_destination(const cryptonote::account_public_address &to, const safex::safex_price_peg &sfx_price_peg); + tx_destination_entry update_safex_price_peg_destination(const cryptonote::account_public_address &to, const safex::safex_price_peg &sfx_price_peg); + + inline bool is_advanced_transaction(const std::vector& sources); bool generate_genesis_block( block& bl @@ -152,12 +195,9 @@ namespace boost a & x.real_output_in_tx_index; a & x.real_out_additional_tx_keys; a & x.amount; - a & x.rct; - a & x.mask; - a & x.multisig_kLRki; a & x.token_amount; - a & x.token_transaction; - a & x.migration; + a & x.referenced_output_type; + a & x.command_type; } @@ -169,6 +209,8 @@ namespace boost a & x.is_subaddress; a & x.token_amount; a & x.token_transaction; + a & x.script_output; + a & x.output_type; } } } diff --git a/src/cryptonote_core/protobuf/blocks.pb.cc b/src/cryptonote_core/protobuf/blocks.pb.cc deleted file mode 100644 index 78f610a9e..000000000 --- a/src/cryptonote_core/protobuf/blocks.pb.cc +++ /dev/null @@ -1,1675 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: blocks.proto - -#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "blocks.pb.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -// @@protoc_insertion_point(includes) - -namespace safex { - -namespace { - -const ::google::protobuf::Descriptor* BlockHeader_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - BlockHeader_reflection_ = NULL; -const ::google::protobuf::Descriptor* Block_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Block_reflection_ = NULL; -const ::google::protobuf::Descriptor* Blocks_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Blocks_reflection_ = NULL; - -} // namespace - - -void protobuf_AssignDesc_blocks_2eproto() GOOGLE_ATTRIBUTE_COLD; -void protobuf_AssignDesc_blocks_2eproto() { - protobuf_AddDesc_blocks_2eproto(); - const ::google::protobuf::FileDescriptor* file = - ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName( - "blocks.proto"); - GOOGLE_CHECK(file != NULL); - BlockHeader_descriptor_ = file->message_type(0); - static const int BlockHeader_offsets_[5] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlockHeader, depth_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlockHeader, hash_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlockHeader, major_version_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlockHeader, minor_version_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlockHeader, prev_hash_), - }; - BlockHeader_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - BlockHeader_descriptor_, - BlockHeader::default_instance_, - BlockHeader_offsets_, - -1, - -1, - -1, - sizeof(BlockHeader), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlockHeader, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(BlockHeader, _is_default_instance_)); - Block_descriptor_ = file->message_type(1); - static const int Block_offsets_[3] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Block, header_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Block, txs_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Block, miner_tx_), - }; - Block_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - Block_descriptor_, - Block::default_instance_, - Block_offsets_, - -1, - -1, - -1, - sizeof(Block), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Block, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Block, _is_default_instance_)); - Blocks_descriptor_ = file->message_type(2); - static const int Blocks_offsets_[4] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Blocks, block_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Blocks, status_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Blocks, untrusted_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Blocks, error_), - }; - Blocks_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - Blocks_descriptor_, - Blocks::default_instance_, - Blocks_offsets_, - -1, - -1, - -1, - sizeof(Blocks), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Blocks, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Blocks, _is_default_instance_)); -} - -namespace { - -GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_); -inline void protobuf_AssignDescriptorsOnce() { - ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_, - &protobuf_AssignDesc_blocks_2eproto); -} - -void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD; -void protobuf_RegisterTypes(const ::std::string&) { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - BlockHeader_descriptor_, &BlockHeader::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Block_descriptor_, &Block::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Blocks_descriptor_, &Blocks::default_instance()); -} - -} // namespace - -void protobuf_ShutdownFile_blocks_2eproto() { - delete BlockHeader::default_instance_; - delete BlockHeader_reflection_; - delete Block::default_instance_; - delete Block_reflection_; - delete Blocks::default_instance_; - delete Blocks_reflection_; -} - -void protobuf_AddDesc_blocks_2eproto() GOOGLE_ATTRIBUTE_COLD; -void protobuf_AddDesc_blocks_2eproto() { - static bool already_here = false; - if (already_here) return; - already_here = true; - GOOGLE_PROTOBUF_VERIFY_VERSION; - - ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( - "\n\014blocks.proto\022\005safex\"k\n\013BlockHeader\022\r\n\005" - "depth\030\001 \001(\004\022\014\n\004hash\030\002 \001(\t\022\025\n\rmajor_versi" - "on\030\003 \001(\r\022\025\n\rminor_version\030\004 \001(\r\022\021\n\tprev_" - "hash\030\005 \001(\t\"J\n\005Block\022\"\n\006header\030\001 \001(\0132\022.sa" - "fex.BlockHeader\022\013\n\003txs\030\002 \003(\t\022\020\n\010miner_tx" - "\030\003 \001(\t\"W\n\006Blocks\022\033\n\005block\030\001 \003(\0132\014.safex." - "Block\022\016\n\006status\030\002 \001(\010\022\021\n\tuntrusted\030\003 \001(\010" - "\022\r\n\005error\030\004 \001(\tb\006proto3", 303); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( - "blocks.proto", &protobuf_RegisterTypes); - BlockHeader::default_instance_ = new BlockHeader(); - Block::default_instance_ = new Block(); - Blocks::default_instance_ = new Blocks(); - BlockHeader::default_instance_->InitAsDefaultInstance(); - Block::default_instance_->InitAsDefaultInstance(); - Blocks::default_instance_->InitAsDefaultInstance(); - ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_blocks_2eproto); -} - -// Force AddDescriptors() to be called at static initialization time. -struct StaticDescriptorInitializer_blocks_2eproto { - StaticDescriptorInitializer_blocks_2eproto() { - protobuf_AddDesc_blocks_2eproto(); - } -} static_descriptor_initializer_blocks_2eproto_; - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int BlockHeader::kDepthFieldNumber; -const int BlockHeader::kHashFieldNumber; -const int BlockHeader::kMajorVersionFieldNumber; -const int BlockHeader::kMinorVersionFieldNumber; -const int BlockHeader::kPrevHashFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -BlockHeader::BlockHeader() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.BlockHeader) -} - -void BlockHeader::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -BlockHeader::BlockHeader(const BlockHeader& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.BlockHeader) -} - -void BlockHeader::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - depth_ = GOOGLE_ULONGLONG(0); - hash_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - major_version_ = 0u; - minor_version_ = 0u; - prev_hash_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -BlockHeader::~BlockHeader() { - // @@protoc_insertion_point(destructor:safex.BlockHeader) - SharedDtor(); -} - -void BlockHeader::SharedDtor() { - hash_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - prev_hash_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void BlockHeader::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* BlockHeader::descriptor() { - protobuf_AssignDescriptorsOnce(); - return BlockHeader_descriptor_; -} - -const BlockHeader& BlockHeader::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_blocks_2eproto(); - return *default_instance_; -} - -BlockHeader* BlockHeader::default_instance_ = NULL; - -BlockHeader* BlockHeader::New(::google::protobuf::Arena* arena) const { - BlockHeader* n = new BlockHeader; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void BlockHeader::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.BlockHeader) -#if defined(__clang__) -#define ZR_HELPER_(f) \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ - __builtin_offsetof(BlockHeader, f) \ - _Pragma("clang diagnostic pop") -#else -#define ZR_HELPER_(f) reinterpret_cast(\ - &reinterpret_cast(16)->f) -#endif - -#define ZR_(first, last) do {\ - ::memset(&first, 0,\ - ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ -} while (0) - - ZR_(major_version_, minor_version_); - depth_ = GOOGLE_ULONGLONG(0); - hash_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - prev_hash_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - -#undef ZR_HELPER_ -#undef ZR_ - -} - -bool BlockHeader::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.BlockHeader) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 depth = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &depth_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_hash; - break; - } - - // optional string hash = 2; - case 2: { - if (tag == 18) { - parse_hash: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_hash())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->hash().data(), this->hash().length(), - ::google::protobuf::internal::WireFormatLite::PARSE, - "safex.BlockHeader.hash")); - } else { - goto handle_unusual; - } - if (input->ExpectTag(24)) goto parse_major_version; - break; - } - - // optional uint32 major_version = 3; - case 3: { - if (tag == 24) { - parse_major_version: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>( - input, &major_version_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(32)) goto parse_minor_version; - break; - } - - // optional uint32 minor_version = 4; - case 4: { - if (tag == 32) { - parse_minor_version: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint32, ::google::protobuf::internal::WireFormatLite::TYPE_UINT32>( - input, &minor_version_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(42)) goto parse_prev_hash; - break; - } - - // optional string prev_hash = 5; - case 5: { - if (tag == 42) { - parse_prev_hash: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_prev_hash())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->prev_hash().data(), this->prev_hash().length(), - ::google::protobuf::internal::WireFormatLite::PARSE, - "safex.BlockHeader.prev_hash")); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.BlockHeader) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.BlockHeader) - return false; -#undef DO_ -} - -void BlockHeader::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.BlockHeader) - // optional uint64 depth = 1; - if (this->depth() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->depth(), output); - } - - // optional string hash = 2; - if (this->hash().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->hash().data(), this->hash().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.BlockHeader.hash"); - ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( - 2, this->hash(), output); - } - - // optional uint32 major_version = 3; - if (this->major_version() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt32(3, this->major_version(), output); - } - - // optional uint32 minor_version = 4; - if (this->minor_version() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt32(4, this->minor_version(), output); - } - - // optional string prev_hash = 5; - if (this->prev_hash().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->prev_hash().data(), this->prev_hash().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.BlockHeader.prev_hash"); - ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( - 5, this->prev_hash(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.BlockHeader) -} - -::google::protobuf::uint8* BlockHeader::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.BlockHeader) - // optional uint64 depth = 1; - if (this->depth() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->depth(), target); - } - - // optional string hash = 2; - if (this->hash().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->hash().data(), this->hash().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.BlockHeader.hash"); - target = - ::google::protobuf::internal::WireFormatLite::WriteStringToArray( - 2, this->hash(), target); - } - - // optional uint32 major_version = 3; - if (this->major_version() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(3, this->major_version(), target); - } - - // optional uint32 minor_version = 4; - if (this->minor_version() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt32ToArray(4, this->minor_version(), target); - } - - // optional string prev_hash = 5; - if (this->prev_hash().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->prev_hash().data(), this->prev_hash().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.BlockHeader.prev_hash"); - target = - ::google::protobuf::internal::WireFormatLite::WriteStringToArray( - 5, this->prev_hash(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.BlockHeader) - return target; -} - -int BlockHeader::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.BlockHeader) - int total_size = 0; - - // optional uint64 depth = 1; - if (this->depth() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->depth()); - } - - // optional string hash = 2; - if (this->hash().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->hash()); - } - - // optional uint32 major_version = 3; - if (this->major_version() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt32Size( - this->major_version()); - } - - // optional uint32 minor_version = 4; - if (this->minor_version() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt32Size( - this->minor_version()); - } - - // optional string prev_hash = 5; - if (this->prev_hash().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->prev_hash()); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void BlockHeader::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.BlockHeader) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const BlockHeader* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.BlockHeader) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.BlockHeader) - MergeFrom(*source); - } -} - -void BlockHeader::MergeFrom(const BlockHeader& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.BlockHeader) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - if (from.depth() != 0) { - set_depth(from.depth()); - } - if (from.hash().size() > 0) { - - hash_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.hash_); - } - if (from.major_version() != 0) { - set_major_version(from.major_version()); - } - if (from.minor_version() != 0) { - set_minor_version(from.minor_version()); - } - if (from.prev_hash().size() > 0) { - - prev_hash_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.prev_hash_); - } -} - -void BlockHeader::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.BlockHeader) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void BlockHeader::CopyFrom(const BlockHeader& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.BlockHeader) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool BlockHeader::IsInitialized() const { - - return true; -} - -void BlockHeader::Swap(BlockHeader* other) { - if (other == this) return; - InternalSwap(other); -} -void BlockHeader::InternalSwap(BlockHeader* other) { - std::swap(depth_, other->depth_); - hash_.Swap(&other->hash_); - std::swap(major_version_, other->major_version_); - std::swap(minor_version_, other->minor_version_); - prev_hash_.Swap(&other->prev_hash_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata BlockHeader::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = BlockHeader_descriptor_; - metadata.reflection = BlockHeader_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// BlockHeader - -// optional uint64 depth = 1; -void BlockHeader::clear_depth() { - depth_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 BlockHeader::depth() const { - // @@protoc_insertion_point(field_get:safex.BlockHeader.depth) - return depth_; -} - void BlockHeader::set_depth(::google::protobuf::uint64 value) { - - depth_ = value; - // @@protoc_insertion_point(field_set:safex.BlockHeader.depth) -} - -// optional string hash = 2; -void BlockHeader::clear_hash() { - hash_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& BlockHeader::hash() const { - // @@protoc_insertion_point(field_get:safex.BlockHeader.hash) - return hash_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void BlockHeader::set_hash(const ::std::string& value) { - - hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.BlockHeader.hash) -} - void BlockHeader::set_hash(const char* value) { - - hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.BlockHeader.hash) -} - void BlockHeader::set_hash(const char* value, size_t size) { - - hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.BlockHeader.hash) -} - ::std::string* BlockHeader::mutable_hash() { - - // @@protoc_insertion_point(field_mutable:safex.BlockHeader.hash) - return hash_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* BlockHeader::release_hash() { - // @@protoc_insertion_point(field_release:safex.BlockHeader.hash) - - return hash_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void BlockHeader::set_allocated_hash(::std::string* hash) { - if (hash != NULL) { - - } else { - - } - hash_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), hash); - // @@protoc_insertion_point(field_set_allocated:safex.BlockHeader.hash) -} - -// optional uint32 major_version = 3; -void BlockHeader::clear_major_version() { - major_version_ = 0u; -} - ::google::protobuf::uint32 BlockHeader::major_version() const { - // @@protoc_insertion_point(field_get:safex.BlockHeader.major_version) - return major_version_; -} - void BlockHeader::set_major_version(::google::protobuf::uint32 value) { - - major_version_ = value; - // @@protoc_insertion_point(field_set:safex.BlockHeader.major_version) -} - -// optional uint32 minor_version = 4; -void BlockHeader::clear_minor_version() { - minor_version_ = 0u; -} - ::google::protobuf::uint32 BlockHeader::minor_version() const { - // @@protoc_insertion_point(field_get:safex.BlockHeader.minor_version) - return minor_version_; -} - void BlockHeader::set_minor_version(::google::protobuf::uint32 value) { - - minor_version_ = value; - // @@protoc_insertion_point(field_set:safex.BlockHeader.minor_version) -} - -// optional string prev_hash = 5; -void BlockHeader::clear_prev_hash() { - prev_hash_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& BlockHeader::prev_hash() const { - // @@protoc_insertion_point(field_get:safex.BlockHeader.prev_hash) - return prev_hash_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void BlockHeader::set_prev_hash(const ::std::string& value) { - - prev_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.BlockHeader.prev_hash) -} - void BlockHeader::set_prev_hash(const char* value) { - - prev_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.BlockHeader.prev_hash) -} - void BlockHeader::set_prev_hash(const char* value, size_t size) { - - prev_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.BlockHeader.prev_hash) -} - ::std::string* BlockHeader::mutable_prev_hash() { - - // @@protoc_insertion_point(field_mutable:safex.BlockHeader.prev_hash) - return prev_hash_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* BlockHeader::release_prev_hash() { - // @@protoc_insertion_point(field_release:safex.BlockHeader.prev_hash) - - return prev_hash_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void BlockHeader::set_allocated_prev_hash(::std::string* prev_hash) { - if (prev_hash != NULL) { - - } else { - - } - prev_hash_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), prev_hash); - // @@protoc_insertion_point(field_set_allocated:safex.BlockHeader.prev_hash) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int Block::kHeaderFieldNumber; -const int Block::kTxsFieldNumber; -const int Block::kMinerTxFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -Block::Block() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.Block) -} - -void Block::InitAsDefaultInstance() { - _is_default_instance_ = true; - header_ = const_cast< ::safex::BlockHeader*>(&::safex::BlockHeader::default_instance()); -} - -Block::Block(const Block& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.Block) -} - -void Block::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - header_ = NULL; - miner_tx_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -Block::~Block() { - // @@protoc_insertion_point(destructor:safex.Block) - SharedDtor(); -} - -void Block::SharedDtor() { - miner_tx_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - delete header_; - } -} - -void Block::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Block::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Block_descriptor_; -} - -const Block& Block::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_blocks_2eproto(); - return *default_instance_; -} - -Block* Block::default_instance_ = NULL; - -Block* Block::New(::google::protobuf::Arena* arena) const { - Block* n = new Block; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void Block::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.Block) - if (GetArenaNoVirtual() == NULL && header_ != NULL) delete header_; - header_ = NULL; - miner_tx_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - txs_.Clear(); -} - -bool Block::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.Block) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional .safex.BlockHeader header = 1; - case 1: { - if (tag == 10) { - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_header())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_txs; - break; - } - - // repeated string txs = 2; - case 2: { - if (tag == 18) { - parse_txs: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->add_txs())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->txs(this->txs_size() - 1).data(), - this->txs(this->txs_size() - 1).length(), - ::google::protobuf::internal::WireFormatLite::PARSE, - "safex.Block.txs")); - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_txs; - if (input->ExpectTag(26)) goto parse_miner_tx; - break; - } - - // optional string miner_tx = 3; - case 3: { - if (tag == 26) { - parse_miner_tx: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_miner_tx())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->miner_tx().data(), this->miner_tx().length(), - ::google::protobuf::internal::WireFormatLite::PARSE, - "safex.Block.miner_tx")); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.Block) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.Block) - return false; -#undef DO_ -} - -void Block::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.Block) - // optional .safex.BlockHeader header = 1; - if (this->has_header()) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 1, *this->header_, output); - } - - // repeated string txs = 2; - for (int i = 0; i < this->txs_size(); i++) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->txs(i).data(), this->txs(i).length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Block.txs"); - ::google::protobuf::internal::WireFormatLite::WriteString( - 2, this->txs(i), output); - } - - // optional string miner_tx = 3; - if (this->miner_tx().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->miner_tx().data(), this->miner_tx().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Block.miner_tx"); - ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( - 3, this->miner_tx(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.Block) -} - -::google::protobuf::uint8* Block::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.Block) - // optional .safex.BlockHeader header = 1; - if (this->has_header()) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 1, *this->header_, false, target); - } - - // repeated string txs = 2; - for (int i = 0; i < this->txs_size(); i++) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->txs(i).data(), this->txs(i).length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Block.txs"); - target = ::google::protobuf::internal::WireFormatLite:: - WriteStringToArray(2, this->txs(i), target); - } - - // optional string miner_tx = 3; - if (this->miner_tx().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->miner_tx().data(), this->miner_tx().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Block.miner_tx"); - target = - ::google::protobuf::internal::WireFormatLite::WriteStringToArray( - 3, this->miner_tx(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.Block) - return target; -} - -int Block::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.Block) - int total_size = 0; - - // optional .safex.BlockHeader header = 1; - if (this->has_header()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - *this->header_); - } - - // optional string miner_tx = 3; - if (this->miner_tx().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->miner_tx()); - } - - // repeated string txs = 2; - total_size += 1 * this->txs_size(); - for (int i = 0; i < this->txs_size(); i++) { - total_size += ::google::protobuf::internal::WireFormatLite::StringSize( - this->txs(i)); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Block::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.Block) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const Block* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.Block) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.Block) - MergeFrom(*source); - } -} - -void Block::MergeFrom(const Block& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.Block) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - txs_.MergeFrom(from.txs_); - if (from.has_header()) { - mutable_header()->::safex::BlockHeader::MergeFrom(from.header()); - } - if (from.miner_tx().size() > 0) { - - miner_tx_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.miner_tx_); - } -} - -void Block::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.Block) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Block::CopyFrom(const Block& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.Block) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Block::IsInitialized() const { - - return true; -} - -void Block::Swap(Block* other) { - if (other == this) return; - InternalSwap(other); -} -void Block::InternalSwap(Block* other) { - std::swap(header_, other->header_); - txs_.UnsafeArenaSwap(&other->txs_); - miner_tx_.Swap(&other->miner_tx_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata Block::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Block_descriptor_; - metadata.reflection = Block_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// Block - -// optional .safex.BlockHeader header = 1; -bool Block::has_header() const { - return !_is_default_instance_ && header_ != NULL; -} -void Block::clear_header() { - if (GetArenaNoVirtual() == NULL && header_ != NULL) delete header_; - header_ = NULL; -} -const ::safex::BlockHeader& Block::header() const { - // @@protoc_insertion_point(field_get:safex.Block.header) - return header_ != NULL ? *header_ : *default_instance_->header_; -} -::safex::BlockHeader* Block::mutable_header() { - - if (header_ == NULL) { - header_ = new ::safex::BlockHeader; - } - // @@protoc_insertion_point(field_mutable:safex.Block.header) - return header_; -} -::safex::BlockHeader* Block::release_header() { - // @@protoc_insertion_point(field_release:safex.Block.header) - - ::safex::BlockHeader* temp = header_; - header_ = NULL; - return temp; -} -void Block::set_allocated_header(::safex::BlockHeader* header) { - delete header_; - header_ = header; - if (header) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.Block.header) -} - -// repeated string txs = 2; -int Block::txs_size() const { - return txs_.size(); -} -void Block::clear_txs() { - txs_.Clear(); -} - const ::std::string& Block::txs(int index) const { - // @@protoc_insertion_point(field_get:safex.Block.txs) - return txs_.Get(index); -} - ::std::string* Block::mutable_txs(int index) { - // @@protoc_insertion_point(field_mutable:safex.Block.txs) - return txs_.Mutable(index); -} - void Block::set_txs(int index, const ::std::string& value) { - // @@protoc_insertion_point(field_set:safex.Block.txs) - txs_.Mutable(index)->assign(value); -} - void Block::set_txs(int index, const char* value) { - txs_.Mutable(index)->assign(value); - // @@protoc_insertion_point(field_set_char:safex.Block.txs) -} - void Block::set_txs(int index, const char* value, size_t size) { - txs_.Mutable(index)->assign( - reinterpret_cast(value), size); - // @@protoc_insertion_point(field_set_pointer:safex.Block.txs) -} - ::std::string* Block::add_txs() { - // @@protoc_insertion_point(field_add_mutable:safex.Block.txs) - return txs_.Add(); -} - void Block::add_txs(const ::std::string& value) { - txs_.Add()->assign(value); - // @@protoc_insertion_point(field_add:safex.Block.txs) -} - void Block::add_txs(const char* value) { - txs_.Add()->assign(value); - // @@protoc_insertion_point(field_add_char:safex.Block.txs) -} - void Block::add_txs(const char* value, size_t size) { - txs_.Add()->assign(reinterpret_cast(value), size); - // @@protoc_insertion_point(field_add_pointer:safex.Block.txs) -} - const ::google::protobuf::RepeatedPtrField< ::std::string>& -Block::txs() const { - // @@protoc_insertion_point(field_list:safex.Block.txs) - return txs_; -} - ::google::protobuf::RepeatedPtrField< ::std::string>* -Block::mutable_txs() { - // @@protoc_insertion_point(field_mutable_list:safex.Block.txs) - return &txs_; -} - -// optional string miner_tx = 3; -void Block::clear_miner_tx() { - miner_tx_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& Block::miner_tx() const { - // @@protoc_insertion_point(field_get:safex.Block.miner_tx) - return miner_tx_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Block::set_miner_tx(const ::std::string& value) { - - miner_tx_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Block.miner_tx) -} - void Block::set_miner_tx(const char* value) { - - miner_tx_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Block.miner_tx) -} - void Block::set_miner_tx(const char* value, size_t size) { - - miner_tx_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Block.miner_tx) -} - ::std::string* Block::mutable_miner_tx() { - - // @@protoc_insertion_point(field_mutable:safex.Block.miner_tx) - return miner_tx_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* Block::release_miner_tx() { - // @@protoc_insertion_point(field_release:safex.Block.miner_tx) - - return miner_tx_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Block::set_allocated_miner_tx(::std::string* miner_tx) { - if (miner_tx != NULL) { - - } else { - - } - miner_tx_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), miner_tx); - // @@protoc_insertion_point(field_set_allocated:safex.Block.miner_tx) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int Blocks::kBlockFieldNumber; -const int Blocks::kStatusFieldNumber; -const int Blocks::kUntrustedFieldNumber; -const int Blocks::kErrorFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -Blocks::Blocks() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.Blocks) -} - -void Blocks::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -Blocks::Blocks(const Blocks& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.Blocks) -} - -void Blocks::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - status_ = false; - untrusted_ = false; - error_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -Blocks::~Blocks() { - // @@protoc_insertion_point(destructor:safex.Blocks) - SharedDtor(); -} - -void Blocks::SharedDtor() { - error_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void Blocks::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Blocks::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Blocks_descriptor_; -} - -const Blocks& Blocks::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_blocks_2eproto(); - return *default_instance_; -} - -Blocks* Blocks::default_instance_ = NULL; - -Blocks* Blocks::New(::google::protobuf::Arena* arena) const { - Blocks* n = new Blocks; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void Blocks::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.Blocks) -#if defined(__clang__) -#define ZR_HELPER_(f) \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ - __builtin_offsetof(Blocks, f) \ - _Pragma("clang diagnostic pop") -#else -#define ZR_HELPER_(f) reinterpret_cast(\ - &reinterpret_cast(16)->f) -#endif - -#define ZR_(first, last) do {\ - ::memset(&first, 0,\ - ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ -} while (0) - - ZR_(status_, untrusted_); - error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - -#undef ZR_HELPER_ -#undef ZR_ - - block_.Clear(); -} - -bool Blocks::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.Blocks) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // repeated .safex.Block block = 1; - case 1: { - if (tag == 10) { - DO_(input->IncrementRecursionDepth()); - parse_loop_block: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( - input, add_block())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(10)) goto parse_loop_block; - input->UnsafeDecrementRecursionDepth(); - if (input->ExpectTag(16)) goto parse_status; - break; - } - - // optional bool status = 2; - case 2: { - if (tag == 16) { - parse_status: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - input, &status_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(24)) goto parse_untrusted; - break; - } - - // optional bool untrusted = 3; - case 3: { - if (tag == 24) { - parse_untrusted: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - input, &untrusted_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(34)) goto parse_error; - break; - } - - // optional string error = 4; - case 4: { - if (tag == 34) { - parse_error: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_error())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->error().data(), this->error().length(), - ::google::protobuf::internal::WireFormatLite::PARSE, - "safex.Blocks.error")); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.Blocks) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.Blocks) - return false; -#undef DO_ -} - -void Blocks::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.Blocks) - // repeated .safex.Block block = 1; - for (unsigned int i = 0, n = this->block_size(); i < n; i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 1, this->block(i), output); - } - - // optional bool status = 2; - if (this->status() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->status(), output); - } - - // optional bool untrusted = 3; - if (this->untrusted() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteBool(3, this->untrusted(), output); - } - - // optional string error = 4; - if (this->error().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->error().data(), this->error().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Blocks.error"); - ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( - 4, this->error(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.Blocks) -} - -::google::protobuf::uint8* Blocks::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.Blocks) - // repeated .safex.Block block = 1; - for (unsigned int i = 0, n = this->block_size(); i < n; i++) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 1, this->block(i), false, target); - } - - // optional bool status = 2; - if (this->status() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->status(), target); - } - - // optional bool untrusted = 3; - if (this->untrusted() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(3, this->untrusted(), target); - } - - // optional string error = 4; - if (this->error().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->error().data(), this->error().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Blocks.error"); - target = - ::google::protobuf::internal::WireFormatLite::WriteStringToArray( - 4, this->error(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.Blocks) - return target; -} - -int Blocks::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.Blocks) - int total_size = 0; - - // optional bool status = 2; - if (this->status() != 0) { - total_size += 1 + 1; - } - - // optional bool untrusted = 3; - if (this->untrusted() != 0) { - total_size += 1 + 1; - } - - // optional string error = 4; - if (this->error().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->error()); - } - - // repeated .safex.Block block = 1; - total_size += 1 * this->block_size(); - for (int i = 0; i < this->block_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->block(i)); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Blocks::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.Blocks) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const Blocks* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.Blocks) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.Blocks) - MergeFrom(*source); - } -} - -void Blocks::MergeFrom(const Blocks& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.Blocks) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - block_.MergeFrom(from.block_); - if (from.status() != 0) { - set_status(from.status()); - } - if (from.untrusted() != 0) { - set_untrusted(from.untrusted()); - } - if (from.error().size() > 0) { - - error_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.error_); - } -} - -void Blocks::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.Blocks) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Blocks::CopyFrom(const Blocks& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.Blocks) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Blocks::IsInitialized() const { - - return true; -} - -void Blocks::Swap(Blocks* other) { - if (other == this) return; - InternalSwap(other); -} -void Blocks::InternalSwap(Blocks* other) { - block_.UnsafeArenaSwap(&other->block_); - std::swap(status_, other->status_); - std::swap(untrusted_, other->untrusted_); - error_.Swap(&other->error_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata Blocks::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Blocks_descriptor_; - metadata.reflection = Blocks_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// Blocks - -// repeated .safex.Block block = 1; -int Blocks::block_size() const { - return block_.size(); -} -void Blocks::clear_block() { - block_.Clear(); -} -const ::safex::Block& Blocks::block(int index) const { - // @@protoc_insertion_point(field_get:safex.Blocks.block) - return block_.Get(index); -} -::safex::Block* Blocks::mutable_block(int index) { - // @@protoc_insertion_point(field_mutable:safex.Blocks.block) - return block_.Mutable(index); -} -::safex::Block* Blocks::add_block() { - // @@protoc_insertion_point(field_add:safex.Blocks.block) - return block_.Add(); -} -::google::protobuf::RepeatedPtrField< ::safex::Block >* -Blocks::mutable_block() { - // @@protoc_insertion_point(field_mutable_list:safex.Blocks.block) - return &block_; -} -const ::google::protobuf::RepeatedPtrField< ::safex::Block >& -Blocks::block() const { - // @@protoc_insertion_point(field_list:safex.Blocks.block) - return block_; -} - -// optional bool status = 2; -void Blocks::clear_status() { - status_ = false; -} - bool Blocks::status() const { - // @@protoc_insertion_point(field_get:safex.Blocks.status) - return status_; -} - void Blocks::set_status(bool value) { - - status_ = value; - // @@protoc_insertion_point(field_set:safex.Blocks.status) -} - -// optional bool untrusted = 3; -void Blocks::clear_untrusted() { - untrusted_ = false; -} - bool Blocks::untrusted() const { - // @@protoc_insertion_point(field_get:safex.Blocks.untrusted) - return untrusted_; -} - void Blocks::set_untrusted(bool value) { - - untrusted_ = value; - // @@protoc_insertion_point(field_set:safex.Blocks.untrusted) -} - -// optional string error = 4; -void Blocks::clear_error() { - error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& Blocks::error() const { - // @@protoc_insertion_point(field_get:safex.Blocks.error) - return error_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Blocks::set_error(const ::std::string& value) { - - error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Blocks.error) -} - void Blocks::set_error(const char* value) { - - error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Blocks.error) -} - void Blocks::set_error(const char* value, size_t size) { - - error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Blocks.error) -} - ::std::string* Blocks::mutable_error() { - - // @@protoc_insertion_point(field_mutable:safex.Blocks.error) - return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* Blocks::release_error() { - // @@protoc_insertion_point(field_release:safex.Blocks.error) - - return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Blocks::set_allocated_error(::std::string* error) { - if (error != NULL) { - - } else { - - } - error_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), error); - // @@protoc_insertion_point(field_set_allocated:safex.Blocks.error) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// @@protoc_insertion_point(namespace_scope) - -} // namespace safex - -// @@protoc_insertion_point(global_scope) diff --git a/src/cryptonote_core/protobuf/blocks.pb.h b/src/cryptonote_core/protobuf/blocks.pb.h deleted file mode 100644 index d2e74d4b0..000000000 --- a/src/cryptonote_core/protobuf/blocks.pb.h +++ /dev/null @@ -1,788 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: blocks.proto - -#ifndef PROTOBUF_blocks_2eproto__INCLUDED -#define PROTOBUF_blocks_2eproto__INCLUDED - -#include - -#include - -#if GOOGLE_PROTOBUF_VERSION < 3000000 -#error This file was generated by a newer version of protoc which is -#error incompatible with your Protocol Buffer headers. Please update -#error your headers. -#endif -#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION -#error This file was generated by an older version of protoc which is -#error incompatible with your Protocol Buffer headers. Please -#error regenerate this file with a newer version of protoc. -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -// @@protoc_insertion_point(includes) - -namespace safex { - -// Internal implementation detail -- do not call these. -void protobuf_AddDesc_blocks_2eproto(); -void protobuf_AssignDesc_blocks_2eproto(); -void protobuf_ShutdownFile_blocks_2eproto(); - -class Block; -class BlockHeader; -class Blocks; - -// =================================================================== - -class BlockHeader : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.BlockHeader) */ { - public: - BlockHeader(); - virtual ~BlockHeader(); - - BlockHeader(const BlockHeader& from); - - inline BlockHeader& operator=(const BlockHeader& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const BlockHeader& default_instance(); - - void Swap(BlockHeader* other); - - // implements Message ---------------------------------------------- - - inline BlockHeader* New() const { return New(NULL); } - - BlockHeader* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const BlockHeader& from); - void MergeFrom(const BlockHeader& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(BlockHeader* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 depth = 1; - void clear_depth(); - static const int kDepthFieldNumber = 1; - ::google::protobuf::uint64 depth() const; - void set_depth(::google::protobuf::uint64 value); - - // optional string hash = 2; - void clear_hash(); - static const int kHashFieldNumber = 2; - const ::std::string& hash() const; - void set_hash(const ::std::string& value); - void set_hash(const char* value); - void set_hash(const char* value, size_t size); - ::std::string* mutable_hash(); - ::std::string* release_hash(); - void set_allocated_hash(::std::string* hash); - - // optional uint32 major_version = 3; - void clear_major_version(); - static const int kMajorVersionFieldNumber = 3; - ::google::protobuf::uint32 major_version() const; - void set_major_version(::google::protobuf::uint32 value); - - // optional uint32 minor_version = 4; - void clear_minor_version(); - static const int kMinorVersionFieldNumber = 4; - ::google::protobuf::uint32 minor_version() const; - void set_minor_version(::google::protobuf::uint32 value); - - // optional string prev_hash = 5; - void clear_prev_hash(); - static const int kPrevHashFieldNumber = 5; - const ::std::string& prev_hash() const; - void set_prev_hash(const ::std::string& value); - void set_prev_hash(const char* value); - void set_prev_hash(const char* value, size_t size); - ::std::string* mutable_prev_hash(); - ::std::string* release_prev_hash(); - void set_allocated_prev_hash(::std::string* prev_hash); - - // @@protoc_insertion_point(class_scope:safex.BlockHeader) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::uint64 depth_; - ::google::protobuf::internal::ArenaStringPtr hash_; - ::google::protobuf::uint32 major_version_; - ::google::protobuf::uint32 minor_version_; - ::google::protobuf::internal::ArenaStringPtr prev_hash_; - mutable int _cached_size_; - friend void protobuf_AddDesc_blocks_2eproto(); - friend void protobuf_AssignDesc_blocks_2eproto(); - friend void protobuf_ShutdownFile_blocks_2eproto(); - - void InitAsDefaultInstance(); - static BlockHeader* default_instance_; -}; -// ------------------------------------------------------------------- - -class Block : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.Block) */ { - public: - Block(); - virtual ~Block(); - - Block(const Block& from); - - inline Block& operator=(const Block& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Block& default_instance(); - - void Swap(Block* other); - - // implements Message ---------------------------------------------- - - inline Block* New() const { return New(NULL); } - - Block* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Block& from); - void MergeFrom(const Block& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(Block* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional .safex.BlockHeader header = 1; - bool has_header() const; - void clear_header(); - static const int kHeaderFieldNumber = 1; - const ::safex::BlockHeader& header() const; - ::safex::BlockHeader* mutable_header(); - ::safex::BlockHeader* release_header(); - void set_allocated_header(::safex::BlockHeader* header); - - // repeated string txs = 2; - int txs_size() const; - void clear_txs(); - static const int kTxsFieldNumber = 2; - const ::std::string& txs(int index) const; - ::std::string* mutable_txs(int index); - void set_txs(int index, const ::std::string& value); - void set_txs(int index, const char* value); - void set_txs(int index, const char* value, size_t size); - ::std::string* add_txs(); - void add_txs(const ::std::string& value); - void add_txs(const char* value); - void add_txs(const char* value, size_t size); - const ::google::protobuf::RepeatedPtrField< ::std::string>& txs() const; - ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_txs(); - - // optional string miner_tx = 3; - void clear_miner_tx(); - static const int kMinerTxFieldNumber = 3; - const ::std::string& miner_tx() const; - void set_miner_tx(const ::std::string& value); - void set_miner_tx(const char* value); - void set_miner_tx(const char* value, size_t size); - ::std::string* mutable_miner_tx(); - ::std::string* release_miner_tx(); - void set_allocated_miner_tx(::std::string* miner_tx); - - // @@protoc_insertion_point(class_scope:safex.Block) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::safex::BlockHeader* header_; - ::google::protobuf::RepeatedPtrField< ::std::string> txs_; - ::google::protobuf::internal::ArenaStringPtr miner_tx_; - mutable int _cached_size_; - friend void protobuf_AddDesc_blocks_2eproto(); - friend void protobuf_AssignDesc_blocks_2eproto(); - friend void protobuf_ShutdownFile_blocks_2eproto(); - - void InitAsDefaultInstance(); - static Block* default_instance_; -}; -// ------------------------------------------------------------------- - -class Blocks : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.Blocks) */ { - public: - Blocks(); - virtual ~Blocks(); - - Blocks(const Blocks& from); - - inline Blocks& operator=(const Blocks& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Blocks& default_instance(); - - void Swap(Blocks* other); - - // implements Message ---------------------------------------------- - - inline Blocks* New() const { return New(NULL); } - - Blocks* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Blocks& from); - void MergeFrom(const Blocks& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(Blocks* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // repeated .safex.Block block = 1; - int block_size() const; - void clear_block(); - static const int kBlockFieldNumber = 1; - const ::safex::Block& block(int index) const; - ::safex::Block* mutable_block(int index); - ::safex::Block* add_block(); - ::google::protobuf::RepeatedPtrField< ::safex::Block >* - mutable_block(); - const ::google::protobuf::RepeatedPtrField< ::safex::Block >& - block() const; - - // optional bool status = 2; - void clear_status(); - static const int kStatusFieldNumber = 2; - bool status() const; - void set_status(bool value); - - // optional bool untrusted = 3; - void clear_untrusted(); - static const int kUntrustedFieldNumber = 3; - bool untrusted() const; - void set_untrusted(bool value); - - // optional string error = 4; - void clear_error(); - static const int kErrorFieldNumber = 4; - const ::std::string& error() const; - void set_error(const ::std::string& value); - void set_error(const char* value); - void set_error(const char* value, size_t size); - ::std::string* mutable_error(); - ::std::string* release_error(); - void set_allocated_error(::std::string* error); - - // @@protoc_insertion_point(class_scope:safex.Blocks) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::RepeatedPtrField< ::safex::Block > block_; - ::google::protobuf::internal::ArenaStringPtr error_; - bool status_; - bool untrusted_; - mutable int _cached_size_; - friend void protobuf_AddDesc_blocks_2eproto(); - friend void protobuf_AssignDesc_blocks_2eproto(); - friend void protobuf_ShutdownFile_blocks_2eproto(); - - void InitAsDefaultInstance(); - static Blocks* default_instance_; -}; -// =================================================================== - - -// =================================================================== - -#if !PROTOBUF_INLINE_NOT_IN_HEADERS -// BlockHeader - -// optional uint64 depth = 1; -inline void BlockHeader::clear_depth() { - depth_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 BlockHeader::depth() const { - // @@protoc_insertion_point(field_get:safex.BlockHeader.depth) - return depth_; -} -inline void BlockHeader::set_depth(::google::protobuf::uint64 value) { - - depth_ = value; - // @@protoc_insertion_point(field_set:safex.BlockHeader.depth) -} - -// optional string hash = 2; -inline void BlockHeader::clear_hash() { - hash_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& BlockHeader::hash() const { - // @@protoc_insertion_point(field_get:safex.BlockHeader.hash) - return hash_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void BlockHeader::set_hash(const ::std::string& value) { - - hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.BlockHeader.hash) -} -inline void BlockHeader::set_hash(const char* value) { - - hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.BlockHeader.hash) -} -inline void BlockHeader::set_hash(const char* value, size_t size) { - - hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.BlockHeader.hash) -} -inline ::std::string* BlockHeader::mutable_hash() { - - // @@protoc_insertion_point(field_mutable:safex.BlockHeader.hash) - return hash_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* BlockHeader::release_hash() { - // @@protoc_insertion_point(field_release:safex.BlockHeader.hash) - - return hash_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void BlockHeader::set_allocated_hash(::std::string* hash) { - if (hash != NULL) { - - } else { - - } - hash_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), hash); - // @@protoc_insertion_point(field_set_allocated:safex.BlockHeader.hash) -} - -// optional uint32 major_version = 3; -inline void BlockHeader::clear_major_version() { - major_version_ = 0u; -} -inline ::google::protobuf::uint32 BlockHeader::major_version() const { - // @@protoc_insertion_point(field_get:safex.BlockHeader.major_version) - return major_version_; -} -inline void BlockHeader::set_major_version(::google::protobuf::uint32 value) { - - major_version_ = value; - // @@protoc_insertion_point(field_set:safex.BlockHeader.major_version) -} - -// optional uint32 minor_version = 4; -inline void BlockHeader::clear_minor_version() { - minor_version_ = 0u; -} -inline ::google::protobuf::uint32 BlockHeader::minor_version() const { - // @@protoc_insertion_point(field_get:safex.BlockHeader.minor_version) - return minor_version_; -} -inline void BlockHeader::set_minor_version(::google::protobuf::uint32 value) { - - minor_version_ = value; - // @@protoc_insertion_point(field_set:safex.BlockHeader.minor_version) -} - -// optional string prev_hash = 5; -inline void BlockHeader::clear_prev_hash() { - prev_hash_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& BlockHeader::prev_hash() const { - // @@protoc_insertion_point(field_get:safex.BlockHeader.prev_hash) - return prev_hash_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void BlockHeader::set_prev_hash(const ::std::string& value) { - - prev_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.BlockHeader.prev_hash) -} -inline void BlockHeader::set_prev_hash(const char* value) { - - prev_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.BlockHeader.prev_hash) -} -inline void BlockHeader::set_prev_hash(const char* value, size_t size) { - - prev_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.BlockHeader.prev_hash) -} -inline ::std::string* BlockHeader::mutable_prev_hash() { - - // @@protoc_insertion_point(field_mutable:safex.BlockHeader.prev_hash) - return prev_hash_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* BlockHeader::release_prev_hash() { - // @@protoc_insertion_point(field_release:safex.BlockHeader.prev_hash) - - return prev_hash_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void BlockHeader::set_allocated_prev_hash(::std::string* prev_hash) { - if (prev_hash != NULL) { - - } else { - - } - prev_hash_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), prev_hash); - // @@protoc_insertion_point(field_set_allocated:safex.BlockHeader.prev_hash) -} - -// ------------------------------------------------------------------- - -// Block - -// optional .safex.BlockHeader header = 1; -inline bool Block::has_header() const { - return !_is_default_instance_ && header_ != NULL; -} -inline void Block::clear_header() { - if (GetArenaNoVirtual() == NULL && header_ != NULL) delete header_; - header_ = NULL; -} -inline const ::safex::BlockHeader& Block::header() const { - // @@protoc_insertion_point(field_get:safex.Block.header) - return header_ != NULL ? *header_ : *default_instance_->header_; -} -inline ::safex::BlockHeader* Block::mutable_header() { - - if (header_ == NULL) { - header_ = new ::safex::BlockHeader; - } - // @@protoc_insertion_point(field_mutable:safex.Block.header) - return header_; -} -inline ::safex::BlockHeader* Block::release_header() { - // @@protoc_insertion_point(field_release:safex.Block.header) - - ::safex::BlockHeader* temp = header_; - header_ = NULL; - return temp; -} -inline void Block::set_allocated_header(::safex::BlockHeader* header) { - delete header_; - header_ = header; - if (header) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.Block.header) -} - -// repeated string txs = 2; -inline int Block::txs_size() const { - return txs_.size(); -} -inline void Block::clear_txs() { - txs_.Clear(); -} -inline const ::std::string& Block::txs(int index) const { - // @@protoc_insertion_point(field_get:safex.Block.txs) - return txs_.Get(index); -} -inline ::std::string* Block::mutable_txs(int index) { - // @@protoc_insertion_point(field_mutable:safex.Block.txs) - return txs_.Mutable(index); -} -inline void Block::set_txs(int index, const ::std::string& value) { - // @@protoc_insertion_point(field_set:safex.Block.txs) - txs_.Mutable(index)->assign(value); -} -inline void Block::set_txs(int index, const char* value) { - txs_.Mutable(index)->assign(value); - // @@protoc_insertion_point(field_set_char:safex.Block.txs) -} -inline void Block::set_txs(int index, const char* value, size_t size) { - txs_.Mutable(index)->assign( - reinterpret_cast(value), size); - // @@protoc_insertion_point(field_set_pointer:safex.Block.txs) -} -inline ::std::string* Block::add_txs() { - // @@protoc_insertion_point(field_add_mutable:safex.Block.txs) - return txs_.Add(); -} -inline void Block::add_txs(const ::std::string& value) { - txs_.Add()->assign(value); - // @@protoc_insertion_point(field_add:safex.Block.txs) -} -inline void Block::add_txs(const char* value) { - txs_.Add()->assign(value); - // @@protoc_insertion_point(field_add_char:safex.Block.txs) -} -inline void Block::add_txs(const char* value, size_t size) { - txs_.Add()->assign(reinterpret_cast(value), size); - // @@protoc_insertion_point(field_add_pointer:safex.Block.txs) -} -inline const ::google::protobuf::RepeatedPtrField< ::std::string>& -Block::txs() const { - // @@protoc_insertion_point(field_list:safex.Block.txs) - return txs_; -} -inline ::google::protobuf::RepeatedPtrField< ::std::string>* -Block::mutable_txs() { - // @@protoc_insertion_point(field_mutable_list:safex.Block.txs) - return &txs_; -} - -// optional string miner_tx = 3; -inline void Block::clear_miner_tx() { - miner_tx_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& Block::miner_tx() const { - // @@protoc_insertion_point(field_get:safex.Block.miner_tx) - return miner_tx_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Block::set_miner_tx(const ::std::string& value) { - - miner_tx_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Block.miner_tx) -} -inline void Block::set_miner_tx(const char* value) { - - miner_tx_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Block.miner_tx) -} -inline void Block::set_miner_tx(const char* value, size_t size) { - - miner_tx_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Block.miner_tx) -} -inline ::std::string* Block::mutable_miner_tx() { - - // @@protoc_insertion_point(field_mutable:safex.Block.miner_tx) - return miner_tx_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* Block::release_miner_tx() { - // @@protoc_insertion_point(field_release:safex.Block.miner_tx) - - return miner_tx_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Block::set_allocated_miner_tx(::std::string* miner_tx) { - if (miner_tx != NULL) { - - } else { - - } - miner_tx_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), miner_tx); - // @@protoc_insertion_point(field_set_allocated:safex.Block.miner_tx) -} - -// ------------------------------------------------------------------- - -// Blocks - -// repeated .safex.Block block = 1; -inline int Blocks::block_size() const { - return block_.size(); -} -inline void Blocks::clear_block() { - block_.Clear(); -} -inline const ::safex::Block& Blocks::block(int index) const { - // @@protoc_insertion_point(field_get:safex.Blocks.block) - return block_.Get(index); -} -inline ::safex::Block* Blocks::mutable_block(int index) { - // @@protoc_insertion_point(field_mutable:safex.Blocks.block) - return block_.Mutable(index); -} -inline ::safex::Block* Blocks::add_block() { - // @@protoc_insertion_point(field_add:safex.Blocks.block) - return block_.Add(); -} -inline ::google::protobuf::RepeatedPtrField< ::safex::Block >* -Blocks::mutable_block() { - // @@protoc_insertion_point(field_mutable_list:safex.Blocks.block) - return &block_; -} -inline const ::google::protobuf::RepeatedPtrField< ::safex::Block >& -Blocks::block() const { - // @@protoc_insertion_point(field_list:safex.Blocks.block) - return block_; -} - -// optional bool status = 2; -inline void Blocks::clear_status() { - status_ = false; -} -inline bool Blocks::status() const { - // @@protoc_insertion_point(field_get:safex.Blocks.status) - return status_; -} -inline void Blocks::set_status(bool value) { - - status_ = value; - // @@protoc_insertion_point(field_set:safex.Blocks.status) -} - -// optional bool untrusted = 3; -inline void Blocks::clear_untrusted() { - untrusted_ = false; -} -inline bool Blocks::untrusted() const { - // @@protoc_insertion_point(field_get:safex.Blocks.untrusted) - return untrusted_; -} -inline void Blocks::set_untrusted(bool value) { - - untrusted_ = value; - // @@protoc_insertion_point(field_set:safex.Blocks.untrusted) -} - -// optional string error = 4; -inline void Blocks::clear_error() { - error_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& Blocks::error() const { - // @@protoc_insertion_point(field_get:safex.Blocks.error) - return error_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Blocks::set_error(const ::std::string& value) { - - error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Blocks.error) -} -inline void Blocks::set_error(const char* value) { - - error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Blocks.error) -} -inline void Blocks::set_error(const char* value, size_t size) { - - error_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Blocks.error) -} -inline ::std::string* Blocks::mutable_error() { - - // @@protoc_insertion_point(field_mutable:safex.Blocks.error) - return error_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* Blocks::release_error() { - // @@protoc_insertion_point(field_release:safex.Blocks.error) - - return error_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Blocks::set_allocated_error(::std::string* error) { - if (error != NULL) { - - } else { - - } - error_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), error); - // @@protoc_insertion_point(field_set_allocated:safex.Blocks.error) -} - -#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - - -// @@protoc_insertion_point(namespace_scope) - -} // namespace safex - -// @@protoc_insertion_point(global_scope) - -#endif // PROTOBUF_blocks_2eproto__INCLUDED diff --git a/src/cryptonote_core/protobuf/get_outs.pb.cc b/src/cryptonote_core/protobuf/get_outs.pb.cc deleted file mode 100644 index cb9504129..000000000 --- a/src/cryptonote_core/protobuf/get_outs.pb.cc +++ /dev/null @@ -1,954 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: get_outs.proto - -#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "get_outs.pb.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -// @@protoc_insertion_point(includes) - -namespace safex { - -namespace { - -const ::google::protobuf::Descriptor* Out_entry_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Out_entry_reflection_ = NULL; -const ::google::protobuf::Descriptor* Outs_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Outs_reflection_ = NULL; - -} // namespace - - -void protobuf_AssignDesc_get_5fouts_2eproto() GOOGLE_ATTRIBUTE_COLD; -void protobuf_AssignDesc_get_5fouts_2eproto() { - protobuf_AddDesc_get_5fouts_2eproto(); - const ::google::protobuf::FileDescriptor* file = - ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName( - "get_outs.proto"); - GOOGLE_CHECK(file != NULL); - Out_entry_descriptor_ = file->message_type(0); - static const int Out_entry_offsets_[4] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Out_entry, key_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Out_entry, unlocked_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Out_entry, height_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Out_entry, txid_), - }; - Out_entry_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - Out_entry_descriptor_, - Out_entry::default_instance_, - Out_entry_offsets_, - -1, - -1, - -1, - sizeof(Out_entry), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Out_entry, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Out_entry, _is_default_instance_)); - Outs_descriptor_ = file->message_type(1); - static const int Outs_offsets_[2] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Outs, outs_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Outs, status_), - }; - Outs_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - Outs_descriptor_, - Outs::default_instance_, - Outs_offsets_, - -1, - -1, - -1, - sizeof(Outs), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Outs, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Outs, _is_default_instance_)); -} - -namespace { - -GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_); -inline void protobuf_AssignDescriptorsOnce() { - ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_, - &protobuf_AssignDesc_get_5fouts_2eproto); -} - -void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD; -void protobuf_RegisterTypes(const ::std::string&) { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Out_entry_descriptor_, &Out_entry::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Outs_descriptor_, &Outs::default_instance()); -} - -} // namespace - -void protobuf_ShutdownFile_get_5fouts_2eproto() { - delete Out_entry::default_instance_; - delete Out_entry_reflection_; - delete Outs::default_instance_; - delete Outs_reflection_; -} - -void protobuf_AddDesc_get_5fouts_2eproto() GOOGLE_ATTRIBUTE_COLD; -void protobuf_AddDesc_get_5fouts_2eproto() { - static bool already_here = false; - if (already_here) return; - already_here = true; - GOOGLE_PROTOBUF_VERIFY_VERSION; - - ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( - "\n\016get_outs.proto\022\005safex\"H\n\tOut_entry\022\013\n\003" - "key\030\001 \001(\014\022\020\n\010unlocked\030\002 \001(\010\022\016\n\006height\030\003 " - "\001(\004\022\014\n\004txid\030\004 \001(\014\"6\n\004Outs\022\036\n\004outs\030\001 \003(\0132" - "\020.safex.Out_entry\022\016\n\006status\030\002 \001(\tb\006proto" - "3", 161); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( - "get_outs.proto", &protobuf_RegisterTypes); - Out_entry::default_instance_ = new Out_entry(); - Outs::default_instance_ = new Outs(); - Out_entry::default_instance_->InitAsDefaultInstance(); - Outs::default_instance_->InitAsDefaultInstance(); - ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_get_5fouts_2eproto); -} - -// Force AddDescriptors() to be called at static initialization time. -struct StaticDescriptorInitializer_get_5fouts_2eproto { - StaticDescriptorInitializer_get_5fouts_2eproto() { - protobuf_AddDesc_get_5fouts_2eproto(); - } -} static_descriptor_initializer_get_5fouts_2eproto_; - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int Out_entry::kKeyFieldNumber; -const int Out_entry::kUnlockedFieldNumber; -const int Out_entry::kHeightFieldNumber; -const int Out_entry::kTxidFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -Out_entry::Out_entry() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.Out_entry) -} - -void Out_entry::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -Out_entry::Out_entry(const Out_entry& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.Out_entry) -} - -void Out_entry::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - key_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - unlocked_ = false; - height_ = GOOGLE_ULONGLONG(0); - txid_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -Out_entry::~Out_entry() { - // @@protoc_insertion_point(destructor:safex.Out_entry) - SharedDtor(); -} - -void Out_entry::SharedDtor() { - key_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - txid_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void Out_entry::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Out_entry::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Out_entry_descriptor_; -} - -const Out_entry& Out_entry::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_get_5fouts_2eproto(); - return *default_instance_; -} - -Out_entry* Out_entry::default_instance_ = NULL; - -Out_entry* Out_entry::New(::google::protobuf::Arena* arena) const { - Out_entry* n = new Out_entry; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void Out_entry::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.Out_entry) - key_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - unlocked_ = false; - height_ = GOOGLE_ULONGLONG(0); - txid_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -bool Out_entry::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.Out_entry) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional bytes key = 1; - case 1: { - if (tag == 10) { - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_key())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(16)) goto parse_unlocked; - break; - } - - // optional bool unlocked = 2; - case 2: { - if (tag == 16) { - parse_unlocked: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - input, &unlocked_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(24)) goto parse_height; - break; - } - - // optional uint64 height = 3; - case 3: { - if (tag == 24) { - parse_height: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &height_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(34)) goto parse_txid; - break; - } - - // optional bytes txid = 4; - case 4: { - if (tag == 34) { - parse_txid: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_txid())); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.Out_entry) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.Out_entry) - return false; -#undef DO_ -} - -void Out_entry::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.Out_entry) - // optional bytes key = 1; - if (this->key().size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 1, this->key(), output); - } - - // optional bool unlocked = 2; - if (this->unlocked() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteBool(2, this->unlocked(), output); - } - - // optional uint64 height = 3; - if (this->height() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(3, this->height(), output); - } - - // optional bytes txid = 4; - if (this->txid().size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 4, this->txid(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.Out_entry) -} - -::google::protobuf::uint8* Out_entry::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.Out_entry) - // optional bytes key = 1; - if (this->key().size() > 0) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 1, this->key(), target); - } - - // optional bool unlocked = 2; - if (this->unlocked() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(2, this->unlocked(), target); - } - - // optional uint64 height = 3; - if (this->height() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(3, this->height(), target); - } - - // optional bytes txid = 4; - if (this->txid().size() > 0) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 4, this->txid(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.Out_entry) - return target; -} - -int Out_entry::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.Out_entry) - int total_size = 0; - - // optional bytes key = 1; - if (this->key().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->key()); - } - - // optional bool unlocked = 2; - if (this->unlocked() != 0) { - total_size += 1 + 1; - } - - // optional uint64 height = 3; - if (this->height() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->height()); - } - - // optional bytes txid = 4; - if (this->txid().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->txid()); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Out_entry::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.Out_entry) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const Out_entry* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.Out_entry) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.Out_entry) - MergeFrom(*source); - } -} - -void Out_entry::MergeFrom(const Out_entry& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.Out_entry) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - if (from.key().size() > 0) { - - key_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.key_); - } - if (from.unlocked() != 0) { - set_unlocked(from.unlocked()); - } - if (from.height() != 0) { - set_height(from.height()); - } - if (from.txid().size() > 0) { - - txid_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.txid_); - } -} - -void Out_entry::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.Out_entry) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Out_entry::CopyFrom(const Out_entry& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.Out_entry) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Out_entry::IsInitialized() const { - - return true; -} - -void Out_entry::Swap(Out_entry* other) { - if (other == this) return; - InternalSwap(other); -} -void Out_entry::InternalSwap(Out_entry* other) { - key_.Swap(&other->key_); - std::swap(unlocked_, other->unlocked_); - std::swap(height_, other->height_); - txid_.Swap(&other->txid_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata Out_entry::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Out_entry_descriptor_; - metadata.reflection = Out_entry_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// Out_entry - -// optional bytes key = 1; -void Out_entry::clear_key() { - key_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& Out_entry::key() const { - // @@protoc_insertion_point(field_get:safex.Out_entry.key) - return key_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Out_entry::set_key(const ::std::string& value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Out_entry.key) -} - void Out_entry::set_key(const char* value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Out_entry.key) -} - void Out_entry::set_key(const void* value, size_t size) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Out_entry.key) -} - ::std::string* Out_entry::mutable_key() { - - // @@protoc_insertion_point(field_mutable:safex.Out_entry.key) - return key_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* Out_entry::release_key() { - // @@protoc_insertion_point(field_release:safex.Out_entry.key) - - return key_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Out_entry::set_allocated_key(::std::string* key) { - if (key != NULL) { - - } else { - - } - key_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), key); - // @@protoc_insertion_point(field_set_allocated:safex.Out_entry.key) -} - -// optional bool unlocked = 2; -void Out_entry::clear_unlocked() { - unlocked_ = false; -} - bool Out_entry::unlocked() const { - // @@protoc_insertion_point(field_get:safex.Out_entry.unlocked) - return unlocked_; -} - void Out_entry::set_unlocked(bool value) { - - unlocked_ = value; - // @@protoc_insertion_point(field_set:safex.Out_entry.unlocked) -} - -// optional uint64 height = 3; -void Out_entry::clear_height() { - height_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 Out_entry::height() const { - // @@protoc_insertion_point(field_get:safex.Out_entry.height) - return height_; -} - void Out_entry::set_height(::google::protobuf::uint64 value) { - - height_ = value; - // @@protoc_insertion_point(field_set:safex.Out_entry.height) -} - -// optional bytes txid = 4; -void Out_entry::clear_txid() { - txid_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& Out_entry::txid() const { - // @@protoc_insertion_point(field_get:safex.Out_entry.txid) - return txid_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Out_entry::set_txid(const ::std::string& value) { - - txid_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Out_entry.txid) -} - void Out_entry::set_txid(const char* value) { - - txid_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Out_entry.txid) -} - void Out_entry::set_txid(const void* value, size_t size) { - - txid_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Out_entry.txid) -} - ::std::string* Out_entry::mutable_txid() { - - // @@protoc_insertion_point(field_mutable:safex.Out_entry.txid) - return txid_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* Out_entry::release_txid() { - // @@protoc_insertion_point(field_release:safex.Out_entry.txid) - - return txid_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Out_entry::set_allocated_txid(::std::string* txid) { - if (txid != NULL) { - - } else { - - } - txid_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), txid); - // @@protoc_insertion_point(field_set_allocated:safex.Out_entry.txid) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int Outs::kOutsFieldNumber; -const int Outs::kStatusFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -Outs::Outs() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.Outs) -} - -void Outs::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -Outs::Outs(const Outs& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.Outs) -} - -void Outs::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - status_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -Outs::~Outs() { - // @@protoc_insertion_point(destructor:safex.Outs) - SharedDtor(); -} - -void Outs::SharedDtor() { - status_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void Outs::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Outs::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Outs_descriptor_; -} - -const Outs& Outs::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_get_5fouts_2eproto(); - return *default_instance_; -} - -Outs* Outs::default_instance_ = NULL; - -Outs* Outs::New(::google::protobuf::Arena* arena) const { - Outs* n = new Outs; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void Outs::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.Outs) - status_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - outs_.Clear(); -} - -bool Outs::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.Outs) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // repeated .safex.Out_entry outs = 1; - case 1: { - if (tag == 10) { - DO_(input->IncrementRecursionDepth()); - parse_loop_outs: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( - input, add_outs())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(10)) goto parse_loop_outs; - input->UnsafeDecrementRecursionDepth(); - if (input->ExpectTag(18)) goto parse_status; - break; - } - - // optional string status = 2; - case 2: { - if (tag == 18) { - parse_status: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_status())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->status().data(), this->status().length(), - ::google::protobuf::internal::WireFormatLite::PARSE, - "safex.Outs.status")); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.Outs) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.Outs) - return false; -#undef DO_ -} - -void Outs::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.Outs) - // repeated .safex.Out_entry outs = 1; - for (unsigned int i = 0, n = this->outs_size(); i < n; i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 1, this->outs(i), output); - } - - // optional string status = 2; - if (this->status().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->status().data(), this->status().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Outs.status"); - ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( - 2, this->status(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.Outs) -} - -::google::protobuf::uint8* Outs::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.Outs) - // repeated .safex.Out_entry outs = 1; - for (unsigned int i = 0, n = this->outs_size(); i < n; i++) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 1, this->outs(i), false, target); - } - - // optional string status = 2; - if (this->status().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->status().data(), this->status().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Outs.status"); - target = - ::google::protobuf::internal::WireFormatLite::WriteStringToArray( - 2, this->status(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.Outs) - return target; -} - -int Outs::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.Outs) - int total_size = 0; - - // optional string status = 2; - if (this->status().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->status()); - } - - // repeated .safex.Out_entry outs = 1; - total_size += 1 * this->outs_size(); - for (int i = 0; i < this->outs_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->outs(i)); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Outs::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.Outs) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const Outs* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.Outs) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.Outs) - MergeFrom(*source); - } -} - -void Outs::MergeFrom(const Outs& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.Outs) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - outs_.MergeFrom(from.outs_); - if (from.status().size() > 0) { - - status_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.status_); - } -} - -void Outs::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.Outs) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Outs::CopyFrom(const Outs& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.Outs) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Outs::IsInitialized() const { - - return true; -} - -void Outs::Swap(Outs* other) { - if (other == this) return; - InternalSwap(other); -} -void Outs::InternalSwap(Outs* other) { - outs_.UnsafeArenaSwap(&other->outs_); - status_.Swap(&other->status_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata Outs::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Outs_descriptor_; - metadata.reflection = Outs_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// Outs - -// repeated .safex.Out_entry outs = 1; -int Outs::outs_size() const { - return outs_.size(); -} -void Outs::clear_outs() { - outs_.Clear(); -} -const ::safex::Out_entry& Outs::outs(int index) const { - // @@protoc_insertion_point(field_get:safex.Outs.outs) - return outs_.Get(index); -} -::safex::Out_entry* Outs::mutable_outs(int index) { - // @@protoc_insertion_point(field_mutable:safex.Outs.outs) - return outs_.Mutable(index); -} -::safex::Out_entry* Outs::add_outs() { - // @@protoc_insertion_point(field_add:safex.Outs.outs) - return outs_.Add(); -} -::google::protobuf::RepeatedPtrField< ::safex::Out_entry >* -Outs::mutable_outs() { - // @@protoc_insertion_point(field_mutable_list:safex.Outs.outs) - return &outs_; -} -const ::google::protobuf::RepeatedPtrField< ::safex::Out_entry >& -Outs::outs() const { - // @@protoc_insertion_point(field_list:safex.Outs.outs) - return outs_; -} - -// optional string status = 2; -void Outs::clear_status() { - status_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& Outs::status() const { - // @@protoc_insertion_point(field_get:safex.Outs.status) - return status_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Outs::set_status(const ::std::string& value) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Outs.status) -} - void Outs::set_status(const char* value) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Outs.status) -} - void Outs::set_status(const char* value, size_t size) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Outs.status) -} - ::std::string* Outs::mutable_status() { - - // @@protoc_insertion_point(field_mutable:safex.Outs.status) - return status_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* Outs::release_status() { - // @@protoc_insertion_point(field_release:safex.Outs.status) - - return status_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Outs::set_allocated_status(::std::string* status) { - if (status != NULL) { - - } else { - - } - status_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), status); - // @@protoc_insertion_point(field_set_allocated:safex.Outs.status) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// @@protoc_insertion_point(namespace_scope) - -} // namespace safex - -// @@protoc_insertion_point(global_scope) diff --git a/src/cryptonote_core/protobuf/get_outs.pb.h b/src/cryptonote_core/protobuf/get_outs.pb.h deleted file mode 100644 index 8c040efad..000000000 --- a/src/cryptonote_core/protobuf/get_outs.pb.h +++ /dev/null @@ -1,467 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: get_outs.proto - -#ifndef PROTOBUF_get_5fouts_2eproto__INCLUDED -#define PROTOBUF_get_5fouts_2eproto__INCLUDED - -#include - -#include - -#if GOOGLE_PROTOBUF_VERSION < 3000000 -#error This file was generated by a newer version of protoc which is -#error incompatible with your Protocol Buffer headers. Please update -#error your headers. -#endif -#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION -#error This file was generated by an older version of protoc which is -#error incompatible with your Protocol Buffer headers. Please -#error regenerate this file with a newer version of protoc. -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -// @@protoc_insertion_point(includes) - -namespace safex { - -// Internal implementation detail -- do not call these. -void protobuf_AddDesc_get_5fouts_2eproto(); -void protobuf_AssignDesc_get_5fouts_2eproto(); -void protobuf_ShutdownFile_get_5fouts_2eproto(); - -class Out_entry; -class Outs; - -// =================================================================== - -class Out_entry : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.Out_entry) */ { - public: - Out_entry(); - virtual ~Out_entry(); - - Out_entry(const Out_entry& from); - - inline Out_entry& operator=(const Out_entry& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Out_entry& default_instance(); - - void Swap(Out_entry* other); - - // implements Message ---------------------------------------------- - - inline Out_entry* New() const { return New(NULL); } - - Out_entry* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Out_entry& from); - void MergeFrom(const Out_entry& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(Out_entry* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional bytes key = 1; - void clear_key(); - static const int kKeyFieldNumber = 1; - const ::std::string& key() const; - void set_key(const ::std::string& value); - void set_key(const char* value); - void set_key(const void* value, size_t size); - ::std::string* mutable_key(); - ::std::string* release_key(); - void set_allocated_key(::std::string* key); - - // optional bool unlocked = 2; - void clear_unlocked(); - static const int kUnlockedFieldNumber = 2; - bool unlocked() const; - void set_unlocked(bool value); - - // optional uint64 height = 3; - void clear_height(); - static const int kHeightFieldNumber = 3; - ::google::protobuf::uint64 height() const; - void set_height(::google::protobuf::uint64 value); - - // optional bytes txid = 4; - void clear_txid(); - static const int kTxidFieldNumber = 4; - const ::std::string& txid() const; - void set_txid(const ::std::string& value); - void set_txid(const char* value); - void set_txid(const void* value, size_t size); - ::std::string* mutable_txid(); - ::std::string* release_txid(); - void set_allocated_txid(::std::string* txid); - - // @@protoc_insertion_point(class_scope:safex.Out_entry) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::internal::ArenaStringPtr key_; - ::google::protobuf::uint64 height_; - ::google::protobuf::internal::ArenaStringPtr txid_; - bool unlocked_; - mutable int _cached_size_; - friend void protobuf_AddDesc_get_5fouts_2eproto(); - friend void protobuf_AssignDesc_get_5fouts_2eproto(); - friend void protobuf_ShutdownFile_get_5fouts_2eproto(); - - void InitAsDefaultInstance(); - static Out_entry* default_instance_; -}; -// ------------------------------------------------------------------- - -class Outs : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.Outs) */ { - public: - Outs(); - virtual ~Outs(); - - Outs(const Outs& from); - - inline Outs& operator=(const Outs& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Outs& default_instance(); - - void Swap(Outs* other); - - // implements Message ---------------------------------------------- - - inline Outs* New() const { return New(NULL); } - - Outs* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Outs& from); - void MergeFrom(const Outs& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(Outs* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // repeated .safex.Out_entry outs = 1; - int outs_size() const; - void clear_outs(); - static const int kOutsFieldNumber = 1; - const ::safex::Out_entry& outs(int index) const; - ::safex::Out_entry* mutable_outs(int index); - ::safex::Out_entry* add_outs(); - ::google::protobuf::RepeatedPtrField< ::safex::Out_entry >* - mutable_outs(); - const ::google::protobuf::RepeatedPtrField< ::safex::Out_entry >& - outs() const; - - // optional string status = 2; - void clear_status(); - static const int kStatusFieldNumber = 2; - const ::std::string& status() const; - void set_status(const ::std::string& value); - void set_status(const char* value); - void set_status(const char* value, size_t size); - ::std::string* mutable_status(); - ::std::string* release_status(); - void set_allocated_status(::std::string* status); - - // @@protoc_insertion_point(class_scope:safex.Outs) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::RepeatedPtrField< ::safex::Out_entry > outs_; - ::google::protobuf::internal::ArenaStringPtr status_; - mutable int _cached_size_; - friend void protobuf_AddDesc_get_5fouts_2eproto(); - friend void protobuf_AssignDesc_get_5fouts_2eproto(); - friend void protobuf_ShutdownFile_get_5fouts_2eproto(); - - void InitAsDefaultInstance(); - static Outs* default_instance_; -}; -// =================================================================== - - -// =================================================================== - -#if !PROTOBUF_INLINE_NOT_IN_HEADERS -// Out_entry - -// optional bytes key = 1; -inline void Out_entry::clear_key() { - key_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& Out_entry::key() const { - // @@protoc_insertion_point(field_get:safex.Out_entry.key) - return key_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Out_entry::set_key(const ::std::string& value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Out_entry.key) -} -inline void Out_entry::set_key(const char* value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Out_entry.key) -} -inline void Out_entry::set_key(const void* value, size_t size) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Out_entry.key) -} -inline ::std::string* Out_entry::mutable_key() { - - // @@protoc_insertion_point(field_mutable:safex.Out_entry.key) - return key_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* Out_entry::release_key() { - // @@protoc_insertion_point(field_release:safex.Out_entry.key) - - return key_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Out_entry::set_allocated_key(::std::string* key) { - if (key != NULL) { - - } else { - - } - key_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), key); - // @@protoc_insertion_point(field_set_allocated:safex.Out_entry.key) -} - -// optional bool unlocked = 2; -inline void Out_entry::clear_unlocked() { - unlocked_ = false; -} -inline bool Out_entry::unlocked() const { - // @@protoc_insertion_point(field_get:safex.Out_entry.unlocked) - return unlocked_; -} -inline void Out_entry::set_unlocked(bool value) { - - unlocked_ = value; - // @@protoc_insertion_point(field_set:safex.Out_entry.unlocked) -} - -// optional uint64 height = 3; -inline void Out_entry::clear_height() { - height_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 Out_entry::height() const { - // @@protoc_insertion_point(field_get:safex.Out_entry.height) - return height_; -} -inline void Out_entry::set_height(::google::protobuf::uint64 value) { - - height_ = value; - // @@protoc_insertion_point(field_set:safex.Out_entry.height) -} - -// optional bytes txid = 4; -inline void Out_entry::clear_txid() { - txid_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& Out_entry::txid() const { - // @@protoc_insertion_point(field_get:safex.Out_entry.txid) - return txid_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Out_entry::set_txid(const ::std::string& value) { - - txid_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Out_entry.txid) -} -inline void Out_entry::set_txid(const char* value) { - - txid_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Out_entry.txid) -} -inline void Out_entry::set_txid(const void* value, size_t size) { - - txid_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Out_entry.txid) -} -inline ::std::string* Out_entry::mutable_txid() { - - // @@protoc_insertion_point(field_mutable:safex.Out_entry.txid) - return txid_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* Out_entry::release_txid() { - // @@protoc_insertion_point(field_release:safex.Out_entry.txid) - - return txid_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Out_entry::set_allocated_txid(::std::string* txid) { - if (txid != NULL) { - - } else { - - } - txid_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), txid); - // @@protoc_insertion_point(field_set_allocated:safex.Out_entry.txid) -} - -// ------------------------------------------------------------------- - -// Outs - -// repeated .safex.Out_entry outs = 1; -inline int Outs::outs_size() const { - return outs_.size(); -} -inline void Outs::clear_outs() { - outs_.Clear(); -} -inline const ::safex::Out_entry& Outs::outs(int index) const { - // @@protoc_insertion_point(field_get:safex.Outs.outs) - return outs_.Get(index); -} -inline ::safex::Out_entry* Outs::mutable_outs(int index) { - // @@protoc_insertion_point(field_mutable:safex.Outs.outs) - return outs_.Mutable(index); -} -inline ::safex::Out_entry* Outs::add_outs() { - // @@protoc_insertion_point(field_add:safex.Outs.outs) - return outs_.Add(); -} -inline ::google::protobuf::RepeatedPtrField< ::safex::Out_entry >* -Outs::mutable_outs() { - // @@protoc_insertion_point(field_mutable_list:safex.Outs.outs) - return &outs_; -} -inline const ::google::protobuf::RepeatedPtrField< ::safex::Out_entry >& -Outs::outs() const { - // @@protoc_insertion_point(field_list:safex.Outs.outs) - return outs_; -} - -// optional string status = 2; -inline void Outs::clear_status() { - status_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& Outs::status() const { - // @@protoc_insertion_point(field_get:safex.Outs.status) - return status_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Outs::set_status(const ::std::string& value) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Outs.status) -} -inline void Outs::set_status(const char* value) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Outs.status) -} -inline void Outs::set_status(const char* value, size_t size) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Outs.status) -} -inline ::std::string* Outs::mutable_status() { - - // @@protoc_insertion_point(field_mutable:safex.Outs.status) - return status_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* Outs::release_status() { - // @@protoc_insertion_point(field_release:safex.Outs.status) - - return status_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Outs::set_allocated_status(::std::string* status) { - if (status != NULL) { - - } else { - - } - status_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), status); - // @@protoc_insertion_point(field_set_allocated:safex.Outs.status) -} - -#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS -// ------------------------------------------------------------------- - - -// @@protoc_insertion_point(namespace_scope) - -} // namespace safex - -// @@protoc_insertion_point(global_scope) - -#endif // PROTOBUF_get_5fouts_2eproto__INCLUDED diff --git a/src/cryptonote_core/protobuf/output_histogram.pb.cc b/src/cryptonote_core/protobuf/output_histogram.pb.cc deleted file mode 100644 index 100a1f61c..000000000 --- a/src/cryptonote_core/protobuf/output_histogram.pb.cc +++ /dev/null @@ -1,960 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: output_histogram.proto - -#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "output_histogram.pb.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -// @@protoc_insertion_point(includes) - -namespace safex { - -namespace { - -const ::google::protobuf::Descriptor* Histogram_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Histogram_reflection_ = NULL; -const ::google::protobuf::Descriptor* Histograms_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Histograms_reflection_ = NULL; - -} // namespace - - -void protobuf_AssignDesc_output_5fhistogram_2eproto() GOOGLE_ATTRIBUTE_COLD; -void protobuf_AssignDesc_output_5fhistogram_2eproto() { - protobuf_AddDesc_output_5fhistogram_2eproto(); - const ::google::protobuf::FileDescriptor* file = - ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName( - "output_histogram.proto"); - GOOGLE_CHECK(file != NULL); - Histogram_descriptor_ = file->message_type(0); - static const int Histogram_offsets_[5] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Histogram, amount_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Histogram, out_type_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Histogram, recent_instances_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Histogram, total_instances_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Histogram, unlocked_instances_), - }; - Histogram_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - Histogram_descriptor_, - Histogram::default_instance_, - Histogram_offsets_, - -1, - -1, - -1, - sizeof(Histogram), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Histogram, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Histogram, _is_default_instance_)); - Histograms_descriptor_ = file->message_type(1); - static const int Histograms_offsets_[2] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Histograms, histograms_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Histograms, status_), - }; - Histograms_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - Histograms_descriptor_, - Histograms::default_instance_, - Histograms_offsets_, - -1, - -1, - -1, - sizeof(Histograms), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Histograms, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Histograms, _is_default_instance_)); -} - -namespace { - -GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_); -inline void protobuf_AssignDescriptorsOnce() { - ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_, - &protobuf_AssignDesc_output_5fhistogram_2eproto); -} - -void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD; -void protobuf_RegisterTypes(const ::std::string&) { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Histogram_descriptor_, &Histogram::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Histograms_descriptor_, &Histograms::default_instance()); -} - -} // namespace - -void protobuf_ShutdownFile_output_5fhistogram_2eproto() { - delete Histogram::default_instance_; - delete Histogram_reflection_; - delete Histograms::default_instance_; - delete Histograms_reflection_; -} - -void protobuf_AddDesc_output_5fhistogram_2eproto() GOOGLE_ATTRIBUTE_COLD; -void protobuf_AddDesc_output_5fhistogram_2eproto() { - static bool already_here = false; - if (already_here) return; - already_here = true; - GOOGLE_PROTOBUF_VERIFY_VERSION; - - ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( - "\n\026output_histogram.proto\022\005safex\"|\n\tHisto" - "gram\022\016\n\006amount\030\001 \001(\004\022\020\n\010out_type\030\002 \001(\004\022\030" - "\n\020recent_instances\030\003 \001(\004\022\027\n\017total_instan" - "ces\030\004 \001(\004\022\032\n\022unlocked_instances\030\005 \001(\004\"B\n" - "\nHistograms\022$\n\nhistograms\030\001 \003(\0132\020.safex." - "Histogram\022\016\n\006status\030\002 \001(\tb\006proto3", 233); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( - "output_histogram.proto", &protobuf_RegisterTypes); - Histogram::default_instance_ = new Histogram(); - Histograms::default_instance_ = new Histograms(); - Histogram::default_instance_->InitAsDefaultInstance(); - Histograms::default_instance_->InitAsDefaultInstance(); - ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_output_5fhistogram_2eproto); -} - -// Force AddDescriptors() to be called at static initialization time. -struct StaticDescriptorInitializer_output_5fhistogram_2eproto { - StaticDescriptorInitializer_output_5fhistogram_2eproto() { - protobuf_AddDesc_output_5fhistogram_2eproto(); - } -} static_descriptor_initializer_output_5fhistogram_2eproto_; - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int Histogram::kAmountFieldNumber; -const int Histogram::kOutTypeFieldNumber; -const int Histogram::kRecentInstancesFieldNumber; -const int Histogram::kTotalInstancesFieldNumber; -const int Histogram::kUnlockedInstancesFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -Histogram::Histogram() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.Histogram) -} - -void Histogram::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -Histogram::Histogram(const Histogram& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.Histogram) -} - -void Histogram::SharedCtor() { - _is_default_instance_ = false; - _cached_size_ = 0; - amount_ = GOOGLE_ULONGLONG(0); - out_type_ = GOOGLE_ULONGLONG(0); - recent_instances_ = GOOGLE_ULONGLONG(0); - total_instances_ = GOOGLE_ULONGLONG(0); - unlocked_instances_ = GOOGLE_ULONGLONG(0); -} - -Histogram::~Histogram() { - // @@protoc_insertion_point(destructor:safex.Histogram) - SharedDtor(); -} - -void Histogram::SharedDtor() { - if (this != default_instance_) { - } -} - -void Histogram::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Histogram::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Histogram_descriptor_; -} - -const Histogram& Histogram::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_output_5fhistogram_2eproto(); - return *default_instance_; -} - -Histogram* Histogram::default_instance_ = NULL; - -Histogram* Histogram::New(::google::protobuf::Arena* arena) const { - Histogram* n = new Histogram; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void Histogram::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.Histogram) -#if defined(__clang__) -#define ZR_HELPER_(f) \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ - __builtin_offsetof(Histogram, f) \ - _Pragma("clang diagnostic pop") -#else -#define ZR_HELPER_(f) reinterpret_cast(\ - &reinterpret_cast(16)->f) -#endif - -#define ZR_(first, last) do {\ - ::memset(&first, 0,\ - ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ -} while (0) - - ZR_(amount_, unlocked_instances_); - -#undef ZR_HELPER_ -#undef ZR_ - -} - -bool Histogram::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.Histogram) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 amount = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &amount_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(16)) goto parse_out_type; - break; - } - - // optional uint64 out_type = 2; - case 2: { - if (tag == 16) { - parse_out_type: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &out_type_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(24)) goto parse_recent_instances; - break; - } - - // optional uint64 recent_instances = 3; - case 3: { - if (tag == 24) { - parse_recent_instances: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &recent_instances_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(32)) goto parse_total_instances; - break; - } - - // optional uint64 total_instances = 4; - case 4: { - if (tag == 32) { - parse_total_instances: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &total_instances_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(40)) goto parse_unlocked_instances; - break; - } - - // optional uint64 unlocked_instances = 5; - case 5: { - if (tag == 40) { - parse_unlocked_instances: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &unlocked_instances_))); - - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.Histogram) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.Histogram) - return false; -#undef DO_ -} - -void Histogram::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.Histogram) - // optional uint64 amount = 1; - if (this->amount() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->amount(), output); - } - - // optional uint64 out_type = 2; - if (this->out_type() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(2, this->out_type(), output); - } - - // optional uint64 recent_instances = 3; - if (this->recent_instances() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(3, this->recent_instances(), output); - } - - // optional uint64 total_instances = 4; - if (this->total_instances() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(4, this->total_instances(), output); - } - - // optional uint64 unlocked_instances = 5; - if (this->unlocked_instances() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(5, this->unlocked_instances(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.Histogram) -} - -::google::protobuf::uint8* Histogram::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.Histogram) - // optional uint64 amount = 1; - if (this->amount() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->amount(), target); - } - - // optional uint64 out_type = 2; - if (this->out_type() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(2, this->out_type(), target); - } - - // optional uint64 recent_instances = 3; - if (this->recent_instances() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(3, this->recent_instances(), target); - } - - // optional uint64 total_instances = 4; - if (this->total_instances() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(4, this->total_instances(), target); - } - - // optional uint64 unlocked_instances = 5; - if (this->unlocked_instances() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(5, this->unlocked_instances(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.Histogram) - return target; -} - -int Histogram::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.Histogram) - int total_size = 0; - - // optional uint64 amount = 1; - if (this->amount() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->amount()); - } - - // optional uint64 out_type = 2; - if (this->out_type() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->out_type()); - } - - // optional uint64 recent_instances = 3; - if (this->recent_instances() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->recent_instances()); - } - - // optional uint64 total_instances = 4; - if (this->total_instances() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->total_instances()); - } - - // optional uint64 unlocked_instances = 5; - if (this->unlocked_instances() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->unlocked_instances()); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Histogram::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.Histogram) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const Histogram* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.Histogram) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.Histogram) - MergeFrom(*source); - } -} - -void Histogram::MergeFrom(const Histogram& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.Histogram) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - if (from.amount() != 0) { - set_amount(from.amount()); - } - if (from.out_type() != 0) { - set_out_type(from.out_type()); - } - if (from.recent_instances() != 0) { - set_recent_instances(from.recent_instances()); - } - if (from.total_instances() != 0) { - set_total_instances(from.total_instances()); - } - if (from.unlocked_instances() != 0) { - set_unlocked_instances(from.unlocked_instances()); - } -} - -void Histogram::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.Histogram) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Histogram::CopyFrom(const Histogram& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.Histogram) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Histogram::IsInitialized() const { - - return true; -} - -void Histogram::Swap(Histogram* other) { - if (other == this) return; - InternalSwap(other); -} -void Histogram::InternalSwap(Histogram* other) { - std::swap(amount_, other->amount_); - std::swap(out_type_, other->out_type_); - std::swap(recent_instances_, other->recent_instances_); - std::swap(total_instances_, other->total_instances_); - std::swap(unlocked_instances_, other->unlocked_instances_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata Histogram::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Histogram_descriptor_; - metadata.reflection = Histogram_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// Histogram - -// optional uint64 amount = 1; -void Histogram::clear_amount() { - amount_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 Histogram::amount() const { - // @@protoc_insertion_point(field_get:safex.Histogram.amount) - return amount_; -} - void Histogram::set_amount(::google::protobuf::uint64 value) { - - amount_ = value; - // @@protoc_insertion_point(field_set:safex.Histogram.amount) -} - -// optional uint64 out_type = 2; -void Histogram::clear_out_type() { - out_type_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 Histogram::out_type() const { - // @@protoc_insertion_point(field_get:safex.Histogram.out_type) - return out_type_; -} - void Histogram::set_out_type(::google::protobuf::uint64 value) { - - out_type_ = value; - // @@protoc_insertion_point(field_set:safex.Histogram.out_type) -} - -// optional uint64 recent_instances = 3; -void Histogram::clear_recent_instances() { - recent_instances_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 Histogram::recent_instances() const { - // @@protoc_insertion_point(field_get:safex.Histogram.recent_instances) - return recent_instances_; -} - void Histogram::set_recent_instances(::google::protobuf::uint64 value) { - - recent_instances_ = value; - // @@protoc_insertion_point(field_set:safex.Histogram.recent_instances) -} - -// optional uint64 total_instances = 4; -void Histogram::clear_total_instances() { - total_instances_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 Histogram::total_instances() const { - // @@protoc_insertion_point(field_get:safex.Histogram.total_instances) - return total_instances_; -} - void Histogram::set_total_instances(::google::protobuf::uint64 value) { - - total_instances_ = value; - // @@protoc_insertion_point(field_set:safex.Histogram.total_instances) -} - -// optional uint64 unlocked_instances = 5; -void Histogram::clear_unlocked_instances() { - unlocked_instances_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 Histogram::unlocked_instances() const { - // @@protoc_insertion_point(field_get:safex.Histogram.unlocked_instances) - return unlocked_instances_; -} - void Histogram::set_unlocked_instances(::google::protobuf::uint64 value) { - - unlocked_instances_ = value; - // @@protoc_insertion_point(field_set:safex.Histogram.unlocked_instances) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int Histograms::kHistogramsFieldNumber; -const int Histograms::kStatusFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -Histograms::Histograms() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.Histograms) -} - -void Histograms::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -Histograms::Histograms(const Histograms& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.Histograms) -} - -void Histograms::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - status_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -Histograms::~Histograms() { - // @@protoc_insertion_point(destructor:safex.Histograms) - SharedDtor(); -} - -void Histograms::SharedDtor() { - status_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void Histograms::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Histograms::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Histograms_descriptor_; -} - -const Histograms& Histograms::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_output_5fhistogram_2eproto(); - return *default_instance_; -} - -Histograms* Histograms::default_instance_ = NULL; - -Histograms* Histograms::New(::google::protobuf::Arena* arena) const { - Histograms* n = new Histograms; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void Histograms::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.Histograms) - status_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - histograms_.Clear(); -} - -bool Histograms::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.Histograms) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // repeated .safex.Histogram histograms = 1; - case 1: { - if (tag == 10) { - DO_(input->IncrementRecursionDepth()); - parse_loop_histograms: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( - input, add_histograms())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(10)) goto parse_loop_histograms; - input->UnsafeDecrementRecursionDepth(); - if (input->ExpectTag(18)) goto parse_status; - break; - } - - // optional string status = 2; - case 2: { - if (tag == 18) { - parse_status: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_status())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->status().data(), this->status().length(), - ::google::protobuf::internal::WireFormatLite::PARSE, - "safex.Histograms.status")); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.Histograms) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.Histograms) - return false; -#undef DO_ -} - -void Histograms::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.Histograms) - // repeated .safex.Histogram histograms = 1; - for (unsigned int i = 0, n = this->histograms_size(); i < n; i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 1, this->histograms(i), output); - } - - // optional string status = 2; - if (this->status().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->status().data(), this->status().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Histograms.status"); - ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( - 2, this->status(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.Histograms) -} - -::google::protobuf::uint8* Histograms::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.Histograms) - // repeated .safex.Histogram histograms = 1; - for (unsigned int i = 0, n = this->histograms_size(); i < n; i++) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 1, this->histograms(i), false, target); - } - - // optional string status = 2; - if (this->status().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->status().data(), this->status().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Histograms.status"); - target = - ::google::protobuf::internal::WireFormatLite::WriteStringToArray( - 2, this->status(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.Histograms) - return target; -} - -int Histograms::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.Histograms) - int total_size = 0; - - // optional string status = 2; - if (this->status().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->status()); - } - - // repeated .safex.Histogram histograms = 1; - total_size += 1 * this->histograms_size(); - for (int i = 0; i < this->histograms_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->histograms(i)); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Histograms::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.Histograms) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const Histograms* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.Histograms) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.Histograms) - MergeFrom(*source); - } -} - -void Histograms::MergeFrom(const Histograms& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.Histograms) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - histograms_.MergeFrom(from.histograms_); - if (from.status().size() > 0) { - - status_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.status_); - } -} - -void Histograms::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.Histograms) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Histograms::CopyFrom(const Histograms& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.Histograms) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Histograms::IsInitialized() const { - - return true; -} - -void Histograms::Swap(Histograms* other) { - if (other == this) return; - InternalSwap(other); -} -void Histograms::InternalSwap(Histograms* other) { - histograms_.UnsafeArenaSwap(&other->histograms_); - status_.Swap(&other->status_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata Histograms::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Histograms_descriptor_; - metadata.reflection = Histograms_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// Histograms - -// repeated .safex.Histogram histograms = 1; -int Histograms::histograms_size() const { - return histograms_.size(); -} -void Histograms::clear_histograms() { - histograms_.Clear(); -} -const ::safex::Histogram& Histograms::histograms(int index) const { - // @@protoc_insertion_point(field_get:safex.Histograms.histograms) - return histograms_.Get(index); -} -::safex::Histogram* Histograms::mutable_histograms(int index) { - // @@protoc_insertion_point(field_mutable:safex.Histograms.histograms) - return histograms_.Mutable(index); -} -::safex::Histogram* Histograms::add_histograms() { - // @@protoc_insertion_point(field_add:safex.Histograms.histograms) - return histograms_.Add(); -} -::google::protobuf::RepeatedPtrField< ::safex::Histogram >* -Histograms::mutable_histograms() { - // @@protoc_insertion_point(field_mutable_list:safex.Histograms.histograms) - return &histograms_; -} -const ::google::protobuf::RepeatedPtrField< ::safex::Histogram >& -Histograms::histograms() const { - // @@protoc_insertion_point(field_list:safex.Histograms.histograms) - return histograms_; -} - -// optional string status = 2; -void Histograms::clear_status() { - status_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& Histograms::status() const { - // @@protoc_insertion_point(field_get:safex.Histograms.status) - return status_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Histograms::set_status(const ::std::string& value) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Histograms.status) -} - void Histograms::set_status(const char* value) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Histograms.status) -} - void Histograms::set_status(const char* value, size_t size) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Histograms.status) -} - ::std::string* Histograms::mutable_status() { - - // @@protoc_insertion_point(field_mutable:safex.Histograms.status) - return status_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* Histograms::release_status() { - // @@protoc_insertion_point(field_release:safex.Histograms.status) - - return status_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Histograms::set_allocated_status(::std::string* status) { - if (status != NULL) { - - } else { - - } - status_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), status); - // @@protoc_insertion_point(field_set_allocated:safex.Histograms.status) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// @@protoc_insertion_point(namespace_scope) - -} // namespace safex - -// @@protoc_insertion_point(global_scope) diff --git a/src/cryptonote_core/protobuf/output_histogram.pb.h b/src/cryptonote_core/protobuf/output_histogram.pb.h deleted file mode 100644 index 0d48ec1f9..000000000 --- a/src/cryptonote_core/protobuf/output_histogram.pb.h +++ /dev/null @@ -1,418 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: output_histogram.proto - -#ifndef PROTOBUF_output_5fhistogram_2eproto__INCLUDED -#define PROTOBUF_output_5fhistogram_2eproto__INCLUDED - -#include - -#include - -#if GOOGLE_PROTOBUF_VERSION < 3000000 -#error This file was generated by a newer version of protoc which is -#error incompatible with your Protocol Buffer headers. Please update -#error your headers. -#endif -#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION -#error This file was generated by an older version of protoc which is -#error incompatible with your Protocol Buffer headers. Please -#error regenerate this file with a newer version of protoc. -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -// @@protoc_insertion_point(includes) - -namespace safex { - -// Internal implementation detail -- do not call these. -void protobuf_AddDesc_output_5fhistogram_2eproto(); -void protobuf_AssignDesc_output_5fhistogram_2eproto(); -void protobuf_ShutdownFile_output_5fhistogram_2eproto(); - -class Histogram; -class Histograms; - -// =================================================================== - -class Histogram : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.Histogram) */ { - public: - Histogram(); - virtual ~Histogram(); - - Histogram(const Histogram& from); - - inline Histogram& operator=(const Histogram& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Histogram& default_instance(); - - void Swap(Histogram* other); - - // implements Message ---------------------------------------------- - - inline Histogram* New() const { return New(NULL); } - - Histogram* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Histogram& from); - void MergeFrom(const Histogram& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(Histogram* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 amount = 1; - void clear_amount(); - static const int kAmountFieldNumber = 1; - ::google::protobuf::uint64 amount() const; - void set_amount(::google::protobuf::uint64 value); - - // optional uint64 out_type = 2; - void clear_out_type(); - static const int kOutTypeFieldNumber = 2; - ::google::protobuf::uint64 out_type() const; - void set_out_type(::google::protobuf::uint64 value); - - // optional uint64 recent_instances = 3; - void clear_recent_instances(); - static const int kRecentInstancesFieldNumber = 3; - ::google::protobuf::uint64 recent_instances() const; - void set_recent_instances(::google::protobuf::uint64 value); - - // optional uint64 total_instances = 4; - void clear_total_instances(); - static const int kTotalInstancesFieldNumber = 4; - ::google::protobuf::uint64 total_instances() const; - void set_total_instances(::google::protobuf::uint64 value); - - // optional uint64 unlocked_instances = 5; - void clear_unlocked_instances(); - static const int kUnlockedInstancesFieldNumber = 5; - ::google::protobuf::uint64 unlocked_instances() const; - void set_unlocked_instances(::google::protobuf::uint64 value); - - // @@protoc_insertion_point(class_scope:safex.Histogram) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::uint64 amount_; - ::google::protobuf::uint64 out_type_; - ::google::protobuf::uint64 recent_instances_; - ::google::protobuf::uint64 total_instances_; - ::google::protobuf::uint64 unlocked_instances_; - mutable int _cached_size_; - friend void protobuf_AddDesc_output_5fhistogram_2eproto(); - friend void protobuf_AssignDesc_output_5fhistogram_2eproto(); - friend void protobuf_ShutdownFile_output_5fhistogram_2eproto(); - - void InitAsDefaultInstance(); - static Histogram* default_instance_; -}; -// ------------------------------------------------------------------- - -class Histograms : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.Histograms) */ { - public: - Histograms(); - virtual ~Histograms(); - - Histograms(const Histograms& from); - - inline Histograms& operator=(const Histograms& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Histograms& default_instance(); - - void Swap(Histograms* other); - - // implements Message ---------------------------------------------- - - inline Histograms* New() const { return New(NULL); } - - Histograms* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Histograms& from); - void MergeFrom(const Histograms& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(Histograms* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // repeated .safex.Histogram histograms = 1; - int histograms_size() const; - void clear_histograms(); - static const int kHistogramsFieldNumber = 1; - const ::safex::Histogram& histograms(int index) const; - ::safex::Histogram* mutable_histograms(int index); - ::safex::Histogram* add_histograms(); - ::google::protobuf::RepeatedPtrField< ::safex::Histogram >* - mutable_histograms(); - const ::google::protobuf::RepeatedPtrField< ::safex::Histogram >& - histograms() const; - - // optional string status = 2; - void clear_status(); - static const int kStatusFieldNumber = 2; - const ::std::string& status() const; - void set_status(const ::std::string& value); - void set_status(const char* value); - void set_status(const char* value, size_t size); - ::std::string* mutable_status(); - ::std::string* release_status(); - void set_allocated_status(::std::string* status); - - // @@protoc_insertion_point(class_scope:safex.Histograms) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::RepeatedPtrField< ::safex::Histogram > histograms_; - ::google::protobuf::internal::ArenaStringPtr status_; - mutable int _cached_size_; - friend void protobuf_AddDesc_output_5fhistogram_2eproto(); - friend void protobuf_AssignDesc_output_5fhistogram_2eproto(); - friend void protobuf_ShutdownFile_output_5fhistogram_2eproto(); - - void InitAsDefaultInstance(); - static Histograms* default_instance_; -}; -// =================================================================== - - -// =================================================================== - -#if !PROTOBUF_INLINE_NOT_IN_HEADERS -// Histogram - -// optional uint64 amount = 1; -inline void Histogram::clear_amount() { - amount_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 Histogram::amount() const { - // @@protoc_insertion_point(field_get:safex.Histogram.amount) - return amount_; -} -inline void Histogram::set_amount(::google::protobuf::uint64 value) { - - amount_ = value; - // @@protoc_insertion_point(field_set:safex.Histogram.amount) -} - -// optional uint64 out_type = 2; -inline void Histogram::clear_out_type() { - out_type_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 Histogram::out_type() const { - // @@protoc_insertion_point(field_get:safex.Histogram.out_type) - return out_type_; -} -inline void Histogram::set_out_type(::google::protobuf::uint64 value) { - - out_type_ = value; - // @@protoc_insertion_point(field_set:safex.Histogram.out_type) -} - -// optional uint64 recent_instances = 3; -inline void Histogram::clear_recent_instances() { - recent_instances_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 Histogram::recent_instances() const { - // @@protoc_insertion_point(field_get:safex.Histogram.recent_instances) - return recent_instances_; -} -inline void Histogram::set_recent_instances(::google::protobuf::uint64 value) { - - recent_instances_ = value; - // @@protoc_insertion_point(field_set:safex.Histogram.recent_instances) -} - -// optional uint64 total_instances = 4; -inline void Histogram::clear_total_instances() { - total_instances_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 Histogram::total_instances() const { - // @@protoc_insertion_point(field_get:safex.Histogram.total_instances) - return total_instances_; -} -inline void Histogram::set_total_instances(::google::protobuf::uint64 value) { - - total_instances_ = value; - // @@protoc_insertion_point(field_set:safex.Histogram.total_instances) -} - -// optional uint64 unlocked_instances = 5; -inline void Histogram::clear_unlocked_instances() { - unlocked_instances_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 Histogram::unlocked_instances() const { - // @@protoc_insertion_point(field_get:safex.Histogram.unlocked_instances) - return unlocked_instances_; -} -inline void Histogram::set_unlocked_instances(::google::protobuf::uint64 value) { - - unlocked_instances_ = value; - // @@protoc_insertion_point(field_set:safex.Histogram.unlocked_instances) -} - -// ------------------------------------------------------------------- - -// Histograms - -// repeated .safex.Histogram histograms = 1; -inline int Histograms::histograms_size() const { - return histograms_.size(); -} -inline void Histograms::clear_histograms() { - histograms_.Clear(); -} -inline const ::safex::Histogram& Histograms::histograms(int index) const { - // @@protoc_insertion_point(field_get:safex.Histograms.histograms) - return histograms_.Get(index); -} -inline ::safex::Histogram* Histograms::mutable_histograms(int index) { - // @@protoc_insertion_point(field_mutable:safex.Histograms.histograms) - return histograms_.Mutable(index); -} -inline ::safex::Histogram* Histograms::add_histograms() { - // @@protoc_insertion_point(field_add:safex.Histograms.histograms) - return histograms_.Add(); -} -inline ::google::protobuf::RepeatedPtrField< ::safex::Histogram >* -Histograms::mutable_histograms() { - // @@protoc_insertion_point(field_mutable_list:safex.Histograms.histograms) - return &histograms_; -} -inline const ::google::protobuf::RepeatedPtrField< ::safex::Histogram >& -Histograms::histograms() const { - // @@protoc_insertion_point(field_list:safex.Histograms.histograms) - return histograms_; -} - -// optional string status = 2; -inline void Histograms::clear_status() { - status_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& Histograms::status() const { - // @@protoc_insertion_point(field_get:safex.Histograms.status) - return status_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Histograms::set_status(const ::std::string& value) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Histograms.status) -} -inline void Histograms::set_status(const char* value) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Histograms.status) -} -inline void Histograms::set_status(const char* value, size_t size) { - - status_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Histograms.status) -} -inline ::std::string* Histograms::mutable_status() { - - // @@protoc_insertion_point(field_mutable:safex.Histograms.status) - return status_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* Histograms::release_status() { - // @@protoc_insertion_point(field_release:safex.Histograms.status) - - return status_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Histograms::set_allocated_status(::std::string* status) { - if (status != NULL) { - - } else { - - } - status_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), status); - // @@protoc_insertion_point(field_set_allocated:safex.Histograms.status) -} - -#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS -// ------------------------------------------------------------------- - - -// @@protoc_insertion_point(namespace_scope) - -} // namespace safex - -// @@protoc_insertion_point(global_scope) - -#endif // PROTOBUF_output_5fhistogram_2eproto__INCLUDED diff --git a/src/cryptonote_core/protobuf/transactions.pb.cc b/src/cryptonote_core/protobuf/transactions.pb.cc deleted file mode 100644 index 9db709410..000000000 --- a/src/cryptonote_core/protobuf/transactions.pb.cc +++ /dev/null @@ -1,5721 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: transactions.proto - -#define INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION -#include "transactions.pb.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -// @@protoc_insertion_point(includes) - -namespace safex { - -namespace { - -const ::google::protobuf::Descriptor* txin_gen_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - txin_gen_reflection_ = NULL; -const ::google::protobuf::Descriptor* txin_to_key_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - txin_to_key_reflection_ = NULL; -const ::google::protobuf::Descriptor* txin_token_to_key_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - txin_token_to_key_reflection_ = NULL; -const ::google::protobuf::Descriptor* txin_token_migration_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - txin_token_migration_reflection_ = NULL; -const ::google::protobuf::Descriptor* txin_v_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - txin_v_reflection_ = NULL; -const ::google::protobuf::Descriptor* txout_to_key_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - txout_to_key_reflection_ = NULL; -const ::google::protobuf::Descriptor* txout_token_to_key_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - txout_token_to_key_reflection_ = NULL; -const ::google::protobuf::Descriptor* txout_target_v_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - txout_target_v_reflection_ = NULL; -const ::google::protobuf::Descriptor* txout_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - txout_reflection_ = NULL; -const ::google::protobuf::Descriptor* SigData_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - SigData_reflection_ = NULL; -const ::google::protobuf::Descriptor* Signature_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Signature_reflection_ = NULL; -const ::google::protobuf::Descriptor* Transaction_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Transaction_reflection_ = NULL; -const ::google::protobuf::Descriptor* Transactions_descriptor_ = NULL; -const ::google::protobuf::internal::GeneratedMessageReflection* - Transactions_reflection_ = NULL; - -} // namespace - - -void protobuf_AssignDesc_transactions_2eproto() GOOGLE_ATTRIBUTE_COLD; -void protobuf_AssignDesc_transactions_2eproto() { - protobuf_AddDesc_transactions_2eproto(); - const ::google::protobuf::FileDescriptor* file = - ::google::protobuf::DescriptorPool::generated_pool()->FindFileByName( - "transactions.proto"); - GOOGLE_CHECK(file != NULL); - txin_gen_descriptor_ = file->message_type(0); - static const int txin_gen_offsets_[1] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_gen, height_), - }; - txin_gen_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - txin_gen_descriptor_, - txin_gen::default_instance_, - txin_gen_offsets_, - -1, - -1, - -1, - sizeof(txin_gen), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_gen, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_gen, _is_default_instance_)); - txin_to_key_descriptor_ = file->message_type(1); - static const int txin_to_key_offsets_[3] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_to_key, amount_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_to_key, k_image_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_to_key, key_offsets_), - }; - txin_to_key_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - txin_to_key_descriptor_, - txin_to_key::default_instance_, - txin_to_key_offsets_, - -1, - -1, - -1, - sizeof(txin_to_key), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_to_key, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_to_key, _is_default_instance_)); - txin_token_to_key_descriptor_ = file->message_type(2); - static const int txin_token_to_key_offsets_[3] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_token_to_key, token_amount_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_token_to_key, k_image_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_token_to_key, key_offsets_), - }; - txin_token_to_key_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - txin_token_to_key_descriptor_, - txin_token_to_key::default_instance_, - txin_token_to_key_offsets_, - -1, - -1, - -1, - sizeof(txin_token_to_key), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_token_to_key, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_token_to_key, _is_default_instance_)); - txin_token_migration_descriptor_ = file->message_type(3); - static const int txin_token_migration_offsets_[3] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_token_migration, token_amount_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_token_migration, bitcoin_burn_transaction_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_token_migration, k_image_), - }; - txin_token_migration_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - txin_token_migration_descriptor_, - txin_token_migration::default_instance_, - txin_token_migration_offsets_, - -1, - -1, - -1, - sizeof(txin_token_migration), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_token_migration, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_token_migration, _is_default_instance_)); - txin_v_descriptor_ = file->message_type(4); - static const int txin_v_offsets_[4] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_v, txin_gen_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_v, txin_to_key_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_v, txin_token_to_key_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_v, txin_token_migration_), - }; - txin_v_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - txin_v_descriptor_, - txin_v::default_instance_, - txin_v_offsets_, - -1, - -1, - -1, - sizeof(txin_v), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_v, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txin_v, _is_default_instance_)); - txout_to_key_descriptor_ = file->message_type(5); - static const int txout_to_key_offsets_[1] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout_to_key, key_), - }; - txout_to_key_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - txout_to_key_descriptor_, - txout_to_key::default_instance_, - txout_to_key_offsets_, - -1, - -1, - -1, - sizeof(txout_to_key), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout_to_key, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout_to_key, _is_default_instance_)); - txout_token_to_key_descriptor_ = file->message_type(6); - static const int txout_token_to_key_offsets_[1] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout_token_to_key, key_), - }; - txout_token_to_key_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - txout_token_to_key_descriptor_, - txout_token_to_key::default_instance_, - txout_token_to_key_offsets_, - -1, - -1, - -1, - sizeof(txout_token_to_key), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout_token_to_key, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout_token_to_key, _is_default_instance_)); - txout_target_v_descriptor_ = file->message_type(7); - static const int txout_target_v_offsets_[2] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout_target_v, txout_to_key_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout_target_v, txout_token_to_key_), - }; - txout_target_v_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - txout_target_v_descriptor_, - txout_target_v::default_instance_, - txout_target_v_offsets_, - -1, - -1, - -1, - sizeof(txout_target_v), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout_target_v, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout_target_v, _is_default_instance_)); - txout_descriptor_ = file->message_type(8); - static const int txout_offsets_[3] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout, amount_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout, token_amount_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout, target_), - }; - txout_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - txout_descriptor_, - txout::default_instance_, - txout_offsets_, - -1, - -1, - -1, - sizeof(txout), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(txout, _is_default_instance_)); - SigData_descriptor_ = file->message_type(9); - static const int SigData_offsets_[2] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SigData, r_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SigData, c_), - }; - SigData_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - SigData_descriptor_, - SigData::default_instance_, - SigData_offsets_, - -1, - -1, - -1, - sizeof(SigData), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SigData, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SigData, _is_default_instance_)); - Signature_descriptor_ = file->message_type(10); - static const int Signature_offsets_[1] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Signature, signature_), - }; - Signature_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - Signature_descriptor_, - Signature::default_instance_, - Signature_offsets_, - -1, - -1, - -1, - sizeof(Signature), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Signature, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Signature, _is_default_instance_)); - Transaction_descriptor_ = file->message_type(11); - static const int Transaction_offsets_[12] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, version_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, unlock_time_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, extra_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, vin_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, vout_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, signatures_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, block_height_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, block_timestamp_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, double_spend_seen_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, in_pool_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, output_indices_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, tx_hash_), - }; - Transaction_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - Transaction_descriptor_, - Transaction::default_instance_, - Transaction_offsets_, - -1, - -1, - -1, - sizeof(Transaction), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transaction, _is_default_instance_)); - Transactions_descriptor_ = file->message_type(12); - static const int Transactions_offsets_[2] = { - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transactions, tx_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transactions, missed_txs_), - }; - Transactions_reflection_ = - ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( - Transactions_descriptor_, - Transactions::default_instance_, - Transactions_offsets_, - -1, - -1, - -1, - sizeof(Transactions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transactions, _internal_metadata_), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(Transactions, _is_default_instance_)); -} - -namespace { - -GOOGLE_PROTOBUF_DECLARE_ONCE(protobuf_AssignDescriptors_once_); -inline void protobuf_AssignDescriptorsOnce() { - ::google::protobuf::GoogleOnceInit(&protobuf_AssignDescriptors_once_, - &protobuf_AssignDesc_transactions_2eproto); -} - -void protobuf_RegisterTypes(const ::std::string&) GOOGLE_ATTRIBUTE_COLD; -void protobuf_RegisterTypes(const ::std::string&) { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - txin_gen_descriptor_, &txin_gen::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - txin_to_key_descriptor_, &txin_to_key::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - txin_token_to_key_descriptor_, &txin_token_to_key::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - txin_token_migration_descriptor_, &txin_token_migration::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - txin_v_descriptor_, &txin_v::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - txout_to_key_descriptor_, &txout_to_key::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - txout_token_to_key_descriptor_, &txout_token_to_key::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - txout_target_v_descriptor_, &txout_target_v::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - txout_descriptor_, &txout::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - SigData_descriptor_, &SigData::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Signature_descriptor_, &Signature::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Transaction_descriptor_, &Transaction::default_instance()); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage( - Transactions_descriptor_, &Transactions::default_instance()); -} - -} // namespace - -void protobuf_ShutdownFile_transactions_2eproto() { - delete txin_gen::default_instance_; - delete txin_gen_reflection_; - delete txin_to_key::default_instance_; - delete txin_to_key_reflection_; - delete txin_token_to_key::default_instance_; - delete txin_token_to_key_reflection_; - delete txin_token_migration::default_instance_; - delete txin_token_migration_reflection_; - delete txin_v::default_instance_; - delete txin_v_reflection_; - delete txout_to_key::default_instance_; - delete txout_to_key_reflection_; - delete txout_token_to_key::default_instance_; - delete txout_token_to_key_reflection_; - delete txout_target_v::default_instance_; - delete txout_target_v_reflection_; - delete txout::default_instance_; - delete txout_reflection_; - delete SigData::default_instance_; - delete SigData_reflection_; - delete Signature::default_instance_; - delete Signature_reflection_; - delete Transaction::default_instance_; - delete Transaction_reflection_; - delete Transactions::default_instance_; - delete Transactions_reflection_; -} - -void protobuf_AddDesc_transactions_2eproto() GOOGLE_ATTRIBUTE_COLD; -void protobuf_AddDesc_transactions_2eproto() { - static bool already_here = false; - if (already_here) return; - already_here = true; - GOOGLE_PROTOBUF_VERIFY_VERSION; - - ::google::protobuf::DescriptorPool::InternalAddGeneratedFile( - "\n\022transactions.proto\022\005safex\"\032\n\010txin_gen\022" - "\016\n\006height\030\001 \001(\004\"C\n\013txin_to_key\022\016\n\006amount" - "\030\001 \001(\004\022\017\n\007k_image\030\002 \001(\014\022\023\n\013key_offsets\030\003" - " \003(\004\"O\n\021txin_token_to_key\022\024\n\014token_amoun" - "t\030\001 \001(\004\022\017\n\007k_image\030\002 \001(\014\022\023\n\013key_offsets\030" - "\003 \003(\004\"_\n\024txin_token_migration\022\024\n\014token_a" - "mount\030\001 \001(\004\022 \n\030bitcoin_burn_transaction\030" - "\002 \001(\t\022\017\n\007k_image\030\003 \001(\014\"\304\001\n\006txin_v\022!\n\010txi" - "n_gen\030\001 \001(\0132\017.safex.txin_gen\022\'\n\013txin_to_" - "key\030\002 \001(\0132\022.safex.txin_to_key\0223\n\021txin_to" - "ken_to_key\030\003 \001(\0132\030.safex.txin_token_to_k" - "ey\0229\n\024txin_token_migration\030\004 \001(\0132\033.safex" - ".txin_token_migration\"\033\n\014txout_to_key\022\013\n" - "\003key\030\001 \001(\014\"!\n\022txout_token_to_key\022\013\n\003key\030" - "\001 \001(\014\"r\n\016txout_target_v\022)\n\014txout_to_key\030" - "\001 \001(\0132\023.safex.txout_to_key\0225\n\022txout_toke" - "n_to_key\030\002 \001(\0132\031.safex.txout_token_to_ke" - "y\"T\n\005txout\022\016\n\006amount\030\001 \001(\004\022\024\n\014token_amou" - "nt\030\002 \001(\004\022%\n\006target\030\003 \001(\0132\025.safex.txout_t" - "arget_v\"\037\n\007SigData\022\t\n\001r\030\001 \001(\014\022\t\n\001c\030\002 \001(\014" - "\".\n\tSignature\022!\n\tsignature\030\001 \003(\0132\016.safex" - ".SigData\"\244\002\n\013Transaction\022\017\n\007version\030\001 \001(" - "\004\022\023\n\013unlock_time\030\002 \001(\004\022\r\n\005extra\030\003 \001(\014\022\032\n" - "\003vin\030\004 \003(\0132\r.safex.txin_v\022\032\n\004vout\030\005 \003(\0132" - "\014.safex.txout\022$\n\nsignatures\030\006 \003(\0132\020.safe" - "x.Signature\022\024\n\014block_height\030\007 \001(\004\022\027\n\017blo" - "ck_timestamp\030\010 \001(\004\022\031\n\021double_spend_seen\030" - "\t \001(\010\022\017\n\007in_pool\030\n \001(\010\022\026\n\016output_indices" - "\030\013 \003(\004\022\017\n\007tx_hash\030\014 \001(\t\"B\n\014Transactions\022" - "\036\n\002tx\030\001 \003(\0132\022.safex.Transaction\022\022\n\nmisse" - "d_txs\030\002 \003(\tb\006proto3", 1219); - ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( - "transactions.proto", &protobuf_RegisterTypes); - txin_gen::default_instance_ = new txin_gen(); - txin_to_key::default_instance_ = new txin_to_key(); - txin_token_to_key::default_instance_ = new txin_token_to_key(); - txin_token_migration::default_instance_ = new txin_token_migration(); - txin_v::default_instance_ = new txin_v(); - txout_to_key::default_instance_ = new txout_to_key(); - txout_token_to_key::default_instance_ = new txout_token_to_key(); - txout_target_v::default_instance_ = new txout_target_v(); - txout::default_instance_ = new txout(); - SigData::default_instance_ = new SigData(); - Signature::default_instance_ = new Signature(); - Transaction::default_instance_ = new Transaction(); - Transactions::default_instance_ = new Transactions(); - txin_gen::default_instance_->InitAsDefaultInstance(); - txin_to_key::default_instance_->InitAsDefaultInstance(); - txin_token_to_key::default_instance_->InitAsDefaultInstance(); - txin_token_migration::default_instance_->InitAsDefaultInstance(); - txin_v::default_instance_->InitAsDefaultInstance(); - txout_to_key::default_instance_->InitAsDefaultInstance(); - txout_token_to_key::default_instance_->InitAsDefaultInstance(); - txout_target_v::default_instance_->InitAsDefaultInstance(); - txout::default_instance_->InitAsDefaultInstance(); - SigData::default_instance_->InitAsDefaultInstance(); - Signature::default_instance_->InitAsDefaultInstance(); - Transaction::default_instance_->InitAsDefaultInstance(); - Transactions::default_instance_->InitAsDefaultInstance(); - ::google::protobuf::internal::OnShutdown(&protobuf_ShutdownFile_transactions_2eproto); -} - -// Force AddDescriptors() to be called at static initialization time. -struct StaticDescriptorInitializer_transactions_2eproto { - StaticDescriptorInitializer_transactions_2eproto() { - protobuf_AddDesc_transactions_2eproto(); - } -} static_descriptor_initializer_transactions_2eproto_; - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int txin_gen::kHeightFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -txin_gen::txin_gen() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.txin_gen) -} - -void txin_gen::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -txin_gen::txin_gen(const txin_gen& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.txin_gen) -} - -void txin_gen::SharedCtor() { - _is_default_instance_ = false; - _cached_size_ = 0; - height_ = GOOGLE_ULONGLONG(0); -} - -txin_gen::~txin_gen() { - // @@protoc_insertion_point(destructor:safex.txin_gen) - SharedDtor(); -} - -void txin_gen::SharedDtor() { - if (this != default_instance_) { - } -} - -void txin_gen::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* txin_gen::descriptor() { - protobuf_AssignDescriptorsOnce(); - return txin_gen_descriptor_; -} - -const txin_gen& txin_gen::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -txin_gen* txin_gen::default_instance_ = NULL; - -txin_gen* txin_gen::New(::google::protobuf::Arena* arena) const { - txin_gen* n = new txin_gen; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void txin_gen::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.txin_gen) - height_ = GOOGLE_ULONGLONG(0); -} - -bool txin_gen::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.txin_gen) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 height = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &height_))); - - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.txin_gen) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.txin_gen) - return false; -#undef DO_ -} - -void txin_gen::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.txin_gen) - // optional uint64 height = 1; - if (this->height() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->height(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.txin_gen) -} - -::google::protobuf::uint8* txin_gen::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.txin_gen) - // optional uint64 height = 1; - if (this->height() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->height(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.txin_gen) - return target; -} - -int txin_gen::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.txin_gen) - int total_size = 0; - - // optional uint64 height = 1; - if (this->height() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->height()); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void txin_gen::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.txin_gen) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const txin_gen* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.txin_gen) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.txin_gen) - MergeFrom(*source); - } -} - -void txin_gen::MergeFrom(const txin_gen& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.txin_gen) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - if (from.height() != 0) { - set_height(from.height()); - } -} - -void txin_gen::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.txin_gen) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void txin_gen::CopyFrom(const txin_gen& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.txin_gen) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool txin_gen::IsInitialized() const { - - return true; -} - -void txin_gen::Swap(txin_gen* other) { - if (other == this) return; - InternalSwap(other); -} -void txin_gen::InternalSwap(txin_gen* other) { - std::swap(height_, other->height_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata txin_gen::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = txin_gen_descriptor_; - metadata.reflection = txin_gen_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// txin_gen - -// optional uint64 height = 1; -void txin_gen::clear_height() { - height_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 txin_gen::height() const { - // @@protoc_insertion_point(field_get:safex.txin_gen.height) - return height_; -} - void txin_gen::set_height(::google::protobuf::uint64 value) { - - height_ = value; - // @@protoc_insertion_point(field_set:safex.txin_gen.height) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int txin_to_key::kAmountFieldNumber; -const int txin_to_key::kKImageFieldNumber; -const int txin_to_key::kKeyOffsetsFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -txin_to_key::txin_to_key() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.txin_to_key) -} - -void txin_to_key::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -txin_to_key::txin_to_key(const txin_to_key& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.txin_to_key) -} - -void txin_to_key::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - amount_ = GOOGLE_ULONGLONG(0); - k_image_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -txin_to_key::~txin_to_key() { - // @@protoc_insertion_point(destructor:safex.txin_to_key) - SharedDtor(); -} - -void txin_to_key::SharedDtor() { - k_image_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void txin_to_key::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* txin_to_key::descriptor() { - protobuf_AssignDescriptorsOnce(); - return txin_to_key_descriptor_; -} - -const txin_to_key& txin_to_key::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -txin_to_key* txin_to_key::default_instance_ = NULL; - -txin_to_key* txin_to_key::New(::google::protobuf::Arena* arena) const { - txin_to_key* n = new txin_to_key; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void txin_to_key::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.txin_to_key) - amount_ = GOOGLE_ULONGLONG(0); - k_image_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - key_offsets_.Clear(); -} - -bool txin_to_key::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.txin_to_key) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 amount = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &amount_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_k_image; - break; - } - - // optional bytes k_image = 2; - case 2: { - if (tag == 18) { - parse_k_image: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_k_image())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(26)) goto parse_key_offsets; - break; - } - - // repeated uint64 key_offsets = 3; - case 3: { - if (tag == 26) { - parse_key_offsets: - DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, this->mutable_key_offsets()))); - } else if (tag == 24) { - DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - 1, 26, input, this->mutable_key_offsets()))); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.txin_to_key) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.txin_to_key) - return false; -#undef DO_ -} - -void txin_to_key::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.txin_to_key) - // optional uint64 amount = 1; - if (this->amount() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->amount(), output); - } - - // optional bytes k_image = 2; - if (this->k_image().size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 2, this->k_image(), output); - } - - // repeated uint64 key_offsets = 3; - if (this->key_offsets_size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteTag(3, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(_key_offsets_cached_byte_size_); - } - for (int i = 0; i < this->key_offsets_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64NoTag( - this->key_offsets(i), output); - } - - // @@protoc_insertion_point(serialize_end:safex.txin_to_key) -} - -::google::protobuf::uint8* txin_to_key::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.txin_to_key) - // optional uint64 amount = 1; - if (this->amount() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->amount(), target); - } - - // optional bytes k_image = 2; - if (this->k_image().size() > 0) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 2, this->k_image(), target); - } - - // repeated uint64 key_offsets = 3; - if (this->key_offsets_size() > 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray( - 3, - ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, - target); - target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray( - _key_offsets_cached_byte_size_, target); - } - for (int i = 0; i < this->key_offsets_size(); i++) { - target = ::google::protobuf::internal::WireFormatLite:: - WriteUInt64NoTagToArray(this->key_offsets(i), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.txin_to_key) - return target; -} - -int txin_to_key::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.txin_to_key) - int total_size = 0; - - // optional uint64 amount = 1; - if (this->amount() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->amount()); - } - - // optional bytes k_image = 2; - if (this->k_image().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->k_image()); - } - - // repeated uint64 key_offsets = 3; - { - int data_size = 0; - for (int i = 0; i < this->key_offsets_size(); i++) { - data_size += ::google::protobuf::internal::WireFormatLite:: - UInt64Size(this->key_offsets(i)); - } - if (data_size > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::Int32Size(data_size); - } - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _key_offsets_cached_byte_size_ = data_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - total_size += data_size; - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void txin_to_key::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.txin_to_key) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const txin_to_key* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.txin_to_key) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.txin_to_key) - MergeFrom(*source); - } -} - -void txin_to_key::MergeFrom(const txin_to_key& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.txin_to_key) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - key_offsets_.MergeFrom(from.key_offsets_); - if (from.amount() != 0) { - set_amount(from.amount()); - } - if (from.k_image().size() > 0) { - - k_image_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.k_image_); - } -} - -void txin_to_key::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.txin_to_key) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void txin_to_key::CopyFrom(const txin_to_key& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.txin_to_key) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool txin_to_key::IsInitialized() const { - - return true; -} - -void txin_to_key::Swap(txin_to_key* other) { - if (other == this) return; - InternalSwap(other); -} -void txin_to_key::InternalSwap(txin_to_key* other) { - std::swap(amount_, other->amount_); - k_image_.Swap(&other->k_image_); - key_offsets_.UnsafeArenaSwap(&other->key_offsets_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata txin_to_key::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = txin_to_key_descriptor_; - metadata.reflection = txin_to_key_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// txin_to_key - -// optional uint64 amount = 1; -void txin_to_key::clear_amount() { - amount_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 txin_to_key::amount() const { - // @@protoc_insertion_point(field_get:safex.txin_to_key.amount) - return amount_; -} - void txin_to_key::set_amount(::google::protobuf::uint64 value) { - - amount_ = value; - // @@protoc_insertion_point(field_set:safex.txin_to_key.amount) -} - -// optional bytes k_image = 2; -void txin_to_key::clear_k_image() { - k_image_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& txin_to_key::k_image() const { - // @@protoc_insertion_point(field_get:safex.txin_to_key.k_image) - return k_image_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txin_to_key::set_k_image(const ::std::string& value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txin_to_key.k_image) -} - void txin_to_key::set_k_image(const char* value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txin_to_key.k_image) -} - void txin_to_key::set_k_image(const void* value, size_t size) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txin_to_key.k_image) -} - ::std::string* txin_to_key::mutable_k_image() { - - // @@protoc_insertion_point(field_mutable:safex.txin_to_key.k_image) - return k_image_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* txin_to_key::release_k_image() { - // @@protoc_insertion_point(field_release:safex.txin_to_key.k_image) - - return k_image_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txin_to_key::set_allocated_k_image(::std::string* k_image) { - if (k_image != NULL) { - - } else { - - } - k_image_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), k_image); - // @@protoc_insertion_point(field_set_allocated:safex.txin_to_key.k_image) -} - -// repeated uint64 key_offsets = 3; -int txin_to_key::key_offsets_size() const { - return key_offsets_.size(); -} -void txin_to_key::clear_key_offsets() { - key_offsets_.Clear(); -} - ::google::protobuf::uint64 txin_to_key::key_offsets(int index) const { - // @@protoc_insertion_point(field_get:safex.txin_to_key.key_offsets) - return key_offsets_.Get(index); -} - void txin_to_key::set_key_offsets(int index, ::google::protobuf::uint64 value) { - key_offsets_.Set(index, value); - // @@protoc_insertion_point(field_set:safex.txin_to_key.key_offsets) -} - void txin_to_key::add_key_offsets(::google::protobuf::uint64 value) { - key_offsets_.Add(value); - // @@protoc_insertion_point(field_add:safex.txin_to_key.key_offsets) -} - const ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >& -txin_to_key::key_offsets() const { - // @@protoc_insertion_point(field_list:safex.txin_to_key.key_offsets) - return key_offsets_; -} - ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >* -txin_to_key::mutable_key_offsets() { - // @@protoc_insertion_point(field_mutable_list:safex.txin_to_key.key_offsets) - return &key_offsets_; -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int txin_token_to_key::kTokenAmountFieldNumber; -const int txin_token_to_key::kKImageFieldNumber; -const int txin_token_to_key::kKeyOffsetsFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -txin_token_to_key::txin_token_to_key() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.txin_token_to_key) -} - -void txin_token_to_key::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -txin_token_to_key::txin_token_to_key(const txin_token_to_key& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.txin_token_to_key) -} - -void txin_token_to_key::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - token_amount_ = GOOGLE_ULONGLONG(0); - k_image_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -txin_token_to_key::~txin_token_to_key() { - // @@protoc_insertion_point(destructor:safex.txin_token_to_key) - SharedDtor(); -} - -void txin_token_to_key::SharedDtor() { - k_image_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void txin_token_to_key::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* txin_token_to_key::descriptor() { - protobuf_AssignDescriptorsOnce(); - return txin_token_to_key_descriptor_; -} - -const txin_token_to_key& txin_token_to_key::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -txin_token_to_key* txin_token_to_key::default_instance_ = NULL; - -txin_token_to_key* txin_token_to_key::New(::google::protobuf::Arena* arena) const { - txin_token_to_key* n = new txin_token_to_key; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void txin_token_to_key::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.txin_token_to_key) - token_amount_ = GOOGLE_ULONGLONG(0); - k_image_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - key_offsets_.Clear(); -} - -bool txin_token_to_key::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.txin_token_to_key) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 token_amount = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &token_amount_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_k_image; - break; - } - - // optional bytes k_image = 2; - case 2: { - if (tag == 18) { - parse_k_image: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_k_image())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(26)) goto parse_key_offsets; - break; - } - - // repeated uint64 key_offsets = 3; - case 3: { - if (tag == 26) { - parse_key_offsets: - DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, this->mutable_key_offsets()))); - } else if (tag == 24) { - DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - 1, 26, input, this->mutable_key_offsets()))); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.txin_token_to_key) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.txin_token_to_key) - return false; -#undef DO_ -} - -void txin_token_to_key::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.txin_token_to_key) - // optional uint64 token_amount = 1; - if (this->token_amount() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->token_amount(), output); - } - - // optional bytes k_image = 2; - if (this->k_image().size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 2, this->k_image(), output); - } - - // repeated uint64 key_offsets = 3; - if (this->key_offsets_size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteTag(3, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(_key_offsets_cached_byte_size_); - } - for (int i = 0; i < this->key_offsets_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64NoTag( - this->key_offsets(i), output); - } - - // @@protoc_insertion_point(serialize_end:safex.txin_token_to_key) -} - -::google::protobuf::uint8* txin_token_to_key::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.txin_token_to_key) - // optional uint64 token_amount = 1; - if (this->token_amount() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->token_amount(), target); - } - - // optional bytes k_image = 2; - if (this->k_image().size() > 0) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 2, this->k_image(), target); - } - - // repeated uint64 key_offsets = 3; - if (this->key_offsets_size() > 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray( - 3, - ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, - target); - target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray( - _key_offsets_cached_byte_size_, target); - } - for (int i = 0; i < this->key_offsets_size(); i++) { - target = ::google::protobuf::internal::WireFormatLite:: - WriteUInt64NoTagToArray(this->key_offsets(i), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.txin_token_to_key) - return target; -} - -int txin_token_to_key::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.txin_token_to_key) - int total_size = 0; - - // optional uint64 token_amount = 1; - if (this->token_amount() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->token_amount()); - } - - // optional bytes k_image = 2; - if (this->k_image().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->k_image()); - } - - // repeated uint64 key_offsets = 3; - { - int data_size = 0; - for (int i = 0; i < this->key_offsets_size(); i++) { - data_size += ::google::protobuf::internal::WireFormatLite:: - UInt64Size(this->key_offsets(i)); - } - if (data_size > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::Int32Size(data_size); - } - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _key_offsets_cached_byte_size_ = data_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - total_size += data_size; - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void txin_token_to_key::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.txin_token_to_key) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const txin_token_to_key* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.txin_token_to_key) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.txin_token_to_key) - MergeFrom(*source); - } -} - -void txin_token_to_key::MergeFrom(const txin_token_to_key& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.txin_token_to_key) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - key_offsets_.MergeFrom(from.key_offsets_); - if (from.token_amount() != 0) { - set_token_amount(from.token_amount()); - } - if (from.k_image().size() > 0) { - - k_image_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.k_image_); - } -} - -void txin_token_to_key::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.txin_token_to_key) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void txin_token_to_key::CopyFrom(const txin_token_to_key& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.txin_token_to_key) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool txin_token_to_key::IsInitialized() const { - - return true; -} - -void txin_token_to_key::Swap(txin_token_to_key* other) { - if (other == this) return; - InternalSwap(other); -} -void txin_token_to_key::InternalSwap(txin_token_to_key* other) { - std::swap(token_amount_, other->token_amount_); - k_image_.Swap(&other->k_image_); - key_offsets_.UnsafeArenaSwap(&other->key_offsets_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata txin_token_to_key::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = txin_token_to_key_descriptor_; - metadata.reflection = txin_token_to_key_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// txin_token_to_key - -// optional uint64 token_amount = 1; -void txin_token_to_key::clear_token_amount() { - token_amount_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 txin_token_to_key::token_amount() const { - // @@protoc_insertion_point(field_get:safex.txin_token_to_key.token_amount) - return token_amount_; -} - void txin_token_to_key::set_token_amount(::google::protobuf::uint64 value) { - - token_amount_ = value; - // @@protoc_insertion_point(field_set:safex.txin_token_to_key.token_amount) -} - -// optional bytes k_image = 2; -void txin_token_to_key::clear_k_image() { - k_image_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& txin_token_to_key::k_image() const { - // @@protoc_insertion_point(field_get:safex.txin_token_to_key.k_image) - return k_image_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txin_token_to_key::set_k_image(const ::std::string& value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txin_token_to_key.k_image) -} - void txin_token_to_key::set_k_image(const char* value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txin_token_to_key.k_image) -} - void txin_token_to_key::set_k_image(const void* value, size_t size) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txin_token_to_key.k_image) -} - ::std::string* txin_token_to_key::mutable_k_image() { - - // @@protoc_insertion_point(field_mutable:safex.txin_token_to_key.k_image) - return k_image_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* txin_token_to_key::release_k_image() { - // @@protoc_insertion_point(field_release:safex.txin_token_to_key.k_image) - - return k_image_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txin_token_to_key::set_allocated_k_image(::std::string* k_image) { - if (k_image != NULL) { - - } else { - - } - k_image_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), k_image); - // @@protoc_insertion_point(field_set_allocated:safex.txin_token_to_key.k_image) -} - -// repeated uint64 key_offsets = 3; -int txin_token_to_key::key_offsets_size() const { - return key_offsets_.size(); -} -void txin_token_to_key::clear_key_offsets() { - key_offsets_.Clear(); -} - ::google::protobuf::uint64 txin_token_to_key::key_offsets(int index) const { - // @@protoc_insertion_point(field_get:safex.txin_token_to_key.key_offsets) - return key_offsets_.Get(index); -} - void txin_token_to_key::set_key_offsets(int index, ::google::protobuf::uint64 value) { - key_offsets_.Set(index, value); - // @@protoc_insertion_point(field_set:safex.txin_token_to_key.key_offsets) -} - void txin_token_to_key::add_key_offsets(::google::protobuf::uint64 value) { - key_offsets_.Add(value); - // @@protoc_insertion_point(field_add:safex.txin_token_to_key.key_offsets) -} - const ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >& -txin_token_to_key::key_offsets() const { - // @@protoc_insertion_point(field_list:safex.txin_token_to_key.key_offsets) - return key_offsets_; -} - ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >* -txin_token_to_key::mutable_key_offsets() { - // @@protoc_insertion_point(field_mutable_list:safex.txin_token_to_key.key_offsets) - return &key_offsets_; -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int txin_token_migration::kTokenAmountFieldNumber; -const int txin_token_migration::kBitcoinBurnTransactionFieldNumber; -const int txin_token_migration::kKImageFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -txin_token_migration::txin_token_migration() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.txin_token_migration) -} - -void txin_token_migration::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -txin_token_migration::txin_token_migration(const txin_token_migration& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.txin_token_migration) -} - -void txin_token_migration::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - token_amount_ = GOOGLE_ULONGLONG(0); - bitcoin_burn_transaction_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - k_image_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -txin_token_migration::~txin_token_migration() { - // @@protoc_insertion_point(destructor:safex.txin_token_migration) - SharedDtor(); -} - -void txin_token_migration::SharedDtor() { - bitcoin_burn_transaction_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - k_image_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void txin_token_migration::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* txin_token_migration::descriptor() { - protobuf_AssignDescriptorsOnce(); - return txin_token_migration_descriptor_; -} - -const txin_token_migration& txin_token_migration::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -txin_token_migration* txin_token_migration::default_instance_ = NULL; - -txin_token_migration* txin_token_migration::New(::google::protobuf::Arena* arena) const { - txin_token_migration* n = new txin_token_migration; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void txin_token_migration::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.txin_token_migration) - token_amount_ = GOOGLE_ULONGLONG(0); - bitcoin_burn_transaction_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - k_image_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -bool txin_token_migration::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.txin_token_migration) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 token_amount = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &token_amount_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_bitcoin_burn_transaction; - break; - } - - // optional string bitcoin_burn_transaction = 2; - case 2: { - if (tag == 18) { - parse_bitcoin_burn_transaction: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_bitcoin_burn_transaction())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->bitcoin_burn_transaction().data(), this->bitcoin_burn_transaction().length(), - ::google::protobuf::internal::WireFormatLite::PARSE, - "safex.txin_token_migration.bitcoin_burn_transaction")); - } else { - goto handle_unusual; - } - if (input->ExpectTag(26)) goto parse_k_image; - break; - } - - // optional bytes k_image = 3; - case 3: { - if (tag == 26) { - parse_k_image: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_k_image())); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.txin_token_migration) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.txin_token_migration) - return false; -#undef DO_ -} - -void txin_token_migration::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.txin_token_migration) - // optional uint64 token_amount = 1; - if (this->token_amount() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->token_amount(), output); - } - - // optional string bitcoin_burn_transaction = 2; - if (this->bitcoin_burn_transaction().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->bitcoin_burn_transaction().data(), this->bitcoin_burn_transaction().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.txin_token_migration.bitcoin_burn_transaction"); - ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( - 2, this->bitcoin_burn_transaction(), output); - } - - // optional bytes k_image = 3; - if (this->k_image().size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 3, this->k_image(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.txin_token_migration) -} - -::google::protobuf::uint8* txin_token_migration::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.txin_token_migration) - // optional uint64 token_amount = 1; - if (this->token_amount() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->token_amount(), target); - } - - // optional string bitcoin_burn_transaction = 2; - if (this->bitcoin_burn_transaction().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->bitcoin_burn_transaction().data(), this->bitcoin_burn_transaction().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.txin_token_migration.bitcoin_burn_transaction"); - target = - ::google::protobuf::internal::WireFormatLite::WriteStringToArray( - 2, this->bitcoin_burn_transaction(), target); - } - - // optional bytes k_image = 3; - if (this->k_image().size() > 0) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 3, this->k_image(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.txin_token_migration) - return target; -} - -int txin_token_migration::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.txin_token_migration) - int total_size = 0; - - // optional uint64 token_amount = 1; - if (this->token_amount() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->token_amount()); - } - - // optional string bitcoin_burn_transaction = 2; - if (this->bitcoin_burn_transaction().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->bitcoin_burn_transaction()); - } - - // optional bytes k_image = 3; - if (this->k_image().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->k_image()); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void txin_token_migration::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.txin_token_migration) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const txin_token_migration* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.txin_token_migration) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.txin_token_migration) - MergeFrom(*source); - } -} - -void txin_token_migration::MergeFrom(const txin_token_migration& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.txin_token_migration) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - if (from.token_amount() != 0) { - set_token_amount(from.token_amount()); - } - if (from.bitcoin_burn_transaction().size() > 0) { - - bitcoin_burn_transaction_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.bitcoin_burn_transaction_); - } - if (from.k_image().size() > 0) { - - k_image_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.k_image_); - } -} - -void txin_token_migration::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.txin_token_migration) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void txin_token_migration::CopyFrom(const txin_token_migration& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.txin_token_migration) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool txin_token_migration::IsInitialized() const { - - return true; -} - -void txin_token_migration::Swap(txin_token_migration* other) { - if (other == this) return; - InternalSwap(other); -} -void txin_token_migration::InternalSwap(txin_token_migration* other) { - std::swap(token_amount_, other->token_amount_); - bitcoin_burn_transaction_.Swap(&other->bitcoin_burn_transaction_); - k_image_.Swap(&other->k_image_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata txin_token_migration::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = txin_token_migration_descriptor_; - metadata.reflection = txin_token_migration_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// txin_token_migration - -// optional uint64 token_amount = 1; -void txin_token_migration::clear_token_amount() { - token_amount_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 txin_token_migration::token_amount() const { - // @@protoc_insertion_point(field_get:safex.txin_token_migration.token_amount) - return token_amount_; -} - void txin_token_migration::set_token_amount(::google::protobuf::uint64 value) { - - token_amount_ = value; - // @@protoc_insertion_point(field_set:safex.txin_token_migration.token_amount) -} - -// optional string bitcoin_burn_transaction = 2; -void txin_token_migration::clear_bitcoin_burn_transaction() { - bitcoin_burn_transaction_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& txin_token_migration::bitcoin_burn_transaction() const { - // @@protoc_insertion_point(field_get:safex.txin_token_migration.bitcoin_burn_transaction) - return bitcoin_burn_transaction_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txin_token_migration::set_bitcoin_burn_transaction(const ::std::string& value) { - - bitcoin_burn_transaction_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txin_token_migration.bitcoin_burn_transaction) -} - void txin_token_migration::set_bitcoin_burn_transaction(const char* value) { - - bitcoin_burn_transaction_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txin_token_migration.bitcoin_burn_transaction) -} - void txin_token_migration::set_bitcoin_burn_transaction(const char* value, size_t size) { - - bitcoin_burn_transaction_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txin_token_migration.bitcoin_burn_transaction) -} - ::std::string* txin_token_migration::mutable_bitcoin_burn_transaction() { - - // @@protoc_insertion_point(field_mutable:safex.txin_token_migration.bitcoin_burn_transaction) - return bitcoin_burn_transaction_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* txin_token_migration::release_bitcoin_burn_transaction() { - // @@protoc_insertion_point(field_release:safex.txin_token_migration.bitcoin_burn_transaction) - - return bitcoin_burn_transaction_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txin_token_migration::set_allocated_bitcoin_burn_transaction(::std::string* bitcoin_burn_transaction) { - if (bitcoin_burn_transaction != NULL) { - - } else { - - } - bitcoin_burn_transaction_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), bitcoin_burn_transaction); - // @@protoc_insertion_point(field_set_allocated:safex.txin_token_migration.bitcoin_burn_transaction) -} - -// optional bytes k_image = 3; -void txin_token_migration::clear_k_image() { - k_image_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& txin_token_migration::k_image() const { - // @@protoc_insertion_point(field_get:safex.txin_token_migration.k_image) - return k_image_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txin_token_migration::set_k_image(const ::std::string& value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txin_token_migration.k_image) -} - void txin_token_migration::set_k_image(const char* value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txin_token_migration.k_image) -} - void txin_token_migration::set_k_image(const void* value, size_t size) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txin_token_migration.k_image) -} - ::std::string* txin_token_migration::mutable_k_image() { - - // @@protoc_insertion_point(field_mutable:safex.txin_token_migration.k_image) - return k_image_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* txin_token_migration::release_k_image() { - // @@protoc_insertion_point(field_release:safex.txin_token_migration.k_image) - - return k_image_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txin_token_migration::set_allocated_k_image(::std::string* k_image) { - if (k_image != NULL) { - - } else { - - } - k_image_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), k_image); - // @@protoc_insertion_point(field_set_allocated:safex.txin_token_migration.k_image) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int txin_v::kTxinGenFieldNumber; -const int txin_v::kTxinToKeyFieldNumber; -const int txin_v::kTxinTokenToKeyFieldNumber; -const int txin_v::kTxinTokenMigrationFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -txin_v::txin_v() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.txin_v) -} - -void txin_v::InitAsDefaultInstance() { - _is_default_instance_ = true; - txin_gen_ = const_cast< ::safex::txin_gen*>(&::safex::txin_gen::default_instance()); - txin_to_key_ = const_cast< ::safex::txin_to_key*>(&::safex::txin_to_key::default_instance()); - txin_token_to_key_ = const_cast< ::safex::txin_token_to_key*>(&::safex::txin_token_to_key::default_instance()); - txin_token_migration_ = const_cast< ::safex::txin_token_migration*>(&::safex::txin_token_migration::default_instance()); -} - -txin_v::txin_v(const txin_v& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.txin_v) -} - -void txin_v::SharedCtor() { - _is_default_instance_ = false; - _cached_size_ = 0; - txin_gen_ = NULL; - txin_to_key_ = NULL; - txin_token_to_key_ = NULL; - txin_token_migration_ = NULL; -} - -txin_v::~txin_v() { - // @@protoc_insertion_point(destructor:safex.txin_v) - SharedDtor(); -} - -void txin_v::SharedDtor() { - if (this != default_instance_) { - delete txin_gen_; - delete txin_to_key_; - delete txin_token_to_key_; - delete txin_token_migration_; - } -} - -void txin_v::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* txin_v::descriptor() { - protobuf_AssignDescriptorsOnce(); - return txin_v_descriptor_; -} - -const txin_v& txin_v::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -txin_v* txin_v::default_instance_ = NULL; - -txin_v* txin_v::New(::google::protobuf::Arena* arena) const { - txin_v* n = new txin_v; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void txin_v::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.txin_v) - if (GetArenaNoVirtual() == NULL && txin_gen_ != NULL) delete txin_gen_; - txin_gen_ = NULL; - if (GetArenaNoVirtual() == NULL && txin_to_key_ != NULL) delete txin_to_key_; - txin_to_key_ = NULL; - if (GetArenaNoVirtual() == NULL && txin_token_to_key_ != NULL) delete txin_token_to_key_; - txin_token_to_key_ = NULL; - if (GetArenaNoVirtual() == NULL && txin_token_migration_ != NULL) delete txin_token_migration_; - txin_token_migration_ = NULL; -} - -bool txin_v::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.txin_v) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional .safex.txin_gen txin_gen = 1; - case 1: { - if (tag == 10) { - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_txin_gen())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_txin_to_key; - break; - } - - // optional .safex.txin_to_key txin_to_key = 2; - case 2: { - if (tag == 18) { - parse_txin_to_key: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_txin_to_key())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(26)) goto parse_txin_token_to_key; - break; - } - - // optional .safex.txin_token_to_key txin_token_to_key = 3; - case 3: { - if (tag == 26) { - parse_txin_token_to_key: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_txin_token_to_key())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(34)) goto parse_txin_token_migration; - break; - } - - // optional .safex.txin_token_migration txin_token_migration = 4; - case 4: { - if (tag == 34) { - parse_txin_token_migration: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_txin_token_migration())); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.txin_v) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.txin_v) - return false; -#undef DO_ -} - -void txin_v::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.txin_v) - // optional .safex.txin_gen txin_gen = 1; - if (this->has_txin_gen()) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 1, *this->txin_gen_, output); - } - - // optional .safex.txin_to_key txin_to_key = 2; - if (this->has_txin_to_key()) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 2, *this->txin_to_key_, output); - } - - // optional .safex.txin_token_to_key txin_token_to_key = 3; - if (this->has_txin_token_to_key()) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 3, *this->txin_token_to_key_, output); - } - - // optional .safex.txin_token_migration txin_token_migration = 4; - if (this->has_txin_token_migration()) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 4, *this->txin_token_migration_, output); - } - - // @@protoc_insertion_point(serialize_end:safex.txin_v) -} - -::google::protobuf::uint8* txin_v::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.txin_v) - // optional .safex.txin_gen txin_gen = 1; - if (this->has_txin_gen()) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 1, *this->txin_gen_, false, target); - } - - // optional .safex.txin_to_key txin_to_key = 2; - if (this->has_txin_to_key()) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 2, *this->txin_to_key_, false, target); - } - - // optional .safex.txin_token_to_key txin_token_to_key = 3; - if (this->has_txin_token_to_key()) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 3, *this->txin_token_to_key_, false, target); - } - - // optional .safex.txin_token_migration txin_token_migration = 4; - if (this->has_txin_token_migration()) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 4, *this->txin_token_migration_, false, target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.txin_v) - return target; -} - -int txin_v::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.txin_v) - int total_size = 0; - - // optional .safex.txin_gen txin_gen = 1; - if (this->has_txin_gen()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - *this->txin_gen_); - } - - // optional .safex.txin_to_key txin_to_key = 2; - if (this->has_txin_to_key()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - *this->txin_to_key_); - } - - // optional .safex.txin_token_to_key txin_token_to_key = 3; - if (this->has_txin_token_to_key()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - *this->txin_token_to_key_); - } - - // optional .safex.txin_token_migration txin_token_migration = 4; - if (this->has_txin_token_migration()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - *this->txin_token_migration_); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void txin_v::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.txin_v) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const txin_v* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.txin_v) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.txin_v) - MergeFrom(*source); - } -} - -void txin_v::MergeFrom(const txin_v& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.txin_v) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - if (from.has_txin_gen()) { - mutable_txin_gen()->::safex::txin_gen::MergeFrom(from.txin_gen()); - } - if (from.has_txin_to_key()) { - mutable_txin_to_key()->::safex::txin_to_key::MergeFrom(from.txin_to_key()); - } - if (from.has_txin_token_to_key()) { - mutable_txin_token_to_key()->::safex::txin_token_to_key::MergeFrom(from.txin_token_to_key()); - } - if (from.has_txin_token_migration()) { - mutable_txin_token_migration()->::safex::txin_token_migration::MergeFrom(from.txin_token_migration()); - } -} - -void txin_v::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.txin_v) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void txin_v::CopyFrom(const txin_v& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.txin_v) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool txin_v::IsInitialized() const { - - return true; -} - -void txin_v::Swap(txin_v* other) { - if (other == this) return; - InternalSwap(other); -} -void txin_v::InternalSwap(txin_v* other) { - std::swap(txin_gen_, other->txin_gen_); - std::swap(txin_to_key_, other->txin_to_key_); - std::swap(txin_token_to_key_, other->txin_token_to_key_); - std::swap(txin_token_migration_, other->txin_token_migration_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata txin_v::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = txin_v_descriptor_; - metadata.reflection = txin_v_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// txin_v - -// optional .safex.txin_gen txin_gen = 1; -bool txin_v::has_txin_gen() const { - return !_is_default_instance_ && txin_gen_ != NULL; -} -void txin_v::clear_txin_gen() { - if (GetArenaNoVirtual() == NULL && txin_gen_ != NULL) delete txin_gen_; - txin_gen_ = NULL; -} -const ::safex::txin_gen& txin_v::txin_gen() const { - // @@protoc_insertion_point(field_get:safex.txin_v.txin_gen) - return txin_gen_ != NULL ? *txin_gen_ : *default_instance_->txin_gen_; -} -::safex::txin_gen* txin_v::mutable_txin_gen() { - - if (txin_gen_ == NULL) { - txin_gen_ = new ::safex::txin_gen; - } - // @@protoc_insertion_point(field_mutable:safex.txin_v.txin_gen) - return txin_gen_; -} -::safex::txin_gen* txin_v::release_txin_gen() { - // @@protoc_insertion_point(field_release:safex.txin_v.txin_gen) - - ::safex::txin_gen* temp = txin_gen_; - txin_gen_ = NULL; - return temp; -} -void txin_v::set_allocated_txin_gen(::safex::txin_gen* txin_gen) { - delete txin_gen_; - txin_gen_ = txin_gen; - if (txin_gen) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txin_v.txin_gen) -} - -// optional .safex.txin_to_key txin_to_key = 2; -bool txin_v::has_txin_to_key() const { - return !_is_default_instance_ && txin_to_key_ != NULL; -} -void txin_v::clear_txin_to_key() { - if (GetArenaNoVirtual() == NULL && txin_to_key_ != NULL) delete txin_to_key_; - txin_to_key_ = NULL; -} -const ::safex::txin_to_key& txin_v::txin_to_key() const { - // @@protoc_insertion_point(field_get:safex.txin_v.txin_to_key) - return txin_to_key_ != NULL ? *txin_to_key_ : *default_instance_->txin_to_key_; -} -::safex::txin_to_key* txin_v::mutable_txin_to_key() { - - if (txin_to_key_ == NULL) { - txin_to_key_ = new ::safex::txin_to_key; - } - // @@protoc_insertion_point(field_mutable:safex.txin_v.txin_to_key) - return txin_to_key_; -} -::safex::txin_to_key* txin_v::release_txin_to_key() { - // @@protoc_insertion_point(field_release:safex.txin_v.txin_to_key) - - ::safex::txin_to_key* temp = txin_to_key_; - txin_to_key_ = NULL; - return temp; -} -void txin_v::set_allocated_txin_to_key(::safex::txin_to_key* txin_to_key) { - delete txin_to_key_; - txin_to_key_ = txin_to_key; - if (txin_to_key) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txin_v.txin_to_key) -} - -// optional .safex.txin_token_to_key txin_token_to_key = 3; -bool txin_v::has_txin_token_to_key() const { - return !_is_default_instance_ && txin_token_to_key_ != NULL; -} -void txin_v::clear_txin_token_to_key() { - if (GetArenaNoVirtual() == NULL && txin_token_to_key_ != NULL) delete txin_token_to_key_; - txin_token_to_key_ = NULL; -} -const ::safex::txin_token_to_key& txin_v::txin_token_to_key() const { - // @@protoc_insertion_point(field_get:safex.txin_v.txin_token_to_key) - return txin_token_to_key_ != NULL ? *txin_token_to_key_ : *default_instance_->txin_token_to_key_; -} -::safex::txin_token_to_key* txin_v::mutable_txin_token_to_key() { - - if (txin_token_to_key_ == NULL) { - txin_token_to_key_ = new ::safex::txin_token_to_key; - } - // @@protoc_insertion_point(field_mutable:safex.txin_v.txin_token_to_key) - return txin_token_to_key_; -} -::safex::txin_token_to_key* txin_v::release_txin_token_to_key() { - // @@protoc_insertion_point(field_release:safex.txin_v.txin_token_to_key) - - ::safex::txin_token_to_key* temp = txin_token_to_key_; - txin_token_to_key_ = NULL; - return temp; -} -void txin_v::set_allocated_txin_token_to_key(::safex::txin_token_to_key* txin_token_to_key) { - delete txin_token_to_key_; - txin_token_to_key_ = txin_token_to_key; - if (txin_token_to_key) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txin_v.txin_token_to_key) -} - -// optional .safex.txin_token_migration txin_token_migration = 4; -bool txin_v::has_txin_token_migration() const { - return !_is_default_instance_ && txin_token_migration_ != NULL; -} -void txin_v::clear_txin_token_migration() { - if (GetArenaNoVirtual() == NULL && txin_token_migration_ != NULL) delete txin_token_migration_; - txin_token_migration_ = NULL; -} -const ::safex::txin_token_migration& txin_v::txin_token_migration() const { - // @@protoc_insertion_point(field_get:safex.txin_v.txin_token_migration) - return txin_token_migration_ != NULL ? *txin_token_migration_ : *default_instance_->txin_token_migration_; -} -::safex::txin_token_migration* txin_v::mutable_txin_token_migration() { - - if (txin_token_migration_ == NULL) { - txin_token_migration_ = new ::safex::txin_token_migration; - } - // @@protoc_insertion_point(field_mutable:safex.txin_v.txin_token_migration) - return txin_token_migration_; -} -::safex::txin_token_migration* txin_v::release_txin_token_migration() { - // @@protoc_insertion_point(field_release:safex.txin_v.txin_token_migration) - - ::safex::txin_token_migration* temp = txin_token_migration_; - txin_token_migration_ = NULL; - return temp; -} -void txin_v::set_allocated_txin_token_migration(::safex::txin_token_migration* txin_token_migration) { - delete txin_token_migration_; - txin_token_migration_ = txin_token_migration; - if (txin_token_migration) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txin_v.txin_token_migration) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int txout_to_key::kKeyFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -txout_to_key::txout_to_key() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.txout_to_key) -} - -void txout_to_key::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -txout_to_key::txout_to_key(const txout_to_key& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.txout_to_key) -} - -void txout_to_key::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - key_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -txout_to_key::~txout_to_key() { - // @@protoc_insertion_point(destructor:safex.txout_to_key) - SharedDtor(); -} - -void txout_to_key::SharedDtor() { - key_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void txout_to_key::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* txout_to_key::descriptor() { - protobuf_AssignDescriptorsOnce(); - return txout_to_key_descriptor_; -} - -const txout_to_key& txout_to_key::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -txout_to_key* txout_to_key::default_instance_ = NULL; - -txout_to_key* txout_to_key::New(::google::protobuf::Arena* arena) const { - txout_to_key* n = new txout_to_key; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void txout_to_key::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.txout_to_key) - key_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -bool txout_to_key::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.txout_to_key) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional bytes key = 1; - case 1: { - if (tag == 10) { - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_key())); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.txout_to_key) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.txout_to_key) - return false; -#undef DO_ -} - -void txout_to_key::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.txout_to_key) - // optional bytes key = 1; - if (this->key().size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 1, this->key(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.txout_to_key) -} - -::google::protobuf::uint8* txout_to_key::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.txout_to_key) - // optional bytes key = 1; - if (this->key().size() > 0) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 1, this->key(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.txout_to_key) - return target; -} - -int txout_to_key::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.txout_to_key) - int total_size = 0; - - // optional bytes key = 1; - if (this->key().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->key()); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void txout_to_key::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.txout_to_key) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const txout_to_key* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.txout_to_key) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.txout_to_key) - MergeFrom(*source); - } -} - -void txout_to_key::MergeFrom(const txout_to_key& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.txout_to_key) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - if (from.key().size() > 0) { - - key_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.key_); - } -} - -void txout_to_key::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.txout_to_key) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void txout_to_key::CopyFrom(const txout_to_key& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.txout_to_key) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool txout_to_key::IsInitialized() const { - - return true; -} - -void txout_to_key::Swap(txout_to_key* other) { - if (other == this) return; - InternalSwap(other); -} -void txout_to_key::InternalSwap(txout_to_key* other) { - key_.Swap(&other->key_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata txout_to_key::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = txout_to_key_descriptor_; - metadata.reflection = txout_to_key_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// txout_to_key - -// optional bytes key = 1; -void txout_to_key::clear_key() { - key_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& txout_to_key::key() const { - // @@protoc_insertion_point(field_get:safex.txout_to_key.key) - return key_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txout_to_key::set_key(const ::std::string& value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txout_to_key.key) -} - void txout_to_key::set_key(const char* value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txout_to_key.key) -} - void txout_to_key::set_key(const void* value, size_t size) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txout_to_key.key) -} - ::std::string* txout_to_key::mutable_key() { - - // @@protoc_insertion_point(field_mutable:safex.txout_to_key.key) - return key_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* txout_to_key::release_key() { - // @@protoc_insertion_point(field_release:safex.txout_to_key.key) - - return key_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txout_to_key::set_allocated_key(::std::string* key) { - if (key != NULL) { - - } else { - - } - key_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), key); - // @@protoc_insertion_point(field_set_allocated:safex.txout_to_key.key) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int txout_token_to_key::kKeyFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -txout_token_to_key::txout_token_to_key() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.txout_token_to_key) -} - -void txout_token_to_key::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -txout_token_to_key::txout_token_to_key(const txout_token_to_key& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.txout_token_to_key) -} - -void txout_token_to_key::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - key_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -txout_token_to_key::~txout_token_to_key() { - // @@protoc_insertion_point(destructor:safex.txout_token_to_key) - SharedDtor(); -} - -void txout_token_to_key::SharedDtor() { - key_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void txout_token_to_key::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* txout_token_to_key::descriptor() { - protobuf_AssignDescriptorsOnce(); - return txout_token_to_key_descriptor_; -} - -const txout_token_to_key& txout_token_to_key::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -txout_token_to_key* txout_token_to_key::default_instance_ = NULL; - -txout_token_to_key* txout_token_to_key::New(::google::protobuf::Arena* arena) const { - txout_token_to_key* n = new txout_token_to_key; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void txout_token_to_key::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.txout_token_to_key) - key_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -bool txout_token_to_key::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.txout_token_to_key) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional bytes key = 1; - case 1: { - if (tag == 10) { - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_key())); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.txout_token_to_key) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.txout_token_to_key) - return false; -#undef DO_ -} - -void txout_token_to_key::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.txout_token_to_key) - // optional bytes key = 1; - if (this->key().size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 1, this->key(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.txout_token_to_key) -} - -::google::protobuf::uint8* txout_token_to_key::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.txout_token_to_key) - // optional bytes key = 1; - if (this->key().size() > 0) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 1, this->key(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.txout_token_to_key) - return target; -} - -int txout_token_to_key::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.txout_token_to_key) - int total_size = 0; - - // optional bytes key = 1; - if (this->key().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->key()); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void txout_token_to_key::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.txout_token_to_key) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const txout_token_to_key* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.txout_token_to_key) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.txout_token_to_key) - MergeFrom(*source); - } -} - -void txout_token_to_key::MergeFrom(const txout_token_to_key& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.txout_token_to_key) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - if (from.key().size() > 0) { - - key_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.key_); - } -} - -void txout_token_to_key::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.txout_token_to_key) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void txout_token_to_key::CopyFrom(const txout_token_to_key& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.txout_token_to_key) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool txout_token_to_key::IsInitialized() const { - - return true; -} - -void txout_token_to_key::Swap(txout_token_to_key* other) { - if (other == this) return; - InternalSwap(other); -} -void txout_token_to_key::InternalSwap(txout_token_to_key* other) { - key_.Swap(&other->key_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata txout_token_to_key::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = txout_token_to_key_descriptor_; - metadata.reflection = txout_token_to_key_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// txout_token_to_key - -// optional bytes key = 1; -void txout_token_to_key::clear_key() { - key_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& txout_token_to_key::key() const { - // @@protoc_insertion_point(field_get:safex.txout_token_to_key.key) - return key_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txout_token_to_key::set_key(const ::std::string& value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txout_token_to_key.key) -} - void txout_token_to_key::set_key(const char* value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txout_token_to_key.key) -} - void txout_token_to_key::set_key(const void* value, size_t size) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txout_token_to_key.key) -} - ::std::string* txout_token_to_key::mutable_key() { - - // @@protoc_insertion_point(field_mutable:safex.txout_token_to_key.key) - return key_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* txout_token_to_key::release_key() { - // @@protoc_insertion_point(field_release:safex.txout_token_to_key.key) - - return key_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void txout_token_to_key::set_allocated_key(::std::string* key) { - if (key != NULL) { - - } else { - - } - key_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), key); - // @@protoc_insertion_point(field_set_allocated:safex.txout_token_to_key.key) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int txout_target_v::kTxoutToKeyFieldNumber; -const int txout_target_v::kTxoutTokenToKeyFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -txout_target_v::txout_target_v() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.txout_target_v) -} - -void txout_target_v::InitAsDefaultInstance() { - _is_default_instance_ = true; - txout_to_key_ = const_cast< ::safex::txout_to_key*>(&::safex::txout_to_key::default_instance()); - txout_token_to_key_ = const_cast< ::safex::txout_token_to_key*>(&::safex::txout_token_to_key::default_instance()); -} - -txout_target_v::txout_target_v(const txout_target_v& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.txout_target_v) -} - -void txout_target_v::SharedCtor() { - _is_default_instance_ = false; - _cached_size_ = 0; - txout_to_key_ = NULL; - txout_token_to_key_ = NULL; -} - -txout_target_v::~txout_target_v() { - // @@protoc_insertion_point(destructor:safex.txout_target_v) - SharedDtor(); -} - -void txout_target_v::SharedDtor() { - if (this != default_instance_) { - delete txout_to_key_; - delete txout_token_to_key_; - } -} - -void txout_target_v::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* txout_target_v::descriptor() { - protobuf_AssignDescriptorsOnce(); - return txout_target_v_descriptor_; -} - -const txout_target_v& txout_target_v::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -txout_target_v* txout_target_v::default_instance_ = NULL; - -txout_target_v* txout_target_v::New(::google::protobuf::Arena* arena) const { - txout_target_v* n = new txout_target_v; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void txout_target_v::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.txout_target_v) - if (GetArenaNoVirtual() == NULL && txout_to_key_ != NULL) delete txout_to_key_; - txout_to_key_ = NULL; - if (GetArenaNoVirtual() == NULL && txout_token_to_key_ != NULL) delete txout_token_to_key_; - txout_token_to_key_ = NULL; -} - -bool txout_target_v::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.txout_target_v) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional .safex.txout_to_key txout_to_key = 1; - case 1: { - if (tag == 10) { - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_txout_to_key())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_txout_token_to_key; - break; - } - - // optional .safex.txout_token_to_key txout_token_to_key = 2; - case 2: { - if (tag == 18) { - parse_txout_token_to_key: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_txout_token_to_key())); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.txout_target_v) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.txout_target_v) - return false; -#undef DO_ -} - -void txout_target_v::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.txout_target_v) - // optional .safex.txout_to_key txout_to_key = 1; - if (this->has_txout_to_key()) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 1, *this->txout_to_key_, output); - } - - // optional .safex.txout_token_to_key txout_token_to_key = 2; - if (this->has_txout_token_to_key()) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 2, *this->txout_token_to_key_, output); - } - - // @@protoc_insertion_point(serialize_end:safex.txout_target_v) -} - -::google::protobuf::uint8* txout_target_v::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.txout_target_v) - // optional .safex.txout_to_key txout_to_key = 1; - if (this->has_txout_to_key()) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 1, *this->txout_to_key_, false, target); - } - - // optional .safex.txout_token_to_key txout_token_to_key = 2; - if (this->has_txout_token_to_key()) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 2, *this->txout_token_to_key_, false, target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.txout_target_v) - return target; -} - -int txout_target_v::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.txout_target_v) - int total_size = 0; - - // optional .safex.txout_to_key txout_to_key = 1; - if (this->has_txout_to_key()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - *this->txout_to_key_); - } - - // optional .safex.txout_token_to_key txout_token_to_key = 2; - if (this->has_txout_token_to_key()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - *this->txout_token_to_key_); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void txout_target_v::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.txout_target_v) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const txout_target_v* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.txout_target_v) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.txout_target_v) - MergeFrom(*source); - } -} - -void txout_target_v::MergeFrom(const txout_target_v& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.txout_target_v) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - if (from.has_txout_to_key()) { - mutable_txout_to_key()->::safex::txout_to_key::MergeFrom(from.txout_to_key()); - } - if (from.has_txout_token_to_key()) { - mutable_txout_token_to_key()->::safex::txout_token_to_key::MergeFrom(from.txout_token_to_key()); - } -} - -void txout_target_v::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.txout_target_v) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void txout_target_v::CopyFrom(const txout_target_v& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.txout_target_v) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool txout_target_v::IsInitialized() const { - - return true; -} - -void txout_target_v::Swap(txout_target_v* other) { - if (other == this) return; - InternalSwap(other); -} -void txout_target_v::InternalSwap(txout_target_v* other) { - std::swap(txout_to_key_, other->txout_to_key_); - std::swap(txout_token_to_key_, other->txout_token_to_key_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata txout_target_v::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = txout_target_v_descriptor_; - metadata.reflection = txout_target_v_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// txout_target_v - -// optional .safex.txout_to_key txout_to_key = 1; -bool txout_target_v::has_txout_to_key() const { - return !_is_default_instance_ && txout_to_key_ != NULL; -} -void txout_target_v::clear_txout_to_key() { - if (GetArenaNoVirtual() == NULL && txout_to_key_ != NULL) delete txout_to_key_; - txout_to_key_ = NULL; -} -const ::safex::txout_to_key& txout_target_v::txout_to_key() const { - // @@protoc_insertion_point(field_get:safex.txout_target_v.txout_to_key) - return txout_to_key_ != NULL ? *txout_to_key_ : *default_instance_->txout_to_key_; -} -::safex::txout_to_key* txout_target_v::mutable_txout_to_key() { - - if (txout_to_key_ == NULL) { - txout_to_key_ = new ::safex::txout_to_key; - } - // @@protoc_insertion_point(field_mutable:safex.txout_target_v.txout_to_key) - return txout_to_key_; -} -::safex::txout_to_key* txout_target_v::release_txout_to_key() { - // @@protoc_insertion_point(field_release:safex.txout_target_v.txout_to_key) - - ::safex::txout_to_key* temp = txout_to_key_; - txout_to_key_ = NULL; - return temp; -} -void txout_target_v::set_allocated_txout_to_key(::safex::txout_to_key* txout_to_key) { - delete txout_to_key_; - txout_to_key_ = txout_to_key; - if (txout_to_key) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txout_target_v.txout_to_key) -} - -// optional .safex.txout_token_to_key txout_token_to_key = 2; -bool txout_target_v::has_txout_token_to_key() const { - return !_is_default_instance_ && txout_token_to_key_ != NULL; -} -void txout_target_v::clear_txout_token_to_key() { - if (GetArenaNoVirtual() == NULL && txout_token_to_key_ != NULL) delete txout_token_to_key_; - txout_token_to_key_ = NULL; -} -const ::safex::txout_token_to_key& txout_target_v::txout_token_to_key() const { - // @@protoc_insertion_point(field_get:safex.txout_target_v.txout_token_to_key) - return txout_token_to_key_ != NULL ? *txout_token_to_key_ : *default_instance_->txout_token_to_key_; -} -::safex::txout_token_to_key* txout_target_v::mutable_txout_token_to_key() { - - if (txout_token_to_key_ == NULL) { - txout_token_to_key_ = new ::safex::txout_token_to_key; - } - // @@protoc_insertion_point(field_mutable:safex.txout_target_v.txout_token_to_key) - return txout_token_to_key_; -} -::safex::txout_token_to_key* txout_target_v::release_txout_token_to_key() { - // @@protoc_insertion_point(field_release:safex.txout_target_v.txout_token_to_key) - - ::safex::txout_token_to_key* temp = txout_token_to_key_; - txout_token_to_key_ = NULL; - return temp; -} -void txout_target_v::set_allocated_txout_token_to_key(::safex::txout_token_to_key* txout_token_to_key) { - delete txout_token_to_key_; - txout_token_to_key_ = txout_token_to_key; - if (txout_token_to_key) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txout_target_v.txout_token_to_key) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int txout::kAmountFieldNumber; -const int txout::kTokenAmountFieldNumber; -const int txout::kTargetFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -txout::txout() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.txout) -} - -void txout::InitAsDefaultInstance() { - _is_default_instance_ = true; - target_ = const_cast< ::safex::txout_target_v*>(&::safex::txout_target_v::default_instance()); -} - -txout::txout(const txout& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.txout) -} - -void txout::SharedCtor() { - _is_default_instance_ = false; - _cached_size_ = 0; - amount_ = GOOGLE_ULONGLONG(0); - token_amount_ = GOOGLE_ULONGLONG(0); - target_ = NULL; -} - -txout::~txout() { - // @@protoc_insertion_point(destructor:safex.txout) - SharedDtor(); -} - -void txout::SharedDtor() { - if (this != default_instance_) { - delete target_; - } -} - -void txout::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* txout::descriptor() { - protobuf_AssignDescriptorsOnce(); - return txout_descriptor_; -} - -const txout& txout::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -txout* txout::default_instance_ = NULL; - -txout* txout::New(::google::protobuf::Arena* arena) const { - txout* n = new txout; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void txout::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.txout) -#if defined(__clang__) -#define ZR_HELPER_(f) \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ - __builtin_offsetof(txout, f) \ - _Pragma("clang diagnostic pop") -#else -#define ZR_HELPER_(f) reinterpret_cast(\ - &reinterpret_cast(16)->f) -#endif - -#define ZR_(first, last) do {\ - ::memset(&first, 0,\ - ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ -} while (0) - - ZR_(amount_, token_amount_); - if (GetArenaNoVirtual() == NULL && target_ != NULL) delete target_; - target_ = NULL; - -#undef ZR_HELPER_ -#undef ZR_ - -} - -bool txout::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.txout) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 amount = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &amount_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(16)) goto parse_token_amount; - break; - } - - // optional uint64 token_amount = 2; - case 2: { - if (tag == 16) { - parse_token_amount: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &token_amount_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(26)) goto parse_target; - break; - } - - // optional .safex.txout_target_v target = 3; - case 3: { - if (tag == 26) { - parse_target: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_target())); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.txout) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.txout) - return false; -#undef DO_ -} - -void txout::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.txout) - // optional uint64 amount = 1; - if (this->amount() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->amount(), output); - } - - // optional uint64 token_amount = 2; - if (this->token_amount() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(2, this->token_amount(), output); - } - - // optional .safex.txout_target_v target = 3; - if (this->has_target()) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 3, *this->target_, output); - } - - // @@protoc_insertion_point(serialize_end:safex.txout) -} - -::google::protobuf::uint8* txout::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.txout) - // optional uint64 amount = 1; - if (this->amount() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->amount(), target); - } - - // optional uint64 token_amount = 2; - if (this->token_amount() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(2, this->token_amount(), target); - } - - // optional .safex.txout_target_v target = 3; - if (this->has_target()) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 3, *this->target_, false, target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.txout) - return target; -} - -int txout::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.txout) - int total_size = 0; - - // optional uint64 amount = 1; - if (this->amount() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->amount()); - } - - // optional uint64 token_amount = 2; - if (this->token_amount() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->token_amount()); - } - - // optional .safex.txout_target_v target = 3; - if (this->has_target()) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - *this->target_); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void txout::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.txout) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const txout* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.txout) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.txout) - MergeFrom(*source); - } -} - -void txout::MergeFrom(const txout& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.txout) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - if (from.amount() != 0) { - set_amount(from.amount()); - } - if (from.token_amount() != 0) { - set_token_amount(from.token_amount()); - } - if (from.has_target()) { - mutable_target()->::safex::txout_target_v::MergeFrom(from.target()); - } -} - -void txout::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.txout) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void txout::CopyFrom(const txout& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.txout) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool txout::IsInitialized() const { - - return true; -} - -void txout::Swap(txout* other) { - if (other == this) return; - InternalSwap(other); -} -void txout::InternalSwap(txout* other) { - std::swap(amount_, other->amount_); - std::swap(token_amount_, other->token_amount_); - std::swap(target_, other->target_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata txout::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = txout_descriptor_; - metadata.reflection = txout_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// txout - -// optional uint64 amount = 1; -void txout::clear_amount() { - amount_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 txout::amount() const { - // @@protoc_insertion_point(field_get:safex.txout.amount) - return amount_; -} - void txout::set_amount(::google::protobuf::uint64 value) { - - amount_ = value; - // @@protoc_insertion_point(field_set:safex.txout.amount) -} - -// optional uint64 token_amount = 2; -void txout::clear_token_amount() { - token_amount_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 txout::token_amount() const { - // @@protoc_insertion_point(field_get:safex.txout.token_amount) - return token_amount_; -} - void txout::set_token_amount(::google::protobuf::uint64 value) { - - token_amount_ = value; - // @@protoc_insertion_point(field_set:safex.txout.token_amount) -} - -// optional .safex.txout_target_v target = 3; -bool txout::has_target() const { - return !_is_default_instance_ && target_ != NULL; -} -void txout::clear_target() { - if (GetArenaNoVirtual() == NULL && target_ != NULL) delete target_; - target_ = NULL; -} -const ::safex::txout_target_v& txout::target() const { - // @@protoc_insertion_point(field_get:safex.txout.target) - return target_ != NULL ? *target_ : *default_instance_->target_; -} -::safex::txout_target_v* txout::mutable_target() { - - if (target_ == NULL) { - target_ = new ::safex::txout_target_v; - } - // @@protoc_insertion_point(field_mutable:safex.txout.target) - return target_; -} -::safex::txout_target_v* txout::release_target() { - // @@protoc_insertion_point(field_release:safex.txout.target) - - ::safex::txout_target_v* temp = target_; - target_ = NULL; - return temp; -} -void txout::set_allocated_target(::safex::txout_target_v* target) { - delete target_; - target_ = target; - if (target) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txout.target) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int SigData::kRFieldNumber; -const int SigData::kCFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -SigData::SigData() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.SigData) -} - -void SigData::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -SigData::SigData(const SigData& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.SigData) -} - -void SigData::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - r_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - c_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -SigData::~SigData() { - // @@protoc_insertion_point(destructor:safex.SigData) - SharedDtor(); -} - -void SigData::SharedDtor() { - r_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - c_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void SigData::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* SigData::descriptor() { - protobuf_AssignDescriptorsOnce(); - return SigData_descriptor_; -} - -const SigData& SigData::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -SigData* SigData::default_instance_ = NULL; - -SigData* SigData::New(::google::protobuf::Arena* arena) const { - SigData* n = new SigData; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void SigData::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.SigData) - r_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - c_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -bool SigData::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.SigData) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional bytes r = 1; - case 1: { - if (tag == 10) { - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_r())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_c; - break; - } - - // optional bytes c = 2; - case 2: { - if (tag == 18) { - parse_c: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_c())); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.SigData) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.SigData) - return false; -#undef DO_ -} - -void SigData::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.SigData) - // optional bytes r = 1; - if (this->r().size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 1, this->r(), output); - } - - // optional bytes c = 2; - if (this->c().size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 2, this->c(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.SigData) -} - -::google::protobuf::uint8* SigData::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.SigData) - // optional bytes r = 1; - if (this->r().size() > 0) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 1, this->r(), target); - } - - // optional bytes c = 2; - if (this->c().size() > 0) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 2, this->c(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.SigData) - return target; -} - -int SigData::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.SigData) - int total_size = 0; - - // optional bytes r = 1; - if (this->r().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->r()); - } - - // optional bytes c = 2; - if (this->c().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->c()); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void SigData::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.SigData) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const SigData* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.SigData) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.SigData) - MergeFrom(*source); - } -} - -void SigData::MergeFrom(const SigData& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.SigData) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - if (from.r().size() > 0) { - - r_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.r_); - } - if (from.c().size() > 0) { - - c_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.c_); - } -} - -void SigData::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.SigData) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void SigData::CopyFrom(const SigData& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.SigData) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool SigData::IsInitialized() const { - - return true; -} - -void SigData::Swap(SigData* other) { - if (other == this) return; - InternalSwap(other); -} -void SigData::InternalSwap(SigData* other) { - r_.Swap(&other->r_); - c_.Swap(&other->c_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata SigData::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = SigData_descriptor_; - metadata.reflection = SigData_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// SigData - -// optional bytes r = 1; -void SigData::clear_r() { - r_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& SigData::r() const { - // @@protoc_insertion_point(field_get:safex.SigData.r) - return r_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void SigData::set_r(const ::std::string& value) { - - r_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.SigData.r) -} - void SigData::set_r(const char* value) { - - r_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.SigData.r) -} - void SigData::set_r(const void* value, size_t size) { - - r_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.SigData.r) -} - ::std::string* SigData::mutable_r() { - - // @@protoc_insertion_point(field_mutable:safex.SigData.r) - return r_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* SigData::release_r() { - // @@protoc_insertion_point(field_release:safex.SigData.r) - - return r_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void SigData::set_allocated_r(::std::string* r) { - if (r != NULL) { - - } else { - - } - r_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), r); - // @@protoc_insertion_point(field_set_allocated:safex.SigData.r) -} - -// optional bytes c = 2; -void SigData::clear_c() { - c_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& SigData::c() const { - // @@protoc_insertion_point(field_get:safex.SigData.c) - return c_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void SigData::set_c(const ::std::string& value) { - - c_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.SigData.c) -} - void SigData::set_c(const char* value) { - - c_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.SigData.c) -} - void SigData::set_c(const void* value, size_t size) { - - c_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.SigData.c) -} - ::std::string* SigData::mutable_c() { - - // @@protoc_insertion_point(field_mutable:safex.SigData.c) - return c_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* SigData::release_c() { - // @@protoc_insertion_point(field_release:safex.SigData.c) - - return c_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void SigData::set_allocated_c(::std::string* c) { - if (c != NULL) { - - } else { - - } - c_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), c); - // @@protoc_insertion_point(field_set_allocated:safex.SigData.c) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int Signature::kSignatureFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -Signature::Signature() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.Signature) -} - -void Signature::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -Signature::Signature(const Signature& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.Signature) -} - -void Signature::SharedCtor() { - _is_default_instance_ = false; - _cached_size_ = 0; -} - -Signature::~Signature() { - // @@protoc_insertion_point(destructor:safex.Signature) - SharedDtor(); -} - -void Signature::SharedDtor() { - if (this != default_instance_) { - } -} - -void Signature::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Signature::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Signature_descriptor_; -} - -const Signature& Signature::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -Signature* Signature::default_instance_ = NULL; - -Signature* Signature::New(::google::protobuf::Arena* arena) const { - Signature* n = new Signature; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void Signature::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.Signature) - signature_.Clear(); -} - -bool Signature::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.Signature) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // repeated .safex.SigData signature = 1; - case 1: { - if (tag == 10) { - DO_(input->IncrementRecursionDepth()); - parse_loop_signature: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( - input, add_signature())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(10)) goto parse_loop_signature; - input->UnsafeDecrementRecursionDepth(); - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.Signature) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.Signature) - return false; -#undef DO_ -} - -void Signature::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.Signature) - // repeated .safex.SigData signature = 1; - for (unsigned int i = 0, n = this->signature_size(); i < n; i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 1, this->signature(i), output); - } - - // @@protoc_insertion_point(serialize_end:safex.Signature) -} - -::google::protobuf::uint8* Signature::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.Signature) - // repeated .safex.SigData signature = 1; - for (unsigned int i = 0, n = this->signature_size(); i < n; i++) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 1, this->signature(i), false, target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.Signature) - return target; -} - -int Signature::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.Signature) - int total_size = 0; - - // repeated .safex.SigData signature = 1; - total_size += 1 * this->signature_size(); - for (int i = 0; i < this->signature_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->signature(i)); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Signature::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.Signature) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const Signature* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.Signature) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.Signature) - MergeFrom(*source); - } -} - -void Signature::MergeFrom(const Signature& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.Signature) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - signature_.MergeFrom(from.signature_); -} - -void Signature::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.Signature) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Signature::CopyFrom(const Signature& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.Signature) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Signature::IsInitialized() const { - - return true; -} - -void Signature::Swap(Signature* other) { - if (other == this) return; - InternalSwap(other); -} -void Signature::InternalSwap(Signature* other) { - signature_.UnsafeArenaSwap(&other->signature_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata Signature::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Signature_descriptor_; - metadata.reflection = Signature_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// Signature - -// repeated .safex.SigData signature = 1; -int Signature::signature_size() const { - return signature_.size(); -} -void Signature::clear_signature() { - signature_.Clear(); -} -const ::safex::SigData& Signature::signature(int index) const { - // @@protoc_insertion_point(field_get:safex.Signature.signature) - return signature_.Get(index); -} -::safex::SigData* Signature::mutable_signature(int index) { - // @@protoc_insertion_point(field_mutable:safex.Signature.signature) - return signature_.Mutable(index); -} -::safex::SigData* Signature::add_signature() { - // @@protoc_insertion_point(field_add:safex.Signature.signature) - return signature_.Add(); -} -::google::protobuf::RepeatedPtrField< ::safex::SigData >* -Signature::mutable_signature() { - // @@protoc_insertion_point(field_mutable_list:safex.Signature.signature) - return &signature_; -} -const ::google::protobuf::RepeatedPtrField< ::safex::SigData >& -Signature::signature() const { - // @@protoc_insertion_point(field_list:safex.Signature.signature) - return signature_; -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int Transaction::kVersionFieldNumber; -const int Transaction::kUnlockTimeFieldNumber; -const int Transaction::kExtraFieldNumber; -const int Transaction::kVinFieldNumber; -const int Transaction::kVoutFieldNumber; -const int Transaction::kSignaturesFieldNumber; -const int Transaction::kBlockHeightFieldNumber; -const int Transaction::kBlockTimestampFieldNumber; -const int Transaction::kDoubleSpendSeenFieldNumber; -const int Transaction::kInPoolFieldNumber; -const int Transaction::kOutputIndicesFieldNumber; -const int Transaction::kTxHashFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -Transaction::Transaction() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.Transaction) -} - -void Transaction::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -Transaction::Transaction(const Transaction& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.Transaction) -} - -void Transaction::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; - version_ = GOOGLE_ULONGLONG(0); - unlock_time_ = GOOGLE_ULONGLONG(0); - extra_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - block_height_ = GOOGLE_ULONGLONG(0); - block_timestamp_ = GOOGLE_ULONGLONG(0); - double_spend_seen_ = false; - in_pool_ = false; - tx_hash_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - -Transaction::~Transaction() { - // @@protoc_insertion_point(destructor:safex.Transaction) - SharedDtor(); -} - -void Transaction::SharedDtor() { - extra_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - tx_hash_.DestroyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - if (this != default_instance_) { - } -} - -void Transaction::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Transaction::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Transaction_descriptor_; -} - -const Transaction& Transaction::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -Transaction* Transaction::default_instance_ = NULL; - -Transaction* Transaction::New(::google::protobuf::Arena* arena) const { - Transaction* n = new Transaction; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void Transaction::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.Transaction) -#if defined(__clang__) -#define ZR_HELPER_(f) \ - _Pragma("clang diagnostic push") \ - _Pragma("clang diagnostic ignored \"-Winvalid-offsetof\"") \ - __builtin_offsetof(Transaction, f) \ - _Pragma("clang diagnostic pop") -#else -#define ZR_HELPER_(f) reinterpret_cast(\ - &reinterpret_cast(16)->f) -#endif - -#define ZR_(first, last) do {\ - ::memset(&first, 0,\ - ZR_HELPER_(last) - ZR_HELPER_(first) + sizeof(last));\ -} while (0) - - ZR_(version_, unlock_time_); - ZR_(block_height_, block_timestamp_); - extra_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - ZR_(double_spend_seen_, in_pool_); - tx_hash_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); - -#undef ZR_HELPER_ -#undef ZR_ - - vin_.Clear(); - vout_.Clear(); - signatures_.Clear(); - output_indices_.Clear(); -} - -bool Transaction::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.Transaction) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional uint64 version = 1; - case 1: { - if (tag == 8) { - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &version_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(16)) goto parse_unlock_time; - break; - } - - // optional uint64 unlock_time = 2; - case 2: { - if (tag == 16) { - parse_unlock_time: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &unlock_time_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(26)) goto parse_extra; - break; - } - - // optional bytes extra = 3; - case 3: { - if (tag == 26) { - parse_extra: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_extra())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(34)) goto parse_vin; - break; - } - - // repeated .safex.txin_v vin = 4; - case 4: { - if (tag == 34) { - parse_vin: - DO_(input->IncrementRecursionDepth()); - parse_loop_vin: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( - input, add_vin())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(34)) goto parse_loop_vin; - if (input->ExpectTag(42)) goto parse_loop_vout; - input->UnsafeDecrementRecursionDepth(); - break; - } - - // repeated .safex.txout vout = 5; - case 5: { - if (tag == 42) { - DO_(input->IncrementRecursionDepth()); - parse_loop_vout: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( - input, add_vout())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(42)) goto parse_loop_vout; - if (input->ExpectTag(50)) goto parse_loop_signatures; - input->UnsafeDecrementRecursionDepth(); - break; - } - - // repeated .safex.Signature signatures = 6; - case 6: { - if (tag == 50) { - DO_(input->IncrementRecursionDepth()); - parse_loop_signatures: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( - input, add_signatures())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(50)) goto parse_loop_signatures; - input->UnsafeDecrementRecursionDepth(); - if (input->ExpectTag(56)) goto parse_block_height; - break; - } - - // optional uint64 block_height = 7; - case 7: { - if (tag == 56) { - parse_block_height: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &block_height_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(64)) goto parse_block_timestamp; - break; - } - - // optional uint64 block_timestamp = 8; - case 8: { - if (tag == 64) { - parse_block_timestamp: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, &block_timestamp_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(72)) goto parse_double_spend_seen; - break; - } - - // optional bool double_spend_seen = 9; - case 9: { - if (tag == 72) { - parse_double_spend_seen: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - input, &double_spend_seen_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(80)) goto parse_in_pool; - break; - } - - // optional bool in_pool = 10; - case 10: { - if (tag == 80) { - parse_in_pool: - DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< - bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( - input, &in_pool_))); - - } else { - goto handle_unusual; - } - if (input->ExpectTag(90)) goto parse_output_indices; - break; - } - - // repeated uint64 output_indices = 11; - case 11: { - if (tag == 90) { - parse_output_indices: - DO_((::google::protobuf::internal::WireFormatLite::ReadPackedPrimitive< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - input, this->mutable_output_indices()))); - } else if (tag == 88) { - DO_((::google::protobuf::internal::WireFormatLite::ReadRepeatedPrimitiveNoInline< - ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( - 1, 90, input, this->mutable_output_indices()))); - } else { - goto handle_unusual; - } - if (input->ExpectTag(98)) goto parse_tx_hash; - break; - } - - // optional string tx_hash = 12; - case 12: { - if (tag == 98) { - parse_tx_hash: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_tx_hash())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->tx_hash().data(), this->tx_hash().length(), - ::google::protobuf::internal::WireFormatLite::PARSE, - "safex.Transaction.tx_hash")); - } else { - goto handle_unusual; - } - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.Transaction) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.Transaction) - return false; -#undef DO_ -} - -void Transaction::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.Transaction) - // optional uint64 version = 1; - if (this->version() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(1, this->version(), output); - } - - // optional uint64 unlock_time = 2; - if (this->unlock_time() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(2, this->unlock_time(), output); - } - - // optional bytes extra = 3; - if (this->extra().size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteBytesMaybeAliased( - 3, this->extra(), output); - } - - // repeated .safex.txin_v vin = 4; - for (unsigned int i = 0, n = this->vin_size(); i < n; i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 4, this->vin(i), output); - } - - // repeated .safex.txout vout = 5; - for (unsigned int i = 0, n = this->vout_size(); i < n; i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 5, this->vout(i), output); - } - - // repeated .safex.Signature signatures = 6; - for (unsigned int i = 0, n = this->signatures_size(); i < n; i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 6, this->signatures(i), output); - } - - // optional uint64 block_height = 7; - if (this->block_height() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(7, this->block_height(), output); - } - - // optional uint64 block_timestamp = 8; - if (this->block_timestamp() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64(8, this->block_timestamp(), output); - } - - // optional bool double_spend_seen = 9; - if (this->double_spend_seen() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteBool(9, this->double_spend_seen(), output); - } - - // optional bool in_pool = 10; - if (this->in_pool() != 0) { - ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->in_pool(), output); - } - - // repeated uint64 output_indices = 11; - if (this->output_indices_size() > 0) { - ::google::protobuf::internal::WireFormatLite::WriteTag(11, ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(_output_indices_cached_byte_size_); - } - for (int i = 0; i < this->output_indices_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteUInt64NoTag( - this->output_indices(i), output); - } - - // optional string tx_hash = 12; - if (this->tx_hash().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->tx_hash().data(), this->tx_hash().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Transaction.tx_hash"); - ::google::protobuf::internal::WireFormatLite::WriteStringMaybeAliased( - 12, this->tx_hash(), output); - } - - // @@protoc_insertion_point(serialize_end:safex.Transaction) -} - -::google::protobuf::uint8* Transaction::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.Transaction) - // optional uint64 version = 1; - if (this->version() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(1, this->version(), target); - } - - // optional uint64 unlock_time = 2; - if (this->unlock_time() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(2, this->unlock_time(), target); - } - - // optional bytes extra = 3; - if (this->extra().size() > 0) { - target = - ::google::protobuf::internal::WireFormatLite::WriteBytesToArray( - 3, this->extra(), target); - } - - // repeated .safex.txin_v vin = 4; - for (unsigned int i = 0, n = this->vin_size(); i < n; i++) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 4, this->vin(i), false, target); - } - - // repeated .safex.txout vout = 5; - for (unsigned int i = 0, n = this->vout_size(); i < n; i++) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 5, this->vout(i), false, target); - } - - // repeated .safex.Signature signatures = 6; - for (unsigned int i = 0, n = this->signatures_size(); i < n; i++) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 6, this->signatures(i), false, target); - } - - // optional uint64 block_height = 7; - if (this->block_height() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(7, this->block_height(), target); - } - - // optional uint64 block_timestamp = 8; - if (this->block_timestamp() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteUInt64ToArray(8, this->block_timestamp(), target); - } - - // optional bool double_spend_seen = 9; - if (this->double_spend_seen() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(9, this->double_spend_seen(), target); - } - - // optional bool in_pool = 10; - if (this->in_pool() != 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->in_pool(), target); - } - - // repeated uint64 output_indices = 11; - if (this->output_indices_size() > 0) { - target = ::google::protobuf::internal::WireFormatLite::WriteTagToArray( - 11, - ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED, - target); - target = ::google::protobuf::io::CodedOutputStream::WriteVarint32ToArray( - _output_indices_cached_byte_size_, target); - } - for (int i = 0; i < this->output_indices_size(); i++) { - target = ::google::protobuf::internal::WireFormatLite:: - WriteUInt64NoTagToArray(this->output_indices(i), target); - } - - // optional string tx_hash = 12; - if (this->tx_hash().size() > 0) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->tx_hash().data(), this->tx_hash().length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Transaction.tx_hash"); - target = - ::google::protobuf::internal::WireFormatLite::WriteStringToArray( - 12, this->tx_hash(), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.Transaction) - return target; -} - -int Transaction::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.Transaction) - int total_size = 0; - - // optional uint64 version = 1; - if (this->version() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->version()); - } - - // optional uint64 unlock_time = 2; - if (this->unlock_time() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->unlock_time()); - } - - // optional bytes extra = 3; - if (this->extra().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::BytesSize( - this->extra()); - } - - // optional uint64 block_height = 7; - if (this->block_height() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->block_height()); - } - - // optional uint64 block_timestamp = 8; - if (this->block_timestamp() != 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::UInt64Size( - this->block_timestamp()); - } - - // optional bool double_spend_seen = 9; - if (this->double_spend_seen() != 0) { - total_size += 1 + 1; - } - - // optional bool in_pool = 10; - if (this->in_pool() != 0) { - total_size += 1 + 1; - } - - // optional string tx_hash = 12; - if (this->tx_hash().size() > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::StringSize( - this->tx_hash()); - } - - // repeated .safex.txin_v vin = 4; - total_size += 1 * this->vin_size(); - for (int i = 0; i < this->vin_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->vin(i)); - } - - // repeated .safex.txout vout = 5; - total_size += 1 * this->vout_size(); - for (int i = 0; i < this->vout_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->vout(i)); - } - - // repeated .safex.Signature signatures = 6; - total_size += 1 * this->signatures_size(); - for (int i = 0; i < this->signatures_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->signatures(i)); - } - - // repeated uint64 output_indices = 11; - { - int data_size = 0; - for (int i = 0; i < this->output_indices_size(); i++) { - data_size += ::google::protobuf::internal::WireFormatLite:: - UInt64Size(this->output_indices(i)); - } - if (data_size > 0) { - total_size += 1 + - ::google::protobuf::internal::WireFormatLite::Int32Size(data_size); - } - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _output_indices_cached_byte_size_ = data_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - total_size += data_size; - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Transaction::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.Transaction) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const Transaction* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.Transaction) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.Transaction) - MergeFrom(*source); - } -} - -void Transaction::MergeFrom(const Transaction& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.Transaction) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - vin_.MergeFrom(from.vin_); - vout_.MergeFrom(from.vout_); - signatures_.MergeFrom(from.signatures_); - output_indices_.MergeFrom(from.output_indices_); - if (from.version() != 0) { - set_version(from.version()); - } - if (from.unlock_time() != 0) { - set_unlock_time(from.unlock_time()); - } - if (from.extra().size() > 0) { - - extra_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.extra_); - } - if (from.block_height() != 0) { - set_block_height(from.block_height()); - } - if (from.block_timestamp() != 0) { - set_block_timestamp(from.block_timestamp()); - } - if (from.double_spend_seen() != 0) { - set_double_spend_seen(from.double_spend_seen()); - } - if (from.in_pool() != 0) { - set_in_pool(from.in_pool()); - } - if (from.tx_hash().size() > 0) { - - tx_hash_.AssignWithDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), from.tx_hash_); - } -} - -void Transaction::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.Transaction) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Transaction::CopyFrom(const Transaction& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.Transaction) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Transaction::IsInitialized() const { - - return true; -} - -void Transaction::Swap(Transaction* other) { - if (other == this) return; - InternalSwap(other); -} -void Transaction::InternalSwap(Transaction* other) { - std::swap(version_, other->version_); - std::swap(unlock_time_, other->unlock_time_); - extra_.Swap(&other->extra_); - vin_.UnsafeArenaSwap(&other->vin_); - vout_.UnsafeArenaSwap(&other->vout_); - signatures_.UnsafeArenaSwap(&other->signatures_); - std::swap(block_height_, other->block_height_); - std::swap(block_timestamp_, other->block_timestamp_); - std::swap(double_spend_seen_, other->double_spend_seen_); - std::swap(in_pool_, other->in_pool_); - output_indices_.UnsafeArenaSwap(&other->output_indices_); - tx_hash_.Swap(&other->tx_hash_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata Transaction::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Transaction_descriptor_; - metadata.reflection = Transaction_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// Transaction - -// optional uint64 version = 1; -void Transaction::clear_version() { - version_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 Transaction::version() const { - // @@protoc_insertion_point(field_get:safex.Transaction.version) - return version_; -} - void Transaction::set_version(::google::protobuf::uint64 value) { - - version_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.version) -} - -// optional uint64 unlock_time = 2; -void Transaction::clear_unlock_time() { - unlock_time_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 Transaction::unlock_time() const { - // @@protoc_insertion_point(field_get:safex.Transaction.unlock_time) - return unlock_time_; -} - void Transaction::set_unlock_time(::google::protobuf::uint64 value) { - - unlock_time_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.unlock_time) -} - -// optional bytes extra = 3; -void Transaction::clear_extra() { - extra_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& Transaction::extra() const { - // @@protoc_insertion_point(field_get:safex.Transaction.extra) - return extra_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Transaction::set_extra(const ::std::string& value) { - - extra_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Transaction.extra) -} - void Transaction::set_extra(const char* value) { - - extra_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Transaction.extra) -} - void Transaction::set_extra(const void* value, size_t size) { - - extra_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Transaction.extra) -} - ::std::string* Transaction::mutable_extra() { - - // @@protoc_insertion_point(field_mutable:safex.Transaction.extra) - return extra_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* Transaction::release_extra() { - // @@protoc_insertion_point(field_release:safex.Transaction.extra) - - return extra_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Transaction::set_allocated_extra(::std::string* extra) { - if (extra != NULL) { - - } else { - - } - extra_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), extra); - // @@protoc_insertion_point(field_set_allocated:safex.Transaction.extra) -} - -// repeated .safex.txin_v vin = 4; -int Transaction::vin_size() const { - return vin_.size(); -} -void Transaction::clear_vin() { - vin_.Clear(); -} -const ::safex::txin_v& Transaction::vin(int index) const { - // @@protoc_insertion_point(field_get:safex.Transaction.vin) - return vin_.Get(index); -} -::safex::txin_v* Transaction::mutable_vin(int index) { - // @@protoc_insertion_point(field_mutable:safex.Transaction.vin) - return vin_.Mutable(index); -} -::safex::txin_v* Transaction::add_vin() { - // @@protoc_insertion_point(field_add:safex.Transaction.vin) - return vin_.Add(); -} -::google::protobuf::RepeatedPtrField< ::safex::txin_v >* -Transaction::mutable_vin() { - // @@protoc_insertion_point(field_mutable_list:safex.Transaction.vin) - return &vin_; -} -const ::google::protobuf::RepeatedPtrField< ::safex::txin_v >& -Transaction::vin() const { - // @@protoc_insertion_point(field_list:safex.Transaction.vin) - return vin_; -} - -// repeated .safex.txout vout = 5; -int Transaction::vout_size() const { - return vout_.size(); -} -void Transaction::clear_vout() { - vout_.Clear(); -} -const ::safex::txout& Transaction::vout(int index) const { - // @@protoc_insertion_point(field_get:safex.Transaction.vout) - return vout_.Get(index); -} -::safex::txout* Transaction::mutable_vout(int index) { - // @@protoc_insertion_point(field_mutable:safex.Transaction.vout) - return vout_.Mutable(index); -} -::safex::txout* Transaction::add_vout() { - // @@protoc_insertion_point(field_add:safex.Transaction.vout) - return vout_.Add(); -} -::google::protobuf::RepeatedPtrField< ::safex::txout >* -Transaction::mutable_vout() { - // @@protoc_insertion_point(field_mutable_list:safex.Transaction.vout) - return &vout_; -} -const ::google::protobuf::RepeatedPtrField< ::safex::txout >& -Transaction::vout() const { - // @@protoc_insertion_point(field_list:safex.Transaction.vout) - return vout_; -} - -// repeated .safex.Signature signatures = 6; -int Transaction::signatures_size() const { - return signatures_.size(); -} -void Transaction::clear_signatures() { - signatures_.Clear(); -} -const ::safex::Signature& Transaction::signatures(int index) const { - // @@protoc_insertion_point(field_get:safex.Transaction.signatures) - return signatures_.Get(index); -} -::safex::Signature* Transaction::mutable_signatures(int index) { - // @@protoc_insertion_point(field_mutable:safex.Transaction.signatures) - return signatures_.Mutable(index); -} -::safex::Signature* Transaction::add_signatures() { - // @@protoc_insertion_point(field_add:safex.Transaction.signatures) - return signatures_.Add(); -} -::google::protobuf::RepeatedPtrField< ::safex::Signature >* -Transaction::mutable_signatures() { - // @@protoc_insertion_point(field_mutable_list:safex.Transaction.signatures) - return &signatures_; -} -const ::google::protobuf::RepeatedPtrField< ::safex::Signature >& -Transaction::signatures() const { - // @@protoc_insertion_point(field_list:safex.Transaction.signatures) - return signatures_; -} - -// optional uint64 block_height = 7; -void Transaction::clear_block_height() { - block_height_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 Transaction::block_height() const { - // @@protoc_insertion_point(field_get:safex.Transaction.block_height) - return block_height_; -} - void Transaction::set_block_height(::google::protobuf::uint64 value) { - - block_height_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.block_height) -} - -// optional uint64 block_timestamp = 8; -void Transaction::clear_block_timestamp() { - block_timestamp_ = GOOGLE_ULONGLONG(0); -} - ::google::protobuf::uint64 Transaction::block_timestamp() const { - // @@protoc_insertion_point(field_get:safex.Transaction.block_timestamp) - return block_timestamp_; -} - void Transaction::set_block_timestamp(::google::protobuf::uint64 value) { - - block_timestamp_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.block_timestamp) -} - -// optional bool double_spend_seen = 9; -void Transaction::clear_double_spend_seen() { - double_spend_seen_ = false; -} - bool Transaction::double_spend_seen() const { - // @@protoc_insertion_point(field_get:safex.Transaction.double_spend_seen) - return double_spend_seen_; -} - void Transaction::set_double_spend_seen(bool value) { - - double_spend_seen_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.double_spend_seen) -} - -// optional bool in_pool = 10; -void Transaction::clear_in_pool() { - in_pool_ = false; -} - bool Transaction::in_pool() const { - // @@protoc_insertion_point(field_get:safex.Transaction.in_pool) - return in_pool_; -} - void Transaction::set_in_pool(bool value) { - - in_pool_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.in_pool) -} - -// repeated uint64 output_indices = 11; -int Transaction::output_indices_size() const { - return output_indices_.size(); -} -void Transaction::clear_output_indices() { - output_indices_.Clear(); -} - ::google::protobuf::uint64 Transaction::output_indices(int index) const { - // @@protoc_insertion_point(field_get:safex.Transaction.output_indices) - return output_indices_.Get(index); -} - void Transaction::set_output_indices(int index, ::google::protobuf::uint64 value) { - output_indices_.Set(index, value); - // @@protoc_insertion_point(field_set:safex.Transaction.output_indices) -} - void Transaction::add_output_indices(::google::protobuf::uint64 value) { - output_indices_.Add(value); - // @@protoc_insertion_point(field_add:safex.Transaction.output_indices) -} - const ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >& -Transaction::output_indices() const { - // @@protoc_insertion_point(field_list:safex.Transaction.output_indices) - return output_indices_; -} - ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >* -Transaction::mutable_output_indices() { - // @@protoc_insertion_point(field_mutable_list:safex.Transaction.output_indices) - return &output_indices_; -} - -// optional string tx_hash = 12; -void Transaction::clear_tx_hash() { - tx_hash_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - const ::std::string& Transaction::tx_hash() const { - // @@protoc_insertion_point(field_get:safex.Transaction.tx_hash) - return tx_hash_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Transaction::set_tx_hash(const ::std::string& value) { - - tx_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Transaction.tx_hash) -} - void Transaction::set_tx_hash(const char* value) { - - tx_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Transaction.tx_hash) -} - void Transaction::set_tx_hash(const char* value, size_t size) { - - tx_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Transaction.tx_hash) -} - ::std::string* Transaction::mutable_tx_hash() { - - // @@protoc_insertion_point(field_mutable:safex.Transaction.tx_hash) - return tx_hash_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - ::std::string* Transaction::release_tx_hash() { - // @@protoc_insertion_point(field_release:safex.Transaction.tx_hash) - - return tx_hash_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} - void Transaction::set_allocated_tx_hash(::std::string* tx_hash) { - if (tx_hash != NULL) { - - } else { - - } - tx_hash_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), tx_hash); - // @@protoc_insertion_point(field_set_allocated:safex.Transaction.tx_hash) -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// =================================================================== - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 -const int Transactions::kTxFieldNumber; -const int Transactions::kMissedTxsFieldNumber; -#endif // !defined(_MSC_VER) || _MSC_VER >= 1900 - -Transactions::Transactions() - : ::google::protobuf::Message(), _internal_metadata_(NULL) { - SharedCtor(); - // @@protoc_insertion_point(constructor:safex.Transactions) -} - -void Transactions::InitAsDefaultInstance() { - _is_default_instance_ = true; -} - -Transactions::Transactions(const Transactions& from) - : ::google::protobuf::Message(), - _internal_metadata_(NULL) { - SharedCtor(); - MergeFrom(from); - // @@protoc_insertion_point(copy_constructor:safex.Transactions) -} - -void Transactions::SharedCtor() { - _is_default_instance_ = false; - ::google::protobuf::internal::GetEmptyString(); - _cached_size_ = 0; -} - -Transactions::~Transactions() { - // @@protoc_insertion_point(destructor:safex.Transactions) - SharedDtor(); -} - -void Transactions::SharedDtor() { - if (this != default_instance_) { - } -} - -void Transactions::SetCachedSize(int size) const { - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); -} -const ::google::protobuf::Descriptor* Transactions::descriptor() { - protobuf_AssignDescriptorsOnce(); - return Transactions_descriptor_; -} - -const Transactions& Transactions::default_instance() { - if (default_instance_ == NULL) protobuf_AddDesc_transactions_2eproto(); - return *default_instance_; -} - -Transactions* Transactions::default_instance_ = NULL; - -Transactions* Transactions::New(::google::protobuf::Arena* arena) const { - Transactions* n = new Transactions; - if (arena != NULL) { - arena->Own(n); - } - return n; -} - -void Transactions::Clear() { -// @@protoc_insertion_point(message_clear_start:safex.Transactions) - tx_.Clear(); - missed_txs_.Clear(); -} - -bool Transactions::MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input) { -#define DO_(EXPRESSION) if (!GOOGLE_PREDICT_TRUE(EXPRESSION)) goto failure - ::google::protobuf::uint32 tag; - // @@protoc_insertion_point(parse_start:safex.Transactions) - for (;;) { - ::std::pair< ::google::protobuf::uint32, bool> p = input->ReadTagWithCutoff(127); - tag = p.first; - if (!p.second) goto handle_unusual; - switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // repeated .safex.Transaction tx = 1; - case 1: { - if (tag == 10) { - DO_(input->IncrementRecursionDepth()); - parse_loop_tx: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtualNoRecursionDepth( - input, add_tx())); - } else { - goto handle_unusual; - } - if (input->ExpectTag(10)) goto parse_loop_tx; - input->UnsafeDecrementRecursionDepth(); - if (input->ExpectTag(18)) goto parse_missed_txs; - break; - } - - // repeated string missed_txs = 2; - case 2: { - if (tag == 18) { - parse_missed_txs: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->add_missed_txs())); - DO_(::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->missed_txs(this->missed_txs_size() - 1).data(), - this->missed_txs(this->missed_txs_size() - 1).length(), - ::google::protobuf::internal::WireFormatLite::PARSE, - "safex.Transactions.missed_txs")); - } else { - goto handle_unusual; - } - if (input->ExpectTag(18)) goto parse_missed_txs; - if (input->ExpectAtEnd()) goto success; - break; - } - - default: { - handle_unusual: - if (tag == 0 || - ::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == - ::google::protobuf::internal::WireFormatLite::WIRETYPE_END_GROUP) { - goto success; - } - DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag)); - break; - } - } - } -success: - // @@protoc_insertion_point(parse_success:safex.Transactions) - return true; -failure: - // @@protoc_insertion_point(parse_failure:safex.Transactions) - return false; -#undef DO_ -} - -void Transactions::SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const { - // @@protoc_insertion_point(serialize_start:safex.Transactions) - // repeated .safex.Transaction tx = 1; - for (unsigned int i = 0, n = this->tx_size(); i < n; i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( - 1, this->tx(i), output); - } - - // repeated string missed_txs = 2; - for (int i = 0; i < this->missed_txs_size(); i++) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->missed_txs(i).data(), this->missed_txs(i).length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Transactions.missed_txs"); - ::google::protobuf::internal::WireFormatLite::WriteString( - 2, this->missed_txs(i), output); - } - - // @@protoc_insertion_point(serialize_end:safex.Transactions) -} - -::google::protobuf::uint8* Transactions::InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* target) const { - // @@protoc_insertion_point(serialize_to_array_start:safex.Transactions) - // repeated .safex.Transaction tx = 1; - for (unsigned int i = 0, n = this->tx_size(); i < n; i++) { - target = ::google::protobuf::internal::WireFormatLite:: - InternalWriteMessageNoVirtualToArray( - 1, this->tx(i), false, target); - } - - // repeated string missed_txs = 2; - for (int i = 0; i < this->missed_txs_size(); i++) { - ::google::protobuf::internal::WireFormatLite::VerifyUtf8String( - this->missed_txs(i).data(), this->missed_txs(i).length(), - ::google::protobuf::internal::WireFormatLite::SERIALIZE, - "safex.Transactions.missed_txs"); - target = ::google::protobuf::internal::WireFormatLite:: - WriteStringToArray(2, this->missed_txs(i), target); - } - - // @@protoc_insertion_point(serialize_to_array_end:safex.Transactions) - return target; -} - -int Transactions::ByteSize() const { -// @@protoc_insertion_point(message_byte_size_start:safex.Transactions) - int total_size = 0; - - // repeated .safex.Transaction tx = 1; - total_size += 1 * this->tx_size(); - for (int i = 0; i < this->tx_size(); i++) { - total_size += - ::google::protobuf::internal::WireFormatLite::MessageSizeNoVirtual( - this->tx(i)); - } - - // repeated string missed_txs = 2; - total_size += 1 * this->missed_txs_size(); - for (int i = 0; i < this->missed_txs_size(); i++) { - total_size += ::google::protobuf::internal::WireFormatLite::StringSize( - this->missed_txs(i)); - } - - GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); - _cached_size_ = total_size; - GOOGLE_SAFE_CONCURRENT_WRITES_END(); - return total_size; -} - -void Transactions::MergeFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_merge_from_start:safex.Transactions) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - const Transactions* source = - ::google::protobuf::internal::DynamicCastToGenerated( - &from); - if (source == NULL) { - // @@protoc_insertion_point(generalized_merge_from_cast_fail:safex.Transactions) - ::google::protobuf::internal::ReflectionOps::Merge(from, this); - } else { - // @@protoc_insertion_point(generalized_merge_from_cast_success:safex.Transactions) - MergeFrom(*source); - } -} - -void Transactions::MergeFrom(const Transactions& from) { -// @@protoc_insertion_point(class_specific_merge_from_start:safex.Transactions) - if (GOOGLE_PREDICT_FALSE(&from == this)) { - ::google::protobuf::internal::MergeFromFail(__FILE__, __LINE__); - } - tx_.MergeFrom(from.tx_); - missed_txs_.MergeFrom(from.missed_txs_); -} - -void Transactions::CopyFrom(const ::google::protobuf::Message& from) { -// @@protoc_insertion_point(generalized_copy_from_start:safex.Transactions) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -void Transactions::CopyFrom(const Transactions& from) { -// @@protoc_insertion_point(class_specific_copy_from_start:safex.Transactions) - if (&from == this) return; - Clear(); - MergeFrom(from); -} - -bool Transactions::IsInitialized() const { - - return true; -} - -void Transactions::Swap(Transactions* other) { - if (other == this) return; - InternalSwap(other); -} -void Transactions::InternalSwap(Transactions* other) { - tx_.UnsafeArenaSwap(&other->tx_); - missed_txs_.UnsafeArenaSwap(&other->missed_txs_); - _internal_metadata_.Swap(&other->_internal_metadata_); - std::swap(_cached_size_, other->_cached_size_); -} - -::google::protobuf::Metadata Transactions::GetMetadata() const { - protobuf_AssignDescriptorsOnce(); - ::google::protobuf::Metadata metadata; - metadata.descriptor = Transactions_descriptor_; - metadata.reflection = Transactions_reflection_; - return metadata; -} - -#if PROTOBUF_INLINE_NOT_IN_HEADERS -// Transactions - -// repeated .safex.Transaction tx = 1; -int Transactions::tx_size() const { - return tx_.size(); -} -void Transactions::clear_tx() { - tx_.Clear(); -} -const ::safex::Transaction& Transactions::tx(int index) const { - // @@protoc_insertion_point(field_get:safex.Transactions.tx) - return tx_.Get(index); -} -::safex::Transaction* Transactions::mutable_tx(int index) { - // @@protoc_insertion_point(field_mutable:safex.Transactions.tx) - return tx_.Mutable(index); -} -::safex::Transaction* Transactions::add_tx() { - // @@protoc_insertion_point(field_add:safex.Transactions.tx) - return tx_.Add(); -} -::google::protobuf::RepeatedPtrField< ::safex::Transaction >* -Transactions::mutable_tx() { - // @@protoc_insertion_point(field_mutable_list:safex.Transactions.tx) - return &tx_; -} -const ::google::protobuf::RepeatedPtrField< ::safex::Transaction >& -Transactions::tx() const { - // @@protoc_insertion_point(field_list:safex.Transactions.tx) - return tx_; -} - -// repeated string missed_txs = 2; -int Transactions::missed_txs_size() const { - return missed_txs_.size(); -} -void Transactions::clear_missed_txs() { - missed_txs_.Clear(); -} - const ::std::string& Transactions::missed_txs(int index) const { - // @@protoc_insertion_point(field_get:safex.Transactions.missed_txs) - return missed_txs_.Get(index); -} - ::std::string* Transactions::mutable_missed_txs(int index) { - // @@protoc_insertion_point(field_mutable:safex.Transactions.missed_txs) - return missed_txs_.Mutable(index); -} - void Transactions::set_missed_txs(int index, const ::std::string& value) { - // @@protoc_insertion_point(field_set:safex.Transactions.missed_txs) - missed_txs_.Mutable(index)->assign(value); -} - void Transactions::set_missed_txs(int index, const char* value) { - missed_txs_.Mutable(index)->assign(value); - // @@protoc_insertion_point(field_set_char:safex.Transactions.missed_txs) -} - void Transactions::set_missed_txs(int index, const char* value, size_t size) { - missed_txs_.Mutable(index)->assign( - reinterpret_cast(value), size); - // @@protoc_insertion_point(field_set_pointer:safex.Transactions.missed_txs) -} - ::std::string* Transactions::add_missed_txs() { - // @@protoc_insertion_point(field_add_mutable:safex.Transactions.missed_txs) - return missed_txs_.Add(); -} - void Transactions::add_missed_txs(const ::std::string& value) { - missed_txs_.Add()->assign(value); - // @@protoc_insertion_point(field_add:safex.Transactions.missed_txs) -} - void Transactions::add_missed_txs(const char* value) { - missed_txs_.Add()->assign(value); - // @@protoc_insertion_point(field_add_char:safex.Transactions.missed_txs) -} - void Transactions::add_missed_txs(const char* value, size_t size) { - missed_txs_.Add()->assign(reinterpret_cast(value), size); - // @@protoc_insertion_point(field_add_pointer:safex.Transactions.missed_txs) -} - const ::google::protobuf::RepeatedPtrField< ::std::string>& -Transactions::missed_txs() const { - // @@protoc_insertion_point(field_list:safex.Transactions.missed_txs) - return missed_txs_; -} - ::google::protobuf::RepeatedPtrField< ::std::string>* -Transactions::mutable_missed_txs() { - // @@protoc_insertion_point(field_mutable_list:safex.Transactions.missed_txs) - return &missed_txs_; -} - -#endif // PROTOBUF_INLINE_NOT_IN_HEADERS - -// @@protoc_insertion_point(namespace_scope) - -} // namespace safex - -// @@protoc_insertion_point(global_scope) diff --git a/src/cryptonote_core/protobuf/transactions.pb.h b/src/cryptonote_core/protobuf/transactions.pb.h deleted file mode 100644 index f601745fc..000000000 --- a/src/cryptonote_core/protobuf/transactions.pb.h +++ /dev/null @@ -1,2683 +0,0 @@ -// Generated by the protocol buffer compiler. DO NOT EDIT! -// source: transactions.proto - -#ifndef PROTOBUF_transactions_2eproto__INCLUDED -#define PROTOBUF_transactions_2eproto__INCLUDED - -#include - -#include - -#if GOOGLE_PROTOBUF_VERSION < 3000000 -#error This file was generated by a newer version of protoc which is -#error incompatible with your Protocol Buffer headers. Please update -#error your headers. -#endif -#if 3000000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION -#error This file was generated by an older version of protoc which is -#error incompatible with your Protocol Buffer headers. Please -#error regenerate this file with a newer version of protoc. -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -// @@protoc_insertion_point(includes) - -namespace safex { - -// Internal implementation detail -- do not call these. -void protobuf_AddDesc_transactions_2eproto(); -void protobuf_AssignDesc_transactions_2eproto(); -void protobuf_ShutdownFile_transactions_2eproto(); - -class SigData; -class Signature; -class Transaction; -class Transactions; -class txin_gen; -class txin_to_key; -class txin_token_migration; -class txin_token_to_key; -class txin_v; -class txout; -class txout_target_v; -class txout_to_key; -class txout_token_to_key; - -// =================================================================== - -class txin_gen : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.txin_gen) */ { - public: - txin_gen(); - virtual ~txin_gen(); - - txin_gen(const txin_gen& from); - - inline txin_gen& operator=(const txin_gen& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const txin_gen& default_instance(); - - void Swap(txin_gen* other); - - // implements Message ---------------------------------------------- - - inline txin_gen* New() const { return New(NULL); } - - txin_gen* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const txin_gen& from); - void MergeFrom(const txin_gen& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(txin_gen* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 height = 1; - void clear_height(); - static const int kHeightFieldNumber = 1; - ::google::protobuf::uint64 height() const; - void set_height(::google::protobuf::uint64 value); - - // @@protoc_insertion_point(class_scope:safex.txin_gen) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::uint64 height_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static txin_gen* default_instance_; -}; -// ------------------------------------------------------------------- - -class txin_to_key : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.txin_to_key) */ { - public: - txin_to_key(); - virtual ~txin_to_key(); - - txin_to_key(const txin_to_key& from); - - inline txin_to_key& operator=(const txin_to_key& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const txin_to_key& default_instance(); - - void Swap(txin_to_key* other); - - // implements Message ---------------------------------------------- - - inline txin_to_key* New() const { return New(NULL); } - - txin_to_key* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const txin_to_key& from); - void MergeFrom(const txin_to_key& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(txin_to_key* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 amount = 1; - void clear_amount(); - static const int kAmountFieldNumber = 1; - ::google::protobuf::uint64 amount() const; - void set_amount(::google::protobuf::uint64 value); - - // optional bytes k_image = 2; - void clear_k_image(); - static const int kKImageFieldNumber = 2; - const ::std::string& k_image() const; - void set_k_image(const ::std::string& value); - void set_k_image(const char* value); - void set_k_image(const void* value, size_t size); - ::std::string* mutable_k_image(); - ::std::string* release_k_image(); - void set_allocated_k_image(::std::string* k_image); - - // repeated uint64 key_offsets = 3; - int key_offsets_size() const; - void clear_key_offsets(); - static const int kKeyOffsetsFieldNumber = 3; - ::google::protobuf::uint64 key_offsets(int index) const; - void set_key_offsets(int index, ::google::protobuf::uint64 value); - void add_key_offsets(::google::protobuf::uint64 value); - const ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >& - key_offsets() const; - ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >* - mutable_key_offsets(); - - // @@protoc_insertion_point(class_scope:safex.txin_to_key) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::uint64 amount_; - ::google::protobuf::internal::ArenaStringPtr k_image_; - ::google::protobuf::RepeatedField< ::google::protobuf::uint64 > key_offsets_; - mutable int _key_offsets_cached_byte_size_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static txin_to_key* default_instance_; -}; -// ------------------------------------------------------------------- - -class txin_token_to_key : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.txin_token_to_key) */ { - public: - txin_token_to_key(); - virtual ~txin_token_to_key(); - - txin_token_to_key(const txin_token_to_key& from); - - inline txin_token_to_key& operator=(const txin_token_to_key& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const txin_token_to_key& default_instance(); - - void Swap(txin_token_to_key* other); - - // implements Message ---------------------------------------------- - - inline txin_token_to_key* New() const { return New(NULL); } - - txin_token_to_key* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const txin_token_to_key& from); - void MergeFrom(const txin_token_to_key& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(txin_token_to_key* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 token_amount = 1; - void clear_token_amount(); - static const int kTokenAmountFieldNumber = 1; - ::google::protobuf::uint64 token_amount() const; - void set_token_amount(::google::protobuf::uint64 value); - - // optional bytes k_image = 2; - void clear_k_image(); - static const int kKImageFieldNumber = 2; - const ::std::string& k_image() const; - void set_k_image(const ::std::string& value); - void set_k_image(const char* value); - void set_k_image(const void* value, size_t size); - ::std::string* mutable_k_image(); - ::std::string* release_k_image(); - void set_allocated_k_image(::std::string* k_image); - - // repeated uint64 key_offsets = 3; - int key_offsets_size() const; - void clear_key_offsets(); - static const int kKeyOffsetsFieldNumber = 3; - ::google::protobuf::uint64 key_offsets(int index) const; - void set_key_offsets(int index, ::google::protobuf::uint64 value); - void add_key_offsets(::google::protobuf::uint64 value); - const ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >& - key_offsets() const; - ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >* - mutable_key_offsets(); - - // @@protoc_insertion_point(class_scope:safex.txin_token_to_key) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::uint64 token_amount_; - ::google::protobuf::internal::ArenaStringPtr k_image_; - ::google::protobuf::RepeatedField< ::google::protobuf::uint64 > key_offsets_; - mutable int _key_offsets_cached_byte_size_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static txin_token_to_key* default_instance_; -}; -// ------------------------------------------------------------------- - -class txin_token_migration : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.txin_token_migration) */ { - public: - txin_token_migration(); - virtual ~txin_token_migration(); - - txin_token_migration(const txin_token_migration& from); - - inline txin_token_migration& operator=(const txin_token_migration& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const txin_token_migration& default_instance(); - - void Swap(txin_token_migration* other); - - // implements Message ---------------------------------------------- - - inline txin_token_migration* New() const { return New(NULL); } - - txin_token_migration* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const txin_token_migration& from); - void MergeFrom(const txin_token_migration& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(txin_token_migration* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 token_amount = 1; - void clear_token_amount(); - static const int kTokenAmountFieldNumber = 1; - ::google::protobuf::uint64 token_amount() const; - void set_token_amount(::google::protobuf::uint64 value); - - // optional string bitcoin_burn_transaction = 2; - void clear_bitcoin_burn_transaction(); - static const int kBitcoinBurnTransactionFieldNumber = 2; - const ::std::string& bitcoin_burn_transaction() const; - void set_bitcoin_burn_transaction(const ::std::string& value); - void set_bitcoin_burn_transaction(const char* value); - void set_bitcoin_burn_transaction(const char* value, size_t size); - ::std::string* mutable_bitcoin_burn_transaction(); - ::std::string* release_bitcoin_burn_transaction(); - void set_allocated_bitcoin_burn_transaction(::std::string* bitcoin_burn_transaction); - - // optional bytes k_image = 3; - void clear_k_image(); - static const int kKImageFieldNumber = 3; - const ::std::string& k_image() const; - void set_k_image(const ::std::string& value); - void set_k_image(const char* value); - void set_k_image(const void* value, size_t size); - ::std::string* mutable_k_image(); - ::std::string* release_k_image(); - void set_allocated_k_image(::std::string* k_image); - - // @@protoc_insertion_point(class_scope:safex.txin_token_migration) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::uint64 token_amount_; - ::google::protobuf::internal::ArenaStringPtr bitcoin_burn_transaction_; - ::google::protobuf::internal::ArenaStringPtr k_image_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static txin_token_migration* default_instance_; -}; -// ------------------------------------------------------------------- - -class txin_v : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.txin_v) */ { - public: - txin_v(); - virtual ~txin_v(); - - txin_v(const txin_v& from); - - inline txin_v& operator=(const txin_v& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const txin_v& default_instance(); - - void Swap(txin_v* other); - - // implements Message ---------------------------------------------- - - inline txin_v* New() const { return New(NULL); } - - txin_v* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const txin_v& from); - void MergeFrom(const txin_v& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(txin_v* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional .safex.txin_gen txin_gen = 1; - bool has_txin_gen() const; - void clear_txin_gen(); - static const int kTxinGenFieldNumber = 1; - const ::safex::txin_gen& txin_gen() const; - ::safex::txin_gen* mutable_txin_gen(); - ::safex::txin_gen* release_txin_gen(); - void set_allocated_txin_gen(::safex::txin_gen* txin_gen); - - // optional .safex.txin_to_key txin_to_key = 2; - bool has_txin_to_key() const; - void clear_txin_to_key(); - static const int kTxinToKeyFieldNumber = 2; - const ::safex::txin_to_key& txin_to_key() const; - ::safex::txin_to_key* mutable_txin_to_key(); - ::safex::txin_to_key* release_txin_to_key(); - void set_allocated_txin_to_key(::safex::txin_to_key* txin_to_key); - - // optional .safex.txin_token_to_key txin_token_to_key = 3; - bool has_txin_token_to_key() const; - void clear_txin_token_to_key(); - static const int kTxinTokenToKeyFieldNumber = 3; - const ::safex::txin_token_to_key& txin_token_to_key() const; - ::safex::txin_token_to_key* mutable_txin_token_to_key(); - ::safex::txin_token_to_key* release_txin_token_to_key(); - void set_allocated_txin_token_to_key(::safex::txin_token_to_key* txin_token_to_key); - - // optional .safex.txin_token_migration txin_token_migration = 4; - bool has_txin_token_migration() const; - void clear_txin_token_migration(); - static const int kTxinTokenMigrationFieldNumber = 4; - const ::safex::txin_token_migration& txin_token_migration() const; - ::safex::txin_token_migration* mutable_txin_token_migration(); - ::safex::txin_token_migration* release_txin_token_migration(); - void set_allocated_txin_token_migration(::safex::txin_token_migration* txin_token_migration); - - // @@protoc_insertion_point(class_scope:safex.txin_v) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::safex::txin_gen* txin_gen_; - ::safex::txin_to_key* txin_to_key_; - ::safex::txin_token_to_key* txin_token_to_key_; - ::safex::txin_token_migration* txin_token_migration_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static txin_v* default_instance_; -}; -// ------------------------------------------------------------------- - -class txout_to_key : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.txout_to_key) */ { - public: - txout_to_key(); - virtual ~txout_to_key(); - - txout_to_key(const txout_to_key& from); - - inline txout_to_key& operator=(const txout_to_key& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const txout_to_key& default_instance(); - - void Swap(txout_to_key* other); - - // implements Message ---------------------------------------------- - - inline txout_to_key* New() const { return New(NULL); } - - txout_to_key* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const txout_to_key& from); - void MergeFrom(const txout_to_key& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(txout_to_key* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional bytes key = 1; - void clear_key(); - static const int kKeyFieldNumber = 1; - const ::std::string& key() const; - void set_key(const ::std::string& value); - void set_key(const char* value); - void set_key(const void* value, size_t size); - ::std::string* mutable_key(); - ::std::string* release_key(); - void set_allocated_key(::std::string* key); - - // @@protoc_insertion_point(class_scope:safex.txout_to_key) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::internal::ArenaStringPtr key_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static txout_to_key* default_instance_; -}; -// ------------------------------------------------------------------- - -class txout_token_to_key : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.txout_token_to_key) */ { - public: - txout_token_to_key(); - virtual ~txout_token_to_key(); - - txout_token_to_key(const txout_token_to_key& from); - - inline txout_token_to_key& operator=(const txout_token_to_key& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const txout_token_to_key& default_instance(); - - void Swap(txout_token_to_key* other); - - // implements Message ---------------------------------------------- - - inline txout_token_to_key* New() const { return New(NULL); } - - txout_token_to_key* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const txout_token_to_key& from); - void MergeFrom(const txout_token_to_key& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(txout_token_to_key* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional bytes key = 1; - void clear_key(); - static const int kKeyFieldNumber = 1; - const ::std::string& key() const; - void set_key(const ::std::string& value); - void set_key(const char* value); - void set_key(const void* value, size_t size); - ::std::string* mutable_key(); - ::std::string* release_key(); - void set_allocated_key(::std::string* key); - - // @@protoc_insertion_point(class_scope:safex.txout_token_to_key) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::internal::ArenaStringPtr key_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static txout_token_to_key* default_instance_; -}; -// ------------------------------------------------------------------- - -class txout_target_v : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.txout_target_v) */ { - public: - txout_target_v(); - virtual ~txout_target_v(); - - txout_target_v(const txout_target_v& from); - - inline txout_target_v& operator=(const txout_target_v& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const txout_target_v& default_instance(); - - void Swap(txout_target_v* other); - - // implements Message ---------------------------------------------- - - inline txout_target_v* New() const { return New(NULL); } - - txout_target_v* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const txout_target_v& from); - void MergeFrom(const txout_target_v& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(txout_target_v* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional .safex.txout_to_key txout_to_key = 1; - bool has_txout_to_key() const; - void clear_txout_to_key(); - static const int kTxoutToKeyFieldNumber = 1; - const ::safex::txout_to_key& txout_to_key() const; - ::safex::txout_to_key* mutable_txout_to_key(); - ::safex::txout_to_key* release_txout_to_key(); - void set_allocated_txout_to_key(::safex::txout_to_key* txout_to_key); - - // optional .safex.txout_token_to_key txout_token_to_key = 2; - bool has_txout_token_to_key() const; - void clear_txout_token_to_key(); - static const int kTxoutTokenToKeyFieldNumber = 2; - const ::safex::txout_token_to_key& txout_token_to_key() const; - ::safex::txout_token_to_key* mutable_txout_token_to_key(); - ::safex::txout_token_to_key* release_txout_token_to_key(); - void set_allocated_txout_token_to_key(::safex::txout_token_to_key* txout_token_to_key); - - // @@protoc_insertion_point(class_scope:safex.txout_target_v) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::safex::txout_to_key* txout_to_key_; - ::safex::txout_token_to_key* txout_token_to_key_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static txout_target_v* default_instance_; -}; -// ------------------------------------------------------------------- - -class txout : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.txout) */ { - public: - txout(); - virtual ~txout(); - - txout(const txout& from); - - inline txout& operator=(const txout& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const txout& default_instance(); - - void Swap(txout* other); - - // implements Message ---------------------------------------------- - - inline txout* New() const { return New(NULL); } - - txout* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const txout& from); - void MergeFrom(const txout& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(txout* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 amount = 1; - void clear_amount(); - static const int kAmountFieldNumber = 1; - ::google::protobuf::uint64 amount() const; - void set_amount(::google::protobuf::uint64 value); - - // optional uint64 token_amount = 2; - void clear_token_amount(); - static const int kTokenAmountFieldNumber = 2; - ::google::protobuf::uint64 token_amount() const; - void set_token_amount(::google::protobuf::uint64 value); - - // optional .safex.txout_target_v target = 3; - bool has_target() const; - void clear_target(); - static const int kTargetFieldNumber = 3; - const ::safex::txout_target_v& target() const; - ::safex::txout_target_v* mutable_target(); - ::safex::txout_target_v* release_target(); - void set_allocated_target(::safex::txout_target_v* target); - - // @@protoc_insertion_point(class_scope:safex.txout) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::uint64 amount_; - ::google::protobuf::uint64 token_amount_; - ::safex::txout_target_v* target_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static txout* default_instance_; -}; -// ------------------------------------------------------------------- - -class SigData : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.SigData) */ { - public: - SigData(); - virtual ~SigData(); - - SigData(const SigData& from); - - inline SigData& operator=(const SigData& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const SigData& default_instance(); - - void Swap(SigData* other); - - // implements Message ---------------------------------------------- - - inline SigData* New() const { return New(NULL); } - - SigData* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const SigData& from); - void MergeFrom(const SigData& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(SigData* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional bytes r = 1; - void clear_r(); - static const int kRFieldNumber = 1; - const ::std::string& r() const; - void set_r(const ::std::string& value); - void set_r(const char* value); - void set_r(const void* value, size_t size); - ::std::string* mutable_r(); - ::std::string* release_r(); - void set_allocated_r(::std::string* r); - - // optional bytes c = 2; - void clear_c(); - static const int kCFieldNumber = 2; - const ::std::string& c() const; - void set_c(const ::std::string& value); - void set_c(const char* value); - void set_c(const void* value, size_t size); - ::std::string* mutable_c(); - ::std::string* release_c(); - void set_allocated_c(::std::string* c); - - // @@protoc_insertion_point(class_scope:safex.SigData) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::internal::ArenaStringPtr r_; - ::google::protobuf::internal::ArenaStringPtr c_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static SigData* default_instance_; -}; -// ------------------------------------------------------------------- - -class Signature : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.Signature) */ { - public: - Signature(); - virtual ~Signature(); - - Signature(const Signature& from); - - inline Signature& operator=(const Signature& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Signature& default_instance(); - - void Swap(Signature* other); - - // implements Message ---------------------------------------------- - - inline Signature* New() const { return New(NULL); } - - Signature* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Signature& from); - void MergeFrom(const Signature& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(Signature* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // repeated .safex.SigData signature = 1; - int signature_size() const; - void clear_signature(); - static const int kSignatureFieldNumber = 1; - const ::safex::SigData& signature(int index) const; - ::safex::SigData* mutable_signature(int index); - ::safex::SigData* add_signature(); - ::google::protobuf::RepeatedPtrField< ::safex::SigData >* - mutable_signature(); - const ::google::protobuf::RepeatedPtrField< ::safex::SigData >& - signature() const; - - // @@protoc_insertion_point(class_scope:safex.Signature) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::RepeatedPtrField< ::safex::SigData > signature_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static Signature* default_instance_; -}; -// ------------------------------------------------------------------- - -class Transaction : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.Transaction) */ { - public: - Transaction(); - virtual ~Transaction(); - - Transaction(const Transaction& from); - - inline Transaction& operator=(const Transaction& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Transaction& default_instance(); - - void Swap(Transaction* other); - - // implements Message ---------------------------------------------- - - inline Transaction* New() const { return New(NULL); } - - Transaction* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Transaction& from); - void MergeFrom(const Transaction& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(Transaction* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // optional uint64 version = 1; - void clear_version(); - static const int kVersionFieldNumber = 1; - ::google::protobuf::uint64 version() const; - void set_version(::google::protobuf::uint64 value); - - // optional uint64 unlock_time = 2; - void clear_unlock_time(); - static const int kUnlockTimeFieldNumber = 2; - ::google::protobuf::uint64 unlock_time() const; - void set_unlock_time(::google::protobuf::uint64 value); - - // optional bytes extra = 3; - void clear_extra(); - static const int kExtraFieldNumber = 3; - const ::std::string& extra() const; - void set_extra(const ::std::string& value); - void set_extra(const char* value); - void set_extra(const void* value, size_t size); - ::std::string* mutable_extra(); - ::std::string* release_extra(); - void set_allocated_extra(::std::string* extra); - - // repeated .safex.txin_v vin = 4; - int vin_size() const; - void clear_vin(); - static const int kVinFieldNumber = 4; - const ::safex::txin_v& vin(int index) const; - ::safex::txin_v* mutable_vin(int index); - ::safex::txin_v* add_vin(); - ::google::protobuf::RepeatedPtrField< ::safex::txin_v >* - mutable_vin(); - const ::google::protobuf::RepeatedPtrField< ::safex::txin_v >& - vin() const; - - // repeated .safex.txout vout = 5; - int vout_size() const; - void clear_vout(); - static const int kVoutFieldNumber = 5; - const ::safex::txout& vout(int index) const; - ::safex::txout* mutable_vout(int index); - ::safex::txout* add_vout(); - ::google::protobuf::RepeatedPtrField< ::safex::txout >* - mutable_vout(); - const ::google::protobuf::RepeatedPtrField< ::safex::txout >& - vout() const; - - // repeated .safex.Signature signatures = 6; - int signatures_size() const; - void clear_signatures(); - static const int kSignaturesFieldNumber = 6; - const ::safex::Signature& signatures(int index) const; - ::safex::Signature* mutable_signatures(int index); - ::safex::Signature* add_signatures(); - ::google::protobuf::RepeatedPtrField< ::safex::Signature >* - mutable_signatures(); - const ::google::protobuf::RepeatedPtrField< ::safex::Signature >& - signatures() const; - - // optional uint64 block_height = 7; - void clear_block_height(); - static const int kBlockHeightFieldNumber = 7; - ::google::protobuf::uint64 block_height() const; - void set_block_height(::google::protobuf::uint64 value); - - // optional uint64 block_timestamp = 8; - void clear_block_timestamp(); - static const int kBlockTimestampFieldNumber = 8; - ::google::protobuf::uint64 block_timestamp() const; - void set_block_timestamp(::google::protobuf::uint64 value); - - // optional bool double_spend_seen = 9; - void clear_double_spend_seen(); - static const int kDoubleSpendSeenFieldNumber = 9; - bool double_spend_seen() const; - void set_double_spend_seen(bool value); - - // optional bool in_pool = 10; - void clear_in_pool(); - static const int kInPoolFieldNumber = 10; - bool in_pool() const; - void set_in_pool(bool value); - - // repeated uint64 output_indices = 11; - int output_indices_size() const; - void clear_output_indices(); - static const int kOutputIndicesFieldNumber = 11; - ::google::protobuf::uint64 output_indices(int index) const; - void set_output_indices(int index, ::google::protobuf::uint64 value); - void add_output_indices(::google::protobuf::uint64 value); - const ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >& - output_indices() const; - ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >* - mutable_output_indices(); - - // optional string tx_hash = 12; - void clear_tx_hash(); - static const int kTxHashFieldNumber = 12; - const ::std::string& tx_hash() const; - void set_tx_hash(const ::std::string& value); - void set_tx_hash(const char* value); - void set_tx_hash(const char* value, size_t size); - ::std::string* mutable_tx_hash(); - ::std::string* release_tx_hash(); - void set_allocated_tx_hash(::std::string* tx_hash); - - // @@protoc_insertion_point(class_scope:safex.Transaction) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::uint64 version_; - ::google::protobuf::uint64 unlock_time_; - ::google::protobuf::internal::ArenaStringPtr extra_; - ::google::protobuf::RepeatedPtrField< ::safex::txin_v > vin_; - ::google::protobuf::RepeatedPtrField< ::safex::txout > vout_; - ::google::protobuf::RepeatedPtrField< ::safex::Signature > signatures_; - ::google::protobuf::uint64 block_height_; - ::google::protobuf::uint64 block_timestamp_; - ::google::protobuf::RepeatedField< ::google::protobuf::uint64 > output_indices_; - mutable int _output_indices_cached_byte_size_; - ::google::protobuf::internal::ArenaStringPtr tx_hash_; - bool double_spend_seen_; - bool in_pool_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static Transaction* default_instance_; -}; -// ------------------------------------------------------------------- - -class Transactions : public ::google::protobuf::Message /* @@protoc_insertion_point(class_definition:safex.Transactions) */ { - public: - Transactions(); - virtual ~Transactions(); - - Transactions(const Transactions& from); - - inline Transactions& operator=(const Transactions& from) { - CopyFrom(from); - return *this; - } - - static const ::google::protobuf::Descriptor* descriptor(); - static const Transactions& default_instance(); - - void Swap(Transactions* other); - - // implements Message ---------------------------------------------- - - inline Transactions* New() const { return New(NULL); } - - Transactions* New(::google::protobuf::Arena* arena) const; - void CopyFrom(const ::google::protobuf::Message& from); - void MergeFrom(const ::google::protobuf::Message& from); - void CopyFrom(const Transactions& from); - void MergeFrom(const Transactions& from); - void Clear(); - bool IsInitialized() const; - - int ByteSize() const; - bool MergePartialFromCodedStream( - ::google::protobuf::io::CodedInputStream* input); - void SerializeWithCachedSizes( - ::google::protobuf::io::CodedOutputStream* output) const; - ::google::protobuf::uint8* InternalSerializeWithCachedSizesToArray( - bool deterministic, ::google::protobuf::uint8* output) const; - ::google::protobuf::uint8* SerializeWithCachedSizesToArray(::google::protobuf::uint8* output) const { - return InternalSerializeWithCachedSizesToArray(false, output); - } - int GetCachedSize() const { return _cached_size_; } - private: - void SharedCtor(); - void SharedDtor(); - void SetCachedSize(int size) const; - void InternalSwap(Transactions* other); - private: - inline ::google::protobuf::Arena* GetArenaNoVirtual() const { - return _internal_metadata_.arena(); - } - inline void* MaybeArenaPtr() const { - return _internal_metadata_.raw_arena_ptr(); - } - public: - - ::google::protobuf::Metadata GetMetadata() const; - - // nested types ---------------------------------------------------- - - // accessors ------------------------------------------------------- - - // repeated .safex.Transaction tx = 1; - int tx_size() const; - void clear_tx(); - static const int kTxFieldNumber = 1; - const ::safex::Transaction& tx(int index) const; - ::safex::Transaction* mutable_tx(int index); - ::safex::Transaction* add_tx(); - ::google::protobuf::RepeatedPtrField< ::safex::Transaction >* - mutable_tx(); - const ::google::protobuf::RepeatedPtrField< ::safex::Transaction >& - tx() const; - - // repeated string missed_txs = 2; - int missed_txs_size() const; - void clear_missed_txs(); - static const int kMissedTxsFieldNumber = 2; - const ::std::string& missed_txs(int index) const; - ::std::string* mutable_missed_txs(int index); - void set_missed_txs(int index, const ::std::string& value); - void set_missed_txs(int index, const char* value); - void set_missed_txs(int index, const char* value, size_t size); - ::std::string* add_missed_txs(); - void add_missed_txs(const ::std::string& value); - void add_missed_txs(const char* value); - void add_missed_txs(const char* value, size_t size); - const ::google::protobuf::RepeatedPtrField< ::std::string>& missed_txs() const; - ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_missed_txs(); - - // @@protoc_insertion_point(class_scope:safex.Transactions) - private: - - ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; - bool _is_default_instance_; - ::google::protobuf::RepeatedPtrField< ::safex::Transaction > tx_; - ::google::protobuf::RepeatedPtrField< ::std::string> missed_txs_; - mutable int _cached_size_; - friend void protobuf_AddDesc_transactions_2eproto(); - friend void protobuf_AssignDesc_transactions_2eproto(); - friend void protobuf_ShutdownFile_transactions_2eproto(); - - void InitAsDefaultInstance(); - static Transactions* default_instance_; -}; -// =================================================================== - - -// =================================================================== - -#if !PROTOBUF_INLINE_NOT_IN_HEADERS -// txin_gen - -// optional uint64 height = 1; -inline void txin_gen::clear_height() { - height_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 txin_gen::height() const { - // @@protoc_insertion_point(field_get:safex.txin_gen.height) - return height_; -} -inline void txin_gen::set_height(::google::protobuf::uint64 value) { - - height_ = value; - // @@protoc_insertion_point(field_set:safex.txin_gen.height) -} - -// ------------------------------------------------------------------- - -// txin_to_key - -// optional uint64 amount = 1; -inline void txin_to_key::clear_amount() { - amount_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 txin_to_key::amount() const { - // @@protoc_insertion_point(field_get:safex.txin_to_key.amount) - return amount_; -} -inline void txin_to_key::set_amount(::google::protobuf::uint64 value) { - - amount_ = value; - // @@protoc_insertion_point(field_set:safex.txin_to_key.amount) -} - -// optional bytes k_image = 2; -inline void txin_to_key::clear_k_image() { - k_image_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& txin_to_key::k_image() const { - // @@protoc_insertion_point(field_get:safex.txin_to_key.k_image) - return k_image_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txin_to_key::set_k_image(const ::std::string& value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txin_to_key.k_image) -} -inline void txin_to_key::set_k_image(const char* value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txin_to_key.k_image) -} -inline void txin_to_key::set_k_image(const void* value, size_t size) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txin_to_key.k_image) -} -inline ::std::string* txin_to_key::mutable_k_image() { - - // @@protoc_insertion_point(field_mutable:safex.txin_to_key.k_image) - return k_image_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* txin_to_key::release_k_image() { - // @@protoc_insertion_point(field_release:safex.txin_to_key.k_image) - - return k_image_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txin_to_key::set_allocated_k_image(::std::string* k_image) { - if (k_image != NULL) { - - } else { - - } - k_image_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), k_image); - // @@protoc_insertion_point(field_set_allocated:safex.txin_to_key.k_image) -} - -// repeated uint64 key_offsets = 3; -inline int txin_to_key::key_offsets_size() const { - return key_offsets_.size(); -} -inline void txin_to_key::clear_key_offsets() { - key_offsets_.Clear(); -} -inline ::google::protobuf::uint64 txin_to_key::key_offsets(int index) const { - // @@protoc_insertion_point(field_get:safex.txin_to_key.key_offsets) - return key_offsets_.Get(index); -} -inline void txin_to_key::set_key_offsets(int index, ::google::protobuf::uint64 value) { - key_offsets_.Set(index, value); - // @@protoc_insertion_point(field_set:safex.txin_to_key.key_offsets) -} -inline void txin_to_key::add_key_offsets(::google::protobuf::uint64 value) { - key_offsets_.Add(value); - // @@protoc_insertion_point(field_add:safex.txin_to_key.key_offsets) -} -inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >& -txin_to_key::key_offsets() const { - // @@protoc_insertion_point(field_list:safex.txin_to_key.key_offsets) - return key_offsets_; -} -inline ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >* -txin_to_key::mutable_key_offsets() { - // @@protoc_insertion_point(field_mutable_list:safex.txin_to_key.key_offsets) - return &key_offsets_; -} - -// ------------------------------------------------------------------- - -// txin_token_to_key - -// optional uint64 token_amount = 1; -inline void txin_token_to_key::clear_token_amount() { - token_amount_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 txin_token_to_key::token_amount() const { - // @@protoc_insertion_point(field_get:safex.txin_token_to_key.token_amount) - return token_amount_; -} -inline void txin_token_to_key::set_token_amount(::google::protobuf::uint64 value) { - - token_amount_ = value; - // @@protoc_insertion_point(field_set:safex.txin_token_to_key.token_amount) -} - -// optional bytes k_image = 2; -inline void txin_token_to_key::clear_k_image() { - k_image_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& txin_token_to_key::k_image() const { - // @@protoc_insertion_point(field_get:safex.txin_token_to_key.k_image) - return k_image_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txin_token_to_key::set_k_image(const ::std::string& value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txin_token_to_key.k_image) -} -inline void txin_token_to_key::set_k_image(const char* value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txin_token_to_key.k_image) -} -inline void txin_token_to_key::set_k_image(const void* value, size_t size) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txin_token_to_key.k_image) -} -inline ::std::string* txin_token_to_key::mutable_k_image() { - - // @@protoc_insertion_point(field_mutable:safex.txin_token_to_key.k_image) - return k_image_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* txin_token_to_key::release_k_image() { - // @@protoc_insertion_point(field_release:safex.txin_token_to_key.k_image) - - return k_image_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txin_token_to_key::set_allocated_k_image(::std::string* k_image) { - if (k_image != NULL) { - - } else { - - } - k_image_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), k_image); - // @@protoc_insertion_point(field_set_allocated:safex.txin_token_to_key.k_image) -} - -// repeated uint64 key_offsets = 3; -inline int txin_token_to_key::key_offsets_size() const { - return key_offsets_.size(); -} -inline void txin_token_to_key::clear_key_offsets() { - key_offsets_.Clear(); -} -inline ::google::protobuf::uint64 txin_token_to_key::key_offsets(int index) const { - // @@protoc_insertion_point(field_get:safex.txin_token_to_key.key_offsets) - return key_offsets_.Get(index); -} -inline void txin_token_to_key::set_key_offsets(int index, ::google::protobuf::uint64 value) { - key_offsets_.Set(index, value); - // @@protoc_insertion_point(field_set:safex.txin_token_to_key.key_offsets) -} -inline void txin_token_to_key::add_key_offsets(::google::protobuf::uint64 value) { - key_offsets_.Add(value); - // @@protoc_insertion_point(field_add:safex.txin_token_to_key.key_offsets) -} -inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >& -txin_token_to_key::key_offsets() const { - // @@protoc_insertion_point(field_list:safex.txin_token_to_key.key_offsets) - return key_offsets_; -} -inline ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >* -txin_token_to_key::mutable_key_offsets() { - // @@protoc_insertion_point(field_mutable_list:safex.txin_token_to_key.key_offsets) - return &key_offsets_; -} - -// ------------------------------------------------------------------- - -// txin_token_migration - -// optional uint64 token_amount = 1; -inline void txin_token_migration::clear_token_amount() { - token_amount_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 txin_token_migration::token_amount() const { - // @@protoc_insertion_point(field_get:safex.txin_token_migration.token_amount) - return token_amount_; -} -inline void txin_token_migration::set_token_amount(::google::protobuf::uint64 value) { - - token_amount_ = value; - // @@protoc_insertion_point(field_set:safex.txin_token_migration.token_amount) -} - -// optional string bitcoin_burn_transaction = 2; -inline void txin_token_migration::clear_bitcoin_burn_transaction() { - bitcoin_burn_transaction_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& txin_token_migration::bitcoin_burn_transaction() const { - // @@protoc_insertion_point(field_get:safex.txin_token_migration.bitcoin_burn_transaction) - return bitcoin_burn_transaction_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txin_token_migration::set_bitcoin_burn_transaction(const ::std::string& value) { - - bitcoin_burn_transaction_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txin_token_migration.bitcoin_burn_transaction) -} -inline void txin_token_migration::set_bitcoin_burn_transaction(const char* value) { - - bitcoin_burn_transaction_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txin_token_migration.bitcoin_burn_transaction) -} -inline void txin_token_migration::set_bitcoin_burn_transaction(const char* value, size_t size) { - - bitcoin_burn_transaction_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txin_token_migration.bitcoin_burn_transaction) -} -inline ::std::string* txin_token_migration::mutable_bitcoin_burn_transaction() { - - // @@protoc_insertion_point(field_mutable:safex.txin_token_migration.bitcoin_burn_transaction) - return bitcoin_burn_transaction_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* txin_token_migration::release_bitcoin_burn_transaction() { - // @@protoc_insertion_point(field_release:safex.txin_token_migration.bitcoin_burn_transaction) - - return bitcoin_burn_transaction_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txin_token_migration::set_allocated_bitcoin_burn_transaction(::std::string* bitcoin_burn_transaction) { - if (bitcoin_burn_transaction != NULL) { - - } else { - - } - bitcoin_burn_transaction_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), bitcoin_burn_transaction); - // @@protoc_insertion_point(field_set_allocated:safex.txin_token_migration.bitcoin_burn_transaction) -} - -// optional bytes k_image = 3; -inline void txin_token_migration::clear_k_image() { - k_image_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& txin_token_migration::k_image() const { - // @@protoc_insertion_point(field_get:safex.txin_token_migration.k_image) - return k_image_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txin_token_migration::set_k_image(const ::std::string& value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txin_token_migration.k_image) -} -inline void txin_token_migration::set_k_image(const char* value) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txin_token_migration.k_image) -} -inline void txin_token_migration::set_k_image(const void* value, size_t size) { - - k_image_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txin_token_migration.k_image) -} -inline ::std::string* txin_token_migration::mutable_k_image() { - - // @@protoc_insertion_point(field_mutable:safex.txin_token_migration.k_image) - return k_image_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* txin_token_migration::release_k_image() { - // @@protoc_insertion_point(field_release:safex.txin_token_migration.k_image) - - return k_image_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txin_token_migration::set_allocated_k_image(::std::string* k_image) { - if (k_image != NULL) { - - } else { - - } - k_image_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), k_image); - // @@protoc_insertion_point(field_set_allocated:safex.txin_token_migration.k_image) -} - -// ------------------------------------------------------------------- - -// txin_v - -// optional .safex.txin_gen txin_gen = 1; -inline bool txin_v::has_txin_gen() const { - return !_is_default_instance_ && txin_gen_ != NULL; -} -inline void txin_v::clear_txin_gen() { - if (GetArenaNoVirtual() == NULL && txin_gen_ != NULL) delete txin_gen_; - txin_gen_ = NULL; -} -inline const ::safex::txin_gen& txin_v::txin_gen() const { - // @@protoc_insertion_point(field_get:safex.txin_v.txin_gen) - return txin_gen_ != NULL ? *txin_gen_ : *default_instance_->txin_gen_; -} -inline ::safex::txin_gen* txin_v::mutable_txin_gen() { - - if (txin_gen_ == NULL) { - txin_gen_ = new ::safex::txin_gen; - } - // @@protoc_insertion_point(field_mutable:safex.txin_v.txin_gen) - return txin_gen_; -} -inline ::safex::txin_gen* txin_v::release_txin_gen() { - // @@protoc_insertion_point(field_release:safex.txin_v.txin_gen) - - ::safex::txin_gen* temp = txin_gen_; - txin_gen_ = NULL; - return temp; -} -inline void txin_v::set_allocated_txin_gen(::safex::txin_gen* txin_gen) { - delete txin_gen_; - txin_gen_ = txin_gen; - if (txin_gen) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txin_v.txin_gen) -} - -// optional .safex.txin_to_key txin_to_key = 2; -inline bool txin_v::has_txin_to_key() const { - return !_is_default_instance_ && txin_to_key_ != NULL; -} -inline void txin_v::clear_txin_to_key() { - if (GetArenaNoVirtual() == NULL && txin_to_key_ != NULL) delete txin_to_key_; - txin_to_key_ = NULL; -} -inline const ::safex::txin_to_key& txin_v::txin_to_key() const { - // @@protoc_insertion_point(field_get:safex.txin_v.txin_to_key) - return txin_to_key_ != NULL ? *txin_to_key_ : *default_instance_->txin_to_key_; -} -inline ::safex::txin_to_key* txin_v::mutable_txin_to_key() { - - if (txin_to_key_ == NULL) { - txin_to_key_ = new ::safex::txin_to_key; - } - // @@protoc_insertion_point(field_mutable:safex.txin_v.txin_to_key) - return txin_to_key_; -} -inline ::safex::txin_to_key* txin_v::release_txin_to_key() { - // @@protoc_insertion_point(field_release:safex.txin_v.txin_to_key) - - ::safex::txin_to_key* temp = txin_to_key_; - txin_to_key_ = NULL; - return temp; -} -inline void txin_v::set_allocated_txin_to_key(::safex::txin_to_key* txin_to_key) { - delete txin_to_key_; - txin_to_key_ = txin_to_key; - if (txin_to_key) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txin_v.txin_to_key) -} - -// optional .safex.txin_token_to_key txin_token_to_key = 3; -inline bool txin_v::has_txin_token_to_key() const { - return !_is_default_instance_ && txin_token_to_key_ != NULL; -} -inline void txin_v::clear_txin_token_to_key() { - if (GetArenaNoVirtual() == NULL && txin_token_to_key_ != NULL) delete txin_token_to_key_; - txin_token_to_key_ = NULL; -} -inline const ::safex::txin_token_to_key& txin_v::txin_token_to_key() const { - // @@protoc_insertion_point(field_get:safex.txin_v.txin_token_to_key) - return txin_token_to_key_ != NULL ? *txin_token_to_key_ : *default_instance_->txin_token_to_key_; -} -inline ::safex::txin_token_to_key* txin_v::mutable_txin_token_to_key() { - - if (txin_token_to_key_ == NULL) { - txin_token_to_key_ = new ::safex::txin_token_to_key; - } - // @@protoc_insertion_point(field_mutable:safex.txin_v.txin_token_to_key) - return txin_token_to_key_; -} -inline ::safex::txin_token_to_key* txin_v::release_txin_token_to_key() { - // @@protoc_insertion_point(field_release:safex.txin_v.txin_token_to_key) - - ::safex::txin_token_to_key* temp = txin_token_to_key_; - txin_token_to_key_ = NULL; - return temp; -} -inline void txin_v::set_allocated_txin_token_to_key(::safex::txin_token_to_key* txin_token_to_key) { - delete txin_token_to_key_; - txin_token_to_key_ = txin_token_to_key; - if (txin_token_to_key) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txin_v.txin_token_to_key) -} - -// optional .safex.txin_token_migration txin_token_migration = 4; -inline bool txin_v::has_txin_token_migration() const { - return !_is_default_instance_ && txin_token_migration_ != NULL; -} -inline void txin_v::clear_txin_token_migration() { - if (GetArenaNoVirtual() == NULL && txin_token_migration_ != NULL) delete txin_token_migration_; - txin_token_migration_ = NULL; -} -inline const ::safex::txin_token_migration& txin_v::txin_token_migration() const { - // @@protoc_insertion_point(field_get:safex.txin_v.txin_token_migration) - return txin_token_migration_ != NULL ? *txin_token_migration_ : *default_instance_->txin_token_migration_; -} -inline ::safex::txin_token_migration* txin_v::mutable_txin_token_migration() { - - if (txin_token_migration_ == NULL) { - txin_token_migration_ = new ::safex::txin_token_migration; - } - // @@protoc_insertion_point(field_mutable:safex.txin_v.txin_token_migration) - return txin_token_migration_; -} -inline ::safex::txin_token_migration* txin_v::release_txin_token_migration() { - // @@protoc_insertion_point(field_release:safex.txin_v.txin_token_migration) - - ::safex::txin_token_migration* temp = txin_token_migration_; - txin_token_migration_ = NULL; - return temp; -} -inline void txin_v::set_allocated_txin_token_migration(::safex::txin_token_migration* txin_token_migration) { - delete txin_token_migration_; - txin_token_migration_ = txin_token_migration; - if (txin_token_migration) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txin_v.txin_token_migration) -} - -// ------------------------------------------------------------------- - -// txout_to_key - -// optional bytes key = 1; -inline void txout_to_key::clear_key() { - key_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& txout_to_key::key() const { - // @@protoc_insertion_point(field_get:safex.txout_to_key.key) - return key_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txout_to_key::set_key(const ::std::string& value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txout_to_key.key) -} -inline void txout_to_key::set_key(const char* value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txout_to_key.key) -} -inline void txout_to_key::set_key(const void* value, size_t size) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txout_to_key.key) -} -inline ::std::string* txout_to_key::mutable_key() { - - // @@protoc_insertion_point(field_mutable:safex.txout_to_key.key) - return key_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* txout_to_key::release_key() { - // @@protoc_insertion_point(field_release:safex.txout_to_key.key) - - return key_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txout_to_key::set_allocated_key(::std::string* key) { - if (key != NULL) { - - } else { - - } - key_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), key); - // @@protoc_insertion_point(field_set_allocated:safex.txout_to_key.key) -} - -// ------------------------------------------------------------------- - -// txout_token_to_key - -// optional bytes key = 1; -inline void txout_token_to_key::clear_key() { - key_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& txout_token_to_key::key() const { - // @@protoc_insertion_point(field_get:safex.txout_token_to_key.key) - return key_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txout_token_to_key::set_key(const ::std::string& value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.txout_token_to_key.key) -} -inline void txout_token_to_key::set_key(const char* value) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.txout_token_to_key.key) -} -inline void txout_token_to_key::set_key(const void* value, size_t size) { - - key_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.txout_token_to_key.key) -} -inline ::std::string* txout_token_to_key::mutable_key() { - - // @@protoc_insertion_point(field_mutable:safex.txout_token_to_key.key) - return key_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* txout_token_to_key::release_key() { - // @@protoc_insertion_point(field_release:safex.txout_token_to_key.key) - - return key_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void txout_token_to_key::set_allocated_key(::std::string* key) { - if (key != NULL) { - - } else { - - } - key_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), key); - // @@protoc_insertion_point(field_set_allocated:safex.txout_token_to_key.key) -} - -// ------------------------------------------------------------------- - -// txout_target_v - -// optional .safex.txout_to_key txout_to_key = 1; -inline bool txout_target_v::has_txout_to_key() const { - return !_is_default_instance_ && txout_to_key_ != NULL; -} -inline void txout_target_v::clear_txout_to_key() { - if (GetArenaNoVirtual() == NULL && txout_to_key_ != NULL) delete txout_to_key_; - txout_to_key_ = NULL; -} -inline const ::safex::txout_to_key& txout_target_v::txout_to_key() const { - // @@protoc_insertion_point(field_get:safex.txout_target_v.txout_to_key) - return txout_to_key_ != NULL ? *txout_to_key_ : *default_instance_->txout_to_key_; -} -inline ::safex::txout_to_key* txout_target_v::mutable_txout_to_key() { - - if (txout_to_key_ == NULL) { - txout_to_key_ = new ::safex::txout_to_key; - } - // @@protoc_insertion_point(field_mutable:safex.txout_target_v.txout_to_key) - return txout_to_key_; -} -inline ::safex::txout_to_key* txout_target_v::release_txout_to_key() { - // @@protoc_insertion_point(field_release:safex.txout_target_v.txout_to_key) - - ::safex::txout_to_key* temp = txout_to_key_; - txout_to_key_ = NULL; - return temp; -} -inline void txout_target_v::set_allocated_txout_to_key(::safex::txout_to_key* txout_to_key) { - delete txout_to_key_; - txout_to_key_ = txout_to_key; - if (txout_to_key) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txout_target_v.txout_to_key) -} - -// optional .safex.txout_token_to_key txout_token_to_key = 2; -inline bool txout_target_v::has_txout_token_to_key() const { - return !_is_default_instance_ && txout_token_to_key_ != NULL; -} -inline void txout_target_v::clear_txout_token_to_key() { - if (GetArenaNoVirtual() == NULL && txout_token_to_key_ != NULL) delete txout_token_to_key_; - txout_token_to_key_ = NULL; -} -inline const ::safex::txout_token_to_key& txout_target_v::txout_token_to_key() const { - // @@protoc_insertion_point(field_get:safex.txout_target_v.txout_token_to_key) - return txout_token_to_key_ != NULL ? *txout_token_to_key_ : *default_instance_->txout_token_to_key_; -} -inline ::safex::txout_token_to_key* txout_target_v::mutable_txout_token_to_key() { - - if (txout_token_to_key_ == NULL) { - txout_token_to_key_ = new ::safex::txout_token_to_key; - } - // @@protoc_insertion_point(field_mutable:safex.txout_target_v.txout_token_to_key) - return txout_token_to_key_; -} -inline ::safex::txout_token_to_key* txout_target_v::release_txout_token_to_key() { - // @@protoc_insertion_point(field_release:safex.txout_target_v.txout_token_to_key) - - ::safex::txout_token_to_key* temp = txout_token_to_key_; - txout_token_to_key_ = NULL; - return temp; -} -inline void txout_target_v::set_allocated_txout_token_to_key(::safex::txout_token_to_key* txout_token_to_key) { - delete txout_token_to_key_; - txout_token_to_key_ = txout_token_to_key; - if (txout_token_to_key) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txout_target_v.txout_token_to_key) -} - -// ------------------------------------------------------------------- - -// txout - -// optional uint64 amount = 1; -inline void txout::clear_amount() { - amount_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 txout::amount() const { - // @@protoc_insertion_point(field_get:safex.txout.amount) - return amount_; -} -inline void txout::set_amount(::google::protobuf::uint64 value) { - - amount_ = value; - // @@protoc_insertion_point(field_set:safex.txout.amount) -} - -// optional uint64 token_amount = 2; -inline void txout::clear_token_amount() { - token_amount_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 txout::token_amount() const { - // @@protoc_insertion_point(field_get:safex.txout.token_amount) - return token_amount_; -} -inline void txout::set_token_amount(::google::protobuf::uint64 value) { - - token_amount_ = value; - // @@protoc_insertion_point(field_set:safex.txout.token_amount) -} - -// optional .safex.txout_target_v target = 3; -inline bool txout::has_target() const { - return !_is_default_instance_ && target_ != NULL; -} -inline void txout::clear_target() { - if (GetArenaNoVirtual() == NULL && target_ != NULL) delete target_; - target_ = NULL; -} -inline const ::safex::txout_target_v& txout::target() const { - // @@protoc_insertion_point(field_get:safex.txout.target) - return target_ != NULL ? *target_ : *default_instance_->target_; -} -inline ::safex::txout_target_v* txout::mutable_target() { - - if (target_ == NULL) { - target_ = new ::safex::txout_target_v; - } - // @@protoc_insertion_point(field_mutable:safex.txout.target) - return target_; -} -inline ::safex::txout_target_v* txout::release_target() { - // @@protoc_insertion_point(field_release:safex.txout.target) - - ::safex::txout_target_v* temp = target_; - target_ = NULL; - return temp; -} -inline void txout::set_allocated_target(::safex::txout_target_v* target) { - delete target_; - target_ = target; - if (target) { - - } else { - - } - // @@protoc_insertion_point(field_set_allocated:safex.txout.target) -} - -// ------------------------------------------------------------------- - -// SigData - -// optional bytes r = 1; -inline void SigData::clear_r() { - r_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& SigData::r() const { - // @@protoc_insertion_point(field_get:safex.SigData.r) - return r_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void SigData::set_r(const ::std::string& value) { - - r_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.SigData.r) -} -inline void SigData::set_r(const char* value) { - - r_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.SigData.r) -} -inline void SigData::set_r(const void* value, size_t size) { - - r_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.SigData.r) -} -inline ::std::string* SigData::mutable_r() { - - // @@protoc_insertion_point(field_mutable:safex.SigData.r) - return r_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* SigData::release_r() { - // @@protoc_insertion_point(field_release:safex.SigData.r) - - return r_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void SigData::set_allocated_r(::std::string* r) { - if (r != NULL) { - - } else { - - } - r_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), r); - // @@protoc_insertion_point(field_set_allocated:safex.SigData.r) -} - -// optional bytes c = 2; -inline void SigData::clear_c() { - c_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& SigData::c() const { - // @@protoc_insertion_point(field_get:safex.SigData.c) - return c_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void SigData::set_c(const ::std::string& value) { - - c_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.SigData.c) -} -inline void SigData::set_c(const char* value) { - - c_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.SigData.c) -} -inline void SigData::set_c(const void* value, size_t size) { - - c_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.SigData.c) -} -inline ::std::string* SigData::mutable_c() { - - // @@protoc_insertion_point(field_mutable:safex.SigData.c) - return c_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* SigData::release_c() { - // @@protoc_insertion_point(field_release:safex.SigData.c) - - return c_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void SigData::set_allocated_c(::std::string* c) { - if (c != NULL) { - - } else { - - } - c_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), c); - // @@protoc_insertion_point(field_set_allocated:safex.SigData.c) -} - -// ------------------------------------------------------------------- - -// Signature - -// repeated .safex.SigData signature = 1; -inline int Signature::signature_size() const { - return signature_.size(); -} -inline void Signature::clear_signature() { - signature_.Clear(); -} -inline const ::safex::SigData& Signature::signature(int index) const { - // @@protoc_insertion_point(field_get:safex.Signature.signature) - return signature_.Get(index); -} -inline ::safex::SigData* Signature::mutable_signature(int index) { - // @@protoc_insertion_point(field_mutable:safex.Signature.signature) - return signature_.Mutable(index); -} -inline ::safex::SigData* Signature::add_signature() { - // @@protoc_insertion_point(field_add:safex.Signature.signature) - return signature_.Add(); -} -inline ::google::protobuf::RepeatedPtrField< ::safex::SigData >* -Signature::mutable_signature() { - // @@protoc_insertion_point(field_mutable_list:safex.Signature.signature) - return &signature_; -} -inline const ::google::protobuf::RepeatedPtrField< ::safex::SigData >& -Signature::signature() const { - // @@protoc_insertion_point(field_list:safex.Signature.signature) - return signature_; -} - -// ------------------------------------------------------------------- - -// Transaction - -// optional uint64 version = 1; -inline void Transaction::clear_version() { - version_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 Transaction::version() const { - // @@protoc_insertion_point(field_get:safex.Transaction.version) - return version_; -} -inline void Transaction::set_version(::google::protobuf::uint64 value) { - - version_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.version) -} - -// optional uint64 unlock_time = 2; -inline void Transaction::clear_unlock_time() { - unlock_time_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 Transaction::unlock_time() const { - // @@protoc_insertion_point(field_get:safex.Transaction.unlock_time) - return unlock_time_; -} -inline void Transaction::set_unlock_time(::google::protobuf::uint64 value) { - - unlock_time_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.unlock_time) -} - -// optional bytes extra = 3; -inline void Transaction::clear_extra() { - extra_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& Transaction::extra() const { - // @@protoc_insertion_point(field_get:safex.Transaction.extra) - return extra_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Transaction::set_extra(const ::std::string& value) { - - extra_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Transaction.extra) -} -inline void Transaction::set_extra(const char* value) { - - extra_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Transaction.extra) -} -inline void Transaction::set_extra(const void* value, size_t size) { - - extra_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Transaction.extra) -} -inline ::std::string* Transaction::mutable_extra() { - - // @@protoc_insertion_point(field_mutable:safex.Transaction.extra) - return extra_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* Transaction::release_extra() { - // @@protoc_insertion_point(field_release:safex.Transaction.extra) - - return extra_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Transaction::set_allocated_extra(::std::string* extra) { - if (extra != NULL) { - - } else { - - } - extra_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), extra); - // @@protoc_insertion_point(field_set_allocated:safex.Transaction.extra) -} - -// repeated .safex.txin_v vin = 4; -inline int Transaction::vin_size() const { - return vin_.size(); -} -inline void Transaction::clear_vin() { - vin_.Clear(); -} -inline const ::safex::txin_v& Transaction::vin(int index) const { - // @@protoc_insertion_point(field_get:safex.Transaction.vin) - return vin_.Get(index); -} -inline ::safex::txin_v* Transaction::mutable_vin(int index) { - // @@protoc_insertion_point(field_mutable:safex.Transaction.vin) - return vin_.Mutable(index); -} -inline ::safex::txin_v* Transaction::add_vin() { - // @@protoc_insertion_point(field_add:safex.Transaction.vin) - return vin_.Add(); -} -inline ::google::protobuf::RepeatedPtrField< ::safex::txin_v >* -Transaction::mutable_vin() { - // @@protoc_insertion_point(field_mutable_list:safex.Transaction.vin) - return &vin_; -} -inline const ::google::protobuf::RepeatedPtrField< ::safex::txin_v >& -Transaction::vin() const { - // @@protoc_insertion_point(field_list:safex.Transaction.vin) - return vin_; -} - -// repeated .safex.txout vout = 5; -inline int Transaction::vout_size() const { - return vout_.size(); -} -inline void Transaction::clear_vout() { - vout_.Clear(); -} -inline const ::safex::txout& Transaction::vout(int index) const { - // @@protoc_insertion_point(field_get:safex.Transaction.vout) - return vout_.Get(index); -} -inline ::safex::txout* Transaction::mutable_vout(int index) { - // @@protoc_insertion_point(field_mutable:safex.Transaction.vout) - return vout_.Mutable(index); -} -inline ::safex::txout* Transaction::add_vout() { - // @@protoc_insertion_point(field_add:safex.Transaction.vout) - return vout_.Add(); -} -inline ::google::protobuf::RepeatedPtrField< ::safex::txout >* -Transaction::mutable_vout() { - // @@protoc_insertion_point(field_mutable_list:safex.Transaction.vout) - return &vout_; -} -inline const ::google::protobuf::RepeatedPtrField< ::safex::txout >& -Transaction::vout() const { - // @@protoc_insertion_point(field_list:safex.Transaction.vout) - return vout_; -} - -// repeated .safex.Signature signatures = 6; -inline int Transaction::signatures_size() const { - return signatures_.size(); -} -inline void Transaction::clear_signatures() { - signatures_.Clear(); -} -inline const ::safex::Signature& Transaction::signatures(int index) const { - // @@protoc_insertion_point(field_get:safex.Transaction.signatures) - return signatures_.Get(index); -} -inline ::safex::Signature* Transaction::mutable_signatures(int index) { - // @@protoc_insertion_point(field_mutable:safex.Transaction.signatures) - return signatures_.Mutable(index); -} -inline ::safex::Signature* Transaction::add_signatures() { - // @@protoc_insertion_point(field_add:safex.Transaction.signatures) - return signatures_.Add(); -} -inline ::google::protobuf::RepeatedPtrField< ::safex::Signature >* -Transaction::mutable_signatures() { - // @@protoc_insertion_point(field_mutable_list:safex.Transaction.signatures) - return &signatures_; -} -inline const ::google::protobuf::RepeatedPtrField< ::safex::Signature >& -Transaction::signatures() const { - // @@protoc_insertion_point(field_list:safex.Transaction.signatures) - return signatures_; -} - -// optional uint64 block_height = 7; -inline void Transaction::clear_block_height() { - block_height_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 Transaction::block_height() const { - // @@protoc_insertion_point(field_get:safex.Transaction.block_height) - return block_height_; -} -inline void Transaction::set_block_height(::google::protobuf::uint64 value) { - - block_height_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.block_height) -} - -// optional uint64 block_timestamp = 8; -inline void Transaction::clear_block_timestamp() { - block_timestamp_ = GOOGLE_ULONGLONG(0); -} -inline ::google::protobuf::uint64 Transaction::block_timestamp() const { - // @@protoc_insertion_point(field_get:safex.Transaction.block_timestamp) - return block_timestamp_; -} -inline void Transaction::set_block_timestamp(::google::protobuf::uint64 value) { - - block_timestamp_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.block_timestamp) -} - -// optional bool double_spend_seen = 9; -inline void Transaction::clear_double_spend_seen() { - double_spend_seen_ = false; -} -inline bool Transaction::double_spend_seen() const { - // @@protoc_insertion_point(field_get:safex.Transaction.double_spend_seen) - return double_spend_seen_; -} -inline void Transaction::set_double_spend_seen(bool value) { - - double_spend_seen_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.double_spend_seen) -} - -// optional bool in_pool = 10; -inline void Transaction::clear_in_pool() { - in_pool_ = false; -} -inline bool Transaction::in_pool() const { - // @@protoc_insertion_point(field_get:safex.Transaction.in_pool) - return in_pool_; -} -inline void Transaction::set_in_pool(bool value) { - - in_pool_ = value; - // @@protoc_insertion_point(field_set:safex.Transaction.in_pool) -} - -// repeated uint64 output_indices = 11; -inline int Transaction::output_indices_size() const { - return output_indices_.size(); -} -inline void Transaction::clear_output_indices() { - output_indices_.Clear(); -} -inline ::google::protobuf::uint64 Transaction::output_indices(int index) const { - // @@protoc_insertion_point(field_get:safex.Transaction.output_indices) - return output_indices_.Get(index); -} -inline void Transaction::set_output_indices(int index, ::google::protobuf::uint64 value) { - output_indices_.Set(index, value); - // @@protoc_insertion_point(field_set:safex.Transaction.output_indices) -} -inline void Transaction::add_output_indices(::google::protobuf::uint64 value) { - output_indices_.Add(value); - // @@protoc_insertion_point(field_add:safex.Transaction.output_indices) -} -inline const ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >& -Transaction::output_indices() const { - // @@protoc_insertion_point(field_list:safex.Transaction.output_indices) - return output_indices_; -} -inline ::google::protobuf::RepeatedField< ::google::protobuf::uint64 >* -Transaction::mutable_output_indices() { - // @@protoc_insertion_point(field_mutable_list:safex.Transaction.output_indices) - return &output_indices_; -} - -// optional string tx_hash = 12; -inline void Transaction::clear_tx_hash() { - tx_hash_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline const ::std::string& Transaction::tx_hash() const { - // @@protoc_insertion_point(field_get:safex.Transaction.tx_hash) - return tx_hash_.GetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Transaction::set_tx_hash(const ::std::string& value) { - - tx_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), value); - // @@protoc_insertion_point(field_set:safex.Transaction.tx_hash) -} -inline void Transaction::set_tx_hash(const char* value) { - - tx_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), ::std::string(value)); - // @@protoc_insertion_point(field_set_char:safex.Transaction.tx_hash) -} -inline void Transaction::set_tx_hash(const char* value, size_t size) { - - tx_hash_.SetNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), - ::std::string(reinterpret_cast(value), size)); - // @@protoc_insertion_point(field_set_pointer:safex.Transaction.tx_hash) -} -inline ::std::string* Transaction::mutable_tx_hash() { - - // @@protoc_insertion_point(field_mutable:safex.Transaction.tx_hash) - return tx_hash_.MutableNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline ::std::string* Transaction::release_tx_hash() { - // @@protoc_insertion_point(field_release:safex.Transaction.tx_hash) - - return tx_hash_.ReleaseNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); -} -inline void Transaction::set_allocated_tx_hash(::std::string* tx_hash) { - if (tx_hash != NULL) { - - } else { - - } - tx_hash_.SetAllocatedNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), tx_hash); - // @@protoc_insertion_point(field_set_allocated:safex.Transaction.tx_hash) -} - -// ------------------------------------------------------------------- - -// Transactions - -// repeated .safex.Transaction tx = 1; -inline int Transactions::tx_size() const { - return tx_.size(); -} -inline void Transactions::clear_tx() { - tx_.Clear(); -} -inline const ::safex::Transaction& Transactions::tx(int index) const { - // @@protoc_insertion_point(field_get:safex.Transactions.tx) - return tx_.Get(index); -} -inline ::safex::Transaction* Transactions::mutable_tx(int index) { - // @@protoc_insertion_point(field_mutable:safex.Transactions.tx) - return tx_.Mutable(index); -} -inline ::safex::Transaction* Transactions::add_tx() { - // @@protoc_insertion_point(field_add:safex.Transactions.tx) - return tx_.Add(); -} -inline ::google::protobuf::RepeatedPtrField< ::safex::Transaction >* -Transactions::mutable_tx() { - // @@protoc_insertion_point(field_mutable_list:safex.Transactions.tx) - return &tx_; -} -inline const ::google::protobuf::RepeatedPtrField< ::safex::Transaction >& -Transactions::tx() const { - // @@protoc_insertion_point(field_list:safex.Transactions.tx) - return tx_; -} - -// repeated string missed_txs = 2; -inline int Transactions::missed_txs_size() const { - return missed_txs_.size(); -} -inline void Transactions::clear_missed_txs() { - missed_txs_.Clear(); -} -inline const ::std::string& Transactions::missed_txs(int index) const { - // @@protoc_insertion_point(field_get:safex.Transactions.missed_txs) - return missed_txs_.Get(index); -} -inline ::std::string* Transactions::mutable_missed_txs(int index) { - // @@protoc_insertion_point(field_mutable:safex.Transactions.missed_txs) - return missed_txs_.Mutable(index); -} -inline void Transactions::set_missed_txs(int index, const ::std::string& value) { - // @@protoc_insertion_point(field_set:safex.Transactions.missed_txs) - missed_txs_.Mutable(index)->assign(value); -} -inline void Transactions::set_missed_txs(int index, const char* value) { - missed_txs_.Mutable(index)->assign(value); - // @@protoc_insertion_point(field_set_char:safex.Transactions.missed_txs) -} -inline void Transactions::set_missed_txs(int index, const char* value, size_t size) { - missed_txs_.Mutable(index)->assign( - reinterpret_cast(value), size); - // @@protoc_insertion_point(field_set_pointer:safex.Transactions.missed_txs) -} -inline ::std::string* Transactions::add_missed_txs() { - // @@protoc_insertion_point(field_add_mutable:safex.Transactions.missed_txs) - return missed_txs_.Add(); -} -inline void Transactions::add_missed_txs(const ::std::string& value) { - missed_txs_.Add()->assign(value); - // @@protoc_insertion_point(field_add:safex.Transactions.missed_txs) -} -inline void Transactions::add_missed_txs(const char* value) { - missed_txs_.Add()->assign(value); - // @@protoc_insertion_point(field_add_char:safex.Transactions.missed_txs) -} -inline void Transactions::add_missed_txs(const char* value, size_t size) { - missed_txs_.Add()->assign(reinterpret_cast(value), size); - // @@protoc_insertion_point(field_add_pointer:safex.Transactions.missed_txs) -} -inline const ::google::protobuf::RepeatedPtrField< ::std::string>& -Transactions::missed_txs() const { - // @@protoc_insertion_point(field_list:safex.Transactions.missed_txs) - return missed_txs_; -} -inline ::google::protobuf::RepeatedPtrField< ::std::string>* -Transactions::mutable_missed_txs() { - // @@protoc_insertion_point(field_mutable_list:safex.Transactions.missed_txs) - return &missed_txs_; -} - -#endif // !PROTOBUF_INLINE_NOT_IN_HEADERS -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - -// ------------------------------------------------------------------- - - -// @@protoc_insertion_point(namespace_scope) - -} // namespace safex - -// @@protoc_insertion_point(global_scope) - -#endif // PROTOBUF_transactions_2eproto__INCLUDED diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 481c7fbf0..a40bf1b4b 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -46,6 +46,7 @@ #include "warnings.h" #include "common/perf_timer.h" #include "crypto/hash.h" +#include "safex/command.h" #undef SAFEX_DEFAULT_LOG_CATEGORY #define SAFEX_DEFAULT_LOG_CATEGORY "txpool" @@ -92,13 +93,17 @@ namespace cryptonote // the whole prepare/handle/cleanup incoming block sequence. class LockedTXN { public: - LockedTXN(Blockchain &b): m_blockchain(b), m_batch(false) { + LockedTXN(Blockchain &b): m_blockchain(b), m_batch(false), m_active(false) { m_batch = m_blockchain.get_db().batch_start(); + m_active = true; } - ~LockedTXN() { try { if (m_batch) { m_blockchain.get_db().batch_stop(); } } catch (const std::exception &e) { MWARNING("LockedTXN dtor filtering exception: " << e.what()); } } + void commit() { try { if (m_batch && m_active) { m_blockchain.get_db().batch_stop(); m_active = false; } } catch (const std::exception &e) { MWARNING("LockedTXN::commit filtering exception: " << e.what()); } } + void abort() { try { if (m_batch && m_active) { m_blockchain.get_db().batch_abort(); m_active = false; } } catch (const std::exception &e) { MWARNING("LockedTXN::abort filtering exception: " << e.what()); } } + ~LockedTXN() { abort(); } private: Blockchain &m_blockchain; bool m_batch; + bool m_active; }; } //--------------------------------------------------------------------------------- @@ -108,7 +113,9 @@ namespace cryptonote } //--------------------------------------------------------------------------------- - bool tx_memory_pool::add_tx(transaction &tx, /*const crypto::hash& tx_prefix_hash,*/ const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version) + + //--------------------------------------------------------------------------------- + bool tx_memory_pool::add_tx(transaction &tx, const crypto::hash &id, size_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool relayed, bool do_not_relay, uint8_t version) { // this should already be called with that lock, but let's make it explicit for clarity CRITICAL_REGION_LOCAL(m_transactions_lock); @@ -142,16 +149,16 @@ namespace cryptonote // fee per kilobyte, size rounded up. uint64_t fee; - if (tx.version == 1) + if (tx.version >= MIN_SUPPORTED_TX_VERSION && tx.version <= m_blockchain.get_maximum_tx_version_supported(version)) { uint64_t inputs_amount = 0; - if(!get_inputs_money_amount(tx, inputs_amount)) + if(!get_inputs_cash_amount(tx, inputs_amount)) { tvc.m_verifivation_failed = true; return false; } - uint64_t outputs_amount = get_outs_money_amount(tx); + uint64_t outputs_amount = get_outs_cash_amount(tx); if(outputs_amount > inputs_amount) { LOG_PRINT_L1("transaction use more money than it has: use " << print_money(outputs_amount) << ", have " << print_money(inputs_amount)); @@ -168,10 +175,40 @@ namespace cryptonote } fee = inputs_amount - outputs_amount; + + uint64_t inputs_token_amount = 0; + if(!get_inputs_token_amount(tx, inputs_token_amount)) + { + tvc.m_verifivation_failed = true; + return false; + } + + uint64_t outputs_token_amount = get_outs_token_amount(tx); + if(outputs_token_amount != inputs_token_amount) + { + crypto::hash problematic_tx; + if (!epee::string_tools::hex_to_pod("1153c9354147a1b4f6199501be6b338f5407c1ecd26e87c537437c166f22f268", problematic_tx)) + return false; + if (tx.hash != problematic_tx){ + LOG_PRINT_L1("Transaction must use same amount of tokens on input and output - output: " << print_money(outputs_token_amount) << ", input " << print_money(inputs_token_amount)); + tvc.m_verifivation_failed = true; + tvc.m_overspend = true; + return false; + } + } + + if(!m_blockchain.are_safex_tokens_unlocked(tx.vin)){ + tvc.m_verifivation_failed = true; + tvc.m_safex_invalid_command_params = true; + return false; + } + } else { - fee = tx.rct_signatures.txnFee; + tvc.m_verifivation_failed = true; + tvc.m_invalid_input = true; + return false; } if (!kept_by_block && !m_blockchain.check_fee(blob_size, fee)) @@ -203,6 +240,14 @@ namespace cryptonote tvc.m_double_spend = true; return false; } + + if (have_tx_safex_restricted(tx)) + { + LOG_PRINT_L1("Transaction with id= "<< id << " has restricted safex usage"); + tvc.m_verifivation_failed = true; + tvc.m_invalid_output = true; + return false; + } } if (!m_blockchain.check_tx_outputs(tx, tvc)) @@ -240,6 +285,7 @@ namespace cryptonote meta.relayed = relayed; meta.do_not_relay = do_not_relay; meta.double_spend_seen = have_tx_keyimges_as_spent(tx); + meta.safex_tx = tx.version >=2; memset(meta.padding, 0, sizeof(meta.padding)); try { @@ -248,7 +294,10 @@ namespace cryptonote m_blockchain.add_txpool_tx(tx, meta); if (!insert_key_images(tx, kept_by_block)) return false; + if (!insert_safex_restrictions(tx, kept_by_block)) + return false; m_txs_by_fee_and_receive_time.emplace(std::pair(fee / (double)blob_size, receive_time), id); + lock.commit(); } catch (const std::exception &e) { @@ -264,7 +313,8 @@ namespace cryptonote tvc.m_invalid_input = true; return false; } - }else + } + else { //update transactions container meta.blob_size = blob_size; @@ -279,6 +329,7 @@ namespace cryptonote meta.relayed = relayed; meta.do_not_relay = do_not_relay; meta.double_spend_seen = false; + meta.safex_tx = tx.version >=2; memset(meta.padding, 0, sizeof(meta.padding)); try @@ -289,7 +340,10 @@ namespace cryptonote m_blockchain.add_txpool_tx(tx, meta); if (!insert_key_images(tx, kept_by_block)) return false; + if (!insert_safex_restrictions(tx, kept_by_block)) + return false; m_txs_by_fee_and_receive_time.emplace(std::pair(fee / (double)blob_size, receive_time), id); + lock.commit(); } catch (const std::exception &e) { @@ -374,6 +428,7 @@ namespace cryptonote m_blockchain.remove_txpool_tx(txid); m_txpool_size -= txblob.size(); remove_transaction_keyimages(tx); + remove_safex_restrictions(tx); MINFO("Pruned tx " << txid << " from txpool: size: " << it->first.second << ", fee/byte: " << it->first.first); m_txs_by_fee_and_receive_time.erase(it--); } @@ -383,6 +438,7 @@ namespace cryptonote return; } } + lock.commit(); if (m_txpool_size > bytes) MINFO("Pool size after pruning is larger than limit: " << m_txpool_size << "/" << bytes); } @@ -392,14 +448,22 @@ namespace cryptonote for(const auto& in: tx.vin) { const crypto::hash id = get_transaction_hash(tx); - if (cryptonote::is_valid_transaction_input_type(in)) { + if (cryptonote::is_valid_transaction_input_type(in, tx.version)) { const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), in); std::unordered_set& kei_image_set = m_spent_key_images[k_image]; CHECK_AND_ASSERT_MES(kept_by_block || kei_image_set.size() == 0, false, "internal error: kept_by_block=" << kept_by_block << ", kei_image_set.size()=" << kei_image_set.size() << ENDL << "txin.k_image=" << k_image << ENDL << "tx_id=" << id ); + + if (in.type() == typeid(txin_to_script)){ + auto input = boost::get(in); + + if(!safex::is_safex_key_image_verification_needed(input.command_type)) + continue; + } auto ins_res = kei_image_set.insert(id); CHECK_AND_ASSERT_MES(ins_res.second, false, "internal error: try to insert duplicate iterator in key_image set"); + } else { LOG_ERROR("wrong input variant type: " << in.type().name() << ", expected " << typeid(txin_to_key).name() << ", " << typeid(txin_token_to_key).name() << " or " << typeid(txin_token_migration).name()); return false; @@ -408,6 +472,72 @@ namespace cryptonote return true; } //--------------------------------------------------------------------------------- + bool tx_memory_pool::insert_safex_restrictions(const transaction &tx, bool kept_by_block) + { + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + m_safex_accounts_in_use.push_back(username); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + m_safex_accounts_in_use.push_back(username); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + m_safex_offers_in_use.push_back(offer.offer_id); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + m_safex_offers_in_use.push_back(offer.offer_id); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_price_peg_data price_peg; + const cryptonote::blobdata pricepegblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(pricepegblob, price_peg); + m_safex_price_peg_update_in_progress.push_back(price_peg.price_peg_id); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::update_price_peg_data price_peg; + const cryptonote::blobdata pricepegblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(pricepegblob, price_peg); + m_safex_price_peg_update_in_progress.push_back(price_peg.price_peg_id); + } else if(vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_purchase) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_purchase_data purchase; + const cryptonote::blobdata purchaseblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(purchaseblob, purchase); + auto it = std::find_if(m_safex_offers_to_purchase.begin(),m_safex_offers_to_purchase.end(), [&purchase](const std::pair& item){ return purchase.offer_id == item.first;}); + if( it != m_safex_offers_to_purchase.end()){ + it->second += purchase.quantity; + } + else + m_safex_offers_to_purchase.push_back(std::make_pair(purchase.offer_id, purchase.quantity)); + } + } + return true; + } + //--------------------------------------------------------------------------------- //FIXME: Can return early before removal of all of the key images. // At the least, need to make sure that a false return here // is treated properly. Should probably not return early, however. @@ -420,8 +550,14 @@ namespace cryptonote crypto::hash actual_hash = get_transaction_hash(tx); for(const txin_v& vi: tx.vin) { - if (cryptonote::is_valid_transaction_input_type(vi)) { + if (cryptonote::is_valid_transaction_input_type(vi, tx.version)) { const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), vi); + if (vi.type() == typeid(const txin_to_script)){ + auto input = boost::get(vi); + + if(!safex::is_safex_key_image_verification_needed(input.command_type)) + continue; + } auto it = m_spent_key_images.find(k_image); CHECK_AND_ASSERT_MES(it != m_spent_key_images.end(), false, "failed to find transaction input in key images. img=" << k_image << ENDL << "transaction id = " << get_transaction_hash(tx)); @@ -447,6 +583,89 @@ namespace cryptonote return true; } //--------------------------------------------------------------------------------- + bool tx_memory_pool::remove_safex_restrictions(const transaction &tx) + { + CRITICAL_REGION_LOCAL(m_transactions_lock); + CRITICAL_REGION_LOCAL1(m_blockchain); + + + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + auto it = std::find(m_safex_accounts_in_use.begin(), m_safex_accounts_in_use.end(), username); + CHECK_AND_ASSERT_MES(it != m_safex_accounts_in_use.end(), false, "failed to find safex restriction for type out_safex_account" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_accounts_in_use.erase(it); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + auto it = std::find(m_safex_accounts_in_use.begin(), m_safex_accounts_in_use.end(), username); + CHECK_AND_ASSERT_MES(it != m_safex_accounts_in_use.end(), false, "failed to find safex restriction for type out_safex_account_update" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_accounts_in_use.erase(it); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + auto it = std::find(m_safex_offers_in_use.begin(), m_safex_offers_in_use.end(), offer.offer_id); + CHECK_AND_ASSERT_MES(it != m_safex_offers_in_use.end(), false, "failed to find safex restriction for type out_safex_offer" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_offers_in_use.erase(it); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + auto it = std::find(m_safex_offers_in_use.begin(), m_safex_offers_in_use.end(), offer.offer_id); + CHECK_AND_ASSERT_MES(it != m_safex_offers_in_use.end(), false, "failed to find safex restriction for type out_safex_offer" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_offers_in_use.erase(it); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_price_peg_data price_peg; + const cryptonote::blobdata pricepegblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(pricepegblob, price_peg); + auto it = std::find(m_safex_price_peg_update_in_progress.begin(), m_safex_price_peg_update_in_progress.end(), price_peg.price_peg_id); + CHECK_AND_ASSERT_MES(it != m_safex_price_peg_update_in_progress.end(), false, "failed to find safex restriction for type out_safex_price_peg_update" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_price_peg_update_in_progress.erase(it); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::update_price_peg_data price_peg; + const cryptonote::blobdata pricepegblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(pricepegblob, price_peg); + auto it = std::find(m_safex_price_peg_update_in_progress.begin(), m_safex_price_peg_update_in_progress.end(), price_peg.price_peg_id); + CHECK_AND_ASSERT_MES(it != m_safex_price_peg_update_in_progress.end(), false, "failed to find safex restriction for type out_safex_price_peg_update" << ENDL << "transaction id = " << get_transaction_hash(tx)); + m_safex_price_peg_update_in_progress.erase(it); + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_purchase) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_purchase_data purchase; + const cryptonote::blobdata purchaseblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(purchaseblob, purchase); + auto it = std::find_if(m_safex_offers_to_purchase.begin(),m_safex_offers_to_purchase.end(), [&purchase](const std::pair& item){ return purchase.offer_id == item.first;}); + CHECK_AND_ASSERT_MES(it != m_safex_offers_to_purchase.end(), false, "failed to find safex restriction for type out_safex_purchase" << ENDL << "transaction id = " << get_transaction_hash(tx)); + if(it->second < purchase.quantity){ + LOG_ERROR("This should not happen! As tx_pool internal calculation is wrong"); + it->second = 0; + } else + it->second -= purchase.quantity; + + } + } + return true; + } + //--------------------------------------------------------------------------------- bool tx_memory_pool::take_tx(const crypto::hash &id, transaction &tx, size_t& blob_size, uint64_t& fee, bool &relayed, bool &do_not_relay, bool &double_spend_seen) { CRITICAL_REGION_LOCAL(m_transactions_lock); @@ -481,6 +700,8 @@ namespace cryptonote m_blockchain.remove_txpool_tx(id); m_txpool_size -= blob_size; remove_transaction_keyimages(tx); + remove_safex_restrictions(tx); + lock.commit(); } catch (const std::exception &e) { @@ -516,7 +737,7 @@ namespace cryptonote uint64_t tx_age = time(nullptr) - meta.receive_time; if((tx_age > CRYPTONOTE_MEMPOOL_TX_LIVETIME && !meta.kept_by_block) || - (tx_age > CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME && meta.kept_by_block) ) + (tx_age > CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME && meta.kept_by_block)) { LOG_PRINT_L1("Tx " << txid << " removed from tx pool due to outdated, age: " << tx_age ); auto sorted_it = find_tx_in_sorted_container(txid); @@ -530,6 +751,31 @@ namespace cryptonote } m_timed_out_transactions.insert(txid); remove.insert(txid); + } else if (tx_age > CRYPTONOTE_MEMPOOL_SAFEX_TX_LIVETIME && meta.safex_tx) + { + cryptonote::blobdata txblob = m_blockchain.get_txpool_tx_blob(txid); + cryptonote::transaction tx; + if (!parse_and_validate_tx_from_blob(txblob, tx)) + { + MERROR("Failed to parse tx from txpool"); + return true; + } + tx_verification_context tvc; + if(!m_blockchain.check_safex_tx(tx, tvc)) + { + LOG_PRINT_L1("Tx " << txid << " removed from tx pool due to outdated, age: " << tx_age ); + auto sorted_it = find_tx_in_sorted_container(txid); + if (sorted_it == m_txs_by_fee_and_receive_time.end()) + { + LOG_PRINT_L1("Removing tx " << txid << " from tx pool, but it was not found in the sorted txs container!"); + } + else + { + m_txs_by_fee_and_receive_time.erase(sorted_it); + } + m_timed_out_transactions.insert(txid); + remove.insert(txid); + } } return true; }, false); @@ -554,6 +800,7 @@ namespace cryptonote m_blockchain.remove_txpool_tx(txid); m_txpool_size -= bd.size(); remove_transaction_keyimages(tx); + remove_safex_restrictions(tx); } } catch (const std::exception &e) @@ -562,6 +809,7 @@ namespace cryptonote // ignore error } } + lock.commit(); } return true; } @@ -623,6 +871,7 @@ namespace cryptonote // continue } } + lock.commit(); } //--------------------------------------------------------------------------------- size_t tx_memory_pool::get_transactions_count(bool include_unrelayed_txes) const @@ -915,8 +1164,15 @@ namespace cryptonote CRITICAL_REGION_LOCAL1(m_blockchain); for(const auto& in: tx.vin) { - if (cryptonote::is_valid_transaction_input_type(in)) { + if (cryptonote::is_valid_transaction_input_type(in, tx.version)) { const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), in); + + if (in.type() == typeid(const txin_to_script)){ + auto input = boost::get(in); + + if(!safex::is_safex_key_image_verification_needed(input.command_type)) + continue; + } if(have_tx_keyimg_as_spent(k_image)) return true; } else { @@ -927,12 +1183,117 @@ namespace cryptonote return false; } //--------------------------------------------------------------------------------- + bool tx_memory_pool::have_tx_safex_restricted(const transaction &tx) const + { + CRITICAL_REGION_LOCAL(m_transactions_lock); + CRITICAL_REGION_LOCAL1(m_blockchain); + for (const auto &vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + if(have_tx_safex_account_in_use(username)) + return true; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_account_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string username{account.username.begin(),account.username.end()}; + if(have_tx_safex_account_in_use(username)) + return true; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + if(have_tx_safex_offer_in_use(offer.offer_id)) + return true; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + if(have_tx_safex_offer_in_use(offer.offer_id)) + return true; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_price_peg_data price_peg; + const cryptonote::blobdata pricepegblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(pricepegblob, price_peg); + if(have_tx_safex_price_peg_in_use(price_peg.price_peg_id)) + return true; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::update_price_peg_data price_peg; + const cryptonote::blobdata pricepegblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(pricepegblob, price_peg); + if(have_tx_safex_price_peg_in_use(price_peg.price_peg_id)) + return true; + } else if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_purchase) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_purchase_data purchase; + const cryptonote::blobdata purchaseblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(purchaseblob, purchase); + uint64_t purchased_quantity = have_tx_safex_purchase_in_use(purchase.offer_id); + if(have_tx_safex_offer_in_use(purchase.offer_id)) + return true; + if(purchased_quantity != 0){ + uint64_t quantity; + bool res = m_blockchain.get_safex_offer_quantity(purchase.offer_id, quantity); + if(!res){ + LOG_ERROR("Error getin offer quantity from blockchain"); + return true; + } + if(quantity < purchased_quantity + purchase.quantity) + return true; + } + } + } + return false; + } + //--------------------------------------------------------------------------------- bool tx_memory_pool::have_tx_keyimg_as_spent(const crypto::key_image& key_im) const { CRITICAL_REGION_LOCAL(m_transactions_lock); return m_spent_key_images.end() != m_spent_key_images.find(key_im); } //--------------------------------------------------------------------------------- + bool tx_memory_pool::have_tx_safex_account_in_use(const std::string &username) const + { + CRITICAL_REGION_LOCAL(m_transactions_lock); + return m_safex_accounts_in_use.end() != std::find(m_safex_accounts_in_use.begin(), m_safex_accounts_in_use.end(), username); + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::have_tx_safex_offer_in_use(const crypto::hash& offer_id) const + { + CRITICAL_REGION_LOCAL(m_transactions_lock); + return m_safex_offers_in_use.end() != std::find(m_safex_offers_in_use.begin(), m_safex_offers_in_use.end(), offer_id); + } + //--------------------------------------------------------------------------------- + bool tx_memory_pool::have_tx_safex_price_peg_in_use(const crypto::hash &price_peg_id) const + { + CRITICAL_REGION_LOCAL(m_transactions_lock); + return m_safex_price_peg_update_in_progress.end() != std::find(m_safex_price_peg_update_in_progress.begin(), m_safex_price_peg_update_in_progress.end(), price_peg_id); + } + //--------------------------------------------------------------------------------- + uint64_t tx_memory_pool::have_tx_safex_purchase_in_use(const crypto::hash &offer_id) const + { + CRITICAL_REGION_LOCAL(m_transactions_lock); + auto it = std::find_if(m_safex_offers_to_purchase.begin(),m_safex_offers_to_purchase.end(), [&offer_id](const std::pair& item){ return offer_id == item.first;}); + return it != m_safex_offers_to_purchase.end() ? it->second : 0; + } + //--------------------------------------------------------------------------------- void tx_memory_pool::lock() const { m_transactions_lock.lock(); @@ -967,7 +1328,7 @@ namespace cryptonote if(true) { //if we already failed on this height and id, skip actual ring signature check - if(txd.last_failed_id == m_blockchain.get_block_id_by_height(txd.last_failed_height)) + if(txd.last_failed_id == m_blockchain.get_block_id_by_height(m_blockchain.get_current_blockchain_height()-1)) return false; //check ring signature again, it is possible (with very small chance) that this transaction become again valid tx_verification_context tvc; @@ -990,12 +1351,90 @@ namespace cryptonote return true; } //--------------------------------------------------------------------------------- + bool tx_memory_pool::is_purchase_possible(txpool_tx_meta_t& txd, transaction &tx, std::unordered_map& offer_quantity_left, std::vector& offers_edited, std::vector& price_pegs_edited) const + { + if(get_tx_type(tx.vout) == tx_out_type::out_safex_offer_update) + { + for (auto vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_offer_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::edit_offer_data offer_data; + const cryptonote::blobdata offereblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(offereblob, offer_data); + + offers_edited.push_back(offer_data.offer_id); + return true; + } + } + return true; + } + + if(get_tx_type(tx.vout) == tx_out_type::out_safex_price_peg_update) + { + for (auto vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_price_peg_update) + { + const txout_to_script &out = boost::get(vout.target); + safex::update_price_peg_data price_peg_data; + const cryptonote::blobdata pricepegblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(pricepegblob, price_peg_data); + + price_pegs_edited.push_back(price_peg_data.price_peg_id); + return true; + } + } + return true; + } + + + if(get_tx_type(tx.vout) != tx_out_type::out_safex_purchase) + return true; + + for (auto vout: tx.vout) + { + if (vout.target.type() == typeid(txout_to_script) && get_tx_out_type(vout.target) == cryptonote::tx_out_type::out_safex_purchase) + { + const txout_to_script &out = boost::get(vout.target); + safex::create_purchase_data purchase; + const cryptonote::blobdata purchaseblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(purchaseblob, purchase); + safex::safex_offer offer_to_purchase; + auto res = m_blockchain.get_safex_offer(purchase.offer_id, offer_to_purchase); + if(!res){ + txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1; + txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height); + return false; + } + + if(offer_quantity_left.count(purchase.offer_id) == 0){ + offer_quantity_left[purchase.offer_id] = offer_to_purchase.quantity; + } + + bool offer_edit_inside = std::find(offers_edited.begin(),offers_edited.end(), purchase.offer_id) != offers_edited.end(); + bool price_peg_update_inside = offer_to_purchase.price_peg_used ? std::find(price_pegs_edited.begin(), price_pegs_edited.end(), offer_to_purchase.price_peg_id) != price_pegs_edited.end() + : false; + + if(offer_quantity_left[purchase.offer_id] < purchase.quantity || offer_edit_inside || price_peg_update_inside){ + txd.last_failed_height = m_blockchain.get_current_blockchain_height()-1; + txd.last_failed_id = m_blockchain.get_block_id_by_height(txd.last_failed_height); + return false; + } + offer_quantity_left[purchase.offer_id] -= purchase.quantity; + } + } + + return true; + } + //--------------------------------------------------------------------------------- bool tx_memory_pool::have_key_images(const std::unordered_set& k_images, const transaction& tx) { for(size_t i = 0; i!= tx.vin.size(); i++) { const txin_v &in = tx.vin[i]; - if (cryptonote::is_valid_transaction_input_type(in)) { + if (cryptonote::is_valid_transaction_input_type(in, tx.version)) { auto k_image_opt = boost::apply_visitor(key_image_visitor(), in); CHECK_AND_ASSERT_MES(k_image_opt, false, "key image available in input is not valid"); if(k_images.count(*k_image_opt)) @@ -1010,15 +1449,22 @@ namespace cryptonote //--------------------------------------------------------------------------------- bool tx_memory_pool::append_key_images(std::unordered_set& k_images, const transaction& tx) { - for(size_t i = 0; i!= tx.vin.size(); i++) + for(auto& txin: tx.vin) { - if (cryptonote::is_valid_transaction_input_type(tx.vin[i])) { - auto k_image_opt = boost::apply_visitor(key_image_visitor(), tx.vin[i]); + if (txin.type() == typeid(txin_to_script)) + { + const txin_to_script& in_to_script = boost::get(txin); + if(!safex::is_safex_key_image_verification_needed(in_to_script.command_type)) + continue; + } + + if (cryptonote::is_valid_transaction_input_type(txin, tx.version)) { + auto k_image_opt = boost::apply_visitor(key_image_visitor(), txin); CHECK_AND_ASSERT_MES(k_image_opt, false, "key image available in input is not valid"); auto i_res = k_images.insert(*k_image_opt); CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: key images pool cache - inserted duplicate image in set: " << *k_image_opt); } else { - LOG_ERROR("wrong input variant type: " << tx.vin[i].type().name() << ", expected " << typeid(txin_to_key).name() << ", " << typeid(txin_token_to_key).name() << " or " << typeid(txin_token_migration).name()); + LOG_ERROR("wrong input variant type: " << txin.type().name() << ", expected " << typeid(txin_to_key).name() << ", " << typeid(txin_token_to_key).name() << " or " << typeid(txin_token_migration).name()); return false; } } @@ -1034,7 +1480,7 @@ namespace cryptonote { //CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, void()); const txin_v &in = tx.vin[i]; - if (cryptonote::is_valid_transaction_input_type(in)) { + if (cryptonote::is_valid_transaction_input_type(in, tx.version)) { const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), in); const key_images_container::const_iterator it = m_spent_key_images.find(k_image); if (it != m_spent_key_images.end()) @@ -1070,6 +1516,7 @@ namespace cryptonote return void(); } } + lock.commit(); } //--------------------------------------------------------------------------------- std::string tx_memory_pool::print_pool(bool short_format) const @@ -1115,7 +1562,7 @@ namespace cryptonote uint64_t best_coinbase = 0, coinbase = 0; total_size = 0; fee = 0; - + //baseline empty block get_block_reward(median_size, total_size, already_generated_coins, best_coinbase, version, height); @@ -1134,6 +1581,16 @@ namespace cryptonote LockedTXN lock(m_blockchain); + //Safex related collections needed for cleaner selection of purchase txs to include in the block + std::unordered_map offer_quantity_left; + std::vector offers_edited; + std::vector price_pegs_edited; + + std::vector safex_accounts_in_block; + std::vector safex_offer_in_block; + std::vector safex_offers_purchase_in_block; + std::vector safex_price_peg_in_block; + auto sorted_it = m_txs_by_fee_and_receive_time.begin(); while (sorted_it != m_txs_by_fee_and_receive_time.end()) { @@ -1197,18 +1654,19 @@ namespace cryptonote // included into the blockchain or that are // missing key images const cryptonote::txpool_tx_meta_t original_meta = meta; - bool ready = is_transaction_ready_to_go(meta, tx); + bool ready = is_transaction_ready_to_go(meta, tx) && is_purchase_possible(meta, tx, offer_quantity_left, offers_edited, price_pegs_edited) + && insert_and_check_safex_restrictions(tx, safex_accounts_in_block, safex_offer_in_block, safex_offers_purchase_in_block, safex_price_peg_in_block); if (memcmp(&original_meta, &meta, sizeof(meta))) { try - { - m_blockchain.update_txpool_tx(sorted_it->second, meta); - } - catch (const std::exception &e) - { - MERROR("Failed to update tx meta: " << e.what()); - // continue, not fatal - } + { + m_blockchain.update_txpool_tx(sorted_it->second, meta); + } + catch (const std::exception &e) + { + MERROR("Failed to update tx meta: " << e.what()); + // continue, not fatal + } } if (!ready) { @@ -1231,6 +1689,7 @@ namespace cryptonote sorted_it++; LOG_PRINT_L2(" added, new block size " << total_size << "/" << max_total_size << ", coinbase " << print_money(best_coinbase)); } + lock.commit(); expected_reward = best_coinbase; LOG_PRINT_L2("Block template filled with " << bl.tx_hashes.size() << " txes, size " @@ -1279,6 +1738,7 @@ namespace cryptonote m_blockchain.remove_txpool_tx(txid); m_txpool_size -= txblob.size(); remove_transaction_keyimages(tx); + remove_safex_restrictions(tx); auto sorted_it = find_tx_in_sorted_container(txid); if (sorted_it == m_txs_by_fee_and_receive_time.end()) { @@ -1296,6 +1756,7 @@ namespace cryptonote // continue } } + lock.commit(); } return n_removed; } @@ -1308,6 +1769,9 @@ namespace cryptonote m_txpool_max_size = max_txpool_size ? max_txpool_size : DEFAULT_TXPOOL_MAX_SIZE; m_txs_by_fee_and_receive_time.clear(); m_spent_key_images.clear(); + m_safex_accounts_in_use.clear(); + m_safex_offers_in_use.clear(); + m_safex_offers_to_purchase.clear(); m_txpool_size = 0; std::vector remove; @@ -1330,6 +1794,11 @@ namespace cryptonote MFATAL("Failed to insert key images from txpool tx"); return false; } + if (!insert_safex_restrictions(tx, meta.kept_by_block)) + { + MFATAL("Failed to insert safex data from txpool tx"); + return false; + } m_txs_by_fee_and_receive_time.emplace(std::pair(meta.fee / (double)meta.blob_size, meta.receive_time), txid); m_txpool_size += meta.blob_size; return true; @@ -1352,6 +1821,7 @@ namespace cryptonote // ignore error } } + lock.commit(); } return true; } diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 740f07e1f..00c58d486 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -62,7 +62,7 @@ namespace cryptonote class txCompare { public: - bool operator()(const tx_by_fee_and_receive_time_entry& a, const tx_by_fee_and_receive_time_entry& b) + bool operator()(const tx_by_fee_and_receive_time_entry& a, const tx_by_fee_and_receive_time_entry& b) const { // sort by greatest first, not least if (a.first.first > b.first.first) return true; @@ -430,6 +430,13 @@ namespace cryptonote */ bool insert_key_images(const transaction &tx, bool kept_by_block); + /** + * @brief insert safex data into m_safex_accounts_in_use, m_safex_offers_in_use, m_safex_price_peg_update_in_progress and m_safex_offers_to_purchase + * + * @return true on success, false on error + */ + bool insert_safex_restrictions(const transaction &tx, bool kept_by_block); + /** * @brief remove old transactions from the pool * @@ -450,6 +457,42 @@ namespace cryptonote */ bool have_tx_keyimg_as_spent(const crypto::key_image& key_im) const; + /** + * @brief check if a transaction in the pool has a safex account usage + * + * @param username Username of the account that is in use + * + * @return true if the safex account is in use already, otherwise false + */ + bool have_tx_safex_account_in_use(const std::string& username) const; + + /** + * @brief check if a transaction in the pool has a safex offer usage + * + * @param username Offer ID of the offer that is in use + * + * @return true if the safex offer is in use already, otherwise false + */ + bool have_tx_safex_offer_in_use(const crypto::hash& offer_id) const; + + /** + * @brief check if a transaction in the pool has a safex price peg usage + * + * @param price_peg_id Price peg ID that is in use + * + * @return true if the safex price peg is in use already, otherwise false + */ + bool have_tx_safex_price_peg_in_use(const crypto::hash& price_peg_id) const; + + /** + * @brief check if a transaction in the pool has a safex purchase for given offer + * + * @param username Offer ID of the offer that is being purchased + * + * @return quantity of units being purchased for givven offer + */ + uint64_t have_tx_safex_purchase_in_use(const crypto::hash& offer_id) const; + /** * @brief check if any spent key image in a transaction is in the pool * @@ -464,6 +507,21 @@ namespace cryptonote */ bool have_tx_keyimges_as_spent(const transaction& tx) const; + /** + * @brief check if any safex restriction in a transaction is in the pool + * + * Checks if any of the safex restrictions(same account doing 2 updates or purchase of same offer) + * in a given transaction are present + * in any of the transactions in the transaction pool. + * + * @note see tx_pool::have_tx_safex_account_in_use + * + * @param tx the transaction to check safex restrictions + * + * @return true if any safex restrictions are present in the pool, otherwise false + */ + bool have_tx_safex_restricted(const transaction& tx) const; + /** * @brief forget a transaction's spent key images * @@ -477,6 +535,15 @@ namespace cryptonote */ bool remove_transaction_keyimages(const transaction& tx); + /** + * @brief forget a transaction's safex restrictions + * + * @param tx the transaction + * + * @return false if any restriction to be removed cannot be found, otherwise true + */ + bool remove_safex_restrictions(const transaction& tx); + /** * @brief check if any of a transaction's spent key images are present in a given set * @@ -506,6 +573,18 @@ namespace cryptonote */ bool is_transaction_ready_to_go(txpool_tx_meta_t& txd, transaction &tx) const; + /** + * @brief check if a transaction is a purchase that can be included in a block + * + * @param txd the transaction to check (and info about it) + * @param tx the transaction to check + * @param offer_quantity_left quantity of offers after commiting purchases before this tx + * @param offers_edited Offers that are edited and are selected for the next block to be mined + * @param price_pegs_edited Price pegs that are updated and are selected for the next block to be mined + * + * @return true if the transaction is good to go, otherwise false + */ + bool is_purchase_possible(txpool_tx_meta_t& txd, transaction &tx, std::unordered_map& offer_quantity_left, std::vector& offers_edited, std::vector& price_pegs_edited) const; /** * @brief mark all transactions double spending the one passed */ @@ -538,7 +617,13 @@ namespace cryptonote #endif //! container for spent key images from the transactions in the pool - key_images_container m_spent_key_images; + key_images_container m_spent_key_images; + + // Safex related members + std::vector m_safex_accounts_in_use; + std::vector m_safex_offers_in_use; + std::vector m_safex_price_peg_update_in_progress; + std::vector> m_safex_offers_to_purchase; //TODO: this time should be a named constant somewhere, not hard-coded //! interval on which to check for stale/"stuck" transactions diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 18c8698e6..a07518777 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -354,7 +354,13 @@ namespace cryptonote m_core.pause_mine(); std::list blocks; blocks.push_back(arg.b); - m_core.prepare_handle_incoming_blocks(blocks); + if (!m_core.prepare_handle_incoming_blocks(blocks)) + { + LOG_PRINT_CCONTEXT_L1("Block verification failed: prepare_handle_incoming_blocks failed, dropping connection"); + drop_connection(context, false, false); + m_core.resume_mine(); + return 1; + } for(auto tx_blob_it = arg.b.txs.begin(); tx_blob_it!=arg.b.txs.end();tx_blob_it++) { cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc); @@ -629,7 +635,12 @@ namespace cryptonote std::list blocks; blocks.push_back(b); - m_core.prepare_handle_incoming_blocks(blocks); + if (!m_core.prepare_handle_incoming_blocks(blocks)) + { + LOG_PRINT_CCONTEXT_L0("Failure in prepare_handle_incoming_blocks"); + m_core.resume_mine(); + return 1; + } block_verification_context bvc = boost::value_initialized(); m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block @@ -1075,7 +1086,11 @@ skip: const boost::posix_time::ptime start = boost::posix_time::microsec_clock::universal_time(); context.m_last_request_time = start; - m_core.prepare_handle_incoming_blocks(blocks); + if (!m_core.prepare_handle_incoming_blocks(blocks)) + { + LOG_ERROR_CCONTEXT("Failure in prepare_handle_incoming_blocks"); + return 1; + } uint64_t block_process_time_full = 0, transactions_process_time_full = 0; size_t num_txs = 0; @@ -1095,6 +1110,11 @@ skip: if (tvc.size() != block_entry.txs.size()) { LOG_ERROR_CCONTEXT("Internal error: tvc.size() != block_entry.txs.size()"); + if (!m_core.cleanup_handle_incoming_blocks()) + { + LOG_PRINT_CCONTEXT_L0("Failure in cleanup_handle_incoming_blocks"); + return 1; + } return 1; } std::list::const_iterator it = block_entry.txs.begin(); diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 6ed2fa32f..0bb730326 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -708,4 +708,57 @@ bool t_command_parser_executor::version(const std::vector& args) return true; } +bool t_command_parser_executor::staked_tokens_on_interval(const std::vector &args) +{ + if (args.size() == 0) { + m_executor.token_locked_on_interval(0,0); + return true; + } + + if(args.size() == 1) { + m_executor.token_locked_on_interval(boost::lexical_cast(args[0]),0); + return true; + } + + if(args.size() == 2) { + m_executor.token_locked_on_interval(boost::lexical_cast(args[0]), boost::lexical_cast(args[1])); + return true; + } + + return false; +} + + +bool t_command_parser_executor::network_fee_on_interval(const std::vector& args) +{ + if (args.size() == 0) { + m_executor.network_fee_on_interval(0,0); + return true; + } + + if(args.size() == 1) { + m_executor.network_fee_on_interval(boost::lexical_cast(args[0]),0); + return true; + } + + if(args.size() == 2) { + m_executor.network_fee_on_interval(boost::lexical_cast(args[0]), boost::lexical_cast(args[1])); + return true; + } + + return false; +} + +bool t_command_parser_executor::safex_account_info(const std::vector &args) +{ + if (args.size() != 1) return false; + + if(args.size() == 1) { + m_executor.safex_account_info(args[0]); + return true; + } + + return false; +} + } // namespace daemonize diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h index 1b62c8a30..2a1ced3f8 100644 --- a/src/daemon/command_parser_executor.h +++ b/src/daemon/command_parser_executor.h @@ -146,6 +146,12 @@ class t_command_parser_executor final bool sync_info(const std::vector& args); bool version(const std::vector& args); + + bool staked_tokens_on_interval(const std::vector &args); + + bool network_fee_on_interval(const std::vector& args); + + bool safex_account_info(const std::vector &args); }; } // namespace daemonize diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 989c2849f..7fad81d30 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -298,6 +298,24 @@ t_command_server::t_command_server( , std::bind(&t_command_parser_executor::version, &m_parser, p::_1) , "Print version information." ); + + m_command_lookup.set_handler( + "safex_token_staked" + , std::bind(&t_command_parser_executor::staked_tokens_on_interval, &m_parser, p::_1) + , "Print amount of staked tokens for given interval (or for current interval if interval is not specified)" + ); + m_command_lookup.set_handler( + "safex_network_fee" + , std::bind(&t_command_parser_executor::network_fee_on_interval, &m_parser, p::_1) + , "Print amount of network fee for given interval (or for current interval if interval is not specified)" + ); + m_command_lookup.set_handler( + "safex_account_info" + , std::bind(&t_command_parser_executor::safex_account_info, &m_parser, p::_1) + , "safex_account_info " + , "Print safex account info" + ); + } bool t_command_server::process_command_str(const std::string& cmd) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index ac0762182..7b96dfb70 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -2004,4 +2004,121 @@ bool t_rpc_command_executor::sync_info() return true; } + +bool t_rpc_command_executor::token_locked_on_interval(const uint64_t& start, const uint64_t& end) +{ + cryptonote::COMMAND_RPC_TOKEN_STAKED::request req = AUTO_VAL_INIT(req); + cryptonote::COMMAND_RPC_TOKEN_STAKED::response res = AUTO_VAL_INIT(res); + + req.interval = start; + req.end = end; + + std::string fail_msg; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/get_staked_tokens", fail_msg.c_str())) + { + tools::fail_msg_writer() << "Failed!"; + return true; + } + } + else + { + if (!m_rpc_server->on_get_locked_tokens(req, res)) + { + tools::fail_msg_writer() << "Failed!"; + return true; + } + } + + if (start == 0) + tools::success_msg_writer() << "Sum of currently staked tokens: " << res.pairs[0].amount/SAFEX_TOKEN<<".00"; + else { + for (auto &item : res.pairs) { + tools::success_msg_writer() << "Interval#: " << item.interval << " / Sum of staked tokens: " << item.amount/SAFEX_TOKEN<<".00"; + } + } + + return false; +} + +bool t_rpc_command_executor::network_fee_on_interval(const uint64_t& start, const uint64_t& end) +{ + cryptonote::COMMAND_RPC_NETWORK_FEE::request req = AUTO_VAL_INIT(req); + cryptonote::COMMAND_RPC_NETWORK_FEE::response res = AUTO_VAL_INIT(res); + + req.interval = start; + req.end = end; + + std::string fail_msg; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/get_network_fee", fail_msg.c_str())) + { + tools::fail_msg_writer() << "Failed!"; + return true; + } + } + else + { + if (!m_rpc_server->on_get_network_fee(req, res)) + { + tools::fail_msg_writer() << "Failed!"; + return true; + } + } + + if (start == 0) + tools::success_msg_writer() << "Current network fee amount: " << cryptonote::print_money(res.pairs[0].amount); + else { + for (auto &item : res.pairs) { + tools::success_msg_writer() << "Interval#: " << item.interval << " / Sum of network fee: " + << cryptonote::print_money(item.amount); + } + } + + return false; +} + + + bool t_rpc_command_executor::safex_account_info(const std::string& safex_username) + { + cryptonote::COMMAND_RPC_SAFEX_ACCOUNT_INFO::request req = AUTO_VAL_INIT(req); + cryptonote::COMMAND_RPC_SAFEX_ACCOUNT_INFO::response res = AUTO_VAL_INIT(res); + + req.username = safex_username; + + std::string fail_msg; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/get_safex_account_info", fail_msg.c_str())) + { + tools::fail_msg_writer() << "Failed!"; + return true; + } + } + else + { + if (!m_rpc_server->on_get_safex_account_info(req, res)) + { + tools::fail_msg_writer() << "Failed to get account info!"; + return false; + } + } + + if(res.status == CORE_RPC_STATUS_SAFEX_ACCOUNT_DOESNT_EXIST){ + tools::fail_msg_writer() << "Account with username " << safex_username << " does not exist"; + } + else { + tools::success_msg_writer() << "Account: " << safex_username; + tools::success_msg_writer() << "Account public key: " << res.pkey; + tools::success_msg_writer() << "Account data: " << res.account_data; + } + + return true; + } + }// namespace daemonize diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index d48cc8214..b4168e689 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -157,6 +157,13 @@ class t_rpc_command_executor final { bool relay_tx(const std::string &txid); bool sync_info(); + + bool token_locked_on_interval(const uint64_t& start, const uint64_t& end); + + bool network_fee_on_interval(const uint64_t& start, const uint64_t& end); + + bool safex_account_info(const std::string& safex_username); + }; } // namespace daemonize diff --git a/src/device/device_ledger.cpp b/src/device/device_ledger.cpp index 0809636a8..b152fc2d0 100644 --- a/src/device/device_ledger.cpp +++ b/src/device/device_ledger.cpp @@ -87,6 +87,18 @@ namespace hw { AKout = keys.AKout; } + ABPkeys &ABPkeys::operator=(const ABPkeys& keys) { + if (&keys == this) + return *this; + Aout = keys.Aout; + Bout = keys.Bout; + is_subaddress = keys.is_subaddress; + index = keys.index; + Pout = keys.Pout; + AKout = keys.AKout; + return *this; + } + bool Keymap::find(const rct::key& P, ABPkeys& keys) const { size_t sz = ABP.size(); for (size_t i=0; i(invoke_http_mode::JON, "/get_safex_accounts", req, res, r)) + return r; + + std::vector> accounts; + bool result = m_core.get_safex_accounts(accounts); + + for(auto acc: accounts) { + COMMAND_RPC_GET_SAFEX_ACCOUNTS::entry ent{acc.first, acc.second}; + res.accounts.push_back(ent); + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_safex_offers(const COMMAND_RPC_GET_SAFEX_OFFERS::request& req, COMMAND_RPC_GET_SAFEX_OFFERS::response& res) + { + PERF_TIMER(on_get_safex_offers); + bool r; + if (use_bootstrap_daemon_if_necessary(invoke_http_mode::JON, "/get_safex_offers", req, res, r)) + return r; + + std::vector offers; + bool result = m_core.get_safex_offers(offers); + + for(auto offer: offers) { + uint64_t offer_height; + result = m_core.get_safex_offer_height(offer.offer_id, offer_height); + if(!result) + continue; + std::string offer_id_str = epee::string_tools::pod_to_hex(offer.offer_id); + std::string price_peg_id_str = epee::string_tools::pod_to_hex(offer.price_peg_id); + COMMAND_RPC_GET_SAFEX_OFFERS::entry ent{offer.title, offer.quantity, offer.price, offer.min_sfx_price, offer.description, + offer.active, offer.price_peg_used, offer.shipping, offer_id_str, price_peg_id_str, offer.seller, + offer.seller_address, offer_height}; + res.offers.push_back(ent); + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_safex_price_pegs(const COMMAND_RPC_GET_SAFEX_PRICE_PEGS::request& req, COMMAND_RPC_GET_SAFEX_PRICE_PEGS::response& res) + { + PERF_TIMER(on_get_safex_price_pegs); + bool r; + if (use_bootstrap_daemon_if_necessary(invoke_http_mode::JON, "/get_safex_price_pegs", req, res, r)) + return r; + + std::vector price_pegs; + bool result = m_core.get_safex_price_pegs(price_pegs,req.currency); + + for(auto price_peg: price_pegs) { + std::string price_peg_id_str = epee::string_tools::pod_to_hex(price_peg.price_peg_id); + COMMAND_RPC_GET_SAFEX_PRICE_PEGS::entry ent{price_peg.title,price_peg_id_str,price_peg.creator,price_peg.description,price_peg.currency,price_peg.rate}; + res.price_pegs.push_back(ent); + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_safex_ratings(const COMMAND_RPC_GET_SAFEX_RATINGS::request& req, COMMAND_RPC_GET_SAFEX_RATINGS::response& res) + { + PERF_TIMER(on_get_safex_ratings); + bool r; + if (use_bootstrap_daemon_if_necessary(invoke_http_mode::JON, "/get_safex_ratings", req, res, r)) + return r; + + std::vector feedbacks; + bool result = m_core.get_safex_feedbacks(feedbacks, req.offer_id); + + for(auto feedback: feedbacks) { + COMMAND_RPC_GET_SAFEX_RATINGS::entry ent{feedback.stars_given,feedback.comment}; + res.ratings.push_back(ent); + } + res.offer_id = feedbacks.at(0).offer_id; + res.status = CORE_RPC_STATUS_OK; + return true; + } + + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res) { PERF_TIMER(on_get_height); @@ -799,8 +883,21 @@ namespace cryptonote add_reason(res.reason, "overspend"); if ((res.fee_too_low = tvc.m_fee_too_low)) add_reason(res.reason, "fee too low"); - if ((res.not_rct = tvc.m_not_rct)) - add_reason(res.reason, "tx is not ringct"); + if ((res.non_supported_version = tvc.m_non_supported_version)) + add_reason(res.reason, "tx version is not supported"); + if ((res.safex_verification_failed = tvc.m_safex_verification_failed)) + add_reason(res.reason, "verification of safex logic has failed"); + if ((res.safex_invalid_command = tvc.m_safex_invalid_command)) + add_reason(res.reason, "invalid safex command"); + if ((res.safex_invalid_command_params = tvc.m_safex_invalid_command_params)) + add_reason(res.reason, "invalid safex command parameters"); + if ((res.safex_invalid_input = tvc.m_safex_invalid_input)) + add_reason(res.reason, "invalid safex script inputs"); + if ((res.safex_command_execution_failed = tvc.m_safex_command_execution_failed)) + add_reason(res.reason, "safex command execution failed"); + + + const std::string punctuation = res.reason.empty() ? "" : ": "; if (tvc.m_verifivation_failed) { @@ -870,8 +967,6 @@ namespace cryptonote add_reason(res.reason, "overspend"); if ((res.fee_too_low = tvc.m_fee_too_low)) add_reason(res.reason, "fee too low"); - if ((res.not_rct = tvc.m_not_rct)) - add_reason(res.reason, "tx is not ringct"); const std::string punctuation = res.reason.empty() ? "" : ": "; if (tvc.m_verifivation_failed) { @@ -2305,6 +2400,406 @@ namespace cryptonote res.status = CORE_RPC_STATUS_OK; return true; } + + + bool core_rpc_server::on_decode_safex_output(const COMMAND_RPC_DECODE_SAFEX_OUTPUT::request& req, COMMAND_RPC_DECODE_SAFEX_OUTPUT::response& res, epee::json_rpc::error& error_resp) + { + PERF_TIMER(on_decode_safex_output); + + res.parsed_fields.clear(); + COMMAND_RPC_DECODE_SAFEX_OUTPUT::parsed_field p; + + tx_out_type output_type = tx_out_type(req.output_type); + + res.status = CORE_RPC_STATUS_OK; + + if(output_type == tx_out_type::out_safex_account) + { + + safex::create_account_data account{}; + const cryptonote::blobdata accblob(std::begin(req.data), std::end(req.data)); + if (!cryptonote::parse_and_validate_from_blob(accblob, account)) + { + res.status = CORE_RPC_STATUS_SAFEX_INVALID_TYPE; + return false; + } + + std::string username(account.username.begin(), account.username.end()); + std::string data(account.account_data.begin(), account.account_data.end()); + std::string pkey_str = epee::string_tools::pod_to_hex(account.pkey); + + p.field="username"; + p.value=username; + res.parsed_fields.push_back(p); + p.field="account_data"; + p.value=data; + res.parsed_fields.push_back(p); + p.field="pkey"; + p.value=pkey_str; + res.parsed_fields.push_back(p); + + } else if(output_type == tx_out_type::out_safex_account_update) + { + + safex::edit_account_data account{}; + const cryptonote::blobdata accblob(std::begin(req.data), std::end(req.data)); + if (!cryptonote::parse_and_validate_from_blob(accblob, account)) + { + res.status = CORE_RPC_STATUS_SAFEX_INVALID_TYPE; + return false; + } + + std::string username(account.username.begin(), account.username.end()); + std::string data(account.account_data.begin(), account.account_data.end()); + + p.field="username"; + p.value=username; + res.parsed_fields.push_back(p); + p.field="account_data"; + p.value=data; + res.parsed_fields.push_back(p); + + } else if (output_type == tx_out_type::out_safex_offer) + { + + safex::create_offer_data offer{}; + const cryptonote::blobdata offerblob(std::begin(req.data), std::end(req.data)); + if (!cryptonote::parse_and_validate_from_blob(offerblob, offer)) + { + res.status = CORE_RPC_STATUS_SAFEX_INVALID_TYPE; + return false; + } + + std::string seller(offer.seller.begin(), offer.seller.end()); + std::string title(offer.title.begin(), offer.title.end()); + std::string description(offer.description.begin(), offer.description.end()); + std::string offer_id = epee::string_tools::pod_to_hex(offer.offer_id); + std::string price_peg_id = epee::string_tools::pod_to_hex(offer.price_peg_id); + std::string quantity = std::to_string(offer.quantity); + std::string price = std::to_string(offer.price); + std::string min_sfx_price = std::to_string(offer.min_sfx_price); + std::string active = epee::string_tools::pod_to_hex(offer.active); + std::string price_peg_used = epee::string_tools::pod_to_hex(offer.price_peg_used); + std::string seller_address = epee::string_tools::pod_to_hex(offer.seller_address); + std::string seller_private_view_key = epee::string_tools::pod_to_hex(offer.seller_private_view_key); + + p.field="seller"; + p.value=seller; + res.parsed_fields.push_back(p); + p.field="title"; + p.value=title; + res.parsed_fields.push_back(p); + p.field="description"; + p.value=description; + res.parsed_fields.push_back(p); + p.field="offer_id"; + p.value=offer_id; + res.parsed_fields.push_back(p); + p.field="price_peg_id"; + p.value=price_peg_id; + res.parsed_fields.push_back(p); + p.field="price"; + p.value=price; + res.parsed_fields.push_back(p); + p.field="min_sfx_price"; + p.value=min_sfx_price; + res.parsed_fields.push_back(p); + p.field="active"; + p.value=active; + res.parsed_fields.push_back(p); + p.field="quantity"; + p.value=quantity; + res.parsed_fields.push_back(p); + p.field="price_peg_used"; + p.value=price_peg_used; + res.parsed_fields.push_back(p); + p.field="seller_address"; + p.value=seller_address; + res.parsed_fields.push_back(p); + p.field="seller_private_view_key"; + p.value=seller_private_view_key; + res.parsed_fields.push_back(p); + + } else if(output_type == tx_out_type::out_safex_offer_update) + { + + safex::edit_offer_data offer{}; + const cryptonote::blobdata offerblob(std::begin(req.data), std::end(req.data)); + if (!cryptonote::parse_and_validate_from_blob(offerblob, offer)) + { + res.status = CORE_RPC_STATUS_SAFEX_INVALID_TYPE; + return false; + } + + std::string seller(offer.seller.begin(), offer.seller.end()); + std::string title(offer.title.begin(), offer.title.end()); + std::string description(offer.description.begin(), offer.description.end()); + std::string offer_id = epee::string_tools::pod_to_hex(offer.offer_id); + std::string price_peg_id = epee::string_tools::pod_to_hex(offer.price_peg_id); + std::string quantity = std::to_string(offer.quantity); + std::string price = std::to_string(offer.price); + std::string min_sfx_price = std::to_string(offer.min_sfx_price); + std::string active = epee::string_tools::pod_to_hex(offer.active); + std::string price_peg_used = epee::string_tools::pod_to_hex(offer.price_peg_used); + + p.field="seller"; + p.value=seller; + res.parsed_fields.push_back(p); + p.field="title"; + p.value=title; + res.parsed_fields.push_back(p); + p.field="description"; + p.value=description; + res.parsed_fields.push_back(p); + p.field="offer_id"; + p.value=offer_id; + res.parsed_fields.push_back(p); + p.field="price_peg_id"; + p.value=price_peg_id; + res.parsed_fields.push_back(p); + p.field="price"; + p.value=price; + res.parsed_fields.push_back(p); + p.field="min_sfx_price"; + p.value=min_sfx_price; + res.parsed_fields.push_back(p); + p.field="active"; + p.value=active; + res.parsed_fields.push_back(p); + p.field="quantity"; + p.value=quantity; + res.parsed_fields.push_back(p); + p.field="price_peg_used"; + p.value=price_peg_used; + res.parsed_fields.push_back(p); + + } else if(output_type == tx_out_type::out_safex_purchase) + { + + safex::create_purchase_data purchase{}; + const cryptonote::blobdata purchaseblob(std::begin(req.data), std::end(req.data)); + if (!cryptonote::parse_and_validate_from_blob(purchaseblob, purchase)) + { + res.status = CORE_RPC_STATUS_SAFEX_INVALID_TYPE; + return false; + } + + std::string offer_id = epee::string_tools::pod_to_hex(purchase.offer_id); + std::string quantity = std::to_string(purchase.quantity); + std::string price = std::to_string(purchase.price); + std::string shipping = epee::string_tools::pod_to_hex(purchase.shipping); + + p.field="offer_id"; + p.value=offer_id; + res.parsed_fields.push_back(p); + p.field="price"; + p.value=price; + res.parsed_fields.push_back(p); + p.field="shipping"; + p.value=shipping; + res.parsed_fields.push_back(p); + p.field="quantity"; + p.value=quantity; + res.parsed_fields.push_back(p); + + + } else if(output_type == tx_out_type::out_safex_feedback_token) + { + + safex::create_feedback_token_data feedback_token{}; + const cryptonote::blobdata feedback_tokenblob(std::begin(req.data), std::end(req.data)); + if (!cryptonote::parse_and_validate_from_blob(feedback_tokenblob, feedback_token)) + { + res.status = CORE_RPC_STATUS_SAFEX_INVALID_TYPE; + return false; + } + + std::string offer_id = epee::string_tools::pod_to_hex(feedback_token.offer_id); + + p.field="offer_id"; + p.value=offer_id; + res.parsed_fields.push_back(p); + + } else if(output_type == tx_out_type::out_safex_feedback) + { + + safex::create_feedback_data feedback{}; + const cryptonote::blobdata feedbackblob(std::begin(req.data), std::end(req.data)); + if (!cryptonote::parse_and_validate_from_blob(feedbackblob, feedback)) + { + res.status = CORE_RPC_STATUS_SAFEX_INVALID_TYPE; + return false; + } + + std::string comment(feedback.comment.begin(), feedback.comment.end()); + std::string offer_id = epee::string_tools::pod_to_hex(feedback.offer_id); + std::string stars_given = std::to_string(feedback.stars_given); + + p.field="comment"; + p.value=comment; + res.parsed_fields.push_back(p); + p.field="stars_given"; + p.value=stars_given; + res.parsed_fields.push_back(p); + p.field="offer_id"; + p.value=offer_id; + res.parsed_fields.push_back(p); + + } else if(output_type == tx_out_type::out_safex_price_peg) + { + + safex::create_price_peg_data price_peg{}; + const cryptonote::blobdata price_pegblob(std::begin(req.data), std::end(req.data)); + if (!cryptonote::parse_and_validate_from_blob(price_pegblob, price_peg)) + { + res.status = CORE_RPC_STATUS_SAFEX_INVALID_TYPE; + return false; + } + + std::string title(price_peg.title.begin(), price_peg.title.end()); + std::string price_peg_id = epee::string_tools::pod_to_hex(price_peg.price_peg_id); + std::string creator(price_peg.creator.begin(), price_peg.creator.end()); + std::string description(price_peg.description.begin(), price_peg.description.end()); + std::string currency(price_peg.currency.begin(), price_peg.currency.end()); + std::string rate = std::to_string(price_peg.rate); + + p.field="title"; + p.value=title; + res.parsed_fields.push_back(p); + p.field="price_peg_id"; + p.value=price_peg_id; + res.parsed_fields.push_back(p); + p.field="creator"; + p.value=creator; + res.parsed_fields.push_back(p); + p.field="description"; + p.value=description; + res.parsed_fields.push_back(p); + p.field="currency"; + p.value=currency; + res.parsed_fields.push_back(p); + p.field="rate"; + p.value=rate; + res.parsed_fields.push_back(p); + + + } else if(output_type == tx_out_type::out_safex_price_peg_update) + { + + safex::update_price_peg_data price_peg{}; + const cryptonote::blobdata price_pegblob(std::begin(req.data), std::end(req.data)); + if (!cryptonote::parse_and_validate_from_blob(price_pegblob, price_peg)) + { + res.status = CORE_RPC_STATUS_SAFEX_INVALID_TYPE; + return false; + } + + std::string price_peg_id = epee::string_tools::pod_to_hex(price_peg.price_peg_id); + std::string rate = std::to_string(price_peg.rate); + + p.field="price_peg_id"; + p.value=price_peg_id; + res.parsed_fields.push_back(p); + p.field="rate"; + p.value=rate; + res.parsed_fields.push_back(p); + + } else + { + res.status = CORE_RPC_STATUS_SAFEX_INVALID_TYPE; + return false; + } + + return true; + } + + bool core_rpc_server::on_get_locked_tokens(const COMMAND_RPC_TOKEN_STAKED::request& req, COMMAND_RPC_TOKEN_STAKED::response& res) + { + if (req.interval == 0) { + // @todo: Implement here to return last interval value. + res.pairs.push_back(COMMAND_RPC_TOKEN_STAKED::result_t{0, m_core.get_staked_tokens()}); + } + else { + if(req.end == 0) { + res.pairs.push_back(COMMAND_RPC_TOKEN_STAKED::result_t{req.interval, m_core.get_locked_tokens_for_interval(req.interval)}); + } + else { + if( req.end >= req.interval) { + for(uint64_t i = req.interval; i < req.end; ++i) { + res.pairs.push_back(COMMAND_RPC_TOKEN_STAKED::result_t{i, m_core.get_locked_tokens_for_interval(i)}); + } + } + else { + return false; + } + } + } + return true; + } + + bool core_rpc_server::on_get_network_fee(const COMMAND_RPC_NETWORK_FEE::request& req, COMMAND_RPC_NETWORK_FEE::response& res) + { + if (req.interval == 0) { + // @todo: Implement here to return last interval value. + res.pairs.push_back(COMMAND_RPC_NETWORK_FEE::result_t{m_core.get_current_interval(), m_core.get_network_fee_for_interval(m_core.get_current_interval())}); + res.status = "OK"; + } + else { + if(req.end == 0) { + res.pairs.push_back(COMMAND_RPC_NETWORK_FEE::result_t{req.interval, m_core.get_network_fee_for_interval(req.interval)}); + res.status = "OK"; + } + else { + if( req.end >= req.interval) { + for(uint64_t i = req.interval; i < req.end; ++i) { + res.pairs.push_back(COMMAND_RPC_NETWORK_FEE::result_t{i, m_core.get_network_fee_for_interval(i)}); + res.status = "OK"; + } + } + else { + res.status = "FAILED"; + return false; + } + } + } + return true; + } + + bool core_rpc_server::on_get_interest_map(const COMMAND_RPC_GET_INTEREST_MAP::request& req, COMMAND_RPC_GET_INTEREST_MAP::response& res) + { + if(req.begin_interval > req.end_interval){ + res.status = "There are no good interval values provided."; + return false; + } + else { + std::map interests = m_core.get_interest_map(req.begin_interval, req.end_interval); + + for(auto interest : interests) + { + res.interest_per_interval.push_back({interest.first, interest.second}); + } + res.status = "OK"; + } + + return true; + } + + bool core_rpc_server::on_get_safex_account_info(const COMMAND_RPC_SAFEX_ACCOUNT_INFO::request &req, COMMAND_RPC_SAFEX_ACCOUNT_INFO::response &res) + { + + safex::safex_account account; + if (!m_core.get_safex_account_info(req.username, account)) { + res.status = CORE_RPC_STATUS_SAFEX_ACCOUNT_DOESNT_EXIST; + return true; + } + + res.pkey = epee::string_tools::pod_to_hex(account.pkey); + + res.account_data = std::string(std::begin(account.account_data), std::end(account.account_data)); + res.status = CORE_RPC_STATUS_OK; + + return true; + } //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_get_transactions_protobuf(const COMMAND_RPC_GET_TRANSACTIONS_PROTOBUF::request& req, diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index f6b9c9bdb..c4ff5b96f 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -118,6 +118,14 @@ namespace cryptonote MAP_URI_AUTO_JON2_IF("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON, !m_restricted) MAP_URI_AUTO_JON2("/get_info", on_get_info, COMMAND_RPC_GET_INFO) MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO) + MAP_URI_AUTO_JON2("/get_staked_tokens", on_get_locked_tokens, COMMAND_RPC_TOKEN_STAKED) + MAP_URI_AUTO_JON2("/get_interest_map", on_get_interest_map, COMMAND_RPC_GET_INTEREST_MAP) + MAP_URI_AUTO_JON2("/get_network_fee", on_get_network_fee, COMMAND_RPC_NETWORK_FEE) + MAP_URI_AUTO_JON2("/get_safex_account_info", on_get_safex_account_info, COMMAND_RPC_SAFEX_ACCOUNT_INFO) + MAP_URI_AUTO_JON2("/get_safex_accounts", on_get_safex_accounts, COMMAND_RPC_GET_SAFEX_ACCOUNTS) + MAP_URI_AUTO_JON2("/get_safex_offers", on_get_safex_offers, COMMAND_RPC_GET_SAFEX_OFFERS) + MAP_URI_AUTO_JON2("/get_safex_ratings", on_get_safex_ratings, COMMAND_RPC_GET_SAFEX_RATINGS) + MAP_URI_AUTO_JON2("/get_safex_price_pegs", on_get_safex_price_pegs, COMMAND_RPC_GET_SAFEX_PRICE_PEGS) MAP_URI_AUTO_JON2("/get_limit", on_get_limit, COMMAND_RPC_GET_LIMIT) MAP_URI_AUTO_JON2_IF("/set_limit", on_set_limit, COMMAND_RPC_SET_LIMIT, !m_restricted) MAP_URI_AUTO_JON2_IF("/out_peers", on_out_peers, COMMAND_RPC_OUT_PEERS, !m_restricted) @@ -160,10 +168,20 @@ namespace cryptonote MAP_JON_RPC_WE_IF("sync_info", on_sync_info, COMMAND_RPC_SYNC_INFO, !m_restricted) MAP_JON_RPC_WE("get_txpool_backlog", on_get_txpool_backlog, COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG) MAP_JON_RPC_WE("get_output_distribution", on_get_output_distribution, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION) + MAP_JON_RPC_WE("decode_safex_output", on_decode_safex_output, COMMAND_RPC_DECODE_SAFEX_OUTPUT) END_JSON_RPC_MAP() END_URI_MAP2() + bool on_get_safex_account_info(const COMMAND_RPC_SAFEX_ACCOUNT_INFO::request &req, COMMAND_RPC_SAFEX_ACCOUNT_INFO::response &res); + bool on_get_interest_map(const COMMAND_RPC_GET_INTEREST_MAP::request& req, COMMAND_RPC_GET_INTEREST_MAP::response& res); + bool on_get_locked_tokens(const COMMAND_RPC_TOKEN_STAKED::request& req, COMMAND_RPC_TOKEN_STAKED::response& res); + bool on_get_network_fee(const COMMAND_RPC_NETWORK_FEE::request& req, COMMAND_RPC_NETWORK_FEE::response& res); + bool on_get_safex_accounts(const COMMAND_RPC_GET_SAFEX_ACCOUNTS::request& req, COMMAND_RPC_GET_SAFEX_ACCOUNTS::response& res); + bool on_get_safex_offers(const COMMAND_RPC_GET_SAFEX_OFFERS::request& req, COMMAND_RPC_GET_SAFEX_OFFERS::response& res); + bool on_get_safex_ratings(const COMMAND_RPC_GET_SAFEX_RATINGS::request& req, COMMAND_RPC_GET_SAFEX_RATINGS::response& res); + bool on_get_safex_price_pegs(const COMMAND_RPC_GET_SAFEX_PRICE_PEGS::request& req, COMMAND_RPC_GET_SAFEX_PRICE_PEGS::response& res); + bool on_get_output_histogram_protobuf(const COMMAND_RPC_GET_OUTPUT_HISTOGRAM_PROTOBUF::request& req, COMMAND_RPC_GET_OUTPUT_HISTOGRAM_PROTOBUF::response& res); bool on_send_proto_raw_tx(const COMMAND_RPC_PROTO_SEND_RAW_TX::request& req, COMMAND_RPC_PROTO_SEND_RAW_TX::response& res); @@ -230,6 +248,7 @@ namespace cryptonote bool on_sync_info(const COMMAND_RPC_SYNC_INFO::request& req, COMMAND_RPC_SYNC_INFO::response& res, epee::json_rpc::error& error_resp); bool on_get_txpool_backlog(const COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_BACKLOG::response& res, epee::json_rpc::error& error_resp); bool on_get_output_distribution(const COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request& req, COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response& res, epee::json_rpc::error& error_resp); + bool on_decode_safex_output(const COMMAND_RPC_DECODE_SAFEX_OUTPUT::request& req, COMMAND_RPC_DECODE_SAFEX_OUTPUT::response& res, epee::json_rpc::error& error_resp); //----------------------- private: diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 9abc46f28..e4563473d 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -42,6 +42,10 @@ namespace cryptonote #define CORE_RPC_STATUS_BUSY "BUSY" #define CORE_RPC_STATUS_NOT_MINING "NOT MINING" +// Safex related status +#define CORE_RPC_STATUS_SAFEX_ACCOUNT_DOESNT_EXIST "SAFEX ACC NOT EXISTS" +#define CORE_RPC_STATUS_SAFEX_INVALID_TYPE "SAFEX INVALID TYPE" + // When making *any* change here, bump minor // If the change is incompatible, then bump major and set minor to 0 // This ensures CORE_RPC_VERSION always increases, that every change @@ -77,6 +81,183 @@ namespace cryptonote }; typedef epee::misc_utils::struct_init response; }; + struct COMMAND_RPC_GET_SAFEX_ACCOUNTS + { + struct request_t + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init request; + + struct entry + { + std::string username; + std::string description; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(username) + KV_SERIALIZE(description) + END_KV_SERIALIZE_MAP() + }; + + struct response_t + { + std::vector accounts; + std::string status; + bool untrusted; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(accounts) + KV_SERIALIZE(status) + KV_SERIALIZE(untrusted); + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init response; + }; + + struct COMMAND_RPC_GET_SAFEX_OFFERS + { + struct request_t + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init request; + + struct entry + { + std::string title; + uint64_t quantity; + uint64_t price; + uint64_t min_sfx_price; + std::vector description; + bool active; + bool price_peg_used; + std::vector shipping; + std::string offer_id; + std::string price_peg_id; + std::string seller; + cryptonote::account_public_address seller_address; + uint64_t height; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(title) + KV_SERIALIZE(quantity) + KV_SERIALIZE(price) + KV_SERIALIZE(min_sfx_price) + KV_SERIALIZE(description) + KV_SERIALIZE(active) + KV_SERIALIZE(price_peg_used) + KV_SERIALIZE(shipping) + KV_SERIALIZE(offer_id) + KV_SERIALIZE(price_peg_id) + KV_SERIALIZE(seller) + KV_SERIALIZE(seller_address) + KV_SERIALIZE(height) + END_KV_SERIALIZE_MAP() + }; + + struct response_t + { + std::vector offers; + std::string status; + bool untrusted; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(offers) + KV_SERIALIZE(status) + KV_SERIALIZE(untrusted); + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init response; + }; + + struct COMMAND_RPC_GET_SAFEX_PRICE_PEGS + { + struct request_t + { + std::string currency; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(currency) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init request; + + struct entry + { + std::string title; + std::string price_peg_id; + std::string creator; + std::vector description; + std::string currency; + uint64_t rate; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(title) + KV_SERIALIZE(price_peg_id) + KV_SERIALIZE(creator) + KV_SERIALIZE(description) + KV_SERIALIZE(currency) + KV_SERIALIZE(rate) + END_KV_SERIALIZE_MAP() + }; + + struct response_t + { + std::vector price_pegs; + std::string status; + bool untrusted; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(price_pegs) + KV_SERIALIZE(status) + KV_SERIALIZE(untrusted); + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init response; + }; + + struct COMMAND_RPC_GET_SAFEX_RATINGS + { + struct request_t + { + crypto::hash offer_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL_POD_AS_BLOB(offer_id) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init request; + + struct entry + { + uint64_t star_rating; + std::string comment; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(star_rating) + KV_SERIALIZE(comment) + END_KV_SERIALIZE_MAP() + }; + + struct response_t + { + crypto::hash offer_id; + std::vector ratings; + std::string status; + bool untrusted; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_VAL_POD_AS_BLOB(offer_id) + KV_SERIALIZE(ratings) + KV_SERIALIZE(status) + KV_SERIALIZE(untrusted); + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init response; + }; struct COMMAND_RPC_GET_BLOCKS_FAST { @@ -1017,7 +1198,12 @@ namespace cryptonote bool too_big; bool overspend; bool fee_too_low; - bool not_rct; + bool non_supported_version; + bool safex_verification_failed; + bool safex_invalid_command; + bool safex_invalid_command_params; + bool safex_invalid_input; + bool safex_command_execution_failed; bool untrusted; BEGIN_KV_SERIALIZE_MAP() @@ -1031,7 +1217,12 @@ namespace cryptonote KV_SERIALIZE(too_big) KV_SERIALIZE(overspend) KV_SERIALIZE(fee_too_low) - KV_SERIALIZE(not_rct) + KV_SERIALIZE(non_supported_version) + KV_SERIALIZE(safex_verification_failed) + KV_SERIALIZE(safex_invalid_command) + KV_SERIALIZE(safex_invalid_command_params) + KV_SERIALIZE(safex_invalid_input) + KV_SERIALIZE(safex_command_execution_failed) KV_SERIALIZE(untrusted) END_KV_SERIALIZE_MAP() }; @@ -2520,6 +2711,44 @@ namespace cryptonote typedef epee::misc_utils::struct_init response; }; + struct COMMAND_RPC_DECODE_SAFEX_OUTPUT + { + struct request_t + { + std::vector data; + uint8_t output_type; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(output_type) + KV_SERIALIZE(data) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init request; + + struct parsed_field + { + std::string field; + std::string value; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(field) + KV_SERIALIZE(value) + END_KV_SERIALIZE_MAP() + }; + + struct response_t + { + std::string status; + std::vector parsed_fields; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(parsed_fields) + END_KV_SERIALIZE_MAP() + }; + typedef epee::misc_utils::struct_init response; + }; + struct COMMAND_RPC_GET_OUTPUTS_PROTOBUF { struct request @@ -2533,67 +2762,191 @@ namespace cryptonote END_KV_SERIALIZE_MAP() }; + struct response + { + std::string protobuf_content; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(protobuf_content) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + //----------------------------------------------- + + struct COMMAND_RPC_PROTO_SEND_RAW_TX + { + struct request + { + std::string proto_content; + bool do_not_relay; + + request() {} + explicit request(const transaction &); + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(proto_content) + KV_SERIALIZE_OPT(do_not_relay, false) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string txid; + std::string status; + std::string reason; + bool not_relayed; + bool low_mixin; + bool double_spend; + bool invalid_input; + bool invalid_output; + bool too_big; + bool overspend; + bool fee_too_low; + bool not_rct; + bool untrusted; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(txid) + KV_SERIALIZE(status) + KV_SERIALIZE(reason) + KV_SERIALIZE(not_relayed) + KV_SERIALIZE(low_mixin) + KV_SERIALIZE(double_spend) + KV_SERIALIZE(invalid_input) + KV_SERIALIZE(invalid_output) + KV_SERIALIZE(too_big) + KV_SERIALIZE(overspend) + KV_SERIALIZE(fee_too_low) + KV_SERIALIZE(not_rct) + KV_SERIALIZE(untrusted) + END_KV_SERIALIZE_MAP() + }; + }; + struct COMMAND_RPC_TOKEN_STAKED + { + struct request + { + uint64_t interval; + uint64_t end; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(interval) + END_KV_SERIALIZE_MAP() + }; + + struct result_t { + uint64_t interval; + uint64_t amount; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(interval) + KV_SERIALIZE(amount) + END_KV_SERIALIZE_MAP() + }; + struct response { - std::string protobuf_content; + std::vector pairs; std::string status; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(protobuf_content) - KV_SERIALIZE(status) + KV_SERIALIZE(status) + KV_SERIALIZE(pairs) END_KV_SERIALIZE_MAP() }; }; - //----------------------------------------------- - struct COMMAND_RPC_PROTO_SEND_RAW_TX + struct COMMAND_RPC_NETWORK_FEE { struct request { - std::string proto_content; - bool do_not_relay; + uint64_t interval; + uint64_t end; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(interval) + END_KV_SERIALIZE_MAP() + }; - request() {} - explicit request(const transaction &); + + struct result_t { + uint64_t interval; + uint64_t amount; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(proto_content) - KV_SERIALIZE_OPT(do_not_relay, false) + KV_SERIALIZE(interval) + KV_SERIALIZE(amount) END_KV_SERIALIZE_MAP() }; + struct response + { + std::vector pairs; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(pairs) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_SAFEX_ACCOUNT_INFO + { + struct request + { + std::string username; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(username) + END_KV_SERIALIZE_MAP() + }; struct response { - std::string txid; + std::string pkey; + std::string account_data; std::string status; - std::string reason; - bool not_relayed; - bool low_mixin; - bool double_spend; - bool invalid_input; - bool invalid_output; - bool too_big; - bool overspend; - bool fee_too_low; - bool not_rct; - bool untrusted; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(txid) + KV_SERIALIZE(pkey) + KV_SERIALIZE(account_data) KV_SERIALIZE(status) - KV_SERIALIZE(reason) - KV_SERIALIZE(not_relayed) - KV_SERIALIZE(low_mixin) - KV_SERIALIZE(double_spend) - KV_SERIALIZE(invalid_input) - KV_SERIALIZE(invalid_output) - KV_SERIALIZE(too_big) - KV_SERIALIZE(overspend) - KV_SERIALIZE(fee_too_low) - KV_SERIALIZE(not_rct) - KV_SERIALIZE(untrusted) END_KV_SERIALIZE_MAP() }; }; + + struct COMMAND_RPC_GET_INTEREST_MAP + { + struct request + { + uint64_t begin_interval; + uint64_t end_interval; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(begin_interval) + KV_SERIALIZE(end_interval) + END_KV_SERIALIZE_MAP() + }; + + struct result_t { + uint64_t interval; + uint64_t cash_per_token; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(interval) + KV_SERIALIZE(cash_per_token) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::vector interest_per_interval; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(interest_per_interval) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + } diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp index ff6b8862d..44e7291a8 100644 --- a/src/rpc/daemon_handler.cpp +++ b/src/rpc/daemon_handler.cpp @@ -378,10 +378,10 @@ namespace rpc if (!res.error_details.empty()) res.error_details += " and "; res.error_details = "fee too low"; } - if (tvc.m_not_rct) + if (tvc.m_non_supported_version) { if (!res.error_details.empty()) res.error_details += " and "; - res.error_details = "tx is not ringct"; + res.error_details = "tx version is not supported"; } if (res.error_details.empty()) { diff --git a/src/wallet/api/win_wrapper/CMakeLists.txt b/src/safex/CMakeLists.txt similarity index 66% rename from src/wallet/api/win_wrapper/CMakeLists.txt rename to src/safex/CMakeLists.txt index 4ede0721c..6e5f514e0 100644 --- a/src/wallet/api/win_wrapper/CMakeLists.txt +++ b/src/safex/CMakeLists.txt @@ -28,24 +28,43 @@ # # Parts of this file are originally copyright (c) 2014-2018 The Monero Project -# include (${PROJECT_SOURCE_DIR}/cmake/libutils.cmake) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(safex_core_sources + command.cpp + fee_distribution.cpp + safex_core.cpp + safex_account.cpp + safex_offer.cpp + safex_purchase.cpp + safex_feedback_token.cpp + safex_feedback.cpp + safex_price_peg.cpp + ) -set(win_wallet_sources - windows_wrapper.cpp -) -set(win_wallet_headers - windows_wrapper.h) +set(safex_core_headers + command.h + fee_distribution.h + safex_account.h + safex_offer.h + safex_purchase.h + safex_feedback_token.h + safex_feedback.h + safex_price_peg.h + ) -if (BUILD_WIN_WALLET_WRAPPER) - add_library(win_wallet_wrapper SHARED ${win_wallet_sources} ${win_wallet_headers}) - set_target_properties(win_wallet_wrapper PROPERTIES LINK_FLAGS "-Wl,--exclude-all-symbols -Wl,--output-def,libwin_wallet_wrapper.def") - target_link_libraries(win_wallet_wrapper - PRIVATE - wallet_api - ) +set(safex_core_private_headers) + +safex_private_headers(safex_core + ${safex_core_private_headers}) -endif() -set_property(TARGET wallet_api PROPERTY EXCLUDE_FROM_ALL TRUE) -set_property(TARGET obj_wallet_api PROPERTY EXCLUDE_FROM_ALL TRUE) +safex_add_library(safex_core + ${safex_core_sources} + ${safex_core_headers} + ${safex_core_private_headers}) + +target_link_libraries(safex_core + PUBLIC + cncrypto + common + PRIVATE + ${EXTRA_LIBRARIES}) diff --git a/src/safex/command.cpp b/src/safex/command.cpp new file mode 100644 index 000000000..a7c3723cd --- /dev/null +++ b/src/safex/command.cpp @@ -0,0 +1,726 @@ +// +// Created by amarko on 4.3.19.. +// + +#include "cryptonote_config.h" +#include "command.h" +#include "cryptonote_core/cryptonote_tx_utils.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_config.h" +#include "cryptonote_core/blockchain.h" + + +#include "fee_distribution.h" + + +#undef SAFEX_DEFAULT_LOG_CATEGORY +#define SAFEX_DEFAULT_LOG_CATEGORY "safex" + +namespace safex +{ + + + token_stake_result* token_stake::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate token stake command", this->get_command_type()); + + token_stake_result *cr = new token_stake_result{}; + cr->token_amount = txin.token_amount; + cr->block_number = blokchainDB.height(); + cr->valid = true; + cr->status = execution_status::ok; + + MINFO("Block height:" << cr->block_number << " interval:" << calculate_interval_for_height(blokchainDB.height(), blokchainDB.get_net_type()) << " stake tokens:" << cr->token_amount); + + return cr; + } + + execution_status token_stake::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + //per input execution, one input could be less than SAFEX_MINIMUM_TOKEN_STAKE_AMOUNT, all inputs must be SAFEX_MINIMUM_TOKEN_STAKE_AMOUNT + if(!tools::is_whole_token_amount(this->get_staked_token_amount())) + return execution_status::error_stake_token_not_whole_amount; + if(!(txin.token_amount == this->get_staked_token_amount())) + return execution_status::error_stake_token_amount_not_matching; + + return execution_status::ok; + } + + token_unstake_result* token_unstake::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate token unstake command", this->get_command_type()); + + + token_unstake_result *cr = new token_unstake_result{}; + cr->token_amount = txin.token_amount; + cr->block_number = blokchainDB.height(); + + uint64_t locked_token_output_index = txin.key_offsets[0]; + cr->interest = calculate_token_interest(locked_token_output_index, cr->block_number, cr->token_amount); + cr->valid = true; + cr->status = execution_status::ok; + + MINFO("Block height:" << cr->block_number << " interval:" << calculate_interval_for_height(blokchainDB.height(), blokchainDB.get_net_type()) << " unstake tokens:" << cr->token_amount); + + return cr; + } + + execution_status token_unstake::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + if(txin.key_offsets.size() != 1) + return execution_status::error_unstake_token_offset_not_one; + + uint64_t staked_token_index = txin.key_offsets[0]; + + try + { + const cryptonote::output_advanced_data_t od = blokchainDB.get_output_advanced_data(cryptonote::tx_out_type::out_staked_token, staked_token_index); + uint64_t token_amount = 0; + epee::string_tools::get_xtype_from_string(token_amount, od.data); + + if(token_amount != txin.token_amount) + return execution_status::error_unstake_token_output_not_found; + + uint64_t expected_interest = blokchainDB.calculate_staked_token_interest_for_output(txin, blokchainDB.height()); + + if(txin.amount > expected_interest) + return execution_status::error_unstake_token_network_fee_not_matching; + + if(od.height + get_safex_minumum_token_lock_period(blokchainDB.get_net_type()) > blokchainDB.height()) + return execution_status::error_unstake_token_minimum_period; + } + catch (...) + { + return execution_status::error_unstake_token_output_not_found; + } + + return execution_status::ok; + } + + + token_collect_result* token_collect::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate token collect command", this->get_command_type()); + + + token_collect_result *cr = new token_collect_result{}; + cr->token_amount = txin.token_amount; + cr->block_number = blokchainDB.height(); + + uint64_t locked_token_output_index = txin.key_offsets[0]; + cr->interest = calculate_token_interest(locked_token_output_index, cr->block_number, cr->token_amount); + cr->valid = true; + cr->status = execution_status::ok; + + return cr; + } + + execution_status token_collect::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + //TODO: GRKI Do not allow token_collect for now + + //todo Get data about locked token output from database using its index + //todo check if db output amount is same as txin amount + //todo check if minimum amount of time is fulfilled + + return execution_status::invalid; + } + + + donate_fee_result* donate_fee::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate donate fee command", this->get_command_type()); + + donate_fee_result *cr = new donate_fee_result{}; + cr->amount = txin.amount; + cr->valid = true; + cr->status = execution_status::ok; + + return cr; + }; + + execution_status donate_fee::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + if(!(txin.amount > 0)) + return execution_status::error_wrong_input_params; + if(txin.token_amount != 0) + return execution_status::error_wrong_input_params; + + return execution_status::ok; + }; + + simple_purchase_result* simple_purchase::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate simple purchase command", this->get_command_type()); + + simple_purchase_result *cr = new simple_purchase_result{}; + cr->offer_id = this->offer_id; + cr->quantity = this->quantity; + cr->price = this->price; + cr->shipping = this->shipping; + cr->valid = true; + cr->status = execution_status::ok; + + return cr; + }; + + execution_status simple_purchase::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); + + safex::safex_offer sfx_offer{}; + if (!blokchainDB.get_offer(cmd->offer_id,sfx_offer)) { + return execution_status::error_offer_non_existant; + } + + if(!sfx_offer.active) + return execution_status::error_purchase_offer_not_active; + + if(sfx_offer.quantity < cmd->quantity) + return execution_status::error_purchase_out_of_stock; + + if(cmd->quantity==0) + return execution_status::error_purchase_quantity_zero; + + uint64_t sfx_price = sfx_offer.min_sfx_price; + + if(sfx_offer.price_peg_used){ + safex::safex_price_peg sfx_price_peg; + if (!blokchainDB.get_safex_price_peg(sfx_offer.price_peg_id,sfx_price_peg)) { + return execution_status::error_offer_price_peg_not_existant; + } + std::string rate_str = cryptonote::print_money(sfx_price_peg.rate); + double rate = stod(rate_str); + + std::string price_str = cryptonote::print_money(sfx_offer.price); + double price_dbl = stod(price_str); + + uint64_t pegged_price = (price_dbl*rate)*SAFEX_CASH_COIN; + + if(sfx_price < pegged_price) + sfx_price = pegged_price; + } + + if(sfx_price * cmd->quantity > cmd->price) + return execution_status::error_purchase_not_enough_funds; + + if(sfx_offer.get_hash() != cmd->get_offerhash()) + return execution_status::error_purchase_wrong_hash; + + return execution_status::ok; + }; + + create_account_result* create_account::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate create account command", this->get_command_type()); + + create_account_result *cr = new create_account_result{this->username, this->pkey, this->account_data}; + cr->valid = true; + cr->status = execution_status::ok; + + return cr; + }; + + execution_status create_account::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + if(txin.token_amount == 0) + return execution_status::error_account_no_tokens; + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); + + for (auto ch: cmd->get_username()) { + if (!(std::islower(ch) || std::isdigit(ch)) && ch!='_' && ch!='-') { + return execution_status::error_invalid_account_name; + } + } + + std::vector dummy{}; + if (blokchainDB.get_account_data(cmd->get_username(), dummy)) { + return execution_status::error_account_already_exists; + } + + if (!crypto::check_key(cmd->get_account_key())) { + return execution_status::error_account_pkey_invalid; + } + + if (cmd->get_username().length() > SAFEX_ACCOUNT_USERNAME_MAX_SIZE) + { + return execution_status::error_account_data_too_big; + } + + if (cmd->get_account_data().size() > SAFEX_ACCOUNT_DATA_MAX_SIZE) + { + return execution_status::error_account_data_too_big; + } + + return execution_status::ok; + }; + + edit_account_result* edit_account::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate edit account command", this->get_command_type()); + + edit_account_result *cr = new edit_account_result{this->username, this->new_account_data}; + cr->valid = true; + cr->status = execution_status::ok; + + return cr; + }; + + execution_status edit_account::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); + + + if(txin.key_offsets.size() != 1) + return execution_status::error_account_offset_not_one; + + uint64_t safex_account_index = txin.key_offsets[0]; + + std::vector dummy{}; + if (!blokchainDB.get_account_data(cmd->get_username(), dummy)) { + return execution_status::error_account_non_existant; + } + + try + { + const cryptonote::output_advanced_data_t od = blokchainDB.get_output_advanced_data(cryptonote::tx_out_type::out_safex_account, safex_account_index); + + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(od.data), std::end(od.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string accusername(begin(account.username), end(account.username)); + + if(accusername != cmd->get_username()) + return execution_status::error_invalid_account_name; + } + catch (...) + { + return execution_status::error_account_non_existant; + } + + if (cmd->get_new_account_data().size() > SAFEX_ACCOUNT_DATA_MAX_SIZE) + { + return execution_status::error_account_data_too_big; + } + + return execution_status::ok; + }; + + + create_offer_result* create_offer::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate create offer command", this->get_command_type()); + + create_offer_result *cr = new create_offer_result{this->offer_id,this->seller,this->price,this->quantity,this->active}; + cr->valid = true; + cr->status = execution_status::ok; + + return cr; + }; + + execution_status create_offer::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); + + if(txin.key_offsets.size() != 1) + return execution_status::error_offer_offset_not_one; + + uint64_t safex_account_index = txin.key_offsets[0]; + + std::vector dummy{}; + if (!blokchainDB.get_account_data(cmd->get_seller(), dummy)) { + return execution_status::error_account_non_existant; + } + + try + { + const cryptonote::output_advanced_data_t od = blokchainDB.get_output_advanced_data(cryptonote::tx_out_type::out_safex_account, safex_account_index); + + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(od.data), std::end(od.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + + if(account.username != cmd->get_seller()) + return execution_status::error_invalid_account_name; + } + catch (...) + { + return execution_status::error_account_non_existant; + } + + + safex::safex_offer sfx_offer{}; + if (blokchainDB.get_offer(cmd->get_offerid(),sfx_offer)) { + return execution_status::error_offer_already_exists; + } + + if(cmd->get_min_sfx_price() < SAFEX_OFFER_MINIMUM_PRICE){ + return execution_status::error_offer_price_too_small; + } + + if(cmd->get_min_sfx_price() > MONEY_SUPPLY){ + return execution_status::error_offer_price_too_big; + } + + if(!cmd->get_price_peg_used() && cmd->get_min_sfx_price() > cmd->get_price()){ + return execution_status::error_offer_price_mismatch; + } + + if (cmd->get_title().size() > SAFEX_OFFER_NAME_MAX_SIZE) + { + MERROR("Offer title is bigger than max allowed " + std::to_string(SAFEX_OFFER_NAME_MAX_SIZE)); + return execution_status::error_offer_data_too_big; + } + + if (cmd->get_description().size() > SAFEX_OFFER_DATA_MAX_SIZE) + { + MERROR("Offer data is bigger than max allowed " + std::to_string(SAFEX_OFFER_DATA_MAX_SIZE)); + return execution_status::error_offer_data_too_big; + } + + safex::safex_price_peg sfx_price_peg{}; + if(cmd->get_price_peg_used() && !blokchainDB.get_safex_price_peg(cmd->get_price_peg_id(),sfx_price_peg)){ + return execution_status::error_offer_price_peg_not_existant; + } + + return execution_status::ok; + }; + + edit_offer_result* edit_offer::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate edit offer command", this->get_command_type()); + + edit_offer_result *cr = new edit_offer_result{this->offer_id,this->seller,this->price,this->quantity,this->active}; + cr->valid = true; + cr->status = execution_status::ok; + + return cr; + }; + + execution_status edit_offer::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); + + if(txin.key_offsets.size() != 1) + return execution_status::error_offer_offset_not_one; + + uint64_t safex_offer_index = txin.key_offsets[0]; + + std::vector dummy{}; + if (!blokchainDB.get_account_data(cmd->get_seller(), dummy)) { + return execution_status::error_account_non_existant; + } + + safex::safex_offer sfx_dummy{}; + if (!blokchainDB.get_offer(cmd->get_offerid(), sfx_dummy)) { + return execution_status::error_offer_non_existant; + } + + try + { + const cryptonote::output_advanced_data_t od = blokchainDB.get_output_advanced_data(cryptonote::tx_out_type::out_safex_offer, safex_offer_index); + + safex::create_offer_data offer; + const cryptonote::blobdata offerblob(std::begin(od.data), std::end(od.data)); + cryptonote::parse_and_validate_from_blob(offerblob, offer); + + if(offer.offer_id != cmd->get_offerid()) + return execution_status::error_offer_invalid_offer_id; + } + catch (...) + { + return execution_status::error_account_non_existant; + } + + if(cmd->get_min_sfx_price() < SAFEX_OFFER_MINIMUM_PRICE){ + return execution_status::error_offer_price_too_small; + } + + if(cmd->get_min_sfx_price() > MONEY_SUPPLY){ + return execution_status::error_offer_price_too_big; + } + + if(!cmd->get_price_peg_used() && cmd->get_min_sfx_price() > cmd->get_price()){ + return execution_status::error_offer_price_mismatch; + } + + if (cmd->get_title().size() > SAFEX_OFFER_NAME_MAX_SIZE) + { + MERROR("Offer title is bigger than max allowed " + std::to_string(SAFEX_OFFER_NAME_MAX_SIZE)); + return execution_status::error_offer_data_too_big; + } + + if (cmd->get_description().size() > SAFEX_OFFER_DATA_MAX_SIZE) + { + MERROR("Offer data is bigger than max allowed " + std::to_string(SAFEX_OFFER_DATA_MAX_SIZE)); + return execution_status::error_offer_data_too_big; + } + + safex::safex_price_peg sfx_price_peg{}; + if(cmd->get_price_peg_used() && !blokchainDB.get_safex_price_peg(cmd->get_price_peg_id(),sfx_price_peg)){ + return execution_status::error_offer_price_peg_not_existant; + } + + return execution_status::ok; + }; + + create_feedback_result* create_feedback::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate create feedback command", this->get_command_type()); + + create_feedback_result *cr = new create_feedback_result{this->offer_id,this->comment,this->stars_given}; + cr->valid = true; + cr->status = execution_status::ok; + + return cr; + }; + + execution_status create_feedback::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); + + if(txin.key_offsets.size() != 1) + return execution_status::error_feedback_offset_not_one; + + uint64_t safex_feedback_token_index = txin.key_offsets[0]; + + try + { + const cryptonote::output_advanced_data_t od = blokchainDB.get_output_advanced_data(cryptonote::tx_out_type::out_safex_feedback_token, safex_feedback_token_index); + + } + catch (...) + { + return execution_status::error_feedback_token_non_existant; + } + + + safex::safex_offer sfx_dummy{}; + if (!blokchainDB.get_offer(cmd->get_offerid(), sfx_dummy)) { + return execution_status::error_offer_non_existant; + } + + uint64_t rating_given = cmd->get_stars_given(); + + if(rating_given > SAFEX_FEEDBACK_MAX_RATING ) + return execution_status::error_feedback_invalid_rating; + + if(cmd->get_comment().size() > SAFEX_FEEDBACK_DATA_MAX_SIZE) + return execution_status::error_feedback_data_too_big; + + return execution_status::ok; + }; + + create_price_peg_result* create_price_peg::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate create price peg command", this->get_command_type()); + + create_price_peg_result *cr = new create_price_peg_result{this->price_peg_id,this->title,this->creator,this->description,this->currency,this->rate}; + cr->valid = true; + cr->status = execution_status::ok; + + return cr; + }; + + execution_status create_price_peg::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); + + std::vector dummy{}; + if (!blokchainDB.get_account_data(cmd->get_creator(), dummy)) { + return execution_status::error_account_non_existant; + } + + if(txin.key_offsets.size() != 1) + return execution_status::error_price_peg_offset_not_one; + + uint64_t safex_account_index = txin.key_offsets[0]; + + try + { + const cryptonote::output_advanced_data_t od = blokchainDB.get_output_advanced_data(cryptonote::tx_out_type::out_safex_account, safex_account_index); + + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(od.data), std::end(od.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + + if(account.username != cmd->get_creator()) + return execution_status::error_invalid_account_name; + } + catch (...) + { + return execution_status::error_account_non_existant; + } + + safex::safex_price_peg dummy_price_peg{}; + if(blokchainDB.get_safex_price_peg(cmd->get_price_peg_id(),dummy_price_peg)) + { + return execution_status::error_price_peg_already_exists; + } + + if (cmd->get_title().size() > SAFEX_PRICE_PEG_NAME_MAX_SIZE) + { + return execution_status::error_price_peg_data_too_big; + } + + if (cmd->get_currency().size() > SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE) + { + return execution_status::error_price_peg_data_too_big; + } + + for (auto ch: cmd->get_currency()) { + if (!std::isupper(ch)) { + return execution_status::error_price_peg_bad_currency_format; + } + } + + if(cmd->get_rate() == 0) + { + return execution_status::error_price_peg_rate_zero; + } + + //check price peg data size + if (cmd->get_description().size() > SAFEX_PRICE_PEG_DATA_MAX_SIZE) + { + return execution_status::error_price_peg_data_too_big; + } + + return execution_status::ok; + }; + + update_price_peg_result* update_price_peg::execute(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + execution_status result = validate(blokchainDB, txin); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(result == execution_status::ok, "Failed to validate update price peg command", this->get_command_type()); + + update_price_peg_result *cr = new update_price_peg_result{this->price_peg_id,this->rate}; + cr->valid = true; + cr->status = execution_status::ok; + + return cr; + }; + + execution_status update_price_peg::validate(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + + std::unique_ptr cmd = safex::safex_command_serializer::parse_safex_command(txin.script); + + if(txin.key_offsets.size() != 1) + return execution_status::error_price_peg_offset_not_one; + + uint64_t safex_price_peg_index = txin.key_offsets[0]; + + try + { + const cryptonote::output_advanced_data_t od = blokchainDB.get_output_advanced_data(cryptonote::tx_out_type::out_safex_price_peg, safex_price_peg_index); + + safex::create_price_peg_data price_peg; + const cryptonote::blobdata price_pegblob(std::begin(od.data), std::end(od.data)); + cryptonote::parse_and_validate_from_blob(price_pegblob, price_peg); + + if(price_peg.price_peg_id != cmd->get_price_peg_id()) + return execution_status::error_price_peg_invalid_price_peg_id; + } + catch (...) + { + return execution_status::error_account_non_existant; + } + + if(cmd->get_rate() == 0) + { + return execution_status::error_price_peg_rate_zero; + } + + safex::safex_price_peg sfx_dummy{}; + if (!blokchainDB.get_safex_price_peg(cmd->get_price_peg_id(), sfx_dummy)) { + return execution_status::error_price_peg_not_existant; + } + + return execution_status::ok; + }; + + bool validate_safex_command(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + //parse command and validate it + try + { + if(!safex::is_safex_key_image_verification_needed(txin.command_type) && txin.key_offsets.size() != 1) + { + LOG_ERROR("Commands that don't have key image verification must have only 1 key offset"); + return false; + } + std::unique_ptr cmd = safex_command_serializer::parse_safex_object(txin.script, txin.command_type); + execution_status result{cmd->validate(blokchainDB, txin)}; + if (result != execution_status::ok) + { + LOG_PRINT_L1("Validation of safex command failed, status:" << static_cast(result)); + return false; + } + } + catch (command_exception &ex) + { + LOG_ERROR("Error in safex command validation:" << ex.what()); + return false; + } + + + return true; + } + + + bool execute_safex_command(const cryptonote::BlockchainDB &blokchainDB, const cryptonote::txin_to_script &txin) + { + //parse command and execute it + try + { + std::unique_ptr cmd = safex_command_serializer::parse_safex_object(txin.script, txin.command_type); + std::shared_ptr result{cmd->execute(blokchainDB, txin)}; + if (result->status != execution_status::ok) + { + LOG_ERROR("Execution of safex command failed, status:" << static_cast(result->status)); + return false; + } + } + catch (command_exception &ex) + { + LOG_ERROR("Error in safex command execution:" << ex.what()); + return false; + } + + + return true; + } + + +} diff --git a/src/safex/command.h b/src/safex/command.h new file mode 100644 index 000000000..6194a86fb --- /dev/null +++ b/src/safex/command.h @@ -0,0 +1,1254 @@ +// +// Created by amarko on 4.3.19.. +// + +#ifndef SAFEX_COMMAND_H +#define SAFEX_COMMAND_H + +#include +#include +#include +#include + +#include "crypto/crypto.h" +#include "crypto/hash.h" +#include "cryptonote_core/blockchain.h" + +#include "storages/portable_storage.h" +#include "serialization/serialization.h" +#include "safex_core.h" + +#include "misc_log_ex.h" +#include "safex_offer.h" +#include "safex_purchase.h" +#include "safex_feedback.h" + +#define CHECK_COMMAND_TYPE(TYPE_TO_CHECK,EXPECTED_TYPE) SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES((TYPE_TO_CHECK == EXPECTED_TYPE), "Could not create command, wrong command type", TYPE_TO_CHECK); + +namespace safex +{ + + /* Binary storage fields */ + static const std::string FIELD_VERSION = "version"; + static const std::string FIELD_COMMAND = "command"; + static const std::string FIELD_STAKE_TOKEN_AMOUNT = "stake_token_amount"; + static const std::string FIELD_STAKED_TOKEN_OUTPUT_INDEX = "staked_token_output_index"; + + + enum class execution_status + { + ok = 0, + invalid = 1, + error_wrong_input_params = 1, + // Safex stake token + error_stake_token_amount_not_matching = 2, + error_stake_token_not_whole_amount = 3, + // Safex account + error_account_data_too_big = 10, + error_account_already_exists = 11, + error_invalid_account_name = 12, + error_account_non_existant = 13, + error_account_no_tokens = 14, + error_account_offset_not_one = 15, + error_account_pkey_invalid = 16, + // Safex purchase + error_offer_non_existant = 20, + error_purchase_out_of_stock = 21, + error_purchase_not_enough_funds = 23, + error_purchase_offer_not_active = 24, + error_purchase_quantity_zero = 25, + error_purchase_wrong_hash = 26, + // Safex offer + error_offer_price_too_big = 30, + error_offer_price_too_small = 31, + error_offer_data_too_big = 32, + error_offer_price_peg_not_existant = 33, + error_offer_price_mismatch = 34, + error_offer_already_exists = 35, + error_offer_invalid_offer_id = 36, + error_offer_offset_not_one = 37, + // Safex feedback + error_feedback_invalid_rating = 40, + error_feedback_data_too_big = 41, + error_feedback_offset_not_one = 42, + error_feedback_token_non_existant = 43, + // Safex price peg + error_price_peg_bad_currency_format = 51, + error_price_peg_data_too_big = 52, + error_price_peg_not_existant = 53, + error_price_peg_rate_zero = 54, + error_price_peg_already_exists = 55, + error_price_peg_offset_not_one = 56, + error_price_peg_invalid_price_peg_id = 57, + // Safex unstake token + error_unstake_token_output_not_found = 60, + error_unstake_token_minimum_period = 61, + error_unstake_token_network_fee_not_matching = 62, + error_unstake_token_offset_not_one = 63, + error_unstake_token_output_not_matching = 64 + }; + + struct execution_result + { + bool valid = false; + execution_status status = execution_status::invalid; + + virtual ~execution_result() = default; + }; + + struct token_stake_result : public execution_result + { + uint64_t token_amount = 0; //staked amount + uint32_t block_number = 0; //block where it is locked + }; + + + struct token_unstake_result : public execution_result + { + uint64_t token_amount = 0; //unlocked token amount + uint64_t interest = 0; //collected interest from network fees over period + uint32_t block_number = 0; //block where it is unlocked + }; + + struct token_collect_result : public execution_result + { + uint64_t token_amount = 0; //amount of tokens that is relocked + uint64_t interest = 0; //collected interest from network fees over period + uint32_t block_number = 0; //block where it is unlocked + }; + + struct donate_fee_result : public execution_result + { + uint64_t amount = 0; //cash amount do donate to newtork token holders + }; + + struct simple_purchase_result : public execution_result + { + + simple_purchase_result(){} + + simple_purchase_result(const crypto::hash &_offer_id, const crypto::hash &_offer_hash, uint64_t _quantity, uint64_t _price, bool _shipping) : + offer_id(_offer_id),offer_hash{_offer_hash}, quantity{_quantity}, + price{_price},shipping{_shipping}{} + + crypto::hash offer_id{}; //unique id of the offer + crypto::hash offer_hash{}; + uint64_t quantity{}; + uint64_t price; + bool shipping{}; + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + FIELD(offer_hash) + FIELD(quantity) + FIELD(price) + FIELD(shipping) + END_SERIALIZE() + }; + + struct create_account_result : public execution_result + { + + create_account_result(){} + + create_account_result(const std::vector &_username, const crypto::public_key &_pkey, const std::vector& _account_data): + username{_username}, pkey{_pkey}, account_data{_account_data}{ + } + + std::vector username{}; + crypto::public_key pkey{}; + std::vector account_data{}; + + BEGIN_SERIALIZE_OBJECT() + FIELD(username) + FIELD(pkey) + FIELD(account_data) + END_SERIALIZE() + }; + + struct edit_account_result : public execution_result + { + edit_account_result(const std::vector &_username, std::vector& _account_data): + username{_username}, account_data{_account_data} { + } + std::vector username{}; + std::vector account_data{}; + + BEGIN_SERIALIZE_OBJECT() + FIELD(username) + FIELD(account_data) + END_SERIALIZE() + }; + +struct create_offer_result : public execution_result +{ + + create_offer_result(){} + + create_offer_result(crypto::hash _offer_id, std::vector _seller, uint64_t _price, uint64_t _quantity, + bool _active): offer_id{_offer_id},seller{_seller},price{_price},quantity{_quantity},active{_active} { + } + + crypto::hash offer_id{}; + std::vector seller{}; + uint64_t quantity{}; + uint64_t price; + bool active{}; + uint64_t output_id{}; + uint64_t output_id_creation{}; + bool edited{false}; + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + FIELD(seller) + FIELD(price) + FIELD(quantity) + FIELD(active) + FIELD(output_id) + FIELD(output_id_creation) + FIELD(edited) + END_SERIALIZE() + +}; + +struct edit_offer_result : public execution_result +{ + + edit_offer_result(){} + + edit_offer_result(crypto::hash _offer_id, std::vector _seller, uint64_t _price, uint64_t _quantity, + bool _active): offer_id{_offer_id},seller{_seller},price{_price},quantity{_quantity},active{_active} { + + } + + crypto::hash offer_id{}; + std::vector seller{}; + uint64_t quantity{}; + uint64_t price; + bool active{}; + uint64_t output_id{}; + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + FIELD(seller) + FIELD(price) + FIELD(quantity) + FIELD(active) + FIELD(output_id) + END_SERIALIZE() + +}; + +struct create_feedback_result : public execution_result +{ + + create_feedback_result(){} + + create_feedback_result(crypto::hash _offer_id, std::vector _comment, uint8_t _stars_given): offer_id{_offer_id},comment{_comment},stars_given{_stars_given} { + + } + + crypto::hash offer_id{}; //unique id of the offer + uint8_t stars_given; + std::vector comment{}; + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + FIELD(stars_given) + FIELD(comment) + END_SERIALIZE() + +}; + +struct create_price_peg_result : public execution_result +{ + + create_price_peg_result(){} + + create_price_peg_result(crypto::hash _price_peg_id, std::vector _title, std::vector _creator, std::vector _description, std::vector _currency,uint64_t _rate) + :price_peg_id{_price_peg_id},title{_title},creator{_creator}, description{_description}, currency{_currency},rate{_rate} { + output_ids.clear(); + } + + std::vector title; //title of the price peg + crypto::hash price_peg_id; //unique id of the price peg + std::vector creator; // username of the price peg + std::vector description; //description of price peg + std::vector currency; + uint64_t rate; + std::vector output_ids{}; + + BEGIN_SERIALIZE_OBJECT() + FIELD(title) + FIELD(price_peg_id) + FIELD(creator) + FIELD(description) + FIELD(currency) + FIELD(rate) + FIELD(output_ids) + END_SERIALIZE() + +}; + + struct update_price_peg_result : public execution_result + { + + update_price_peg_result(){} + + update_price_peg_result(crypto::hash _price_peg_id,uint64_t _rate) + :price_peg_id{_price_peg_id},rate{_rate} { + output_ids.clear(); + } + + crypto::hash price_peg_id; //unique id of the price peg + uint64_t rate; + std::vector output_ids{}; + + BEGIN_SERIALIZE_OBJECT() + FIELD(price_peg_id) + FIELD(rate) + FIELD(output_ids) + END_SERIALIZE() + + }; + + struct command_data + { + + }; + + struct token_stake_data : public command_data + { + uint32_t reserved = 0; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(reserved) + END_SERIALIZE() + }; + + struct donate_fee_data : public command_data + { + uint32_t reserved = 0; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(reserved) + END_SERIALIZE() + }; + + struct create_account_data : public command_data + { + std::vector username{}; + crypto::public_key pkey; + std::vector account_data{}; + + create_account_data() {} + create_account_data(const std::string &_username, const crypto::public_key &_pkey, const std::vector &_account_data): username(_username.begin(), _username.end()), pkey{_pkey}, account_data{_account_data} + { + + } + + BEGIN_SERIALIZE_OBJECT() + FIELD(username) + FIELD(pkey) + FIELD(account_data) + END_SERIALIZE() + }; + + struct edit_account_data : public command_data + { + std::vector username{}; + std::vector account_data{}; + + edit_account_data() {} + + edit_account_data(const std::string &_username, const std::vector &_account_data): username(_username.begin(), _username.end()), account_data{_account_data} + { + + } + + + BEGIN_SERIALIZE_OBJECT() + FIELD(username) + FIELD(account_data) + END_SERIALIZE() + }; + + struct create_offer_data : public command_data + { + crypto::hash offer_id{}; + crypto::hash price_peg_id{}; + std::vector seller{}; + std::vector title{}; + uint64_t quantity; + uint64_t price; + uint64_t min_sfx_price; + std::vector description{}; + bool active{false}; + bool price_peg_used{false}; + crypto::secret_key seller_private_view_key; + cryptonote::account_public_address seller_address; + + create_offer_data() {} + create_offer_data(const safex::safex_offer& offer): offer_id{offer.offer_id}, description{offer.description},quantity{offer.quantity},price{offer.price},seller(offer.seller.begin(),offer.seller.end()),active{offer.active},title{offer.title.begin(),offer.title.end()},seller_address{offer.seller_address},seller_private_view_key{offer.seller_private_view_key}, + price_peg_id{offer.price_peg_id},min_sfx_price{offer.min_sfx_price},price_peg_used{offer.price_peg_used} + { + } + create_offer_data(const crypto::hash &_offer_id, const std::vector &_seller, const std::vector &_title, const uint64_t &_quantity, const uint64_t &_price, const std::vector &_offer_data,const bool &_active, const cryptonote::account_public_address& _seller_address, const crypto::secret_key& _seller_private_view_key, const crypto::hash& _price_peg_id, const uint64_t _min_sfx_price, const bool _price_peg_used): + offer_id{_offer_id},seller{_seller},title{_title},quantity{_quantity},price{_price},description{_offer_data},active{_active},seller_address{_seller_address},seller_private_view_key{_seller_private_view_key},price_peg_id{_price_peg_id},min_sfx_price{_min_sfx_price},price_peg_used{_price_peg_used}{} + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + FIELD(price_peg_id) + FIELD(seller) + FIELD(title) + FIELD(price) + FIELD(min_sfx_price) + FIELD(quantity) + FIELD(active) + FIELD(price_peg_used) + FIELD(description) + FIELD(seller_private_view_key) + FIELD(seller_address) + END_SERIALIZE() + }; + + struct edit_offer_data : public command_data + { + crypto::hash offer_id{}; + crypto::hash price_peg_id{}; + std::vector seller{}; + std::vector title{}; + uint64_t quantity; + uint64_t price; + uint64_t min_sfx_price; + std::vector description{}; + bool active{false}; + bool price_peg_used{false}; + + edit_offer_data() {} + edit_offer_data(const safex::safex_offer& offer): offer_id{offer.offer_id},title{offer.title.begin(),offer.title.end()}, description{offer.description},quantity{offer.quantity},price{offer.price},seller(offer.seller.begin(),offer.seller.end()),active{offer.active}, + price_peg_id{offer.price_peg_id},min_sfx_price{offer.min_sfx_price},price_peg_used{offer.price_peg_used} + { + } + edit_offer_data(const crypto::hash &_offer_id, const std::vector &_seller, const std::vector &_title, const uint64_t &_quantity, const uint64_t &_price, const std::vector &_offer_data,const bool &_active, const crypto::hash& _price_peg_id, const uint64_t _min_sfx_price, const bool _price_peg_used): + offer_id{_offer_id},seller{_seller},title{_title},quantity{_quantity},price{_price},description{_offer_data},active{_active},price_peg_id{_price_peg_id},min_sfx_price{_min_sfx_price},price_peg_used{_price_peg_used}{} + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + FIELD(price_peg_id) + FIELD(seller) + FIELD(title) + FIELD(price) + FIELD(min_sfx_price) + FIELD(quantity) + FIELD(active) + FIELD(price_peg_used) + FIELD(description) + END_SERIALIZE() + }; + + struct create_purchase_data : public command_data + { + crypto::hash offer_id{}; //unique id of the offer + crypto::hash offer_hash{}; + uint64_t quantity{}; + uint64_t price; + bool shipping{}; + + create_purchase_data() {} + create_purchase_data(const safex::safex_purchase& purchase): offer_id{purchase.offer_id},offer_hash{purchase.offer_hash},quantity{purchase.quantity},price{purchase.price}, + shipping{purchase.shipping} + { + } + create_purchase_data(const crypto::hash &_offer_id, const crypto::hash &_offer_hash, const uint64_t &_quantity, const uint64_t &_price): + offer_id{_offer_id},offer_hash{_offer_hash},quantity{_quantity},price{_price}{} + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + FIELD(offer_hash) + FIELD(quantity) + FIELD(price) + FIELD(shipping) + END_SERIALIZE() + }; + + struct create_feedback_token_data : public command_data + { + crypto::hash offer_id{}; //unique id of the offer + + + create_feedback_token_data() {} + create_feedback_token_data(const safex::safex_purchase& purchase): offer_id{purchase.offer_id} + { + } + create_feedback_token_data(const safex::safex_feedback_token& feedback_token): offer_id{feedback_token.offer_id} + { + } + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + END_SERIALIZE() + }; + + struct create_feedback_data : public command_data + { + crypto::hash offer_id{}; //unique id of the offer + uint8_t stars_given; + std::vector comment{}; + + create_feedback_data() {} + create_feedback_data(const safex::safex_feedback& feedback): offer_id{feedback.offer_id},stars_given{feedback.stars_given},comment{feedback.comment.begin(),feedback.comment.end()}{ + } + create_feedback_data(const crypto::hash &_offer_id, const uint8_t &_stars_given, const std::vector _comment): + offer_id{_offer_id},stars_given{_stars_given},comment{_comment}{} + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + FIELD(stars_given) + FIELD(comment) + END_SERIALIZE() + }; + + + struct create_price_peg_data : public command_data + { + std::vector title; //title of the price peg + crypto::hash price_peg_id; //unique id of the price peg + std::vector creator; // username of the price peg + std::vector description; //description of price peg + std::vector currency; + uint64_t rate; + + create_price_peg_data() {} + create_price_peg_data(const safex::safex_price_peg& price_peg): title{price_peg.title.begin(),price_peg.title.end()}, description{price_peg.description},price_peg_id{price_peg.price_peg_id},creator{price_peg.creator.begin(),price_peg.creator.end()},currency(price_peg.currency.begin(),price_peg.currency.end()),rate{price_peg.rate} + { + } + + create_price_peg_data(const std::vector& _title, const crypto::hash& _price_peg_id, const std::vector& _creator, const std::vector& _description, const std::vector& _currency, const uint64_t& _rate): + title{_title},price_peg_id{_price_peg_id}, creator{_creator},description{_description},currency{_currency},rate{_rate} + { + } + + BEGIN_SERIALIZE_OBJECT() + FIELD(title) + FIELD(price_peg_id) + FIELD(creator) + FIELD(description) + FIELD(currency) + FIELD(rate) + END_SERIALIZE() + }; + + struct update_price_peg_data : public command_data + { + crypto::hash price_peg_id; //unique id of the price peg + uint64_t rate; + + update_price_peg_data() {} + update_price_peg_data(const safex::safex_price_peg& price_peg): price_peg_id{price_peg.price_peg_id},rate{price_peg.rate} + { + } + + update_price_peg_data(const crypto::hash& _price_peg_id, const uint64_t& _rate): + price_peg_id{_price_peg_id}, rate{_rate} + { + } + + BEGIN_SERIALIZE_OBJECT() + FIELD(price_peg_id) + FIELD(rate) + END_SERIALIZE() + }; + + /** + * @brief script command representation + * + * Safex Command protocol is intended to expand functionality + * of the blockchain and to enable easy addition of the new features + * without having to make significant changes + * to the current blockchain core protocol. + */ + class command + { + public: + + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _command_type actuall command, like stake token + * */ + command(const uint32_t _version, const command_t _command_type) : version(_version), command_type(_command_type) + { + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES((_command_type < command_t::invalid_command), "Invalid command type", _command_type); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES((_version <= SAFEX_COMMAND_PROTOCOL_VERSION), "Unsupported command protocol version " + std::to_string(_version), command_type); + + } + + virtual execution_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) = 0; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) = 0; + + uint32_t get_version() const + { return version; } + + command_t get_command_type() const + { return command_type; } + + virtual ~command() = default; + + BEGIN_SERIALIZE_OBJECT() + VARINT_FIELD(version) + VARINT_FIELD(command_type) + END_SERIALIZE() + + private: + + uint32_t version; + command_t command_type; + }; + + //Dummy command for serialization + class dummy_command : public command + { + public: + + friend class safex_command_serializer; + + dummy_command() : command(0, command_t::nop) {} + + virtual execution_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override {return new execution_result{};}; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override {return execution_status::ok;}; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + END_SERIALIZE() + }; + + + //Token stake command + class token_stake : public command + { + public: + + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _token_amount amount of tokens to lock + * */ + token_stake(const uint32_t _version, const uint64_t _token_amount) : command(_version, command_t::token_stake), stake_token_amount(_token_amount) { + + } + + token_stake() : command(0, command_t::token_stake), stake_token_amount(0) { + + } + + uint64_t get_staked_token_amount() const { return stake_token_amount; } + + virtual token_stake_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::token_stake); + VARINT_FIELD(stake_token_amount) + END_SERIALIZE() + + private: + + uint64_t stake_token_amount; + }; + + + //Token unlock command + class token_unstake : public command + { + public: + + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _staked_token_output_index global index of txout_to_script output that is being unlocked + * */ + token_unstake(const uint32_t _version, const uint64_t _staked_token_output_index) : command(_version, command_t::token_unstake), + staked_token_output_index(_staked_token_output_index) { + + } + + token_unstake() : command(0, command_t::token_unstake), staked_token_output_index(0) { + + } + + uint64_t get_staked_token_output_index() const { return staked_token_output_index; } + + virtual token_unstake_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::token_unstake); + VARINT_FIELD(staked_token_output_index) + END_SERIALIZE() + + private: + + uint64_t staked_token_output_index; + }; + + + //Token collect command + class token_collect : public command + { + public: + + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _staked_token_output_index global index of txout_to_script output that is being unstaked + * + * */ + token_collect(const uint32_t _version, const uint64_t _staked_token_output_index) : command(_version, command_t::token_collect), + staked_token_output_index(_staked_token_output_index) {} + + token_collect() : command(0, command_t::token_collect), staked_token_output_index(0) {} + + uint64_t get_staked_token_output_index() const { return staked_token_output_index; } + + virtual token_collect_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::token_collect); + VARINT_FIELD(staked_token_output_index) + END_SERIALIZE() + + private: + + uint64_t staked_token_output_index; + }; + + class donate_fee : public command + { + public: + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _donate_amount //amount of safex cash that will be donated to the network token holder to be distributed as interest + * */ + donate_fee(const uint32_t _version, const uint64_t _donation_safex_cash_amount) : command(_version, command_t::donate_network_fee), + donation_safex_cash_amount(_donation_safex_cash_amount) {} + + donate_fee() : command(0, command_t::donate_network_fee), donation_safex_cash_amount(0) {} + + uint64_t get_locked_token_output_index() const { return donation_safex_cash_amount; } + + virtual donate_fee_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::donate_network_fee); + VARINT_FIELD(donation_safex_cash_amount) + END_SERIALIZE() + + private: + + uint64_t donation_safex_cash_amount; + }; + + class simple_purchase : public command + { + public: + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _simple_purchase_price Simple purschase cash amount + * */ + simple_purchase(const uint32_t _version, const safex::create_purchase_data &sfx_purchase) : command(_version, command_t::simple_purchase), + offer_id(sfx_purchase.offer_id),offer_hash{sfx_purchase.offer_hash},quantity{sfx_purchase.quantity}, + price{sfx_purchase.price},shipping{sfx_purchase.shipping}{} + + simple_purchase() : command(0, command_t::simple_purchase) {} + + crypto::hash get_offerid(){ return offer_id; } + crypto::hash get_offerhash(){ return offer_hash; } + uint64_t get_quantity(){ return quantity; } + uint64_t get_price(){ return price; } + bool get_shipping() { return shipping; } + + virtual simple_purchase_result* execute(const cryptonote::BlockchainDB &blockchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::simple_purchase); + FIELD(offer_id) + FIELD(offer_hash) + FIELD(quantity) + FIELD(price) + FIELD(shipping) + END_SERIALIZE() + + private: + + crypto::hash offer_id{}; //unique id of the offer + crypto::hash offer_hash{}; + uint64_t quantity{}; + uint64_t price{}; + bool shipping{}; + }; + + class create_account : public command + { + public: + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _username //new account username + * @param _pkey //public account key, that is used to verify signatures of account owner actions + * @param _account_data //account description + * */ + create_account(const uint32_t _version, std::vector &_username, const crypto::public_key &_pkey, const std::vector &_account_data) : + command(_version, command_t::create_account), username(_username), pkey{_pkey}, account_data{_account_data} {} + + create_account(const uint32_t _version, const std::string &_username, const crypto::public_key &_pkey, const std::string &_account_data) : + command(_version, command_t::create_account), username(_username.begin(), _username.end()), pkey{_pkey}, account_data(_account_data.begin(), _account_data.end()) {} + + create_account() : command(0, command_t::create_account), username{}, pkey{}, account_data{} {} + + std::string get_username() const { return std::string(std::begin(username), std::end(username)); } + crypto::public_key get_account_key() const { return pkey; } + std::vector get_account_data() const { return account_data; } + + virtual create_account_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::create_account); + FIELD(username) + FIELD(pkey) + FIELD(account_data) + END_SERIALIZE() + + private: + + std::vector username{}; + crypto::public_key pkey; + std::vector account_data{}; + }; + + class edit_account : public command + { + public: + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _username //new account username + * @param _account_data //new account description data + * */ + edit_account(const uint32_t _version, const std::vector _username, const std::vector _new_account_data) : + command(_version, command_t::edit_account), username(_username), new_account_data{_new_account_data} {} + + edit_account(const uint32_t _version, const std::string &_username, const std::string &_new_account_data) : + command(_version, command_t::edit_account), username(_username.begin(), _username.end()), new_account_data(_new_account_data.begin(), _new_account_data.end()) {} + + + edit_account() : command(0, command_t::edit_account), username{}, new_account_data{} {} + + std::string get_username() const { return std::string(username.begin(), username.end()); } + std::vector get_new_account_data() const { return new_account_data; } + + virtual edit_account_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::edit_account); + FIELD(username) + FIELD(new_account_data) + END_SERIALIZE() + + private: + + std::vector username{}; + std::vector new_account_data{}; + }; + +class create_offer : public command +{ +public: + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param offer //offer data + * */ + create_offer(const uint32_t _version, const safex::create_offer_data &offer) : + command(_version, command_t::create_offer), offer_id(offer.offer_id), description{offer.description}, + seller{offer.seller},title{offer.title},price{offer.price},quantity{offer.quantity},active{offer.active},seller_address{offer.seller_address},seller_private_view_key{offer.seller_private_view_key}, + min_sfx_price{offer.min_sfx_price},price_peg_id{offer.price_peg_id},price_peg_used{offer.price_peg_used}{ + } + + create_offer() : command(0, command_t::create_offer), offer_id{}, description{} {} + + crypto::hash get_offerid() const { return offer_id; } + crypto::hash get_price_peg_id() const { return price_peg_id; } + std::vector get_seller() const { return seller; } + std::vector get_title() const { return title; } + uint64_t get_price() const { return price; } + uint64_t get_min_sfx_price() const { return min_sfx_price; } + uint64_t get_quantity() const { return quantity; } + bool get_active() const { return active; } + bool get_price_peg_used() const { return price_peg_used; } + std::vector get_description() const { return description; } + cryptonote::account_public_address get_seller_address() const { return seller_address; } + crypto::secret_key get_seller_private_view_key() const { return seller_private_view_key; } + + virtual create_offer_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::create_offer); + FIELD(offer_id) + FIELD(price_peg_id) + FIELD(seller) + FIELD(title) + FIELD(price) + FIELD(min_sfx_price) + FIELD(quantity) + FIELD(active) + FIELD(price_peg_used) + FIELD(description) + FIELD(seller_private_view_key) + FIELD(seller_address) + END_SERIALIZE() + +private: + crypto::hash offer_id{}; + crypto::hash price_peg_id{}; + std::vector seller{}; + std::vector title{}; + uint64_t quantity{}; + uint64_t price; + uint64_t min_sfx_price; + std::vector description{}; + bool active{}; + bool price_peg_used{}; // is offer using price peg + crypto::secret_key seller_private_view_key; + cryptonote::account_public_address seller_address; +}; + +class edit_offer : public command +{ +public: + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _offerid //ID of the offer + * @param _offer_data //offer data + * */ + edit_offer(const uint32_t _version, const safex::edit_offer_data &offer) : + command(_version, command_t::edit_offer), offer_id(offer.offer_id), title{offer.title}, description{offer.description}, + seller{offer.seller},price{offer.price},quantity{offer.quantity},active{offer.active}, + min_sfx_price{offer.min_sfx_price},price_peg_id{offer.price_peg_id},price_peg_used{offer.price_peg_used}{ + } + + edit_offer() : command(0, command_t::edit_offer), offer_id{}, description{} {} + + crypto::hash get_offerid() const { return offer_id; } + crypto::hash get_price_peg_id() const { return price_peg_id; } + std::vector get_seller() const { return seller; } + uint64_t get_price() const { return price; } + uint64_t get_min_sfx_price() const { return min_sfx_price; } + uint64_t get_quantity() const { return quantity; } + bool get_active() const { return active; } + bool get_price_peg_used() const { return price_peg_used; } + std::vector get_title() const { return title; }; + std::vector get_description() const { return description; } + + virtual edit_offer_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::edit_offer); + FIELD(offer_id) + FIELD(price_peg_id) + FIELD(seller) + FIELD(title) + FIELD(price) + FIELD(min_sfx_price) + FIELD(quantity) + FIELD(active) + FIELD(price_peg_used) + FIELD(description) + END_SERIALIZE() + +private: + crypto::hash offer_id{}; + crypto::hash price_peg_id{}; + std::vector seller{}; + std::vector title{}; + uint64_t quantity{}; + uint64_t price{}; + uint64_t min_sfx_price; + std::vector description{}; + bool active{}; + bool price_peg_used{}; // is offer using price peg +}; + +class create_feedback : public command +{ +public: + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _offerid //ID of the offer + * */ + create_feedback(const uint32_t _version, const safex::create_feedback_data &feedback) : + command(_version, command_t::create_feedback), offer_id(feedback.offer_id), comment{feedback.comment}, stars_given{feedback.stars_given}{ + } + + create_feedback() : command(0, command_t::create_feedback), offer_id{}, stars_given{}, comment{} {} + + crypto::hash get_offerid() const { return offer_id; } + std::vector get_comment() const { return comment; } + uint8_t get_stars_given() const { return stars_given; } + + virtual create_feedback_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::create_feedback); + FIELD(offer_id) + FIELD(stars_given) + FIELD(comment) + END_SERIALIZE() + +private: + crypto::hash offer_id{}; //unique id of the offer + uint8_t stars_given; + std::vector comment{}; +}; + +class create_price_peg : public command +{ +public: + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _price_peg_data //price peg data + * */ + create_price_peg(const uint32_t _version, const safex::create_price_peg_data &price_peg) : + command(_version, command_t::create_price_peg), title(price_peg.title), description{price_peg.description}, + price_peg_id{price_peg.price_peg_id},creator{price_peg.creator},currency{price_peg.currency},rate{price_peg.rate}{ + } + + create_price_peg() : command(0, command_t::create_price_peg), price_peg_id{}, description{} {} + + crypto::hash get_price_peg_id() const { return price_peg_id; } + std::vector get_creator() const { return creator; } + std::vector get_title() const { return title; } + std::vector get_description() const { return description; } + std::vector get_currency() const { return currency; } + uint64_t get_rate() const { return rate; } + + virtual create_price_peg_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::create_price_peg); + FIELD(title) + FIELD(price_peg_id) + FIELD(creator) + FIELD(description) + FIELD(currency) + FIELD(rate) + END_SERIALIZE() + +private: + std::vector title; //title of the price peg + crypto::hash price_peg_id; //unique id of the price peg + std::vector creator; // username of the price peg + std::vector description; //description of price peg + std::vector currency; + uint64_t rate; +}; + +class update_price_peg : public command +{ +public: + friend class safex_command_serializer; + + /** + * @param _version Safex command protocol version + * @param _price_peg_data //price peg data + * */ + update_price_peg(const uint32_t _version, const safex::update_price_peg_data &price_peg) : + command(_version, command_t::update_price_peg), + price_peg_id{price_peg.price_peg_id},rate{price_peg.rate}{ + } + + update_price_peg() : command(0, command_t::update_price_peg), price_peg_id{}{} + + crypto::hash get_price_peg_id() const { return price_peg_id; } + uint64_t get_rate() const { return rate; } + + virtual update_price_peg_result* execute(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + virtual execution_status validate(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin) override; + + BEGIN_SERIALIZE_OBJECT() + FIELDS(*static_cast(this)) + CHECK_COMMAND_TYPE(this->get_command_type(), command_t::update_price_peg); + FIELD(price_peg_id) + FIELD(rate) + END_SERIALIZE() + +private: + crypto::hash price_peg_id; //unique id of the price peg + uint64_t rate; +}; + + bool execute_safex_command(const cryptonote::BlockchainDB &blokchain, const cryptonote::txin_to_script &txin); + /* Validation is like execution, but without effects on the database */ + bool validate_safex_command(const cryptonote::BlockchainDB &blockchain, const cryptonote::txin_to_script &txin); + + + + class safex_command_serializer + { + public: + + template + static bool serialize_safex_object(const CommandOrData &commandOrData, std::vector &buffer) + { + cryptonote::blobdata blob = cryptonote::t_serializable_object_to_blob(commandOrData); + buffer.resize(blob.size()); + memcpy(&buffer[0], blob.data(), blob.size()); + return true; + } + + template + static std::unique_ptr parse_safex_command(const std::vector &buffer) + { + return std::unique_ptr(parse_safex_object(buffer)); + } + + static std::unique_ptr parse_safex_object(const std::vector &buffer, const safex::command_t command_type) + { + + switch(command_type) { + case safex::command_t::token_stake: + return std::unique_ptr(parse_safex_object(buffer)); + break; + case safex::command_t::token_unstake: + return std::unique_ptr(parse_safex_object(buffer)); + break; + case safex::command_t::token_collect: + return std::unique_ptr(parse_safex_object(buffer)); + break; + case safex::command_t::donate_network_fee: + return std::unique_ptr(parse_safex_object(buffer)); + break; + case safex::command_t::simple_purchase: + return std::unique_ptr(parse_safex_object(buffer)); + break; + case safex::command_t::create_account: + return std::unique_ptr(parse_safex_object(buffer)); + break; + case safex::command_t::edit_account: + return std::unique_ptr(parse_safex_object(buffer)); + break; + case safex::command_t::create_offer: + return std::unique_ptr(parse_safex_object(buffer)); + break; + case safex::command_t::edit_offer: + return std::unique_ptr(parse_safex_object(buffer)); + break; + case safex::command_t::create_feedback: + return std::unique_ptr(parse_safex_object(buffer)); + break; + case safex::command_t::create_price_peg: + return std::unique_ptr(parse_safex_object(buffer)); + break; + case safex::command_t::update_price_peg: + return std::unique_ptr(parse_safex_object(buffer)); + break; + default: + SAFEX_COMMAND_ASSERT_MES_AND_THROW("Unknown safex command type", safex::command_t::invalid_command); + break; + } + } + + static inline command_t get_command_type(const std::vector &script) + { + + cryptonote::blobdata command_blob; + const uint8_t* serialized_buffer_ptr = &script[0]; + std::copy(serialized_buffer_ptr, serialized_buffer_ptr + 2, std::back_inserter(command_blob)); + + std::stringstream ss; + ss << command_blob; + binary_archive ba(ss); + dummy_command temp; //just take any command, we just need command type deserialized + bool r = ::serialization::serialize(ba, static_cast(temp)); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(r, "Failed to parse command from blob", command_t::invalid_command); + + return static_cast(temp.get_command_type()); + } + + private: + + template + static CommandOrData* parse_safex_object(const std::vector &buffer) + { + cryptonote::blobdata command_blob; + const uint8_t* serialized_buffer_ptr = &buffer[0]; + std::copy(serialized_buffer_ptr, serialized_buffer_ptr + buffer.size(), std::back_inserter(command_blob)); + + std::stringstream ss; + ss << command_blob; + binary_archive ba(ss); + + CommandOrData* commandOrData = new CommandOrData(); + bool r = ::serialization::serialize(ba, *commandOrData); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(r, "Failed to parse command or data from blob", command_t::invalid_command); + return commandOrData; + } + + template + static bool parse_safex_object(const std::vector &buffer, CommandOrData &commandOrData) + { + cryptonote::blobdata command_blob; + const uint8_t* serialized_buffer_ptr = &buffer[0]; + std::copy(serialized_buffer_ptr, serialized_buffer_ptr + buffer.size(), std::back_inserter(command_blob)); + + std::stringstream ss; + ss << command_blob; + binary_archive ba(ss); + bool r = ::serialization::serialize(ba, commandOrData); + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(r, "Failed to parse command or data from blob", command_t::invalid_command); + return true; + } + }; + + +} //namespace safex + + +#endif //SAFEX_COMMAND_H diff --git a/src/safex/fee_distribution.cpp b/src/safex/fee_distribution.cpp new file mode 100644 index 000000000..0fa13a378 --- /dev/null +++ b/src/safex/fee_distribution.cpp @@ -0,0 +1,22 @@ +// +// Created by amarko on 13.3.19.. +// + +#include "fee_distribution.h" + + +namespace safex +{ + + /* + * High level function to calculate interest for locked token output. + * Returns Safex cash amount that shuld be distributed to token holder as interest + */ + uint64_t calculate_token_interest(uint64_t locked_token_output_index, uint64_t end_block, uint64_t locked_token_amount) { + + + return 0; + } + + +} diff --git a/src/safex/fee_distribution.h b/src/safex/fee_distribution.h new file mode 100644 index 000000000..f29525ef1 --- /dev/null +++ b/src/safex/fee_distribution.h @@ -0,0 +1,19 @@ +// +// Created by amarko on 13.3.19.. +// + +#ifndef SAFEX_FEE_DISTRIBUTION_H +#define SAFEX_FEE_DISTRIBUTION_H + +#include + +namespace safex +{ + + uint64_t calculate_token_interest(uint64_t locked_token_output_index, uint64_t end_block, uint64_t locked_token_amount); + + +} + + +#endif //SAFEX_FEE_DISTRIBUTION_H diff --git a/src/safex/safex_account.cpp b/src/safex/safex_account.cpp new file mode 100644 index 000000000..f996d2c9b --- /dev/null +++ b/src/safex/safex_account.cpp @@ -0,0 +1,113 @@ +// +// Created by amarko on 22.7.19.. +// + +#include +#include +#include + +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_core.h" +#include "safex/command.h" +#include "safex_account.h" + + + +namespace safex +{ + + void safex_account_keys::set_device( hw::device &hwdev) { + m_device = &hwdev; + MCDEBUG("device", "safex_account_keys::set_device device type: "<(txout); + CHECK_AND_ASSERT_MES(out.output_type == static_cast(cryptonote::tx_out_type::out_safex_account), false, "Parsing account key from non account output"); + safex::create_account_data account{}; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + if (!cryptonote::parse_and_validate_from_blob(accblob, account)) + { + ASSERT_MES_AND_THROW("Failed to parse and validate account from blob"); + } + + pkey = account.pkey; + return true; + } + + bool check_safex_account_signature(const crypto::hash &tx_prefix_hash, const crypto::public_key &sender_safex_account_key, const crypto::signature &signature) + { + return crypto::check_signature(tx_prefix_hash, sender_safex_account_key, signature) ? 1 : 0; + } + +} diff --git a/src/safex/safex_account.h b/src/safex/safex_account.h new file mode 100644 index 000000000..0bb67ae77 --- /dev/null +++ b/src/safex/safex_account.h @@ -0,0 +1,170 @@ +// +// Created by amarko on 22.7.19.. +// + +#ifndef SAFEX_SAFEX_ACCOUNT_H +#define SAFEX_SAFEX_ACCOUNT_H + + +#include +#include + +#include "device/device.hpp" +#include "crypto/crypto.h" +#include "serialization/keyvalue_serialization.h" + +#include "safex_core.h" + +#undef SAFEX_DEFAULT_LOG_CATEGORY +#define SAFEX_DEFAULT_LOG_CATEGORY "safex_account" + +namespace safex +{ + + const int MAX_ACCOUNT_DATA_SIZE = 1024; + + + bool parse_safex_account_key(const cryptonote::txout_target_v &txout, crypto::public_key& pkey); + + bool check_safex_account_signature(const crypto::hash &tx_prefix_hash, const crypto::public_key &sender_safex_account_key, const crypto::signature &signature); + + + struct safex_account_keys + { + + + safex_account_keys &operator=(const safex_account_keys &) = default; + + hw::device &get_device() const; + + bool valid() const + { + return ((m_secret_key != crypto::secret_key{}) && (m_public_key != crypto::public_key{}) && crypto::check_key(m_public_key)); + } + + template + inline void serialize(t_archive &a, const unsigned int ver) + { + a & m_public_key; + a & m_secret_key; + } + + void set_device(hw::device &hwdev); + + crypto::public_key m_public_key; + crypto::secret_key m_secret_key; + hw::device *m_device = &hw::get_device("default"); + + crypto::public_key get_public_key() const { + return m_public_key; + } + + crypto::secret_key get_secret_key() const { + return m_secret_key; + } + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_public_key) + KV_SERIALIZE(m_secret_key) + END_KV_SERIALIZE_MAP() + + + }; + + class safex_account_key_handler + { + public: + safex_account_key_handler() {} + + crypto::secret_key generate(const crypto::secret_key &recovery_key = crypto::secret_key(), bool recover = false); + + void create_from_device(const std::string &device_name); + + void create_from_keys(const crypto::secret_key &privatekey); + + const safex_account_keys &get_keys() const { + return m_keys; + }; + + hw::device &get_device() const + { return m_keys.get_device(); } + + void set_device(hw::device &hwdev) + { m_keys.set_device(hwdev); } + + uint64_t get_createtime() const + { return m_creation_timestamp; } + + void set_createtime(uint64_t val) + { m_creation_timestamp = val; } + + template + inline void serialize(t_archive &a, const unsigned int /*ver*/) + { + a & m_keys; + a & m_creation_timestamp; + } + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(m_keys) + KV_SERIALIZE(m_creation_timestamp) + END_KV_SERIALIZE_MAP() + + private: + void set_null(); + + std::string username; + safex_account_keys m_keys; + uint64_t m_creation_timestamp; + }; + + struct safex_account + { + public: + safex_account(): username{}, pkey{}, account_data{} { + CHECK_AND_ASSERT_MES_NO_RET(account_data.size() < MAX_ACCOUNT_DATA_SIZE, "Safex account data size limited to " << MAX_ACCOUNT_DATA_SIZE); + } + + safex_account(const std::string _username, const crypto::public_key _pkey, const std::vector &_account_data) : + username{_username}, pkey{_pkey}, account_data{_account_data} + { + + } + + bool valid() const { + return (!(username.empty())); + } + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(username) + KV_SERIALIZE(pkey) + KV_SERIALIZE(account_data) + END_KV_SERIALIZE_MAP() + + BEGIN_SERIALIZE_OBJECT() + FIELD(username) + FIELD(pkey) + FIELD(account_data) + FIELD(activated) + END_SERIALIZE() + + template + inline void serialize(t_archive &a, const unsigned int /*ver*/) + { + a & username; + a & pkey; + a & account_data; + a & activated; + } + + + std::string username; + crypto::public_key pkey; + std::vector account_data; + bool activated{false}; + }; +} + + +#endif //SAFEX_SAFEX_ACCOUNT_H diff --git a/src/safex/safex_core.cpp b/src/safex/safex_core.cpp new file mode 100644 index 000000000..c5a7f6d3d --- /dev/null +++ b/src/safex/safex_core.cpp @@ -0,0 +1,13 @@ +// +// Created by amarko on 29.3.19.. +// + +#include "safex_core.h" + + +namespace safex +{ + + + +} \ No newline at end of file diff --git a/src/safex/safex_core.h b/src/safex/safex_core.h new file mode 100644 index 000000000..89cba3c13 --- /dev/null +++ b/src/safex/safex_core.h @@ -0,0 +1,295 @@ +// +// Created by amarko on 26.3.19.. +// + +#include +#include +#include +#include +#include +#include +#include "misc_log_ex.h" +#include "cryptonote_config.h" + +#ifndef SAFEX_SAFEX_CORE_H +#define SAFEX_SAFEX_CORE_H + + +namespace safex +{ + typedef std::map map_interval_interest; //key is interval starting block, value is safex cash per token interest + + + struct account_username { + + account_username(std::string ss) { + username = std::vector(ss.begin(), ss.end()); + } + + account_username(const char* cc, uint32_t size) { + username = std::vector(cc, cc+size); + } + + account_username(const std::vector &vv) { + username = std::vector(vv.begin(), vv.end()); + } + + const char* c_str() const { + return (const char*)username.data(); + } + + crypto::hash hash() const {return crypto::cn_fast_hash(username.data(), username.size());} + + std::vector username = std::vector(64, 0); //todo decide if we would use utf8 or something else + + }; + +/** +* It is indicator in transaction version 2 extra field, to ease transaction verification +* */ + enum class command_domain : uint32_t + { + none = 0x00, + token_locking = 0x01 + }; + +/** + * Command type + * */ + enum class command_t : uint32_t + { + nop = 0x0, + token_stake = 0x01, + token_unstake = 0x02, + token_collect = 0x03, + donate_network_fee = 0x04, /* Donate safex cash to newtork token holders */ + simple_purchase = 0x06, + create_account = 0x0A, /* Create Safex account */ + edit_account = 0x0B, /* Edit Safex account */ + create_offer = 0x10, + edit_offer = 0x11, + create_feedback = 0x12, + create_price_peg = 0x13, + update_price_peg = 0x14, + invalid_command + }; + +/** + * In case of error during execution, exception will be thrown + * */ + class command_exception : public std::exception + { + public: + + command_exception(const command_t _command_type, const std::string &_message) : command_type{_command_type}, what_message{_message} + { + + } + + virtual const char *what() const noexcept override + { + return what_message.c_str(); + } + + command_t getCommand() + { return command_type; } + + + private: + + const command_t command_type; + const std::string what_message; + + }; + +#define SAFEX_COMMAND_ASSERT_MES_AND_THROW(message, command_type) {LOG_ERROR(message); std::stringstream ss; ss << message; throw safex::command_exception(command_type, ss.str());} +#define SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES(expr, message, command_type) do {if(!(expr)) SAFEX_COMMAND_ASSERT_MES_AND_THROW(message, command_type);} while(0) + +/** +* Returns if input needs key_image verification +* +* +* @return true if it needs key_image verification, false otherwise +*/ + inline bool is_safex_key_image_verification_needed(const safex::command_t& command_type) +{ + + if(command_type == safex::command_t::edit_account + || command_type == safex::command_t::create_offer + || command_type == safex::command_t::edit_offer + || command_type == safex::command_t::create_price_peg + || command_type == safex::command_t::update_price_peg) + return false; + else + return true; +} + + /** + * Returns number of blocks in interval + * + * + * @return number of blocks + */ + inline uint64_t get_safex_interval_period(const cryptonote::network_type nettype = cryptonote::network_type::MAINNET) + { + + if (nettype == cryptonote::network_type::FAKECHAIN) + return SAFEX_DEFAULT_INTERVAL_PERIOD_FAKECHAIN; + else if (nettype == cryptonote::network_type::TESTNET) + return SAFEX_DEFAULT_INTERVAL_PERIOD_TESTNET; + else if (nettype == cryptonote::network_type::STAGENET) + return SAFEX_DEFAULT_INTERVAL_PERIOD_STAGENET; + else + return SAFEX_DEFAULT_INTERVAL_PERIOD; + } + + + /** + * Calculates locking interval where block height belongs + * + * For example, blocks with height from 1-1000 will be first locked belong to interval 1, + * and will be first locked from interval 2 (from block 1001) + * @param height - block height + * @param nettype network type, main, test or fake + * @return interval + */ + inline uint64_t calculate_interval_for_height(const uint64_t height, const cryptonote::network_type nettype) + { + if (height == 0) + return 0; //zero height is zero interval + uint64_t interval = (height - 1) / get_safex_interval_period(nettype) + 1; //blocks 1-1000 first interval, 1001-2000 second etc. + return interval; //returns interval number + } + + /** + * Calculates locking interval starting block where block with height belongs + * + * @param height - block height + * @param nettype network type, main, test or fake + * @return interval starting block + */ + inline uint64_t calculate_interval_starting_block_for_height(const uint64_t height, const cryptonote::network_type nettype) + { + uint64_t interval = calculate_interval_for_height(height, nettype); + uint64_t result = (interval-1) * get_safex_interval_period(nettype) + 1; + return result; + } + + /** + * Check if block is valid interval representation (interval starting block) + * + * For first interval, value is 1, for second 1001, for third 2001, etc + * @param block_height - block height + * @return true or false + */ + inline bool is_interval_starting_block(const uint64_t block_height, const cryptonote::network_type nettype) + { + return ((block_height - 1) % get_safex_interval_period(nettype) == 0); + } + + /** + * Check if block is interval last block + * + * @param block_height - block height + * @return true or false + */ + inline bool is_interval_last_block(const uint64_t block_height, const cryptonote::network_type nettype) + { + return is_interval_starting_block(block_height+1, nettype); + } + + /** + * Check if block is valid interval representation (interval starting block) + * + * For first interval, value is 1, for second 1001, for third 2001, etc + * @param block_height - block height + * @return true or false + */ + inline uint64_t calulate_starting_block_for_interval(const uint64_t interval, const cryptonote::network_type nettype) + { + uint64_t result = (interval-1) * get_safex_interval_period(nettype) + 1; + return result; + } + + /** + * Return minimal token lock period + * + * @return number of blocks that is munimum token lock period + */ + inline uint64_t get_safex_minumum_token_lock_period(const cryptonote::network_type nettype) + { + + if (nettype == cryptonote::network_type::FAKECHAIN) + return SAFEX_DEFAULT_MINUMUM_TOKEN_STAKE_PERIOD_FAKECHAIN; + else if (nettype == cryptonote::network_type::TESTNET) + return SAFEX_DEFAULT_MINUMUM_TOKEN_STAKE_PERIOD_TESTNET; + else if(nettype == cryptonote::network_type::STAGENET) + return SAFEX_DEFAULT_MINUMUM_TOKEN_STAKE_PERIOD_STAGENET; + else + return SAFEX_DEFAULT_MINUMUM_TOKEN_STAKE_PERIOD; + } + + /** + * Return safex account creation token fee unlock period + * + * @return number of blocks that is munimum for tokens to be unlocked + */ + inline uint64_t get_safex_minumum_account_create_token_lock_period(const cryptonote::network_type nettype) + { + if (nettype == cryptonote::network_type::FAKECHAIN) + return SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN; + else if (nettype == cryptonote::network_type::TESTNET) + return SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_TESTNET; + else if(nettype == cryptonote::network_type::STAGENET) + return SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_STAGENET; + else + return SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD; + } + + /** + * Calculate amount safex network fee + * + * @param cash_amount amount of saxex cash in transaction + * @param nettype network type + * @param command_type safex network fee may depend of differend scenearious + * @return + */ + inline uint64_t calculate_safex_network_fee(const uint64_t cash_amount, const cryptonote::network_type nettype, const safex::command_t command_type) + { + uint64_t fee = 0; + + //todo handle multiplication that overflows + SAFEX_COMMAND_CHECK_AND_ASSERT_THROW_MES((cash_amount * SAFEX_DEFAULT_NETWORK_FEE_PERCENTAGE) >= cash_amount, "Overflow calculating transaction fee", command_type); + + switch (nettype) { + default: + fee = cash_amount * SAFEX_DEFAULT_NETWORK_FEE_PERCENTAGE / 100; + } + + return fee; + } + + + /** + * Gets minumum token stake amount + * + * @return + */ + inline uint64_t get_minimum_token_stake_amount(const cryptonote::network_type nettype = cryptonote::network_type::MAINNET) + { + + switch (nettype) { + case cryptonote::network_type::TESTNET: + return SAFEX_MINIMUM_TOKEN_STAKE_AMOUNT; + + default: + return SAFEX_MINIMUM_TOKEN_STAKE_AMOUNT; + } + } + + + + +} + +#endif //SAFEX_SAFEX_CORE_H diff --git a/src/safex/safex_feedback.cpp b/src/safex/safex_feedback.cpp new file mode 100644 index 000000000..bb834f00f --- /dev/null +++ b/src/safex/safex_feedback.cpp @@ -0,0 +1,20 @@ +// +// Created by Igor Grkavac on 24.01.20.. +// + +#include +#include +#include + +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_core.h" +#include "safex/command.h" +#include "safex_feedback.h" + + + +namespace safex +{ + + +} diff --git a/src/safex/safex_feedback.h b/src/safex/safex_feedback.h new file mode 100644 index 000000000..f8c81fbbd --- /dev/null +++ b/src/safex/safex_feedback.h @@ -0,0 +1,108 @@ +// +// Created by Igor Grkavac on 24.01.20. +// + +#ifndef SAFEX_SAFEX_FEEDBACK_H +#define SAFEX_SAFEX_FEEDBACK_H + + +#include +#include + +#include "device/device.hpp" +#include "crypto/crypto.h" +#include "serialization/keyvalue_serialization.h" +#include "cryptonote_basic/cryptonote_format_utils.h" + + +#include "safex_core.h" + +#undef SAFEX_DEFAULT_LOG_CATEGORY +#define SAFEX_DEFAULT_LOG_CATEGORY "safex_feedback" + +namespace safex +{ + + struct safex_feedback + { + + public: + safex_feedback(): comment{}, stars_given{}, offer_id{0}{ + } + + safex_feedback(const uint8_t _stars_given, const std::string _comment, const crypto::hash &_id):stars_given{_stars_given},comment{_comment}, + offer_id{_id} + { + } + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(offer_id) + KV_SERIALIZE(stars_given) + KV_SERIALIZE(comment) + END_KV_SERIALIZE_MAP() + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + FIELD(stars_given) + FIELD(comment) + END_SERIALIZE() + + template + inline void serialize(t_archive &a, const unsigned int /*ver*/) + { + a & offer_id; + a & stars_given; + a & comment; + } + + crypto::hash offer_id{}; //unique id of the offer + uint8_t stars_given; + std::string comment{}; + private: + + + }; + + struct safex_feedback_db_data + { + + public: + safex_feedback_db_data(): output_id{},stars_given{},comment{} { + } + + safex_feedback_db_data(const uint64_t _output_id, const uint8_t _stars_given, const std::string _comment):output_id{_output_id},stars_given{_stars_given},comment{_comment.begin(),_comment.end()} + { + } + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(output_id) + KV_SERIALIZE(stars_given) + KV_SERIALIZE(comment) + END_KV_SERIALIZE_MAP() + + BEGIN_SERIALIZE_OBJECT() + FIELD(output_id) + FIELD(stars_given) + FIELD(comment) + END_SERIALIZE() + + template + inline void serialize(t_archive &a, const unsigned int /*ver*/) + { + a & output_id; + a & stars_given; + a & comment; + } + uint64_t output_id; + uint8_t stars_given; + std::vector comment{}; + private: + + + }; +} + + +#endif //SAFEX_SAFEX_FEEDBACK_H diff --git a/src/safex/safex_feedback_token.cpp b/src/safex/safex_feedback_token.cpp new file mode 100644 index 000000000..a86ab30c0 --- /dev/null +++ b/src/safex/safex_feedback_token.cpp @@ -0,0 +1,20 @@ +// +// Created by Igor Grkavac on 24.01.20.. +// + +#include +#include +#include + +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_core.h" +#include "safex/command.h" +#include "safex_feedback_token.h" + + + +namespace safex +{ + + +} diff --git a/src/safex/safex_feedback_token.h b/src/safex/safex_feedback_token.h new file mode 100644 index 000000000..138f84142 --- /dev/null +++ b/src/safex/safex_feedback_token.h @@ -0,0 +1,74 @@ +// +// Created by Igor Grkavac on 24.01.20. +// + +#ifndef SAFEX_SAFEX_FEEDBACK_TOKEN_H +#define SAFEX_SAFEX_FEEDBACK_TOKEN_H + + +#include +#include + +#include "device/device.hpp" +#include "crypto/crypto.h" +#include "serialization/keyvalue_serialization.h" +#include "cryptonote_basic/cryptonote_format_utils.h" + + +#include "safex_core.h" + +#undef SAFEX_DEFAULT_LOG_CATEGORY +#define SAFEX_DEFAULT_LOG_CATEGORY "safex_feedback_token" + +namespace safex +{ + + struct safex_feedback_token + { + + public: + safex_feedback_token(): quantity{}, price{}, shipping{}, offer_id{0}{ + + } + + safex_feedback_token(const uint64_t _quantity, const uint64_t _price, crypto::hash &_id, bool _shipping):quantity{_quantity},price{_price}, + offer_id{_id},shipping{_shipping} + { + } + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(offer_id) + KV_SERIALIZE(quantity) + KV_SERIALIZE(price) + KV_SERIALIZE(shipping) + END_KV_SERIALIZE_MAP() + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + FIELD(quantity) + FIELD(price) + FIELD(shipping) + END_SERIALIZE() + + template + inline void serialize(t_archive &a, const unsigned int /*ver*/) + { + a & offer_id; + a & quantity; + a & price; + a & shipping; + } + + crypto::hash offer_id; + uint64_t quantity; + uint64_t price; + bool shipping; + private: + + + }; +} + + +#endif //SAFEX_SAFEX_FEEDBACK_TOKEN_H diff --git a/src/safex/safex_offer.cpp b/src/safex/safex_offer.cpp new file mode 100644 index 000000000..57e474000 --- /dev/null +++ b/src/safex/safex_offer.cpp @@ -0,0 +1,67 @@ +// +// Created by amarko on 22.7.19.. +// + +#include +#include +#include +#include + +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_core.h" +#include "safex/command.h" +#include "safex_offer.h" + + + +namespace safex +{ + + crypto::hash safex_offer::create_offer_id(std::string& username){ + + crypto::hash id{}; + std::string offer_id_string = username; + + auto time_now = std::chrono::system_clock::now(); + auto nanosec = time_now.time_since_epoch(); + std::string time_now_string{std::to_string(nanosec.count())}; + + offer_id_string.append(time_now_string); + + bool res = cryptonote::get_object_hash(std::vector{offer_id_string.begin(),offer_id_string.end()},id); + + if(!res){ + //error + } + return id; + } + + crypto::hash safex_offer::get_hash(){ + + crypto::hash offer_hash{}; + + std::vector offer_scalar; + + std::vector title_vec{std::begin(title),std::end(title)}; + + offer_scalar.insert(offer_scalar.end(),std::begin(offer_id.data),std::end(offer_id.data)); + offer_scalar.insert(offer_scalar.end(),title_vec.begin(),title_vec.end()); + offer_scalar.insert(offer_scalar.end(),description.begin(),description.end()); + + bool res = cryptonote::get_object_hash(offer_scalar,offer_hash); + + if(!res) + return {}; + + return offer_hash; + + } + + void safex_offer::set_price_peg(crypto::hash& _price_peg_id, uint64_t _price, uint64_t _min_sfx_price){ + price_peg_used = true; + price_peg_id = _price_peg_id; + price = _price; + min_sfx_price = _min_sfx_price; + } + +} diff --git a/src/safex/safex_offer.h b/src/safex/safex_offer.h new file mode 100644 index 000000000..7137f22e6 --- /dev/null +++ b/src/safex/safex_offer.h @@ -0,0 +1,131 @@ +// +// Created by amarko on 22.7.19.. +// + +#ifndef SAFEX_SAFEX_OFFER_H +#define SAFEX_SAFEX_OFFER_H + + +#include +#include + +#include "device/device.hpp" +#include "crypto/crypto.h" +#include "serialization/keyvalue_serialization.h" +#include "cryptonote_basic/cryptonote_format_utils.h" + + +#include "safex_core.h" +#include "safex_price_peg.h" + +#undef SAFEX_DEFAULT_LOG_CATEGORY +#define SAFEX_DEFAULT_LOG_CATEGORY "safex_offer" + +namespace safex +{ + + + struct safex_offer + { + public: + safex_offer(): title{}, quantity{}, price{}, description{}, active{false}, shipping{}, offer_id{0}, seller{} { + + } + + safex_offer(const std::string &_title, const uint64_t _quantity, const uint64_t _price, const std::vector &_description, + crypto::hash _id, std::string seller_username, bool _active = true , const cryptonote::account_public_address& _seller_address = {}, const crypto::secret_key& view_key = {}):title{_title},quantity{_quantity},price{_price},min_sfx_price{_price}, + description{_description},offer_id{_id},seller{seller_username},active{_active},seller_private_view_key{view_key},seller_address{_seller_address},price_peg_used{false} + { + } + + safex_offer(const std::string &_title, const uint64_t _quantity, const uint64_t _price, const std::vector &_description, + crypto::hash _id, std::string seller_username, bool _active, const cryptonote::account_public_address& _seller_address, bool _price_peg_used, crypto::hash _price_peg_id, uint64_t _min_sfx_price):title{_title},quantity{_quantity},price{_price}, + description{_description},offer_id{_id},seller{seller_username},active{_active},seller_address{_seller_address},price_peg_used{_price_peg_used},price_peg_id{_price_peg_id},min_sfx_price{_min_sfx_price} + { + } + + + safex_offer(const std::string &_title, const uint64_t _quantity, const uint64_t _price, const std::string& _description, + std::string seller_username, const crypto::secret_key& view_key, const cryptonote::account_public_address& _seller_address = {}): + title{_title}, quantity{_quantity}, price{_price}, min_sfx_price{_price}, active{true}, shipping{}, seller{seller_username},seller_private_view_key{view_key},seller_address{_seller_address},price_peg_used{false}, price_peg_id{} { + + description = std::vector(_description.begin(),_description.end()); + offer_id = create_offer_id(seller_username); + } + + void set_price_peg(crypto::hash& _price_peg_id, uint64_t _price, uint64_t _min_sfx_price); + crypto::hash get_hash(); + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(title) + KV_SERIALIZE(quantity) + KV_SERIALIZE(price) + KV_SERIALIZE(price_peg_id) + KV_SERIALIZE(min_sfx_price) + KV_SERIALIZE(description) + KV_SERIALIZE(active) + KV_SERIALIZE(price_peg_used) + KV_SERIALIZE(shipping) + KV_SERIALIZE(offer_id) + KV_SERIALIZE(seller) + KV_SERIALIZE(seller_private_view_key) + KV_SERIALIZE(seller_address) + END_KV_SERIALIZE_MAP() + + BEGIN_SERIALIZE_OBJECT() + FIELD(title) + VARINT_FIELD(quantity) + FIELD(price) + FIELD(price_peg_id) + FIELD(min_sfx_price) + FIELD(description) + FIELD(active) + FIELD(price_peg_used) + FIELD(shipping) + FIELD(offer_id) + FIELD(seller) + FIELD(seller_private_view_key) + FIELD(seller_address) + END_SERIALIZE() + + template + inline void serialize(t_archive &a, const unsigned int /*ver*/) + { + a & title; + a & quantity; + a & price; + a & price_peg_id; + a & min_sfx_price; + a & description; + a & active; + a & price_peg_used; + a & shipping; + a & offer_id; + a & seller; + a & seller_private_view_key; + a & seller_address; + } + + + std::string title; //title of the offer + uint64_t quantity; + uint64_t price; + uint64_t min_sfx_price; + std::vector description; //description of offer, JSON or other format TBD. + bool active; //is offer active + bool price_peg_used; // is offer using price peg + std::vector shipping; + crypto::hash offer_id; //unique id of the offer + crypto::hash price_peg_id; //id of the price peg to be used + std::string seller; // username of the seller + crypto::secret_key seller_private_view_key; + cryptonote::account_public_address seller_address; + + private: + crypto::hash create_offer_id(std::string& username); + + }; +} + + +#endif //SAFEX_SAFEX_OFFER_H diff --git a/src/safex/safex_price_peg.cpp b/src/safex/safex_price_peg.cpp new file mode 100644 index 000000000..2854bebbb --- /dev/null +++ b/src/safex/safex_price_peg.cpp @@ -0,0 +1,39 @@ +// +// Created by Igor Grkavac on 04.02.20. +// + +#include +#include +#include +#include + +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_core.h" +#include "safex/command.h" +#include "safex_price_peg.h" + + + +namespace safex +{ + + crypto::hash safex_price_peg::create_price_peg_id(std::string& username){ + + crypto::hash id{}; + std::string price_peg_id_string = username; + + auto time_now = std::chrono::system_clock::now(); + auto nanosec = time_now.time_since_epoch(); + std::string time_now_string{std::to_string(nanosec.count())}; + + price_peg_id_string.append(time_now_string); + + bool res = cryptonote::get_object_hash(std::vector{price_peg_id_string.begin(),price_peg_id_string.end()},id); + + if(!res){ + //error + } + return id; + } + +} diff --git a/src/safex/safex_price_peg.h b/src/safex/safex_price_peg.h new file mode 100644 index 000000000..aa29b8181 --- /dev/null +++ b/src/safex/safex_price_peg.h @@ -0,0 +1,97 @@ +// +// Created by Igor Grkavac on 04.02.20. +// + +#ifndef SAFEX_SAFEX_PRICE_PEG_H +#define SAFEX_SAFEX_PRICE_PEG_H + + +#include +#include + +#include "device/device.hpp" +#include "crypto/crypto.h" +#include "serialization/keyvalue_serialization.h" +#include "cryptonote_basic/cryptonote_format_utils.h" + + +#include "safex_core.h" + +#undef SAFEX_DEFAULT_LOG_CATEGORY +#define SAFEX_DEFAULT_LOG_CATEGORY "safex_price_peg" + +namespace safex +{ + + + struct safex_price_peg + { + public: + safex_price_peg(): title{}, creator{}, currency{}, description{}, rate{}, price_peg_id{0} { + + } + + safex_price_peg(const std::string &_title, const std::string _creator, const std::string _currency, const std::vector &_description, crypto::hash _price_peg_id, uint64_t _rate): + title{_title},creator{_creator}, currency{_currency}, description{_description},price_peg_id{_price_peg_id},rate{_rate} + { + } + + safex_price_peg(const std::vector &_title, const std::vector _creator, const std::vector _currency, const std::vector &_description, crypto::hash _price_peg_id, uint64_t _rate): + title{_title.begin(),_title.end()},creator{_creator.begin(),_creator.end()}, currency{_currency.begin(),_currency.end()}, description{_description},price_peg_id{_price_peg_id},rate{_rate} + { + } + + + safex_price_peg(const std::string &_title, std::string _creator, const std::string _currency, const std::string &_description, uint64_t _rate): + title{_title},creator{_creator}, currency{_currency}, rate{_rate} + { + + description = std::vector(_description.begin(),_description.end()); + price_peg_id = create_price_peg_id(_creator); + + } + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(title) + KV_SERIALIZE(price_peg_id) + KV_SERIALIZE(creator) + KV_SERIALIZE(description) + KV_SERIALIZE(currency) + KV_SERIALIZE(rate) + END_KV_SERIALIZE_MAP() + + BEGIN_SERIALIZE_OBJECT() + FIELD(title) + VARINT_FIELD(price_peg_id) + FIELD(creator) + FIELD(description) + FIELD(currency) + FIELD(rate) + END_SERIALIZE() + + template + inline void serialize(t_archive &a, const unsigned int /*ver*/) + { + a & title; + a & price_peg_id; + a & creator; + a & description; + a & currency; + a & rate; + } + + + std::string title; //title of the price peg + crypto::hash price_peg_id; //unique id of the price peg + std::string creator; // username of the price peg + std::vector description; //description of price peg + std::string currency; + uint64_t rate; + + private: + crypto::hash create_price_peg_id(std::string& username); + + }; +} + + +#endif //SAFEX_SAFEX_PRICE_PEG_H diff --git a/src/safex/safex_purchase.cpp b/src/safex/safex_purchase.cpp new file mode 100644 index 000000000..15235546c --- /dev/null +++ b/src/safex/safex_purchase.cpp @@ -0,0 +1,20 @@ +// +// Created by Igor Grkavac on 21.10.19.. +// + +#include +#include +#include + +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_core.h" +#include "safex/command.h" +#include "safex_purchase.h" + + + +namespace safex +{ + + +} diff --git a/src/safex/safex_purchase.h b/src/safex/safex_purchase.h new file mode 100644 index 000000000..cb4c6ef36 --- /dev/null +++ b/src/safex/safex_purchase.h @@ -0,0 +1,78 @@ +// +// Created by Igor Grkavac on 21.10.19.. +// + +#ifndef SAFEX_SAFEX_PURCHASE_H +#define SAFEX_SAFEX_PURCHASE_H + + +#include +#include + +#include "device/device.hpp" +#include "crypto/crypto.h" +#include "serialization/keyvalue_serialization.h" +#include "cryptonote_basic/cryptonote_format_utils.h" + + +#include "safex_core.h" + +#undef SAFEX_DEFAULT_LOG_CATEGORY +#define SAFEX_DEFAULT_LOG_CATEGORY "simple_purchase" + +namespace safex +{ + + struct safex_purchase + { + + public: + safex_purchase(): quantity{}, price{}, shipping{}, offer_id{0}, offer_hash{}{ + + } + + safex_purchase(const uint64_t _quantity, const uint64_t _price, crypto::hash &_id, crypto::hash _offer_hash, bool _shipping):quantity{_quantity},price{_price}, + offer_id{_id}, offer_hash{_offer_hash}, shipping{_shipping} + { + } + + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(offer_id) + KV_SERIALIZE(offer_hash) + KV_SERIALIZE(quantity) + KV_SERIALIZE(price) + KV_SERIALIZE(shipping) + END_KV_SERIALIZE_MAP() + + BEGIN_SERIALIZE_OBJECT() + FIELD(offer_id) + FIELD(offer_hash) + FIELD(quantity) + FIELD(price) + FIELD(shipping) + END_SERIALIZE() + + template + inline void serialize(t_archive &a, const unsigned int /*ver*/) + { + a & offer_id; + a & offer_hash; + a & quantity; + a & price; + a & shipping; + } + + crypto::hash offer_id; + crypto::hash offer_hash; + uint64_t quantity; + uint64_t price; + bool shipping; + private: + + + }; +} + + +#endif //SAFEX_SAFEX_PURCHASE_H diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp index 0161278b2..c7e92d487 100644 --- a/src/serialization/json_object.cpp +++ b/src/serialization/json_object.cpp @@ -215,6 +215,20 @@ void fromJsonValue(const rapidjson::Value& val, long& i) to_int64(val, i); } +void fromJsonValue(const rapidjson::Value& val, safex::command_t& command_type) +{ + uint32_t temp; + to_uint(val, temp); + command_type = static_cast(temp); +} + +void toJsonValue(rapidjson::Document& doc, const safex::command_t& command_type, rapidjson::Value& val) +{ + uint32_t temp = static_cast(command_type); + val = rapidjson::Value(temp); +} + + void toJsonValue(rapidjson::Document& doc, const cryptonote::transaction& tx, rapidjson::Value& val) { val.SetObject(); @@ -381,9 +395,12 @@ void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_to_script& txi { val.SetObject(); - INSERT_INTO_JSON_OBJECT(val, doc, prev, txin.prev); - INSERT_INTO_JSON_OBJECT(val, doc, prevout, txin.prevout); - INSERT_INTO_JSON_OBJECT(val, doc, sigset, txin.sigset); + INSERT_INTO_JSON_OBJECT(val, doc, prev, txin.key_offsets); + INSERT_INTO_JSON_OBJECT(val, doc, k_image, txin.k_image); + INSERT_INTO_JSON_OBJECT(val, doc, amount, txin.amount); + INSERT_INTO_JSON_OBJECT(val, doc, token_amount, txin.token_amount); + INSERT_INTO_JSON_OBJECT(val, doc, command_type, txin.command_type); + INSERT_INTO_JSON_OBJECT(val, doc, script, txin.script); } @@ -394,9 +411,12 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_script& txin throw WRONG_TYPE("json object"); } - GET_FROM_JSON_OBJECT(val, txin.prev, prev); - GET_FROM_JSON_OBJECT(val, txin.prevout, prevout); - GET_FROM_JSON_OBJECT(val, txin.sigset, sigset); + GET_FROM_JSON_OBJECT(val, txin.key_offsets, prev); + GET_FROM_JSON_OBJECT(val, txin.k_image, k_image); + GET_FROM_JSON_OBJECT(val, txin.amount, amount); + GET_FROM_JSON_OBJECT(val, txin.token_amount, token_amount); + GET_FROM_JSON_OBJECT(val, txin.command_type, command_type); + GET_FROM_JSON_OBJECT(val, txin.script, script); } void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_to_scripthash& txin, rapidjson::Value& val) @@ -551,8 +571,9 @@ void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_to_script& tx { val.SetObject(); - INSERT_INTO_JSON_OBJECT(val, doc, keys, txout.keys); - INSERT_INTO_JSON_OBJECT(val, doc, script, txout.script); + INSERT_INTO_JSON_OBJECT(val, doc, script, txout.output_type); + INSERT_INTO_JSON_OBJECT(val, doc, key, txout.key); + INSERT_INTO_JSON_OBJECT(val, doc, data, txout.data); } @@ -563,8 +584,10 @@ void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_script& txo throw WRONG_TYPE("json object"); } - GET_FROM_JSON_OBJECT(val, txout.keys, keys); - GET_FROM_JSON_OBJECT(val, txout.script, script); + GET_FROM_JSON_OBJECT(val, txout.output_type, script); + GET_FROM_JSON_OBJECT(val, txout.key, key); + GET_FROM_JSON_OBJECT(val, txout.data, data); + } void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_to_scripthash& txout, rapidjson::Value& val) diff --git a/src/serialization/json_object.h b/src/serialization/json_object.h index ab85ddfe5..f589b1f9d 100644 --- a/src/serialization/json_object.h +++ b/src/serialization/json_object.h @@ -182,6 +182,10 @@ inline void toJsonValue(rapidjson::Document& doc, const long i, rapidjson::Value } void fromJsonValue(const rapidjson::Value& val, long& i); +void fromJsonValue(const rapidjson::Value& val, safex::command_t& command_type); +void toJsonValue(rapidjson::Document& doc, const safex::command_t& command_type, rapidjson::Value& val); + + // end integers void toJsonValue(rapidjson::Document& doc, const cryptonote::transaction& tx, rapidjson::Value& val); diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt index ea49f271e..15cc0213a 100644 --- a/src/simplewallet/CMakeLists.txt +++ b/src/simplewallet/CMakeLists.txt @@ -29,7 +29,7 @@ # Parts of this file are originally copyright (c) 2014-2018 The Monero Project set(simplewallet_sources - simplewallet.cpp) + simplewallet.cpp simplewallet_safex.cpp simplewallet_common.cpp) set(simplewallet_headers) @@ -56,6 +56,7 @@ target_link_libraries(simplewallet ${Boost_CHRONO_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_FILESYSTEM_LIBRARY} + ${Boost_LOCALE_LIBRARY} ${ICU_LIBRARIES} ${Boost_THREAD_LIBRARY} ${CMAKE_THREAD_LIBS_INIT} diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index dbfc44b36..31790694f 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -64,6 +64,7 @@ #include "wallet/wallet_args.h" #include "version.h" #include +#include "simplewallet_common.h" #ifdef WIN32 #include @@ -78,469 +79,10 @@ using namespace std; using namespace epee; using namespace cryptonote; using boost::lexical_cast; -namespace po = boost::program_options; -typedef cryptonote::simple_wallet sw; #undef SAFEX_DEFAULT_LOG_CATEGORY #define SAFEX_DEFAULT_LOG_CATEGORY "wallet.simplewallet" -#define EXTENDED_LOGS_FILE "wallet_details.log" - -#define ENABLE_ADVANCED_OPTIONS 0 //some aditional features - -#define MIN_RING_SIZE 7 // Used to inform user about min ring size -- does not track actual protocol - -#define OUTPUT_EXPORT_FILE_MAGIC "Safex output export\003" - -#define LOCK_IDLE_SCOPE() \ - bool auto_refresh_enabled = m_auto_refresh_enabled.load(std::memory_order_relaxed); \ - m_auto_refresh_enabled.store(false, std::memory_order_relaxed); \ - /* stop any background refresh, and take over */ \ - m_wallet->stop(); \ - m_idle_mutex.lock(); \ - while (m_auto_refresh_refreshing) \ - m_idle_cond.notify_one(); \ - m_idle_mutex.unlock(); \ -/* if (auto_refresh_run)*/ \ - /*m_auto_refresh_thread.join();*/ \ - boost::unique_lock lock(m_idle_mutex); \ - epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ \ - m_auto_refresh_enabled.store(auto_refresh_enabled, std::memory_order_relaxed); \ - }) - -enum TransferType { - TransferOriginal, - TransferNew, - TransferLocked, - TransferMigration, - TransferToken -}; - -namespace -{ - const std::array allowed_priority_strings = {{"default", "unimportant", "normal", "elevated", "priority"}}; - const auto arg_wallet_file = wallet_args::arg_wallet_file(); - const command_line::arg_descriptor arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to "), ""}; - const command_line::arg_descriptor arg_generate_from_device = {"generate-from-device", sw::tr("Generate new wallet from device and save it to "), ""}; - const command_line::arg_descriptor arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""}; - const command_line::arg_descriptor arg_generate_from_spend_key = {"generate-from-spend-key", sw::tr("Generate deterministic wallet from spend key"), ""}; - const command_line::arg_descriptor arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""}; - const auto arg_generate_from_json = wallet_args::arg_generate_from_json(); - const command_line::arg_descriptor arg_mnemonic_language = {"mnemonic-language", sw::tr("Language for mnemonic"), ""}; - const command_line::arg_descriptor arg_electrum_seed = {"electrum-seed", sw::tr("Specify Electrum seed for wallet recovery/creation"), ""}; - const command_line::arg_descriptor arg_restore_deterministic_wallet = {"restore-deterministic-wallet", sw::tr("Recover wallet using Electrum-style mnemonic seed"), false}; - const command_line::arg_descriptor arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false}; - const command_line::arg_descriptor arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false}; - const command_line::arg_descriptor arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false}; - const command_line::arg_descriptor arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0}; - const command_line::arg_descriptor arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the safex network"), false}; - const command_line::arg_descriptor arg_create_address_file = {"create-address-file", sw::tr("Create an address file for new wallets"), false}; - const command_line::arg_descriptor arg_subaddress_lookahead = {"subaddress-lookahead", tools::wallet::tr("Set subaddress lookahead sizes to :"), ""}; - const command_line::arg_descriptor arg_use_english_language_names = {"use-english-language-names", sw::tr("Display English language names"), false}; - - const command_line::arg_descriptor< std::vector > arg_command = {"command", ""}; - -#ifdef WIN32 - // Translate from CP850 to UTF-8; - // std::getline for a Windows console returns a string in CP437 or CP850; as simplewallet, - // like all of Safex, is assumed to work internally with UTF-8 throughout, even on Windows - // (although only implemented partially), a translation to UTF-8 is needed for input. - // - // Note that if a program is started inside the MSYS2 shell somebody already translates - // console input to UTF-8, but it's not clear how one could detect that in order to avoid - // double-translation; this code here thus breaks UTF-8 input within a MSYS2 shell, - // unfortunately. - // - // Note also that input for passwords is NOT translated, to remain compatible with any - // passwords containing special characters that predate this switch to UTF-8 support. - static std::string cp850_to_utf8(const std::string &cp850_str) - { - boost::locale::generator gen; - gen.locale_cache_enabled(true); - std::locale loc = gen("en_US.CP850"); - return boost::locale::conv::to_utf(cp850_str, loc); - } -#endif - - std::string input_line(const std::string& prompt) - { -#ifdef HAVE_READLINE - rdln::suspend_readline pause_readline; -#endif - std::cout << prompt; - - std::string buf; - std::getline(std::cin, buf); -#ifdef WIN32 - buf = cp850_to_utf8(buf); -#endif - - return epee::string_tools::trim(buf); - } - - boost::optional password_prompter(const char *prompt, bool verify) - { -#ifdef HAVE_READLINE - rdln::suspend_readline pause_readline; -#endif - auto pwd_container = tools::password_container::prompt(verify, prompt); - if (!pwd_container) - { - tools::fail_msg_writer() << tr("failed to read wallet password"); - } - return pwd_container; - } - - boost::optional default_password_prompter(bool verify) - { - return password_prompter(verify ? tr("Enter a new password for the wallet") : tr("Wallet password"), verify); - } - - inline std::string interpret_rpc_response(bool ok, const std::string& status) - { - std::string err; - if (ok) - { - if (status == CORE_RPC_STATUS_BUSY) - { - err = sw::tr("daemon is busy. Please try again later."); - } - else if (status != CORE_RPC_STATUS_OK) - { - err = status; - } - } - else - { - err = sw::tr("possibly lost connection to daemon"); - } - return err; - } - - tools::scoped_message_writer success_msg_writer(bool color = false) - { - return tools::scoped_message_writer(color ? console_color_green : console_color_default, false, std::string(), el::Level::Info); - } - - tools::scoped_message_writer message_writer(epee::console_colors color = epee::console_color_default, bool bright = false) - { - return tools::scoped_message_writer(color, bright); - } - - tools::scoped_message_writer fail_msg_writer() - { - return tools::scoped_message_writer(console_color_red, true, sw::tr("Error: "), el::Level::Error); - } - - bool parse_bool(const std::string& s, bool& result) - { - if (s == "1" || command_line::is_yes(s)) - { - result = true; - return true; - } - if (s == "0" || command_line::is_no(s)) - { - result = false; - return true; - } - - boost::algorithm::is_iequal ignore_case{}; - if (boost::algorithm::equals("true", s, ignore_case) || boost::algorithm::equals(simple_wallet::tr("true"), s, ignore_case)) - { - result = true; - return true; - } - if (boost::algorithm::equals("false", s, ignore_case) || boost::algorithm::equals(simple_wallet::tr("false"), s, ignore_case)) - { - result = false; - return true; - } - - return false; - } - - template - bool parse_bool_and_use(const std::string& s, F func) - { - bool r; - if (parse_bool(s, r)) - { - func(r); - return true; - } - else - { - fail_msg_writer() << tr("invalid argument: must be either 0/1, true/false, y/n, yes/no"); - return false; - } - } - - const struct - { - const char *name; - tools::wallet::RefreshType refresh_type; - } refresh_type_names[] = - { - { "full", tools::wallet::RefreshFull }, - { "optimize-coinbase", tools::wallet::RefreshOptimizeCoinbase }, - { "optimized-coinbase", tools::wallet::RefreshOptimizeCoinbase }, - { "no-coinbase", tools::wallet::RefreshNoCoinbase }, - { "default", tools::wallet::RefreshDefault }, - }; - - bool parse_refresh_type(const std::string &s, tools::wallet::RefreshType &refresh_type) - { - for (size_t n = 0; n < sizeof(refresh_type_names) / sizeof(refresh_type_names[0]); ++n) - { - if (s == refresh_type_names[n].name) - { - refresh_type = refresh_type_names[n].refresh_type; - return true; - } - } - fail_msg_writer() << cryptonote::simple_wallet::tr("failed to parse refresh type"); - return false; - } - - std::string get_refresh_type_name(tools::wallet::RefreshType type) - { - for (size_t n = 0; n < sizeof(refresh_type_names) / sizeof(refresh_type_names[0]); ++n) - { - if (type == refresh_type_names[n].refresh_type) - return refresh_type_names[n].name; - } - return "invalid"; - } - - std::string get_version_string(uint32_t version) - { - return boost::lexical_cast(version >> 16) + "." + boost::lexical_cast(version & 0xffff); - } - - std::string oa_prompter(const std::string &url, const std::vector &addresses, bool dnssec_valid) - { - if (addresses.empty()) - return {}; - // prompt user for confirmation. - // inform user of DNSSEC validation status as well. - std::string dnssec_str; - if (dnssec_valid) - { - dnssec_str = tr("DNSSEC validation passed"); - } - else - { - dnssec_str = tr("WARNING: DNSSEC validation was unsuccessful, this address may not be correct!"); - } - std::stringstream prompt; - prompt << tr("For URL: ") << url - << ", " << dnssec_str << std::endl - << tr(" Safex Address = ") << addresses[0] - << std::endl - << tr("Is this OK? (Y/n) ") - ; - // prompt the user for confirmation given the dns query and dnssec status - std::string confirm_dns_ok = input_line(prompt.str()); - if (std::cin.eof()) - { - return {}; - } - if (!command_line::is_yes(confirm_dns_ok)) - { - std::cout << tr("you have cancelled the transfer request") << std::endl; - return {}; - } - return addresses[0]; - } - - bool parse_subaddress_indices(const std::string& arg, std::set& subaddr_indices) - { - subaddr_indices.clear(); - - if (arg.substr(0, 6) != "index=") - return false; - std::string subaddr_indices_str_unsplit = arg.substr(6, arg.size() - 6); - std::vector subaddr_indices_str; - boost::split(subaddr_indices_str, subaddr_indices_str_unsplit, boost::is_any_of(",")); - - for (const auto& subaddr_index_str : subaddr_indices_str) - { - uint32_t subaddr_index; - if(!epee::string_tools::get_xtype_from_string(subaddr_index, subaddr_index_str)) - { - fail_msg_writer() << tr("failed to parse index: ") << subaddr_index_str; - subaddr_indices.clear(); - return false; - } - subaddr_indices.insert(subaddr_index); - } - return true; - } - - boost::optional> parse_subaddress_lookahead(const std::string& str) - { - auto pos = str.find(":"); - bool r = pos != std::string::npos; - uint32_t major; - r = r && epee::string_tools::get_xtype_from_string(major, str.substr(0, pos)); - uint32_t minor; - r = r && epee::string_tools::get_xtype_from_string(minor, str.substr(pos + 1)); - if (r) - { - return std::make_pair(major, minor); - } - else - { - fail_msg_writer() << tr("invalid format for subaddress lookahead; must be :"); - return {}; - } - } - - void handle_transfer_exception(const std::exception_ptr &e, bool trusted_daemon) - { - bool warn_of_possible_attack = !trusted_daemon; - try - { - std::rethrow_exception(e); - } - catch (const tools::error::daemon_busy&) - { - fail_msg_writer() << tr("daemon is busy. Please try again later."); - } - catch (const tools::error::no_connection_to_daemon&) - { - fail_msg_writer() << tr("no connection to daemon. Please make sure daemon is running."); - } - catch (const tools::error::wallet_rpc_error& e) - { - LOG_ERROR("RPC error: " << e.to_string()); - fail_msg_writer() << tr("RPC error: ") << e.what(); - } - catch (const tools::error::get_random_outs_error &e) - { - fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what(); - } - catch (const tools::error::not_enough_unlocked_money& e) - { - LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") % - print_money(e.available()) % - print_money(e.tx_amount())); - fail_msg_writer() << tr("Not enough money in unlocked balance"); - warn_of_possible_attack = false; - } - catch (const tools::error::not_enough_unlocked_tokens& e) - { - LOG_PRINT_L0(boost::format("not enough tokens to transfer, available only %s, sent amount %s") % - print_money(e.token_available()) % - print_money(e.tx_token_amount())); - fail_msg_writer() << tr("Not enough tokens in unlocked balance"); - warn_of_possible_attack = false; - } - catch (const tools::error::not_enough_money& e) - { - LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") % - print_money(e.available()) % - print_money(e.tx_amount())); - fail_msg_writer() << tr("Not enough money in unlocked balance"); - warn_of_possible_attack = false; - } - catch (const tools::error::tx_not_possible& e) - { - LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") % - print_money(e.available()) % - print_money(e.tx_amount() + e.fee()) % - print_money(e.tx_amount()) % - print_money(e.fee())); - fail_msg_writer() << tr("Failed to find a way to create transactions. This is usually due to dust which is so small it cannot pay for itself in fees, or trying to send more money than the unlocked balance, or not leaving enough for fees"); - warn_of_possible_attack = false; - } - catch (const tools::error::not_enough_outs_to_mix& e) - { - auto writer = fail_msg_writer(); - writer << tr("not enough outputs for specified ring size") << " = " << (e.mixin_count() + 1) << ":"; - for (std::pair outs_for_amount : e.scanty_outs()) - { - writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.first) << ", " << tr("found outputs to use") << " = " << outs_for_amount.second; - } - writer << tr("Please use sweep_unmixable."); - } - catch (const tools::error::tx_not_constructed&) - { - fail_msg_writer() << tr("transaction was not constructed"); - warn_of_possible_attack = false; - } - catch (const tools::error::tx_rejected& e) - { - fail_msg_writer() << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); - std::string reason = e.reason(); - if (!reason.empty()) - fail_msg_writer() << tr("Reason: ") << reason; - } - catch (const tools::error::tx_sum_overflow& e) - { - fail_msg_writer() << e.what(); - warn_of_possible_attack = false; - } - catch (const tools::error::zero_destination&) - { - fail_msg_writer() << tr("one of destinations is zero"); - warn_of_possible_attack = false; - } - catch (const tools::error::tx_too_big& e) - { - fail_msg_writer() << tr("failed to find a suitable way to split transactions"); - warn_of_possible_attack = false; - } - catch (const tools::error::transfer_error& e) - { - LOG_ERROR("unknown transfer error: " << e.to_string()); - fail_msg_writer() << tr("unknown transfer error: ") << e.what(); - } - catch (const tools::error::wallet_internal_error& e) - { - LOG_ERROR("internal error: " << e.to_string()); - fail_msg_writer() << tr("internal error: ") << e.what(); - } - catch (const std::exception& e) - { - LOG_ERROR("unexpected error: " << e.what()); - fail_msg_writer() << tr("unexpected error: ") << e.what(); - } - - if (warn_of_possible_attack) - fail_msg_writer() << tr("There was an error, which could mean the node may be trying to get you to retry creating a transaction, and zero in on which outputs you own. Or it could be a bona fide error. It may be prudent to disconnect from this node, and not try to send a tranasction immediately. Alternatively, connect to another node so the original node cannot correlate information."); - } - - bool check_file_overwrite(const std::string &filename) - { - boost::system::error_code errcode; - if (boost::filesystem::exists(filename, errcode)) - { - if (boost::ends_with(filename, ".keys")) - { - fail_msg_writer() << boost::format(tr("File %s likely stores wallet private keys! Use a different file name.")) % filename; - return false; - } - return command_line::is_yes(input_line((boost::format(tr("File %s already exists. Are you sure to overwrite it? (Y/Yes/N/No): ")) % filename).str())); - } - return true; - } -} - -bool parse_priority(const std::string& arg, uint32_t& priority) -{ - auto priority_pos = std::find( - allowed_priority_strings.begin(), - allowed_priority_strings.end(), - arg); - if(priority_pos != allowed_priority_strings.end()) { - priority = std::distance(allowed_priority_strings.begin(), priority_pos); - return true; - } - return false; -} - std::string simple_wallet::get_commands_str() { std::stringstream ss; @@ -1395,6 +937,10 @@ simple_wallet::simple_wallet() boost::bind(&simple_wallet::show_token_balance, this, _1), tr("balance_token [detail]"), tr("Show the wallet's Safex Token balance of the currently selected account.")); + m_cmd_binder.set_handler("balance_staked_token", + boost::bind(&simple_wallet::show_staked_token_balance, this, _1), + tr("balance_staked_token [detail]"), + tr("Show the wallet's staked Safex Token balance of the currently selected account.")); m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), tr("incoming_transfers [available|unavailable] [verbose] [index=[,[,...]]]"), @@ -1501,7 +1047,7 @@ simple_wallet::simple_wallet() "refresh-type \n " " Set the wallet's refresh behaviour.\n " "priority [0|1|2|3|4]\n " - " Set the fee too default/unimportant/normal/elevated/priority.\n " + " Set the fee to default/unimportant/normal/elevated/priority.\n " "confirm-missing-payment-id <1|0>\n " "ask-password <1|0>\n " "unit \n " @@ -1577,13 +1123,17 @@ simple_wallet::simple_wallet() tr("show_transfers [in|out|pending|failed|pool] [index=[,,...]] [ []]"), tr("Show the incoming/outgoing transfers within an optional height range.")); m_cmd_binder.set_handler("unspent_cash_outputs", - boost::bind(&simple_wallet::unspent_outputs, this, _1, false), + boost::bind(&simple_wallet::unspent_outputs, this, _1, tx_out_type::out_cash), tr("unspent_cash_outputs [index=[,,...]] [ []]"), tr("Show the unspent Safex cash outputs of a specified address within an optional amount range.")); m_cmd_binder.set_handler("unspent_token_outputs", - boost::bind(&simple_wallet::unspent_outputs, this, _1, true), + boost::bind(&simple_wallet::unspent_outputs, this, _1, tx_out_type::out_token), tr("unspent_token_outputs [index=[,,...]] [ []]"), tr("Show the unspent token outputs of a specified address within an optional amount range.")); + m_cmd_binder.set_handler("unspent_staked_token_outputs", + boost::bind(&simple_wallet::unspent_outputs, this, _1, tx_out_type::out_staked_token), + tr("unspent_staked_token_outputs [index=[,,...]] [ []]"), + tr("Show the unspent staked token outputs of a specified address within an optional amount range.")); m_cmd_binder.set_handler("rescan_bc", boost::bind(&simple_wallet::rescan_blockchain, this, _1), tr("Rescan the blockchain from scratch.")); @@ -1657,6 +1207,91 @@ simple_wallet::simple_wallet() boost::bind(&simple_wallet::help, this, _1), tr("help []"), tr("Show the help section or the documentation about a .")); + + m_cmd_binder.set_handler("stake_token", + boost::bind(&simple_wallet::stake_token, this, _1), + tr("stake_token [index=[,,...]] [] []
[]"), + tr("Stake with
as staked tokens holder, optionally set payment_id, priority, ring_size for input tokens or subaddress index to use")); + + m_cmd_binder.set_handler("unstake_token", + boost::bind(&simple_wallet::unstake_token, this, _1), + tr("unstake_token [index=] []
[]"), + tr("Unstake with
as staked tokens holder, optionally set payment_id, priority, and subaddress index")); + + m_cmd_binder.set_handler("safex_purchase", + boost::bind(&simple_wallet::safex_purchase, this, _1), + tr("safex_purchase [index=[,,...]] [] [] "), + tr("Safex purchase. 95% of cash sent is given to the seller, 5% is taken as fee")); + + m_cmd_binder.set_handler("safex_feedback", + boost::bind(&simple_wallet::safex_feedback, this, _1), + tr("safex_feedback \n" + "safex_feedback [index=[,,...]] [] [] \n"), + tr("If no arguments are given, show all offers that you can give feedback\n" + "If arguments are given, give feedback for purchased offer with with and ")); + + m_cmd_binder.set_handler("donate_safex_fee", + boost::bind(&simple_wallet::donate_safex_fee, this, _1), + tr("donate_safex_fee [index=[,,...]] [] [] []"), + tr("Donate to network, optionally set payment_id, priority, ring_size for input cash or cash output subaddress indice")); + + m_cmd_binder.set_handler("list_offers", + boost::bind(&simple_wallet::list_offers, this, _1), + tr("list_offers"), + tr("List current offers in the Blockchain.")); + + m_cmd_binder.set_handler("list_price_pegs", + boost::bind(&simple_wallet::list_price_pegs, this, _1), + tr("list_price_pegs [currency]\n"), + tr("List price pegs in the Blockchain.\n" + "If no currency is given, list all price pegs in the Blockchain")); + + m_cmd_binder.set_handler("list_ratings", + boost::bind(&simple_wallet::list_ratings, this, _1), + tr("list_ratings "), + tr("List ratings in the Blockchain for given offer.")); + + m_cmd_binder.set_handler("get_my_interest", + boost::bind(&simple_wallet::get_my_interest, this, _1), + tr("get_my_interest"), + tr("Amount of collected interest so far for locked tokens.")); + + m_cmd_binder.set_handler("safex_account", + boost::bind(&simple_wallet::safex_account, this, _1), + tr("safex_account\n" + " safex_account new \n" + " safex_account remove \n" + " safex_account recover \n" + " safex_account keys \n" + " safex_account create [index=[,,...]] [] [] \n" + " safex_account edit [index=[,,...]] [] [] "), + tr("If no arguments are specified, the wallet shows all the existing safex accounts along with their balances.\n" + "If the \"new\" argument is specified, keys for specified username and provided account data are generated\n" + "If the \"remove\" argument is specified, account with provided username is deleted\n" + "If the \"recover\" argument is specified, account with provided username and private key is recovered\n" + "If the \"keys\" argument is specified, public/private account keys are printed\n" + "If the \"create\" argument is specified, the wallet creates a new safex account with username, label and account data initialized from parameters\n" + "If the \"edit\" argument is specified, the wallet edits account data specified by username.\n" + "Optionally set priority, ring_size for input tokens or subaddress index to use")); + + m_cmd_binder.set_handler("safex_offer", + boost::bind(&simple_wallet::safex_offer, this, _1), + tr("safex_offer\n" + " safex_offer create [index=[,,...]] [] [] \n" + " safex_offer edit [index=[,,...]] [] [] "), + tr("If no arguments are specified, the wallet shows all the existing safex offers for current account.\n" + "If the \"create\" argument is specified, the wallet creates a new safex offer and create a transaction\n" + "If the \"edit\" argument is specified, given offer will be edited with new arguments")); + + m_cmd_binder.set_handler("safex_price_peg", + boost::bind(&simple_wallet::safex_price_peg, this, _1), + tr("safex_price_peg\n" + " safex_price_peg create [index=[,,...]] [] [] \n" + " safex_price_peg update [index=[,,...]] [] [] "), + tr("If no arguments are specified, the wallet shows all the existing safex price pegs for current account.\n" + "If the \"create\" argument is specified, the wallet creates a new safex price peg and creates a transaction\n" + "If the \"update\" argument is specified, given price peg will be updated with new arguments")); + } //---------------------------------------------------------------------------------------------------- bool simple_wallet::set_variable(const std::vector &args) @@ -2559,58 +2194,7 @@ bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, return true; } -//---------------------------------------------------------------------------------------------------- -bool simple_wallet::new_wallet(const boost::program_options::variables_map& vm, - const std::string &multisig_keys, const std::string &old_language) -{ - auto rc = tools::wallet::make_new(vm, password_prompter); - m_wallet = std::move(rc.first); - if (!m_wallet) - { - return false; - } - - if (!m_subaddress_lookahead.empty()) - { - auto lookahead = parse_subaddress_lookahead(m_subaddress_lookahead); - assert(lookahead); - m_wallet->set_subaddress_lookahead(lookahead->first, lookahead->second); - } - - std::string mnemonic_language = old_language; - std::vector language_list; - crypto::ElectrumWords::get_language_list(language_list); - if (mnemonic_language.empty() && std::find(language_list.begin(), language_list.end(), m_mnemonic_language) != language_list.end()) - { - mnemonic_language = m_mnemonic_language; - } - - m_wallet->set_seed_language(mnemonic_language); - - bool create_address_file = command_line::get_arg(vm, arg_create_address_file); - - try - { - m_wallet->generate(m_wallet_file, std::move(rc.second).password(), multisig_keys, create_address_file); - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total) || !ready) - { - fail_msg_writer() << tr("failed to generate new mutlisig wallet"); - return false; - } - message_writer(console_color_white, true) << boost::format(tr("Generated new %u/%u multisig wallet: ")) % threshold % total - << m_wallet->get_account().get_public_address_str(m_wallet->nettype()); - } - catch (const std::exception& e) - { - fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); - return false; - } - - return true; -} //---------------------------------------------------------------------------------------------------- bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm) { @@ -2635,8 +2219,6 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm) uint32_t threshold, total; 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 prefix = tr("Opened wallet"); message_writer(console_color_white, true) << @@ -2746,13 +2328,26 @@ bool simple_wallet::save(const std::vector &args) return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::save_watch_only(const std::vector &args/* = std::vector()*/) +bool simple_wallet::save_safex(const epee::wipeable_string& password) { - if (m_wallet->multisig()) + try { - fail_msg_writer() << tr("wallet is multisig and cannot save a watch-only version"); - return true; + LOCK_IDLE_SCOPE(); + + m_wallet->store_safex(password); + success_msg_writer() << tr("Wallet safex data saved"); } + catch (const std::exception& e) + { + fail_msg_writer() << e.what(); + return false; + } + + return true; +} +//---------------------------------------------------------------------------------------------------- +bool simple_wallet::save_watch_only(const std::vector &args/* = std::vector()*/) +{ const auto pwd_container = password_prompter(tr("Password for new watch-only wallet"), true); @@ -2948,7 +2543,6 @@ void simple_wallet::on_tokens_received(uint64_t height, const crypto::hash &txid else m_refresh_progress_reporter.update(height, true); } -//---------------------------------------------------------------------------------------------------- void simple_wallet::on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) { // Not implemented in CLI wallet @@ -3083,8 +2677,6 @@ bool simple_wallet::refresh(const std::vector& args) bool simple_wallet::show_balance_unlocked(bool detailed) { std::string extra; - if (m_wallet->has_multisig_partial_key_images()) - extra = tr(" (Some owned outputs have partial key images - import_multisig_info needed)"); success_msg_writer() << tr("Currently selected account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0}); const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account]; success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag); @@ -3118,6 +2710,7 @@ bool simple_wallet::show_balance(const std::vector &args/* = std::v LOCK_IDLE_SCOPE(); show_balance_unlocked(args.size() == 1); show_token_balance_unlocked(args.size() == 1); + show_staked_token_balance_unlocked(args.size() == 1); return true; } //---------------------------------------------------------------------------------------------------- @@ -3136,8 +2729,6 @@ bool simple_wallet::show_cash_balance(const std::vector &args/* = s bool simple_wallet::show_token_balance_unlocked(bool detailed) { std::string extra; - if (m_wallet->has_multisig_partial_key_images()) - extra = tr(" (Some owned token outputs have partial key images - import_multisig_info needed)"); success_msg_writer() << tr("Currently selected token account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0}); const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account]; success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag); @@ -3678,14 +3269,16 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vectoralways_confirm_transfers() || ptx_vector.size() > 1) { @@ -3888,20 +3483,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vectormultisig()) - { - bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_safex_tx"); - if (!r) - { - fail_msg_writer() << tr("Failed to write transaction(s) to file"); - } - else - { - success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_safex_tx"; - } - } - else if (m_wallet->watch_only()) + if (m_wallet->watch_only()) { bool r = m_wallet->save_tx(ptx_vector, "unsigned_safex_tx"); if (!r) @@ -3931,205 +3513,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector &args_) -{ -// "migrate []
"" - if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } - if (!try_connect_to_daemon()) - return true; - - LOCK_IDLE_SCOPE(); - - std::vector local_args = args_; - - uint32_t priority = 0; - if (local_args.size() > 0 && parse_priority(local_args[0], priority)) - local_args.erase(local_args.begin()); - - priority = m_wallet->adjust_priority(priority); - - const size_t expexted_num_of_args = 3; //for TransferMigration - if(local_args.size() != expexted_num_of_args) - { - fail_msg_writer() << tr("wrong number of arguments"); - fail_msg_writer() << tr("migration command expected parameters: migrate []
"); - return true; - } - - cryptonote::address_parse_info info; - cryptonote::tx_destination_entry token_destination; - if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[0], oa_prompter)) - { - fail_msg_writer() << tr("failed to parse address"); - return true; - } - token_destination.addr = info.address; - token_destination.is_subaddress = info.is_subaddress; - token_destination.token_transaction = true; - - //parse bitcoin transaction hash - cryptonote::blobdata expected_bitcoin_hash_data; - if (!epee::string_tools::parse_hexstr_to_binbuff(std::string(local_args[1]), expected_bitcoin_hash_data) || expected_bitcoin_hash_data.size() != sizeof(crypto::hash)) - { - fail_msg_writer() << tr("failed to parse bitcoin transaction hash"); - return true; - } - const crypto::hash bitcoin_burn_transaction = *reinterpret_cast(expected_bitcoin_hash_data.data()); - - bool ok = cryptonote::parse_amount(token_destination.token_amount, local_args[2]); - if(!ok || 0 == token_destination.token_amount) - { - fail_msg_writer() << tr("token amount is wrong: ") << local_args[0] << ' ' << local_args[2] << - ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits::max()); - return true; - } - - if(!tools::is_whole_coin_amount(token_destination.token_amount)) - { - fail_msg_writer() << tr("token amount must be whole number. ") << local_args[0] << ' ' << local_args[2]; - return true; - } - - std::stringstream prompt; - prompt << "Perform migration transaction: address: " << cryptonote::get_account_address_as_str(m_wallet->nettype(), false, token_destination.addr) \ - << " bitcoin tx hash:" << epee::string_tools::pod_to_hex(bitcoin_burn_transaction) \ - << " token amount:" << print_money(token_destination.token_amount) \ - << tr("Is this okay anyway? (Y/Yes/N/No): "); - //std::string prompt_str = prompt.str(); -// if (!prompt_str.empty()) -// { -// std::string accepted = input_line(prompt_str); -// if (std::cin.eof()) -// return true; -// if (!command_line::is_yes(accepted)) -// { -// fail_msg_writer() << tr("transaction cancelled."); -// -// return true; -// } -// } - - - //airdrop reward calculation - cryptonote::tx_destination_entry airdrop_destination; - airdrop_destination.addr = info.address; - airdrop_destination.is_subaddress = info.is_subaddress; - airdrop_destination.token_transaction = false; - airdrop_destination.amount = cryptonote::get_airdrop_cash(token_destination.token_amount); - - vector dsts; - dsts.push_back(token_destination); - dsts.push_back(airdrop_destination); - - - //for migration transaction, extra nonce is so far not used - std::vector extra; - - try - { - // figure out what tx will be necessary - std::vector ptx_vector; - uint64_t bc_height, unlock_block = 0; - std::string err; - - ptx_vector = m_wallet->create_transactions_migration(dsts, bitcoin_burn_transaction, 0 /* unlock_time */, priority, extra, m_trusted_daemon); - - if (ptx_vector.empty()) - { - fail_msg_writer() << tr("No outputs found, or daemon is not ready"); - return true; - } - - // if we need to check for backlog, check the worst case tx - if (m_wallet->confirm_backlog()) - { - std::stringstream prompt; - double worst_fee_per_byte = std::numeric_limits::max(); - for (size_t n = 0; n < ptx_vector.size(); ++n) - { - const uint64_t blob_size = cryptonote::tx_to_blob(ptx_vector[n].tx).size(); - const double fee_per_byte = ptx_vector[n].fee / (double)blob_size; - if (fee_per_byte < worst_fee_per_byte) - { - worst_fee_per_byte = fee_per_byte; - } - } - try - { - std::vector> nblocks = m_wallet->estimate_backlog({std::make_pair(worst_fee_per_byte, worst_fee_per_byte)}); - if (nblocks.size() != 1) - { - prompt << "Internal error checking for backlog. " << tr("Is this okay anyway? (Y/Yes/N/No): "); - } - else - { - if (nblocks[0].first > m_wallet->get_confirm_backlog_threshold()) - prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No): ")) % nblocks[0].first).str(); - } - } - catch (const std::exception &e) - { - prompt << tr("Failed to check for backlog: ") << e.what() << ENDL << tr("Is this okay anyway? (Y/Yes/N/No): "); - } - - std::string prompt_str = prompt.str(); - if (!prompt_str.empty()) - { - std::string accepted = input_line(prompt_str); - if (std::cin.eof()) - return true; - if (!command_line::is_yes(accepted)) - { - fail_msg_writer() << tr("transaction cancelled."); - - return true; - } - } - } - - // actually commit the transactions - if (m_wallet->multisig()) - { - bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_safex_tx"); - if (!r) - { - fail_msg_writer() << tr("Failed to write transaction(s) to file"); - } - else - { - success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_safex_tx"; - } - } - else if (m_wallet->watch_only()) - { - bool r = m_wallet->save_tx(ptx_vector, "unsigned_safex_migration"); - if (!r) - { - fail_msg_writer() << tr("Failed to write transaction(s) to file"); - } - else - { - success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_safex_migration"; - } - } - else - { - commit_or_save(ptx_vector, m_do_not_relay); - } - } - catch (const std::exception &e) - { - handle_transfer_exception(std::current_exception(), m_trusted_daemon); - } - catch (...) - { - LOG_ERROR("unknown error"); - fail_msg_writer() << tr("unknown error"); - } - - return true; -} -//---------------------------------------------------------------------------------------------------- bool simple_wallet::transfer(const std::vector &args_) { return transfer_main(TransferOriginal, args_); @@ -4184,19 +3567,22 @@ bool simple_wallet::sweep_unmixable(const std::vector &args_) { total_fee += ptx_vector[n].fee; for (auto i: ptx_vector[n].selected_transfers) - total_unmixable += m_wallet->get_transfer_details(i).amount(); + total_unmixable += out_type == cryptonote::tx_out_type::out_token ? m_wallet->get_transfer_details(i).token_amount() : m_wallet->get_transfer_details(i).amount(); } + std::string type = out_type == cryptonote::tx_out_type::out_token ? "tokens" : "cash"; std::string prompt_str = tr("Sweeping ") + print_money(total_unmixable); if (ptx_vector.size() > 1) { - prompt_str = (boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) % + prompt_str = (boost::format(tr("Sweeping %s %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) % print_money(total_unmixable) % + type % ((unsigned long long)ptx_vector.size()) % print_money(total_fee)).str(); } else { - prompt_str = (boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) % + prompt_str = (boost::format(tr("Sweeping %s %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) % print_money(total_unmixable) % + type % print_money(total_fee)).str(); } std::string accepted = input_line(prompt_str); @@ -4210,19 +3596,7 @@ bool simple_wallet::sweep_unmixable(const std::vector &args_) } // actually commit the transactions - if (m_wallet->multisig()) - { - bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_safex_tx"); - if (!r) - { - fail_msg_writer() << tr("Failed to write transaction(s) to file"); - } - else - { - success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_safex_tx"; - } - } - else if (m_wallet->watch_only()) + if (m_wallet->watch_only()) { bool r = m_wallet->save_tx(ptx_vector, "unsigned_safex_tx"); if (!r) @@ -4371,7 +3745,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector &a payment_id_seen = true; } - // prompt is there is no payment id and confirmation is required + // prompt if there is no payment id and confirmation is required if (!payment_id_seen && m_wallet->confirm_missing_payment_id()) { std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): ")); @@ -4443,19 +3817,7 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector &a } // actually commit the transactions - if (m_wallet->multisig()) - { - bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_safex_tx"); - if (!r) - { - fail_msg_writer() << tr("Failed to write transaction(s) to file"); - } - else - { - success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_safex_tx"; - } - } - else if (m_wallet->watch_only()) + if (m_wallet->watch_only()) { bool r = m_wallet->save_tx(ptx_vector, "unsigned_safex_tx"); if (!r) @@ -4640,19 +4002,7 @@ bool simple_wallet::sweep_single(const std::vector &args_) } // actually commit the transactions - if (m_wallet->multisig()) - { - bool r = m_wallet->save_multisig_tx(ptx_vector, "multisig_safex_tx"); - if (!r) - { - fail_msg_writer() << tr("Failed to write transaction(s) to file"); - } - else - { - success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_safex_tx"; - } - } - else if (m_wallet->watch_only()) + if (m_wallet->watch_only()) { bool r = m_wallet->save_tx(ptx_vector, "unsigned_safex_tx"); if (!r) @@ -4860,11 +4210,7 @@ bool simple_wallet::sign_transfer(const std::vector &args_) fail_msg_writer() << tr("command not supported by HW wallet"); return true; } - if(m_wallet->multisig()) - { - fail_msg_writer() << tr("This is a multisig wallet, simplewallet does not support it"); - return true; - } + if(m_wallet->watch_only()) { fail_msg_writer() << tr("This is a watch only wallet"); @@ -5320,7 +4666,7 @@ bool simple_wallet::get_reserve_proof(const std::vector &args) return true; } - if (m_wallet->watch_only() || m_wallet->multisig()) + if (m_wallet->watch_only()) { fail_msg_writer() << tr("The reserve proof can be generated only by a full wallet"); return true; @@ -5652,14 +4998,18 @@ bool simple_wallet::show_transfers(const std::vector &args_) return true; } //---------------------------------------------------------------------------------------------------- -bool simple_wallet::unspent_outputs(const std::vector &args_, bool token_outputs) +bool simple_wallet::unspent_outputs(const std::vector &args_, cryptonote::tx_out_type out_type) { - const char *string_prefix = token_outputs ? " token" : ""; + + const char *string_prefix = (out_type == cryptonote::tx_out_type::out_token) ? " token" : + (out_type == cryptonote::tx_out_type::out_staked_token) ? " staked token" : ""; if(args_.size() > 3) { - if (token_outputs) + if (out_type == cryptonote::tx_out_type::out_token) fail_msg_writer() << tr("usage: unspent_token_outputs [index=[,,...]] [ []]"); + else if (out_type == cryptonote::tx_out_type::out_staked_token) + fail_msg_writer() << tr("usage: unspent_staked_token_outputs [index=[,,...]] [ []]"); else fail_msg_writer() << tr("usage: unspent_cash_outputs [index=[,,...]] [ []]"); return true; @@ -5710,15 +5060,12 @@ bool simple_wallet::unspent_outputs(const std::vector &args_, bool for (const auto& td : transfers) { uint64_t value_amount = 0; - if (token_outputs) { - if (!td.m_token_transfer) - continue; - value_amount = td.token_amount(); - } else { - if (td.m_token_transfer) - continue; - value_amount = td.amount(); - } + + if (td.get_out_type() != out_type) + continue; + + value_amount = out_type == tx_out_type::out_token || out_type == tx_out_type::out_staked_token ? td.token_amount():td.amount(); + if (td.m_spent || value_amount < min_amount || value_amount > max_amount || td.m_subaddr_index.major != m_current_subaddress_account || (subaddr_indices.count(td.m_subaddr_index.minor) == 0 && !subaddr_indices.empty())) continue; @@ -5737,7 +5084,10 @@ bool simple_wallet::unspent_outputs(const std::vector &args_, bool for (const auto& amount_tds : amount_to_tds) { auto& tds = amount_tds.second; - success_msg_writer() << (token_outputs ? tr("\nToken amount: ") : tr("\nAmount: ")) << print_money(amount_tds.first) << tr(", number of keys: ") << tds.size(); + success_msg_writer() << ((out_type == cryptonote::tx_out_type::out_token) ? tr("\nToken amount: "): + (out_type == cryptonote::tx_out_type::out_staked_token) ? tr("\nStaked token amount: "): tr("\nAmount: ")) + << print_money(amount_tds.first) << tr(", number of keys: ") << tds.size(); + for (size_t i = 0; i < tds.size(); ) { std::ostringstream oss; @@ -5750,7 +5100,7 @@ bool simple_wallet::unspent_outputs(const std::vector &args_, bool << tr("\nMin block height: ") << min_height << tr("\nMax block height: ") << max_height << tr("\nMin") << tr(string_prefix) << tr(" amount found: ") << print_money(found_min_amount) - << tr("\nMin") << tr(string_prefix) << tr(" amount found: ") << print_money(found_max_amount) + << tr("\nMax") << tr(string_prefix) << tr(" amount found: ") << print_money(found_max_amount) << tr("\nTotal count: ") << count; const size_t histogram_height = 10; const size_t histogram_width = 50; @@ -5807,6 +5157,9 @@ bool simple_wallet::unspent_outputs(const std::vector &args_, bool //---------------------------------------------------------------------------------------------------- bool simple_wallet::rescan_blockchain(const std::vector &args_) { + if (!args_.empty()) + if (args_[0] == "hard") + m_wallet->set_refresh_from_block_height(0); return refresh_main(0, true); } //---------------------------------------------------------------------------------------------------- @@ -6033,7 +5386,7 @@ void simple_wallet::print_accounts() { const std::pair, std::vector>& account_tags = m_wallet->get_account_tags(); size_t num_untagged_accounts = m_wallet->get_num_subaddress_accounts(); - for (const std::pair& p : account_tags.first) + for (const std::pair& p : account_tags.first) { const std::string& tag = p.first; print_accounts(tag); @@ -6048,6 +5401,7 @@ void simple_wallet::print_accounts() { success_msg_writer() << tr("\nGrand total:\n Cash balance: ") << print_money(m_wallet->balance_all()) << tr(", unlocked cash balance: ") << print_money(m_wallet->unlocked_balance_all()); success_msg_writer() << tr("\n Token balance: ") << print_money(m_wallet->token_balance_all()) << tr(", unlocked token balance: ") << print_money(m_wallet->unlocked_token_balance_all()); + success_msg_writer() << tr("\n Staked token balance: ") << print_money(m_wallet->staked_token_balance_all()) << tr(", unlocked staked token balance: ") << print_money(m_wallet->unlocked_staked_token_balance_all()); } } //---------------------------------------------------------------------------------------------------- @@ -6068,13 +5422,14 @@ void simple_wallet::print_accounts(const std::string& tag) success_msg_writer() << tr("Accounts with tag: ") << tag; success_msg_writer() << tr("Tag's description: ") << account_tags.first.find(tag)->second; } - success_msg_writer() << boost::format(" %15s %21s %23s %21s %25s %21s") % tr("Account") % tr("Cash balance") % tr("Unlocked cash balance") % tr("Token balance") % tr("Unlocked token balance") % tr("Label"); + success_msg_writer() << boost::format(" %15s %21s %23s %21s %25s %21s %25s %21s") % tr("Account") % tr("Cash balance") % tr("Unlocked cash balance") % tr("Token balance") % tr("Unlocked token balance") % tr("Staked balance") % tr("Staked Unlocked balance") % tr("Label"); uint64_t total_balance = 0, total_unlocked_balance = 0, total_token_balance = 0, total_unlocked_token_balance = 0; + uint64_t total_staked = 0, total_unlocked_staked = 0; for (uint32_t account_index = 0; account_index < m_wallet->get_num_subaddress_accounts(); ++account_index) { if (account_tags.second[account_index] != tag) continue; - success_msg_writer() << boost::format(tr(" %c%8u %6s %23s %21s %21s %25s %21s")) + success_msg_writer() << boost::format(tr(" %c%8u %6s %23s %21s %21s %25s %21s %25s %21s")) % (m_current_subaddress_account == account_index ? '*' : ' ') % account_index % m_wallet->get_subaddress_as_str({account_index, 0}).substr(0, 6) @@ -6082,14 +5437,20 @@ void simple_wallet::print_accounts(const std::string& tag) % print_money(m_wallet->unlocked_balance(account_index)) % print_money(m_wallet->token_balance(account_index)) % print_money(m_wallet->unlocked_token_balance(account_index)) + % print_money(m_wallet->staked_token_balance(account_index)) + % print_money(m_wallet->unlocked_staked_token_balance(account_index)) % m_wallet->get_subaddress_label({account_index, 0}); + + + total_staked += m_wallet->staked_token_balance(account_index); + total_unlocked_staked += m_wallet->unlocked_staked_token_balance(account_index); total_balance += m_wallet->balance(account_index); total_unlocked_balance += m_wallet->unlocked_balance(account_index); total_token_balance += m_wallet->token_balance(account_index); total_unlocked_token_balance += m_wallet->unlocked_token_balance(account_index); } - success_msg_writer() << tr("----------------------------------------------------------------------------------------------------------------------------------------"); - success_msg_writer() << boost::format(tr("%17s %23s %21s %21s %25s")) % "Total" % print_money(total_balance) % print_money(total_unlocked_balance) % print_money(total_token_balance) % print_money(total_unlocked_token_balance); + success_msg_writer() << tr("---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------"); + success_msg_writer() << boost::format(tr("%17s %23s %21s %21s %25s %21s %25s")) % "Total" % print_money(total_balance) % print_money(total_unlocked_balance) % print_money(total_token_balance) % print_money(total_unlocked_token_balance) % print_money(total_staked) % print_money(total_unlocked_staked);; } //---------------------------------------------------------------------------------------------------- bool simple_wallet::print_address(const std::vector &args/* = std::vector()*/) @@ -6446,8 +5807,6 @@ bool simple_wallet::wallet_info(const std::vector &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 type = tr("Normal"); message_writer() << tr("Type: ") << type; @@ -6474,11 +5833,7 @@ bool simple_wallet::sign(const std::vector &args) fail_msg_writer() << tr("wallet is watch-only and cannot sign"); return true; } - if (m_wallet->multisig()) - { - fail_msg_writer() << tr("This wallet is multisig and cannot sign"); - return true; - } + if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } std::string filename = args[0]; std::string data; @@ -6751,6 +6106,39 @@ bool simple_wallet::import_outputs(const std::vector &args) return true; } //---------------------------------------------------------------------------------------------------- +namespace { + std::string get_output_type_string(const tx_out_type& type) { + success_msg_writer() << static_cast(type); + if(type == tx_out_type::out_cash) { + return std::string("Cash transfer"); + } else if(type == tx_out_type::out_token) { + return std::string("Token transfer"); + }else if(type == tx_out_type::out_staked_token) { + return std::string("Stake token transfer"); + }else if(type == tx_out_type::out_network_fee) { + return std::string("Collect network fee transfer"); + }else if(type == tx_out_type::out_bitcoin_migration) { + return std::string("Migration transfer"); + }else if(type == tx_out_type::out_safex_account) { + return std::string("Create Safex account transfer"); + } else if(type == tx_out_type::out_safex_account_update) { + return std::string("Update Safex account transfer"); + }else if(type == tx_out_type::out_safex_offer) { + return std::string("Create Safex offer transfer"); + }else if(type == tx_out_type::out_safex_offer_update) { + return std::string("Update Safex offer transfer"); + }else if(type == tx_out_type::out_safex_purchase) { + return std::string("Safex purchase transfer"); + }else if(type == tx_out_type::out_safex_feedback_token) { + return std::string("Safex purchase transfer"); + }else if(type == tx_out_type::out_safex_feedback) { + return std::string("Safex feedback transfer"); + } else { + return std::string("Unknown type of transfer"); + } + } +} +//---------------------------------------------------------------------------------------------------- bool simple_wallet::show_transfer(const std::vector &args) { if (args.size() != 1) @@ -6779,6 +6167,7 @@ bool simple_wallet::show_transfer(const std::vector &args) payment_id = payment_id.substr(0,16); success_msg_writer() << "Incoming transaction found"; success_msg_writer() << "txid: " << txid; + success_msg_writer() << "Transfer type: " << get_output_type_string(pd.m_output_type); success_msg_writer() << "Height: " << pd.m_block_height; success_msg_writer() << "Timestamp: " << get_human_readable_timestamp(pd.m_timestamp); success_msg_writer() << "Amount: " << print_money(pd.m_amount); @@ -6816,6 +6205,9 @@ bool simple_wallet::show_transfer(const std::vector &args) uint64_t change = pd.m_change == (uint64_t)-1 ? 0 : pd.m_change; // change may not be known uint64_t token_change = pd.m_token_change == (uint64_t)-1 ? 0 : pd.m_token_change; uint64_t fee = pd.m_amount_in - pd.m_amount_out; + bool unstake_token_transfer = false; + if(pd.m_amount_out > pd.m_amount_in) + unstake_token_transfer = true; std::string dests; for (const auto &d: pd.m_dests) { if (!dests.empty()) @@ -6827,6 +6219,7 @@ bool simple_wallet::show_transfer(const std::vector &args) payment_id = payment_id.substr(0,16); success_msg_writer() << "Outgoing transaction found"; success_msg_writer() << "txid: " << txid; + success_msg_writer() << "Transfer type: " << get_output_type_string(unstake_token_transfer ? tx_out_type::out_network_fee : pd.m_output_type); success_msg_writer() << "Height: " << pd.m_block_height; success_msg_writer() << "Timestamp: " << get_human_readable_timestamp(pd.m_timestamp); success_msg_writer() << "Amount: " << print_money(pd.m_amount_in - change - fee); @@ -6834,7 +6227,10 @@ bool simple_wallet::show_transfer(const std::vector &args) success_msg_writer() << "Payment ID: " << payment_id; success_msg_writer() << "Change: " << print_money(change); success_msg_writer() << "Token Change: " << print_money(token_change); - success_msg_writer() << "Fee: " << print_money(fee); + if(unstake_token_transfer) + success_msg_writer() << "Network fee collected(after tx fee payed): " << print_money(pd.m_amount_out - pd.m_amount_in); + else + success_msg_writer() << "Fee: " << print_money(fee); success_msg_writer() << "Destinations: " << dests; success_msg_writer() << "Note: " << m_wallet->get_tx_note(txid); return true; @@ -6855,6 +6251,7 @@ bool simple_wallet::show_transfer(const std::vector &args) payment_id = payment_id.substr(0,16); success_msg_writer() << "Unconfirmed incoming transaction found in the txpool"; success_msg_writer() << "txid: " << txid; + success_msg_writer() << "Transfer type: " << get_output_type_string(pd.m_output_type); success_msg_writer() << "Timestamp: " << get_human_readable_timestamp(pd.m_timestamp); success_msg_writer() << "Amount: " << print_money(pd.m_amount); success_msg_writer() << "Token Amount: " << print_money(pd.m_token_amount); @@ -6949,6 +6346,9 @@ void simple_wallet::commit_or_save(std::vector& ptx_v ptx_vector.pop_back(); } } + + + //---------------------------------------------------------------------------------------------------- int main(int argc, char* argv[]) { diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 936e34084..8b4aca10d 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -58,6 +58,28 @@ */ namespace cryptonote { + enum TransferType { + TransferOriginal, + TransferNew, + TransferLocked, + TransferMigration, + TransferToken + }; + + enum CommandType { + TransferStakeToken, + TransferUnstakeToken, + TransferDonation, + TransferPurchase, + TransferCreateAccount, + TransferEditAccount, + TransferCreateOffer, + TransferEditOffer, + TransferFeedback, + TransferCreatePricePeg, + TransferUpdatePricePeg + }; + /*! * \brief Manages wallet operations. This is the most abstracted wallet class. */ @@ -94,8 +116,6 @@ namespace cryptonote bool recover, bool two_random, const std::string &old_language); bool new_wallet(const boost::program_options::variables_map& vm, const cryptonote::account_public_address& address, const boost::optional& spendkey, const crypto::secret_key& viewkey); - bool new_wallet(const boost::program_options::variables_map& vm, - const std::string &multisig_keys, const std::string &old_language); bool new_wallet(const boost::program_options::variables_map& vm, const std::string& device_name); bool open_wallet(const boost::program_options::variables_map& vm); bool close_wallet(); @@ -142,6 +162,11 @@ namespace cryptonote bool set_daemon(const std::vector &args); bool save_bc(const std::vector &args); bool refresh(const std::vector &args); + + + bool show_staked_token_balance_unlocked(bool detailed = false); + bool show_staked_token_balance(const std::vector &args = std::vector()); + bool show_balance_unlocked(bool detailed = false); bool show_balance(const std::vector &args = std::vector()); bool show_cash_balance(const std::vector &args = std::vector()); @@ -174,6 +199,7 @@ namespace cryptonote bool print_integrated_address(const std::vector &args = std::vector()); bool address_book(const std::vector &args = std::vector()); bool save(const std::vector &args); + bool save_safex(const epee::wipeable_string& password); bool save_watch_only(const std::vector &args); bool set_variable(const std::vector &args); bool rescan_spent(const std::vector &args); @@ -187,7 +213,7 @@ namespace cryptonote bool get_reserve_proof(const std::vector &args); bool check_reserve_proof(const std::vector &args); bool show_transfers(const std::vector &args); - bool unspent_outputs(const std::vector &args, bool token_outputs); + bool unspent_outputs(const std::vector &args, cryptonote::tx_out_type out_type); bool rescan_blockchain(const std::vector &args); bool refresh_main(uint64_t start_height, bool reset = false, bool is_init = false); bool set_tx_note(const std::vector &args); @@ -207,7 +233,6 @@ namespace cryptonote bool change_password(const std::vector& args); bool payment_id(const std::vector &args); bool print_fee_info(const std::vector &args); - bool accept_loaded_tx(const tools::wallet::multisig_tx_set &txs); bool print_ring(const std::vector& args); bool set_ring(const std::vector& args); bool save_known_rings(const std::vector& args); @@ -226,6 +251,41 @@ namespace cryptonote std::string get_prompt() const; bool print_seed(bool encrypted); + /************************************ SAFEX MARKETPLACE FUNCTIONALITIES *****************************************/ + + bool attach_price_peg(safex::safex_offer& sfx_offer); + bool get_my_interest(const std::vector& args); + void print_safex_accounts(); + void print_my_safex_offers(); + void print_not_given_feedbacks(); + void print_my_safex_price_pegs(); + void print_my_safex_offer(safex::safex_offer& offer, std::vector& price_pegs); + void print_safex_offer(safex::safex_offer& offer); + void print_safex_price_peg(safex::safex_price_peg& price_peg); + void print_price_pegs(const std::vector& price_pegs); + + + bool list_offers(const std::vector& args); + bool list_ratings(const std::vector& args); + bool list_price_pegs(const std::vector& args); + // Function responsible for + bool create_command(CommandType command_type, const std::vector &args); + + bool stake_token(const std::vector &args); + bool unstake_token(const std::vector &args); + bool donate_safex_fee(const std::vector& args); + bool staked_token_balance(const std::vector &args); + bool safex_account(const std::vector &args/* = std::vector()*/); + + bool safex_offer(const std::vector &args); + + bool safex_purchase(const std::vector& args); + + bool safex_feedback(const std::vector& args); + + bool safex_price_peg(const std::vector &args); + /****************************************************************************************************************/ + /*! * \brief Prints the seed with a nice message * \param seed seed to print @@ -251,6 +311,7 @@ namespace cryptonote virtual void on_new_block(uint64_t height, const cryptonote::block& block); virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index); virtual void on_tokens_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t token_amount, const cryptonote::subaddress_index& subaddr_index); + virtual void on_advanced_output_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, const txout_to_script &txout, const cryptonote::subaddress_index& subaddr_index); virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index); virtual void on_unconfirmed_tokens_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t token_amount, const cryptonote::subaddress_index& subaddr_index); virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index); diff --git a/src/simplewallet/simplewallet_common.cpp b/src/simplewallet/simplewallet_common.cpp new file mode 100644 index 000000000..d5ff91de4 --- /dev/null +++ b/src/simplewallet/simplewallet_common.cpp @@ -0,0 +1,408 @@ + #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "include_base_utils.h" +#include "common/i18n.h" +#include "common/command_line.h" +#include "common/util.h" +#include "common/dns_utils.h" +#include "common/base58.h" +#include "common/scoped_message_writer.h" +#include "cryptonote_protocol/cryptonote_protocol_handler.h" +#include "simplewallet.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "storages/http_abstract_invoke.h" +#include "rpc/core_rpc_server_commands_defs.h" +#include "crypto/crypto.h" // for crypto::secret_key definition +#include "mnemonics/electrum-words.h" +#include "rapidjson/document.h" +#include "common/json_util.h" +#include "ringct/rctSigs.h" +#include "wallet/wallet_args.h" +#include "version.h" +#include +#include "simplewallet_common.h" + +using namespace std; +using namespace epee; +using namespace cryptonote; + +#ifdef WIN32 + #include + #include + // Translate from CP850 to UTF-8; + // std::getline for a Windows console returns a string in CP437 or CP850; as simplewallet, + // like all of Safex, is assumed to work internally with UTF-8 throughout, even on Windows + // (although only implemented partially), a translation to UTF-8 is needed for input. + // + // Note that if a program is started inside the MSYS2 shell somebody already translates + // console input to UTF-8, but it's not clear how one could detect that in order to avoid + // double-translation; this code here thus breaks UTF-8 input within a MSYS2 shell, + // unfortunately. + // + // Note also that input for passwords is NOT translated, to remain compatible with any + // passwords containing special characters that predate this switch to UTF-8 support. + static std::string cp850_to_utf8(const std::string &cp850_str) + { + boost::locale::generator gen; + gen.locale_cache_enabled(true); + std::locale loc = gen("en_US.CP850"); + return boost::locale::conv::to_utf(cp850_str, loc); + } +#endif + + std::string input_line(const std::string& prompt) + { +#ifdef HAVE_READLINE + rdln::suspend_readline pause_readline; +#endif + std::cout << prompt; + + std::string buf; + std::getline(std::cin, buf); +#ifdef WIN32 + buf = cp850_to_utf8(buf); +#endif + + return epee::string_tools::trim(buf); + } + + boost::optional password_prompter(const char *prompt, bool verify) + { +#ifdef HAVE_READLINE + rdln::suspend_readline pause_readline; +#endif + auto pwd_container = tools::password_container::prompt(verify, prompt); + if (!pwd_container) + { + tools::fail_msg_writer() << tr("failed to read wallet password"); + } + return pwd_container; + } + + boost::optional default_password_prompter(bool verify) + { + return password_prompter(verify ? tr("Enter a new password for the wallet") : tr("Wallet password"), verify); + } + +std::string interpret_rpc_response(bool ok, const std::string& status) + { + std::string err; + if (ok) + { + if (status == CORE_RPC_STATUS_BUSY) + { + err = sw::tr("daemon is busy. Please try again later."); + } + else if (status != CORE_RPC_STATUS_OK) + { + err = status; + } + } + else + { + err = sw::tr("possibly lost connection to daemon"); + } + return err; + } + + tools::scoped_message_writer success_msg_writer(bool color) + { + return tools::scoped_message_writer(color ? console_color_green : console_color_default, false, std::string(), el::Level::Info); + } + + tools::scoped_message_writer message_writer(epee::console_colors color, bool bright ) + { + return tools::scoped_message_writer(color, bright); + } + + tools::scoped_message_writer fail_msg_writer() + { + return tools::scoped_message_writer(console_color_red, true, sw::tr("Error: "), el::Level::Error); + } + + bool parse_bool(const std::string& s, bool& result) + { + if (s == "1" || command_line::is_yes(s)) + { + result = true; + return true; + } + if (s == "0" || command_line::is_no(s)) + { + result = false; + return true; + } + + boost::algorithm::is_iequal ignore_case{}; + if (boost::algorithm::equals("true", s, ignore_case) || boost::algorithm::equals(simple_wallet::tr("true"), s, ignore_case)) + { + result = true; + return true; + } + if (boost::algorithm::equals("false", s, ignore_case) || boost::algorithm::equals(simple_wallet::tr("false"), s, ignore_case)) + { + result = false; + return true; + } + + return false; + } + + bool parse_refresh_type(const std::string &s, tools::wallet::RefreshType &refresh_type) + { + for (size_t n = 0; n < sizeof(refresh_type_names) / sizeof(refresh_type_names[0]); ++n) + { + if (s == refresh_type_names[n].name) + { + refresh_type = refresh_type_names[n].refresh_type; + return true; + } + } + fail_msg_writer() << cryptonote::simple_wallet::tr("failed to parse refresh type"); + return false; + } + + std::string get_refresh_type_name(tools::wallet::RefreshType type) + { + for (size_t n = 0; n < sizeof(refresh_type_names) / sizeof(refresh_type_names[0]); ++n) + { + if (type == refresh_type_names[n].refresh_type) + return refresh_type_names[n].name; + } + return "invalid"; + } + + std::string get_version_string(uint32_t version) + { + return boost::lexical_cast(version >> 16) + "." + boost::lexical_cast(version & 0xffff); + } + + std::string oa_prompter(const std::string &url, const std::vector &addresses, bool dnssec_valid) + { + if (addresses.empty()) + return {}; + // prompt user for confirmation. + // inform user of DNSSEC validation status as well. + std::string dnssec_str; + if (dnssec_valid) + { + dnssec_str = tr("DNSSEC validation passed"); + } + else + { + dnssec_str = tr("WARNING: DNSSEC validation was unsuccessful, this address may not be correct!"); + } + std::stringstream prompt; + prompt << tr("For URL: ") << url + << ", " << dnssec_str << std::endl + << tr(" Safex Address = ") << addresses[0] + << std::endl + << tr("Is this OK? (Y/n) ") + ; + // prompt the user for confirmation given the dns query and dnssec status + std::string confirm_dns_ok = input_line(prompt.str()); + if (std::cin.eof()) + { + return {}; + } + if (!command_line::is_yes(confirm_dns_ok)) + { + std::cout << tr("you have cancelled the transfer request") << std::endl; + return {}; + } + return addresses[0]; + } + + bool parse_subaddress_indices(const std::string& arg, std::set& subaddr_indices) + { + subaddr_indices.clear(); + + if (arg.substr(0, 6) != "index=") + return false; + std::string subaddr_indices_str_unsplit = arg.substr(6, arg.size() - 6); + std::vector subaddr_indices_str; + boost::split(subaddr_indices_str, subaddr_indices_str_unsplit, boost::is_any_of(",")); + + for (const auto& subaddr_index_str : subaddr_indices_str) + { + uint32_t subaddr_index; + if(!epee::string_tools::get_xtype_from_string(subaddr_index, subaddr_index_str)) + { + fail_msg_writer() << tr("failed to parse index: ") << subaddr_index_str; + subaddr_indices.clear(); + return false; + } + subaddr_indices.insert(subaddr_index); + } + return true; + } + + boost::optional> parse_subaddress_lookahead(const std::string& str) + { + auto pos = str.find(":"); + bool r = pos != std::string::npos; + uint32_t major; + r = r && epee::string_tools::get_xtype_from_string(major, str.substr(0, pos)); + uint32_t minor; + r = r && epee::string_tools::get_xtype_from_string(minor, str.substr(pos + 1)); + if (r) + { + return std::make_pair(major, minor); + } + else + { + fail_msg_writer() << tr("invalid format for subaddress lookahead; must be :"); + return {}; + } + } + + void handle_transfer_exception(const std::exception_ptr &e, bool trusted_daemon) + { + bool warn_of_possible_attack = !trusted_daemon; + try + { + std::rethrow_exception(e); + } + catch (const tools::error::daemon_busy&) + { + fail_msg_writer() << tr("daemon is busy. Please try again later."); + } + catch (const tools::error::no_connection_to_daemon&) + { + fail_msg_writer() << tr("no connection to daemon. Please make sure daemon is running."); + } + catch (const tools::error::wallet_rpc_error& e) + { + LOG_ERROR("RPC error: " << e.to_string()); + fail_msg_writer() << tr("RPC error: ") << e.what(); + } + catch (const tools::error::get_random_outs_error &e) + { + fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what(); + } + catch (const tools::error::not_enough_unlocked_cash& e) + { + LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") % + print_money(e.available()) % + print_money(e.tx_amount())); + fail_msg_writer() << tr("Not enough money in unlocked balance"); + warn_of_possible_attack = false; + } + catch (const tools::error::not_enough_unlocked_tokens& e) + { + LOG_PRINT_L0(boost::format("not enough tokens to transfer, available only %s, sent amount %s") % + print_money(e.token_available()) % + print_money(e.tx_token_amount())); + fail_msg_writer() << tr("Not enough tokens in unlocked balance"); + warn_of_possible_attack = false; + } + catch (const tools::error::not_enough_cash& e) + { + LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, sent amount %s") % + print_money(e.available()) % + print_money(e.tx_amount())); + fail_msg_writer() << tr("Not enough money in unlocked balance"); + warn_of_possible_attack = false; + } + catch (const tools::error::tx_not_possible& e) + { + LOG_PRINT_L0(boost::format("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)") % + print_money(e.available()) % + print_money(e.tx_amount() + e.fee()) % + print_money(e.tx_amount()) % + print_money(e.fee())); + fail_msg_writer() << tr("Failed to find a way to create transactions. This is usually due to dust which is so small it cannot pay for itself in fees, or trying to send more money than the unlocked balance, or not leaving enough for fees"); + warn_of_possible_attack = false; + } + catch (const tools::error::not_enough_outs_to_mix& e) + { + auto writer = fail_msg_writer(); + writer << tr("not enough outputs for specified ring size") << " = " << (e.mixin_count() + 1) << ":"; + for (std::pair outs_for_amount : e.scanty_outs()) + { + writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.first) << ", " << tr("found outputs to use") << " = " << outs_for_amount.second; + } + writer << tr("Please use sweep_unmixable."); + } + catch (const tools::error::tx_not_constructed&) + { + fail_msg_writer() << tr("transaction was not constructed"); + warn_of_possible_attack = false; + } + catch (const tools::error::tx_rejected& e) + { + fail_msg_writer() << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); + std::string reason = e.reason(); + if (!reason.empty()) + fail_msg_writer() << tr("Reason: ") << reason; + } + catch (const tools::error::tx_sum_overflow& e) + { + fail_msg_writer() << e.what(); + warn_of_possible_attack = false; + } + catch (const tools::error::zero_destination&) + { + fail_msg_writer() << tr("one of destinations is zero"); + warn_of_possible_attack = false; + } + catch (const tools::error::tx_too_big& e) + { + fail_msg_writer() << tr("failed to find a suitable way to split transactions"); + warn_of_possible_attack = false; + } + catch (const tools::error::transfer_error& e) + { + LOG_ERROR("unknown transfer error: " << e.to_string()); + fail_msg_writer() << tr("unknown transfer error: ") << e.what(); + } + catch (const tools::error::wallet_internal_error& e) + { + LOG_ERROR("internal error: " << e.to_string()); + fail_msg_writer() << tr("internal error: ") << e.what(); + } + catch (const std::exception& e) + { + LOG_ERROR("unexpected error: " << e.what()); + fail_msg_writer() << tr("unexpected error: ") << e.what(); + } + + if (warn_of_possible_attack) + fail_msg_writer() << tr("There was an error, which could mean the node may be trying to get you to retry creating a transaction, and zero in on which outputs you own. Or it could be a bona fide error. It may be prudent to disconnect from this node, and not try to send a tranasction immediately. Alternatively, connect to another node so the original node cannot correlate information."); + } + + bool check_file_overwrite(const std::string &filename) + { + boost::system::error_code errcode; + if (boost::filesystem::exists(filename, errcode)) + { + if (boost::ends_with(filename, ".keys")) + { + fail_msg_writer() << boost::format(tr("File %s likely stores wallet private keys! Use a different file name.")) % filename; + return false; + } + return command_line::is_yes(input_line((boost::format(tr("File %s already exists. Are you sure to overwrite it? (Y/Yes/N/No): ")) % filename).str())); + } + return true; + } + +bool parse_priority(const std::string& arg, uint32_t& priority) +{ + auto priority_pos = std::find( + allowed_priority_strings.begin(), + allowed_priority_strings.end(), + arg); + if(priority_pos != allowed_priority_strings.end()) { + priority = std::distance(allowed_priority_strings.begin(), priority_pos); + return true; + } + return false; +} \ No newline at end of file diff --git a/src/simplewallet/simplewallet_common.h b/src/simplewallet/simplewallet_common.h new file mode 100644 index 000000000..3d3934c6a --- /dev/null +++ b/src/simplewallet/simplewallet_common.h @@ -0,0 +1,152 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include "include_base_utils.h" +#include "common/i18n.h" +#include "common/command_line.h" +#include "common/util.h" +#include "common/dns_utils.h" +#include "common/base58.h" +#include "common/scoped_message_writer.h" +#include "cryptonote_protocol/cryptonote_protocol_handler.h" +#include "simplewallet.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "storages/http_abstract_invoke.h" +#include "rpc/core_rpc_server_commands_defs.h" +#include "crypto/crypto.h" // for crypto::secret_key definition +#include "mnemonics/electrum-words.h" +#include "rapidjson/document.h" +#include "common/json_util.h" +#include "ringct/rctSigs.h" +#include "version.h" +#include +#include + +#undef SAFEX_DEFAULT_LOG_CATEGORY +#define SAFEX_DEFAULT_LOG_CATEGORY "wallet.simplewallet" + +#define EXTENDED_LOGS_FILE "wallet_details.log" + +#define ENABLE_ADVANCED_OPTIONS 0 //some aditional features + +#define MIN_RING_SIZE 7 // Used to inform user about min ring size -- does not track actual protocol + +#define OUTPUT_EXPORT_FILE_MAGIC "Safex output export\003" + +#define LOCK_IDLE_SCOPE() \ + bool auto_refresh_enabled = m_auto_refresh_enabled.load(std::memory_order_relaxed); \ + m_auto_refresh_enabled.store(false, std::memory_order_relaxed); \ + /* stop any background refresh, and take over */ \ + m_wallet->stop(); \ + m_idle_mutex.lock(); \ + while (m_auto_refresh_refreshing) \ + m_idle_cond.notify_one(); \ + m_idle_mutex.unlock(); \ +/* if (auto_refresh_run)*/ \ + /*m_auto_refresh_thread.join();*/ \ + boost::unique_lock lock(m_idle_mutex); \ + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){ \ + m_auto_refresh_enabled.store(auto_refresh_enabled, std::memory_order_relaxed); \ + }) + +namespace po = boost::program_options; +typedef cryptonote::simple_wallet sw; + +const std::array allowed_priority_strings = {{"default", "unimportant", "normal", "elevated", "priority"}}; + const auto arg_wallet_file = wallet_args::arg_wallet_file(); + const command_line::arg_descriptor arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to "), ""}; + const command_line::arg_descriptor arg_generate_from_device = {"generate-from-device", sw::tr("Generate new wallet from device and save it to "), ""}; + const command_line::arg_descriptor arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""}; + const command_line::arg_descriptor arg_generate_from_spend_key = {"generate-from-spend-key", sw::tr("Generate deterministic wallet from spend key"), ""}; + const command_line::arg_descriptor arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""}; + const auto arg_generate_from_json = wallet_args::arg_generate_from_json(); + const command_line::arg_descriptor arg_mnemonic_language = {"mnemonic-language", sw::tr("Language for mnemonic"), ""}; + const command_line::arg_descriptor arg_electrum_seed = {"electrum-seed", sw::tr("Specify Electrum seed for wallet recovery/creation"), ""}; + const command_line::arg_descriptor arg_restore_deterministic_wallet = {"restore-deterministic-wallet", sw::tr("Recover wallet using Electrum-style mnemonic seed"), false}; + const command_line::arg_descriptor arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false}; + const command_line::arg_descriptor arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false}; + const command_line::arg_descriptor arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false}; + const command_line::arg_descriptor arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0}; + const command_line::arg_descriptor arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the safex network"), false}; + const command_line::arg_descriptor arg_create_address_file = {"create-address-file", sw::tr("Create an address file for new wallets"), false}; + const command_line::arg_descriptor arg_subaddress_lookahead = {"subaddress-lookahead", tools::wallet::tr("Set subaddress lookahead sizes to :"), ""}; + const command_line::arg_descriptor arg_use_english_language_names = {"use-english-language-names", sw::tr("Display English language names"), false}; + + const command_line::arg_descriptor< std::vector > arg_command = {"command", ""}; + +#ifdef WIN32 + // Translate from CP850 to UTF-8; + // std::getline for a Windows console returns a string in CP437 or CP850; as simplewallet, + // like all of Safex, is assumed to work internally with UTF-8 throughout, even on Windows + // (although only implemented partially), a translation to UTF-8 is needed for input. + // + // Note that if a program is started inside the MSYS2 shell somebody already translates + // console input to UTF-8, but it's not clear how one could detect that in order to avoid + // double-translation; this code here thus breaks UTF-8 input within a MSYS2 shell, + // unfortunately. + // + // Note also that input for passwords is NOT translated, to remain compatible with any + // passwords containing special characters that predate this switch to UTF-8 support. + static std::string cp850_to_utf8(const std::string &cp850_str); +#endif + + std::string input_line(const std::string& prompt); + + boost::optional password_prompter(const char *prompt, bool verify); + boost::optional default_password_prompter(bool verify); + + std::string interpret_rpc_response(bool ok, const std::string& status); + tools::scoped_message_writer success_msg_writer(bool color = false); + + tools::scoped_message_writer message_writer(epee::console_colors color = epee::console_color_default, bool bright = false); + tools::scoped_message_writer fail_msg_writer(); + + bool parse_bool(const std::string& s, bool& result); + +template + bool parse_bool_and_use(const std::string& s, F func) + { + bool r; + if (parse_bool(s, r)) + { + func(r); + return true; + } + else + { + fail_msg_writer() << tr("invalid argument: must be either 0/1, true/false, y/n, yes/no"); + return false; + } + } + + const struct + { + const char *name; + tools::wallet::RefreshType refresh_type; + } refresh_type_names[] = + { + { "full", tools::wallet::RefreshFull }, + { "optimize-coinbase", tools::wallet::RefreshOptimizeCoinbase }, + { "optimized-coinbase", tools::wallet::RefreshOptimizeCoinbase }, + { "no-coinbase", tools::wallet::RefreshNoCoinbase }, + { "default", tools::wallet::RefreshDefault }, + }; + + bool parse_refresh_type(const std::string &s, tools::wallet::RefreshType &refresh_type); + + std::string get_refresh_type_name(tools::wallet::RefreshType type); + + std::string get_version_string(uint32_t version); + std::string oa_prompter(const std::string &url, const std::vector &addresses, bool dnssec_valid); + + bool parse_subaddress_indices(const std::string& arg, std::set& subaddr_indices); + boost::optional> parse_subaddress_lookahead(const std::string& str); + void handle_transfer_exception(const std::exception_ptr &e, bool trusted_daemon); + bool check_file_overwrite(const std::string &filename); + +bool parse_priority(const std::string& arg, uint32_t& priority); diff --git a/src/simplewallet/simplewallet_safex.cpp b/src/simplewallet/simplewallet_safex.cpp new file mode 100644 index 000000000..6ad455e8c --- /dev/null +++ b/src/simplewallet/simplewallet_safex.cpp @@ -0,0 +1,1694 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "include_base_utils.h" +#include "common/i18n.h" +#include "common/command_line.h" +#include "common/util.h" +#include "common/dns_utils.h" +#include "common/base58.h" +#include "common/scoped_message_writer.h" +#include "cryptonote_protocol/cryptonote_protocol_handler.h" +#include "simplewallet.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "storages/http_abstract_invoke.h" +#include "rpc/core_rpc_server_commands_defs.h" +#include "crypto/crypto.h" // for crypto::secret_key definition +#include "mnemonics/electrum-words.h" +#include "rapidjson/document.h" +#include "common/json_util.h" +#include "ringct/rctSigs.h" +#include "wallet/wallet_args.h" +#include "version.h" +#include +#include +#include "simplewallet_common.h" +#include "safex/safex_account.h" + +using namespace std; +using namespace epee; +using namespace cryptonote; +using boost::lexical_cast; + +namespace cryptonote +{ + + + bool simple_wallet::create_command(CommandType command_type, const std::vector &args_) + { + //todo Uncomment +// if (m_wallet->ask_password() && !get_and_verify_password()) +// { return true; } + if (!try_connect_to_daemon()) + return true; + + + LOCK_IDLE_SCOPE(); + + std::vector local_args = args_; + + + + std::set subaddr_indices; + if (!local_args.empty() && local_args[0].substr(0, 6) == "index=") + { + if (!parse_subaddress_indices(local_args[0], subaddr_indices)) + return true; + local_args.erase(local_args.begin()); + } + + uint32_t priority = 0; + if (!local_args.empty() && parse_priority(local_args[0], priority)) + local_args.erase(local_args.begin()); + + priority = m_wallet->adjust_priority(priority); + + size_t fake_outs_count = 0; + if (!local_args.empty()) + { + size_t ring_size; + + if (command_type == CommandType::TransferUnstakeToken) + { + ring_size = 1; + fake_outs_count = 0; + } + else if (!epee::string_tools::get_xtype_from_string(ring_size, local_args[0])) + { + fake_outs_count = m_wallet->default_mixin(); + if (fake_outs_count == 0) + fake_outs_count = DEFAULT_MIX; + } + else if (ring_size == 0) + { + fail_msg_writer() << tr("Ring size must not be 0"); + return true; + } + else + { + fake_outs_count = ring_size - 1; + local_args.erase(local_args.begin()); + } + } + uint64_t adjusted_fake_outs_count = m_wallet->adjust_mixin(fake_outs_count); + if (adjusted_fake_outs_count > fake_outs_count) + { + fail_msg_writer() << (boost::format(tr("ring size %u is too small, minimum is %u")) % (fake_outs_count + 1) % (adjusted_fake_outs_count + 1)).str(); + return true; + } + + size_t min_args{2}; + + switch (command_type) { + case CommandType::TransferDonation: + case CommandType::TransferCreateAccount: + min_args = 1; + break; + + case CommandType::TransferFeedback: + min_args = 3; + break; + + case CommandType::TransferCreateOffer: + case CommandType::TransferCreatePricePeg: + min_args = 5; + break; + + case CommandType::TransferUpdatePricePeg: + min_args = 3; + break; + + case CommandType::TransferEditOffer: + min_args = 7; + break; + + default: + //min_args is 2 + break; + } + + if (local_args.size() < min_args) + { + fail_msg_writer() << tr("wrong number of arguments"); + return true; + } + + std::string payment_id_str; + std::vector extra; + bool payment_id_seen = false; + bool command_supports_payment_id = (command_type != CommandType::TransferCreateAccount) && (command_type != CommandType::TransferEditAccount) && + (command_type != CommandType::TransferCreateOffer) && (command_type != CommandType::TransferEditOffer) && + (command_type != CommandType::TransferFeedback) && (command_type != CommandType::TransferCreatePricePeg) && + (command_type != CommandType::TransferUpdatePricePeg); + bool expect_even = (min_args % 2 == 1); + if (command_supports_payment_id && ((expect_even ? 0 : 1) == local_args.size() % 2)) + { + payment_id_str = local_args.back(); + local_args.pop_back(); + + crypto::hash payment_id; + bool r = tools::wallet::parse_long_payment_id(payment_id_str, payment_id); + if (r) + { + std::string extra_nonce; + set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id); + r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + } + else + { + crypto::hash8 payment_id8; + r = tools::wallet::parse_short_payment_id(payment_id_str, payment_id8); + if (r) + { + std::string extra_nonce; + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8); + r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + } + } + + if (!r) + { + fail_msg_writer() << tr("payment id has invalid format, expected 16 or 64 character hex string: ") << payment_id_str; + return true; + } + payment_id_seen = true; + } + uint64_t safex_network_fee = 0; + + vector dsts; + + safex::safex_account my_safex_account = AUTO_VAL_INIT(my_safex_account); + if (command_type == CommandType::TransferCreateAccount || command_type == CommandType::TransferEditAccount) { + //use my own current subaddress as destination + cryptonote::address_parse_info info = AUTO_VAL_INIT(info); + std::string destination_addr = m_wallet->get_subaddress_as_str({m_current_subaddress_account, 0}); + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), destination_addr)) + { + fail_msg_writer() << tr("failed to parse address"); + return true; + } + + const std::string &sfx_username = local_args[0]; + if (!m_wallet->get_safex_account(sfx_username, my_safex_account)) { + fail_msg_writer() << tr("unknown safex account username"); + return true; + }; + + if (command_type == CommandType::TransferCreateAccount) + { + if (!crypto::check_key(my_safex_account.pkey)) { + fail_msg_writer() << tr("invalid account public key"); + return true; + } + + cryptonote::tx_destination_entry de_account = create_safex_account_destination(info.address, my_safex_account.username, my_safex_account.pkey, my_safex_account.account_data); + + dsts.push_back(de_account); + + //lock tokens for account creation + cryptonote::tx_destination_entry token_create_fee = AUTO_VAL_INIT(token_create_fee); + token_create_fee.addr = info.address; + token_create_fee.is_subaddress = info.is_subaddress; + token_create_fee.token_amount = SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE; + token_create_fee.output_type = tx_out_type::out_token; + dsts.push_back(token_create_fee); + } + else if (command_type == CommandType::TransferEditAccount) { + + std::ostringstream accdata_ostr; + std::copy(local_args.begin() + 1, local_args.end(), ostream_iterator(accdata_ostr, " ")); + const std::string accdata_str = accdata_ostr.str(); + std::vector new_accdata(accdata_str.begin(), accdata_str.end()-1); + if (new_accdata.size() == 0) { + fail_msg_writer() << tr("failed to parse account data"); + return false; + } + cryptonote::tx_destination_entry de_account_update = edit_safex_account_destination(info.address, my_safex_account.username, new_accdata); + + dsts.push_back(de_account_update); + + } + } + else if(command_type == CommandType::TransferCreateOffer || command_type == CommandType::TransferEditOffer){ + //use my own current subaddress as destination + cryptonote::address_parse_info info = AUTO_VAL_INIT(info); + std::string destination_addr = m_wallet->get_subaddress_as_str({m_current_subaddress_account, 0}); + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), destination_addr)) + { + fail_msg_writer() << tr("failed to parse address"); + return true; + } + + const std::string &sfx_username = local_args[0]; + if (!m_wallet->get_safex_account(sfx_username, my_safex_account)) { + fail_msg_writer() << tr("unknown safex account username"); + return true; + }; + + if (command_type == CommandType::TransferCreateOffer) { + + std::string offer_title = local_args[1]; + uint64_t price; + uint64_t quantity; + + try{ + + bool ok = cryptonote::parse_amount(price, local_args[2]); + if(!ok || price == 0) + { + fail_msg_writer() << tr("amount is wrong: ") << local_args[2] << + ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits::max()); + return true; + } + + quantity = stoull(local_args[3]); + + long double check_price = stold(local_args[2]); + long double check_quantity = stold(local_args[3]); + + if(check_price < 0 || check_quantity < 0){ + fail_msg_writer() << tr("Negative amount or quantity entered"); + return true; + } + } + catch(std::invalid_argument& e){ + fail_msg_writer() << tr("One of the arguments is missing. Please check needed arguments again."); + return true; + } + + std::ostringstream offerdata_ostr; + std::copy(local_args.begin() + 4, local_args.end(), ostream_iterator(offerdata_ostr, " ")); + std::string description = offerdata_ostr.str(); + + safex::safex_offer sfx_offer{offer_title, quantity, price, description, my_safex_account.username,m_wallet->get_account().get_keys().m_view_secret_key,m_wallet->get_account().get_keys().m_account_address}; + + std::string confirm = input_line(tr("Do you want to attach this offer to a price peg? (Y/Yes/N/No): ")); + if (!std::cin.eof() && command_line::is_yes(confirm)) { + if(!attach_price_peg(sfx_offer)) + return true; + } + if(sfx_offer.min_sfx_price < SAFEX_OFFER_MINIMUM_PRICE){ + fail_msg_writer() << tr("Minimum price is wrong: ") << print_money(sfx_offer.min_sfx_price) << + ", " << tr("expected number from ") << print_money(SAFEX_OFFER_MINIMUM_PRICE) << tr(" to ") << print_money(std::numeric_limits::max()); + return true; + } + + cryptonote::tx_destination_entry de_offer = create_safex_offer_destination(info.address, sfx_offer); + dsts.push_back(de_offer); + + } + else if (command_type == CommandType::TransferEditOffer) { + + crypto::hash offer_id_hash; + epee::string_tools::hex_to_pod(local_args[1], offer_id_hash); + + std::string offer_title = local_args[2]; + uint64_t price; + uint64_t quantity; + bool active; + + + try { + + bool ok = cryptonote::parse_amount(price, local_args[3]); + if(!ok || price == 0) + { + fail_msg_writer() << tr("amount is wrong: ") << local_args[3] << + ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits::max()); + return true; + } + + quantity = stoull(local_args[4]); + active = stoi(local_args[5]); + + long double check_price = stold(local_args[3]); + long double check_quantity = stold(local_args[4]); + int check_active = stoi(local_args[5]); + + if(check_price < 0 || check_quantity < 0 || (check_active != 1 && check_active != 0) ){ + fail_msg_writer() << tr("Negative amount, quantity, or active not 1 or 0 entered"); + return true; + } + + } + catch(std::invalid_argument& e){ + fail_msg_writer() << tr("One of the arguments is missing. Please check needed arguments again."); + return true; + } + + std::ostringstream offerdata_ostr; + std::copy(local_args.begin() + 6, local_args.end(), ostream_iterator(offerdata_ostr, " ")); + std::string description = offerdata_ostr.str(); + + safex::safex_offer sfx_offer{offer_title, quantity, price, std::vector{description.begin(),description.end()}, + offer_id_hash, my_safex_account.username, active, m_wallet->get_account().get_keys().m_account_address, m_wallet->get_account().get_keys().m_view_secret_key}; + + std::string confirm = input_line(tr("Do you want to attach this offer to a price peg? (Y/Yes/N/No): ")); + if (!std::cin.eof() && command_line::is_yes(confirm)) { + if(!attach_price_peg(sfx_offer)) + return true; + } + + if(sfx_offer.min_sfx_price < SAFEX_OFFER_MINIMUM_PRICE){ + fail_msg_writer() << tr("Minimum price is wrong: ") << print_money(sfx_offer.min_sfx_price) << + ", " << tr("expected number from ") << print_money(SAFEX_OFFER_MINIMUM_PRICE) << tr(" to ") << print_money(std::numeric_limits::max()); + return true; + } + + cryptonote::tx_destination_entry de_offer_update = edit_safex_offer_destination(info.address, sfx_offer); + dsts.push_back(de_offer_update); + + } + } + else if (command_type == CommandType::TransferPurchase) + { + crypto::hash purchase_offer_id{}; + std::vector offers = m_wallet->get_safex_offers(); + std::vector::iterator offer_to_purchase; + uint64_t quantity_to_purchase; + + if (!epee::string_tools::get_xtype_from_string(quantity_to_purchase, local_args.back())){ + fail_msg_writer() << tr("Bad quantity to purchase given!!!"); + return true; + } + local_args.pop_back(); + if(!epee::string_tools::hex_to_pod(local_args.back(), purchase_offer_id)){ + fail_msg_writer() << tr("Bad offer ID given!!!"); + return true; + } + + offer_to_purchase = std::find_if(offers.begin(), offers.end(), [purchase_offer_id](safex::safex_offer offer){ + return offer.offer_id == purchase_offer_id;}); + + if(offer_to_purchase!=offers.end()) + local_args.pop_back(); + else { + fail_msg_writer() << tr("There is no offer with given id!!"); + return true; + } + + cryptonote::tx_destination_entry de = AUTO_VAL_INIT(de); + + uint64_t sfx_price; + bool res = m_wallet->calculate_sfx_price(*offer_to_purchase, sfx_price); + if(!res) { + fail_msg_writer() << tr("Error calculating SFX price for purchase!!"); + return true; + } + + uint64_t total_sfx_to_pay = quantity_to_purchase*sfx_price; + + safex_network_fee = calculate_safex_network_fee(total_sfx_to_pay, m_wallet->nettype(), safex::command_t::simple_purchase); + + de.amount = total_sfx_to_pay - safex_network_fee; + de.output_type = tx_out_type::out_cash; + + cryptonote::address_parse_info info = AUTO_VAL_INIT(info); + cryptonote::tx_destination_entry de_purchase = AUTO_VAL_INIT(de_purchase); + std::string destination_addr = m_wallet->get_subaddress_as_str({m_current_subaddress_account, 0}); + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), destination_addr)) + { + fail_msg_writer() << tr("failed to parse address"); + return true; + } + //Purchase + safex::create_purchase_data safex_purchase_output_data{purchase_offer_id, offer_to_purchase->get_hash(), quantity_to_purchase, total_sfx_to_pay}; + blobdata blobdata = cryptonote::t_serializable_object_to_blob(safex_purchase_output_data); + de_purchase = tx_destination_entry{0, offer_to_purchase->seller_address, false, tx_out_type::out_safex_purchase, blobdata}; + dsts.push_back(de_purchase); + + //Feedback token + safex::safex_feedback_token safex_feedback_token_output_data; + safex_feedback_token_output_data.offer_id = purchase_offer_id; + cryptonote::tx_destination_entry de_feedback_token = AUTO_VAL_INIT(de_feedback_token); + de_feedback_token = create_safex_feedback_token_destination(info.address, safex_feedback_token_output_data); + dsts.push_back(de_feedback_token); + + de.addr = offer_to_purchase->seller_address; + + dsts.push_back(de); + } + else if (command_type == CommandType::TransferFeedback) + { + crypto::hash purchase_offer_id{}; + uint64_t stars_given; + std::string comment; + + cryptonote::address_parse_info info = AUTO_VAL_INIT(info); + std::string destination_addr = m_wallet->get_subaddress_as_str({m_current_subaddress_account, 0}); + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), destination_addr)) + { + fail_msg_writer() << tr("failed to parse address"); + return true; + } + + if(!epee::string_tools::hex_to_pod(local_args.front(), purchase_offer_id)){ + fail_msg_writer() << tr("Bad offer ID given!!!"); + return true; + } + local_args.erase(local_args.begin()); + + if (!epee::string_tools::get_xtype_from_string(stars_given, local_args.front())){ + fail_msg_writer() << tr("Bad stars rating format given!!!"); + return true; + } + + if((uint64_t)stars_given > 3){ + fail_msg_writer() << tr("Feedback rating can be from 0 to 3. given: ")<< stars_given; + return true; + } + + std::ostringstream comment_ostr; + std::copy(local_args.begin() + 1, local_args.end(), ostream_iterator(comment_ostr, " ")); + comment = comment_ostr.str(); + + safex::safex_feedback sfx_feedback{(uint8_t)stars_given,comment,purchase_offer_id}; + + + cryptonote::tx_destination_entry de = AUTO_VAL_INIT(de); + + tx_destination_entry de_feedback = create_safex_feedback_destination(info.address, sfx_feedback); + dsts.push_back(de_feedback); + } + else if(command_type == CommandType::TransferCreatePricePeg || command_type == CommandType::TransferUpdatePricePeg){ + //use my own current subaddress as destination + cryptonote::address_parse_info info = AUTO_VAL_INIT(info); + std::string destination_addr = m_wallet->get_subaddress_as_str({m_current_subaddress_account, 0}); + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), destination_addr)) + { + fail_msg_writer() << tr("failed to parse address"); + return true; + } + + const std::string &sfx_username = local_args[0]; + if (!m_wallet->get_safex_account(sfx_username, my_safex_account)) { + fail_msg_writer() << tr("unknown safex account username"); + return true; + }; + + if (command_type == CommandType::TransferCreatePricePeg) { + + std::string price_peg_title = local_args[1]; + std::string price_peg_currency = local_args[2]; + uint64_t rate; + + if(price_peg_currency.length() > SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE){ + fail_msg_writer() << tr("Currency must be equal or less than ") << SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE<(pricepeg_ostr, " ")); + std::string description = pricepeg_ostr.str(); + + safex::safex_price_peg sfx_price_peg{price_peg_title,sfx_username,price_peg_currency,description,rate}; + + cryptonote::tx_destination_entry de_price_peg = create_safex_price_peg_destination(info.address, sfx_price_peg); + dsts.push_back(de_price_peg); + + } else if (command_type == CommandType::TransferUpdatePricePeg) { + + crypto::hash price_peg_id_hash; + epee::string_tools::hex_to_pod(local_args[1], price_peg_id_hash); + + uint64_t rate; + + try { + rate = stod(local_args[2])*COIN; + } + catch(std::invalid_argument& e){ + fail_msg_writer() << tr("One of the arguments is missing. Please check needed arguments again."); + return true; + } + + safex::safex_price_peg sfx_price_peg{}; + + sfx_price_peg.price_peg_id = price_peg_id_hash; + sfx_price_peg.rate = rate; + + cryptonote::tx_destination_entry de_price_peg_update = update_safex_price_peg_destination(info.address, sfx_price_peg); + dsts.push_back(de_price_peg_update); + + } + } + else + { + + for (size_t i = 0; i < local_args.size(); i += 2) + { + cryptonote::address_parse_info info = AUTO_VAL_INIT(info); + cryptonote::tx_destination_entry de = AUTO_VAL_INIT(de); + + if (command_type == CommandType::TransferDonation) + { + //use my own address as destination + std::string destination_addr = m_wallet->get_subaddress_as_str({m_current_subaddress_account, 0}); + local_args.insert(local_args.begin() + i, destination_addr); + } + + if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[i], oa_prompter)) + { + fail_msg_writer() << tr("failed to parse address"); + return true; + } + de.addr = info.address; + de.is_subaddress = info.is_subaddress; + + if (info.has_payment_id) + { + if (payment_id_seen) + { + fail_msg_writer() << tr("a single transaction cannot use more than one payment id: ") << local_args[i]; + return true; + } + + std::string extra_nonce; + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id); + bool r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + if (!r) + { + fail_msg_writer() << tr("failed to set up payment id, though it was decoded correctly"); + return true; + } + payment_id_seen = true; + } + + uint64_t value_amount = 0; + + bool ok = cryptonote::parse_amount(value_amount, local_args[i + 1]); + if (!ok || 0 == value_amount) + { + fail_msg_writer() << tr("amount is wrong: ") << local_args[i] << ' ' << local_args[i + 1] << + ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits::max()); + return true; + } + + + if (command_type == CommandType::TransferStakeToken) + { + if (!tools::is_whole_token_amount(value_amount)) + { + fail_msg_writer() << tr("token amount must be whole number. ") << local_args[i] << ' ' << local_args[i + 1]; + return true; + } + + uint64_t minimum_tokens = safex::get_minimum_token_stake_amount(m_wallet->nettype()); + + if (value_amount < minimum_tokens) + { + fail_msg_writer() << tr("token amount must be at least. ") << print_money(minimum_tokens); + return true; + } + de.token_amount = value_amount; + de.script_output = true; + de.output_type = tx_out_type::out_staked_token; + } else if (command_type == CommandType::TransferUnstakeToken) + { + if (!tools::is_whole_token_amount(value_amount)) + { + fail_msg_writer() << tr("token amount must be whole number. ") << local_args[i] << ' ' << local_args[i + 1]; + return true; + } + de.token_amount = value_amount; + de.script_output = false; + de.output_type = tx_out_type::out_token; + } else if (command_type == CommandType::TransferDonation) + { + de.amount = value_amount; + de.script_output = true; + de.output_type = tx_out_type::out_network_fee; + } + // Allow to collect outputs for regular SFX transaction. + + dsts.push_back(de); + } + } + + // If its demo purchase, make special destination_entry for network fee. + if(command_type == CommandType::TransferPurchase) { + cryptonote::tx_destination_entry de_net_fee = AUTO_VAL_INIT(de_net_fee); + std::string destination_addr = m_wallet->get_subaddress_as_str({m_current_subaddress_account, 0}); + + cryptonote::address_parse_info info = AUTO_VAL_INIT(info); + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), destination_addr)) + { + fail_msg_writer() << tr("failed to parse address"); + return true; + } + + de_net_fee.addr = info.address; + de_net_fee.is_subaddress = info.is_subaddress; + de_net_fee.amount = safex_network_fee; + de_net_fee.script_output = true; + de_net_fee.output_type = tx_out_type::out_network_fee; + + dsts.push_back(de_net_fee); + } + + try + { + // figure out what tx will be necessary + std::vector ptx_vector; + uint64_t unlock_block = 0; + std::string err; + safex::command_t command = safex::command_t::nop; + switch (command_type) + { + case CommandType::TransferStakeToken: + command = safex::command_t::token_stake; + break; + + case CommandType::TransferUnstakeToken: + command = safex::command_t::token_unstake; + break; + + case CommandType::TransferPurchase: + command = safex::command_t::simple_purchase; + break; + + case CommandType::TransferDonation: + command = safex::command_t::donate_network_fee; + break; + + case CommandType::TransferCreateAccount: + command = safex::command_t::create_account; + break; + + case CommandType::TransferEditAccount: + command = safex::command_t::edit_account; + break; + + case CommandType::TransferCreateOffer: + command = safex::command_t::create_offer; + break; + + case CommandType::TransferEditOffer: + command = safex::command_t::edit_offer; + break; + + case CommandType::TransferFeedback: + command = safex::command_t::create_feedback; + break; + + case CommandType::TransferCreatePricePeg: + command = safex::command_t::create_price_peg; + break; + + case CommandType::TransferUpdatePricePeg: + command = safex::command_t::update_price_peg; + break; + + default: + LOG_ERROR("Unknown command method, using original"); + return true; + } + + + + + ptx_vector = m_wallet->create_transactions_advanced(command, dsts, fake_outs_count, unlock_block, priority, extra, m_current_subaddress_account, subaddr_indices, m_trusted_daemon, my_safex_account); + + + + if (ptx_vector.empty()) + { + fail_msg_writer() << tr("No outputs found, or daemon is not ready"); + return true; + } + + // if we need to check for backlog, check the worst case tx + if (m_wallet->confirm_backlog()) + { + std::stringstream prompt; + double worst_fee_per_byte = std::numeric_limits::max(); + for (size_t n = 0; n < ptx_vector.size(); ++n) + { + const uint64_t blob_size = cryptonote::tx_to_blob(ptx_vector[n].tx).size(); + const double fee_per_byte = ptx_vector[n].fee / (double) blob_size; + if (fee_per_byte < worst_fee_per_byte) + { + worst_fee_per_byte = fee_per_byte; + } + } + try + { + std::vector> nblocks = m_wallet->estimate_backlog({std::make_pair(worst_fee_per_byte, worst_fee_per_byte)}); + if (nblocks.size() != 1) + { + prompt << "Internal error checking for backlog. " << tr("Is this okay anyway? (Y/Yes/N/No): "); + } + else + { + if (nblocks[0].first > m_wallet->get_confirm_backlog_threshold()) + prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No): ")) % nblocks[0].first).str(); + } + } + catch (const std::exception &e) + { + prompt << tr("Failed to check for backlog: ") << e.what() << ENDL << tr("Is this okay anyway? (Y/Yes/N/No): "); + } + + std::string prompt_str = prompt.str(); + if (!prompt_str.empty()) + { + std::string accepted = input_line(prompt_str); + if (std::cin.eof()) + return true; + if (!command_line::is_yes(accepted)) + { + fail_msg_writer() << tr("transaction cancelled."); + + return true; + } + } + } + + // if more than one tx necessary, prompt user to confirm + if (m_wallet->always_confirm_transfers() || ptx_vector.size() > 1) + { + uint64_t total_sent = 0; + uint64_t total_token_sent = 0; + uint64_t total_fee = 0; + uint64_t dust_not_in_fee = 0; + uint64_t token_dust_not_in_fee = 0; + uint64_t dust_in_fee = 0; + for (size_t n = 0; n < ptx_vector.size(); ++n) + { + total_fee += ptx_vector[n].fee; + for (auto i: ptx_vector[n].selected_transfers) + { + total_sent += m_wallet->get_transfer_details(i).amount(); + total_token_sent += m_wallet->get_transfer_details(i).token_amount(); + } + total_sent -= ptx_vector[n].change_dts.amount + ptx_vector[n].fee; + total_token_sent -= ptx_vector[n].change_token_dts.token_amount; + + if (ptx_vector[n].dust_added_to_fee) + dust_in_fee += ptx_vector[n].dust; + else + dust_not_in_fee += ptx_vector[n].dust; + + token_dust_not_in_fee += ptx_vector[n].change_token_dts.token_amount; + } + + std::stringstream prompt; + for (size_t n = 0; n < ptx_vector.size(); ++n) + { + prompt << tr("\nTransaction ") << (n + 1) << "/" << ptx_vector.size() << ":\n"; + subaddr_indices.clear(); + for (uint32_t i : ptx_vector[n].construction_data.subaddr_indices) + subaddr_indices.insert(i); + + if (subaddr_indices.size() > 1) + prompt << tr("WARNING: Outputs of multiple addresses are being used together, which might potentially compromise your privacy.\n"); + } + + if (command_type == CommandType::TransferStakeToken) + prompt << boost::format(tr("Staking %s tokens. ")) % print_money(total_token_sent); + + + if (ptx_vector.size() > 1) + { + prompt << boost::format(tr("Your transaction needs to be split into %llu transactions. " + "This will result in a transaction fee being applied to each transaction, for a total fee of %s")) % + ((unsigned long long) ptx_vector.size()) % print_money(total_fee); + } + else + { + prompt << boost::format(tr("The transaction fee is %s. ")) % + print_money(total_fee); + } + 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 and %s tokens change will be sent to dust address ")) + % print_money(dust_not_in_fee) % print_money(token_dust_not_in_fee); + + if (m_wallet->print_ring_members()) + { + if (!print_ring_members(ptx_vector, prompt)) + return true; + } + bool default_ring_size = true; + for (const auto &ptx: ptx_vector) + { + for (const auto &vin: ptx.tx.vin) + { + if (vin.type() == typeid(txin_to_key)) + { + const txin_to_key &in_to_key = boost::get(vin); + if (in_to_key.key_offsets.size() != DEFAULT_MIX + 1) + default_ring_size = false; + } + } + } + if (m_wallet->confirm_non_default_ring_size() && !default_ring_size) + { + prompt << tr("\nWARNING: this is a non default ring size, which may harm your privacy. Default is recommended."); + } + prompt << ENDL << tr("Is this okay? (Y/Yes/N/No): "); + + std::string accepted = input_line(prompt.str()); + if (std::cin.eof()) + return true; + if (!command_line::is_yes(accepted)) + { + fail_msg_writer() << tr("transaction cancelled."); + + return true; + } + } + + if (m_wallet->watch_only()) + { + bool r = m_wallet->save_tx(ptx_vector, "unsigned_safex_tx"); + if (!r) + { + fail_msg_writer() << tr("Failed to write transaction(s) to file"); + } + else + { + success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "unsigned_safex_tx"; + } + } + else + { + commit_or_save(ptx_vector, m_do_not_relay); + } + } + catch (const std::exception &e) + { + handle_transfer_exception(std::current_exception(), m_trusted_daemon); + } + catch (...) + { + LOG_ERROR("unknown error"); + fail_msg_writer() << tr("unknown error"); + } + + if(command_type == CommandType::TransferDonation) { + success_msg_writer() << boost::format(tr("You successfully donated network!!! ")); + } + + + return true; + } + + bool simple_wallet::stake_token(const std::vector &args) + { + return create_command(CommandType::TransferStakeToken, args); + } + + bool simple_wallet::unstake_token(const std::vector &args) + { + return create_command(CommandType::TransferUnstakeToken, args); + } + + bool simple_wallet::donate_safex_fee(const std::vector &args) + { + return create_command(CommandType::TransferDonation, args); + } + + bool simple_wallet::staked_token_balance(const std::vector &args) + { + return false; + } + + bool simple_wallet::show_staked_token_balance_unlocked(bool detailed) + { + std::string extra; + success_msg_writer() << tr("Currently selected token account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0}); + const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account]; + success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag); + success_msg_writer() << tr("Staked token balance: ") << print_money(m_wallet->staked_token_balance(m_current_subaddress_account)) << ", " + << tr("unlocked staked token balance: ") << print_money(m_wallet->unlocked_staked_token_balance(m_current_subaddress_account)) << extra; + std::map token_balance_per_subaddress = m_wallet->staked_token_balance_per_subaddress(m_current_subaddress_account); + std::map unlocked_balance_per_subaddress = m_wallet->unlocked_staked_token_balance_per_subaddress(m_current_subaddress_account); + if (!detailed || token_balance_per_subaddress.empty()) + return true; + + success_msg_writer() << tr("Staked token balance per address:"); + success_msg_writer() << boost::format("%15s %21s %21s %7s %21s") % tr("Address") % tr("Balance") % tr("Unlocked balance") % tr("Outputs") % tr("Label"); + std::vector transfers; + m_wallet->get_transfers(transfers); + + for (const auto& i : token_balance_per_subaddress) + { + cryptonote::subaddress_index subaddr_index = {m_current_subaddress_account, i.first}; + std::string address_str = m_wallet->get_subaddress_as_str(subaddr_index).substr(0, 6); + uint64_t num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&subaddr_index](const tools::wallet::transfer_details& td) { return td.m_output_type == tx_out_type::out_staked_token && !td.m_spent && td.m_subaddr_index == subaddr_index; }); + success_msg_writer() << boost::format(tr("%8u %6s %21s %21s %7u %21s")) % i.first % address_str % print_money(i.second) % print_money(unlocked_balance_per_subaddress[i.first]) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index); + } + return true; + } + + bool simple_wallet::show_staked_token_balance(const std::vector &args/* = std::vector()*/) + { + if (args.size() > 1 || (args.size() == 1 && args[0] != "detail")) + { + fail_msg_writer() << tr("usage: balance_cash [detail]"); + return true; + } + LOCK_IDLE_SCOPE(); + show_staked_token_balance_unlocked(args.size() == 1); + return true; + } + + bool simple_wallet::safex_purchase(const std::vector& args) { + if (args.empty()) + { + success_msg_writer() << tr("usage:\n" + " safex_purchase [index=[,,...]] [] [] \n"); + return true; + } + return create_command(CommandType::TransferPurchase, args); + } + + bool simple_wallet::safex_feedback(const std::vector& args) { + if (args.empty()) + { + // print all the possible feedbacks to give + LOCK_IDLE_SCOPE(); + print_not_given_feedbacks(); + return true; + } + return create_command(CommandType::TransferFeedback, args); + } + + bool simple_wallet::list_offers(const std::vector& args) { + + + std::vector sfx_price_pegs = m_wallet->get_safex_price_pegs(); + + success_msg_writer() << tr(std::string(78,'#').c_str()) << tr(" Safex offers in the Blockchain ") << tr(std::string(77,'#').c_str()); + + success_msg_writer() << boost::format("#%|=20|#%|=20|#%|=20|#%|=30|#%|=20|#%|=70|#") % tr("Offer title") % tr("Price") % tr("Quantity") % tr("Seller") % tr("Description") %tr("Offer ID"); + success_msg_writer() << tr(std::string(1,'#').c_str()) << tr(std::string(185,'#').c_str()) << tr(std::string(1,'#').c_str()); + + bool first = false; + + + for (auto &offer: m_wallet->get_safex_offers()) { + + if(!offer.active || offer.quantity == 0) + continue; + + if(first) + success_msg_writer() << boost::format("#%|=20|#%|=20|#%|=20|#%|=30|#%|=20|#%|=70|#") % tr(std::string(20, '-').c_str()) % tr(std::string(20, '-').c_str()) + % tr(std::string(20, '-').c_str()) % tr(std::string(30, '-').c_str()) % tr(std::string(20, '-').c_str()) %tr(std::string(70, '-').c_str()); + + + first = true; + print_safex_offer(offer); + + } + success_msg_writer() << tr(std::string(1,'#').c_str()) << tr(std::string(185,'#').c_str()) << tr(std::string(1,'#').c_str()); + + return true; + } + + bool simple_wallet::list_price_pegs(const std::vector& args) { + + std::string currency = args.empty()?"":args[0]; + auto price_pegs = m_wallet->get_safex_price_pegs(currency); + + print_price_pegs(price_pegs); + + return true; + } + + void simple_wallet::print_price_pegs(const std::vector& price_pegs){ + success_msg_writer() << tr(std::string(81,'#').c_str()) << tr(" Safex price pegs in the Blockchain ") << tr(std::string(80,'#').c_str()); + + success_msg_writer() << boost::format("#%|=30|#%|=20|#%|=20|#%|=30|#%|=20|#%|=70|#") % tr("Price peg title") % tr("Currency") % tr("Rate") % tr("Creator") %tr("Description") %tr("Price peg ID"); + success_msg_writer() << tr(std::string(1,'#').c_str()) << tr(std::string(195,'#').c_str()) << tr(std::string(1,'#').c_str()); + + bool first = false; + + + for (auto price_peg: price_pegs) { + + if(first) + success_msg_writer() << boost::format("#%|=30|#%|=20|#%|=20|#%|=30|#%|=20|#%|=70|#") % tr(std::string(30, '-').c_str()) % tr(std::string(20, '-').c_str()) + % tr(std::string(20, '-').c_str()) % tr(std::string(30, '-').c_str()) % tr(std::string(20, '-').c_str()) %tr(std::string(70, '-').c_str()); + + first = true; + + print_safex_price_peg(price_peg); + } + success_msg_writer() << tr(std::string(1,'#').c_str()) << tr(std::string(195,'#').c_str()) << tr(std::string(1,'#').c_str()); + } + + void simple_wallet::print_not_given_feedbacks(){ + + auto offers = m_wallet->get_safex_offers(); + + success_msg_writer() << tr(std::string(31,'#').c_str()) << tr(" Safex feedbacks left to give for offers: ") << tr(std::string(30,'#').c_str()); + + success_msg_writer() << boost::format("#%|=20|#%|=80|#") % tr("Offer title") % tr("Offer ID"); + success_msg_writer() << boost::format("#%|=101|#") % std::string(101,'#'); + bool first = false; + for (auto &offer_id: m_wallet->get_my_safex_feedbacks_to_give()) { + + auto it = std::find_if(offers.begin(), offers.end(), [offer_id](const safex::safex_offer &sfx_offer) { + return offer_id == sfx_offer.offer_id; + }); + + if (first) + success_msg_writer() << boost::format("#%|=20|#%|=80|#") % std::string(20, '-') % std::string(80, '-'); + if (it != offers.end()) { + first = true; + success_msg_writer() << boost::format("#%|=20|#%|=80|#") % it->title % offer_id; + } + } + success_msg_writer() << boost::format("#%|=101|#") % std::string(101,'#'); + } + + bool simple_wallet::list_ratings(const std::vector& args) { + + crypto::hash offer_id; + if(args.empty() || !epee::string_tools::hex_to_pod(args.front(), offer_id)) { + fail_msg_writer() << tr("Bad offer ID given!!!"); + return true; + } + double avg_rating = 0; + success_msg_writer() << tr(std::string(72,'#').c_str()) << tr(" Safex rating for offer ") << tr(std::string(73,'#').c_str()); + success_msg_writer() << tr(std::string(50,'#').c_str()) << boost::format("%|=68|") % tr(args.front().c_str()) << tr(std::string(51,'#').c_str()); + success_msg_writer() << boost::format("#%|=6|#%|=160|#") % tr("Rating") %tr("Comment"); + success_msg_writer() << tr(std::string(169,'#').c_str()); + auto ratings = m_wallet->get_safex_ratings(offer_id); + bool first = false; + for (auto &rating: ratings) { + + if(first) + success_msg_writer() << boost::format("#%|=6|#%|=160|#") % tr(std::string(6, '-').c_str()) % tr(std::string(160, '-').c_str()); + first = true; + success_msg_writer() << boost::format("#%|=6|#%|=160|#") % (uint64_t)rating.stars_given % rating.comment; + avg_rating += rating.stars_given; + } + success_msg_writer() << tr(std::string(169,'#').c_str()); + + success_msg_writer() << boost::format("#AVG rating for this offer is : %|=10|%|=126|#") % (ratings.size()==0?avg_rating:avg_rating/ratings.size()) % tr(std::string(1,' ').c_str()); + success_msg_writer() << tr(std::string(169,'#').c_str()); + + return true; + } + + bool simple_wallet::attach_price_peg(safex::safex_offer& sfx_offer){ + std::string currency = input_line( + tr("For what currency do you want to attach your offer? (leave blank to list all price pegs in the BC): ")); + auto price_pegs = m_wallet->get_safex_price_pegs(currency); + if (price_pegs.empty()) { + fail_msg_writer() << tr("No price peg for given currency found!"); + return false; + } + + print_price_pegs(price_pegs); + + std::string price_peg_id_str = input_line(tr("Enter price peg ID to choose : ")); + + bool found = false; + crypto::hash price_peg_id; + if(!epee::string_tools::hex_to_pod(price_peg_id_str, price_peg_id)){ + fail_msg_writer() << tr("Bad price peg ID given!!!"); + return false; + } + + for (auto price_peg: price_pegs) + if(price_peg.price_peg_id == price_peg_id){ + currency = price_peg.currency; + found = true; + break; + } + if(!found){ + fail_msg_writer() << tr("No price peg from list selected!"); + return false; + } + + std::string prompt = "Enter price in "+currency+" : "; + std::string price_str = input_line(tr(prompt.c_str())); + uint64_t new_price; + + bool ok = cryptonote::parse_amount(new_price, price_str); + if(!ok || 0 == new_price) + { + fail_msg_writer() << tr("amount is wrong: ") << price_str << + ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits::max()); + return false; + } + + prompt = "Enter minimum SFX price : "; + std::string min_price_str = input_line(tr(prompt.c_str())); + uint64_t min_price; + + ok = cryptonote::parse_amount(min_price, min_price_str); + if(!ok || 0 == min_price) + { + fail_msg_writer() << tr("amount is wrong: ") << min_price_str << + ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits::max()); + return false; + } + sfx_offer.set_price_peg(price_peg_id,new_price,min_price); + + return true; + } + + bool simple_wallet::get_my_interest(const std::vector& args) + { + std::vector> interest_per_output; + uint64_t collected_interest = m_wallet->get_current_interest(interest_per_output); + + success_msg_writer() << tr("Collected interest so far is: ") << print_money(collected_interest); + success_msg_writer() << boost::format("%30s %20s") % tr("Output amount") % tr("Available interest"); + for(auto& pair : interest_per_output) + { + success_msg_writer() << boost::format("%30s %20s") % print_money(pair.first) % print_money(pair.second); + } + return true; + } + + void simple_wallet::print_safex_accounts() + { + success_msg_writer() << tr(std::string(56,'#').c_str()) << tr(" Safex accounts ") << tr(std::string(55,'#').c_str()); + success_msg_writer() << boost::format("#%|=30|#%|=80|#%|=13|#") % tr("Account Username") % tr("Account Data") % tr("Activated"); + success_msg_writer() << tr(std::string(127,'#').c_str()); + bool first = false; + + for (auto& acc: m_wallet->get_safex_accounts()) { + if(first) + success_msg_writer() << boost::format("#%|=30|#%|=80|#%|=13|#") % tr(std::string(30, '-').c_str()) % tr(std::string(80, '-').c_str()) % tr(std::string(13, '-').c_str()); + first=true; + uint8_t status = m_wallet->get_safex_account_status(acc); + std::string status_str = (status==0?"No":(status==1?"Pending":"Yes")); + + success_msg_writer() << boost::format("#%|=30|#%|=80|#%|=13|#") % acc.username % std::string(begin(acc.account_data), end(acc.account_data)) % status_str; + } + success_msg_writer() << tr(std::string(127,'#').c_str()); + + } + + void simple_wallet::print_safex_offer(safex::safex_offer& offer){ + + + uint64_t sfx_price; + bool res = m_wallet->calculate_sfx_price(offer,sfx_price); + + if(!res) + return; + + auto size_desc = offer.description.size(); + + uint64_t lines = size_desc / 20 + 1; + + auto desc = offer.description; + + uint64_t avaliable = size_desc > 20 ? 20: size_desc; + + for(uint64_t i = 0; i < lines; i++){ + if(i==lines/2) + success_msg_writer() << boost::format("#%|=20|#%|=20|#%|=20|#%|=30|#%|=20|#%|=70|#") % offer.title % print_money(sfx_price) % offer.quantity % offer.seller % + std::string(begin(desc), begin(desc)+avaliable) % offer.offer_id; + else + success_msg_writer() << boost::format("#%|=20|#%|=20|#%|=20|#%|=30|#%|=20|#%|=70|#") % " " % " " % " " % " " % + std::string(begin(desc), begin(desc)+avaliable) % " "; + desc = std::vector(desc.begin()+avaliable,desc.end()); + size_desc = size_desc - avaliable; + avaliable = size_desc > 20 ? 20: size_desc; + } + + + } + + void simple_wallet::print_safex_price_peg(safex::safex_price_peg& price_peg){ + + + auto size_desc = price_peg.description.size(); + + uint64_t lines = size_desc / 20 + 1; + + auto desc = price_peg.description; + + uint64_t avaliable = size_desc > 20 ? 20: size_desc; + + for(uint64_t i = 0; i < lines; i++){ + if(i==lines/2) + success_msg_writer() << boost::format("#%|=30|#%|=20|#%|=20|#%|=30|#%|=20|#%|=70|#") % price_peg.title % price_peg.currency % print_money(price_peg.rate)% price_peg.creator % + std::string(begin(desc), begin(desc)+avaliable) % price_peg.price_peg_id; + else + success_msg_writer() << boost::format("#%|=30|#%|=20|#%|=20|#%|=30|#%|=20|#%|=70|#") % " " % " " % " " % " " % + std::string(begin(desc), begin(desc)+avaliable) % " "; + desc = std::vector(desc.begin()+avaliable,desc.end()); + size_desc = size_desc - avaliable; + avaliable = size_desc > 20 ? 20: size_desc; + } + + + } + + + void simple_wallet::print_my_safex_offer(safex::safex_offer& offer, std::vector& price_pegs){ + + auto size_desc = offer.description.size(); + + uint64_t lines = size_desc / 20 + 1; + + auto desc = offer.description; + + uint64_t avaliable = size_desc > 20 ? 20: size_desc; + + auto price_peg_id = offer.price_peg_id; + + auto it = std::find_if(price_pegs.begin(), price_pegs.end(), [price_peg_id](const safex::safex_price_peg &sfx_price_peg) { return price_peg_id == sfx_price_peg.price_peg_id; }); + + std::string currency = "SFX"; + + if(it!=price_pegs.end()) + currency = it->currency; + + for(uint64_t i = 0; i < lines; i++){ + if(i==lines/2) + success_msg_writer() << boost::format("#%|=20|#%|=20|#%|=20|#%|=20|#%|=30|#%|=69|#%|=20|#%|=20|#%|=70|#%|=20|#") % offer.title % print_money(offer.price) % currency % offer.quantity % offer.seller % (offer.price_peg_used?epee::string_tools::pod_to_hex(offer.price_peg_id):"N/A") % print_money(offer.min_sfx_price) % + std::string(begin(desc), begin(desc)+avaliable) % offer.offer_id % (offer.active?"True":"False"); + else + success_msg_writer() << boost::format("#%|=20|#%|=20|#%|=20|#%|=20|#%|=30|#%|=69|#%|=20|#%|=20|#%|=70|#%|=20|#") % " " % " " % " " % " " % " " % " " % " " % + std::string(begin(desc), begin(desc)+avaliable) % " " % " "; + desc = std::vector(desc.begin()+avaliable,desc.end()); + size_desc = size_desc - avaliable; + avaliable = size_desc > 20 ? 20: size_desc; + } + + + } + + + void simple_wallet::print_my_safex_offers() { + success_msg_writer() << tr(std::string(153,'#').c_str()) << tr(" Safex offers ") << tr(std::string(153,'#').c_str()); + success_msg_writer() << boost::format("#%|=20|#%|=20|#%|=20|#%|=20|#%|=30|#%|=69|#%|=20|#%|=20|#%|=70|#%|=20|#") % tr("Offer title") % tr("Price") % tr("Currency") % tr("Quantity") % tr("Seller") % tr("Price peg") % tr("Minimum SFX price") % tr("Description") %tr("Offer ID") %tr("Active"); + success_msg_writer() << tr(std::string(320,'#').c_str()); + + bool first = false; + + auto price_pegs = m_wallet->get_safex_price_pegs(""); + + for (auto &offer: m_wallet->get_my_safex_offers()) { + + if(first) + success_msg_writer() << boost::format("#%|=20|#%|=20|#%|=20|#%|=20|#%|=30|#%|=69|#%|=20|#%|=20|#%|=70|#%|=20|#") % tr(std::string(20, '-').c_str()) % tr(std::string(20, '-').c_str()) % tr(std::string(20, '-').c_str()) + % tr(std::string(20, '-').c_str()) % tr(std::string(30, '-').c_str()) % tr(std::string(69, '-').c_str()) + % tr(std::string(20, '-').c_str()) % tr(std::string(20, '-').c_str()) %tr(std::string(70, '-').c_str()) %tr(std::string(20,'-').c_str()); + + first = true; + print_my_safex_offer(offer, price_pegs); + + } + success_msg_writer() << tr(std::string(320,'#').c_str()) ; + + } + + void simple_wallet::print_my_safex_price_pegs() { + success_msg_writer() << tr(std::string(104,'#').c_str()) << tr(" Safex price pegs ") << tr(std::string(104,'#').c_str()); + success_msg_writer() << boost::format("#%|=20|#%|=20|#%|=20|#%|=30|#%|=60|#%|=69|#") % "Price peg title" % "Currency" % "Rate" % "Creator" % "Description" % "Price peg ID"; + success_msg_writer() << tr(std::string(1,'#').c_str()) << tr(std::string(224,'#').c_str()) << tr(std::string(1,'#').c_str()); + + bool first = false; + + for(auto price_peg: m_wallet->get_my_safex_price_pegs()) { + + if(first) + success_msg_writer() << boost::format("#%|=20|#%|=20|#%|=20|#%|=30|#%|=60|#%|=69|#") % tr(std::string(20, '-').c_str()) % tr(std::string(20, '-').c_str()) % tr(std::string(20, '-').c_str()) % tr(std::string(30, '-').c_str()) % tr(std::string(60, '-').c_str()) %tr(std::string(69, '-').c_str()); + + first = true; + + success_msg_writer() << boost::format("#%|=20|#%|=20|#%|=20|#%|=30|#%|=60|#%|=69|#") % price_peg.title % price_peg.currency % + print_money(price_peg.rate) % price_peg.creator % + std::string(begin(price_peg.description), end(price_peg.description)) % price_peg.price_peg_id; + + } + success_msg_writer() << tr(std::string(226,'#').c_str()); + + } + + + bool simple_wallet::safex_account(const std::vector &args/* = std::vector()*/) + { + // Usage: + // safex_account + // safex_account new + // safex_account remove + // safex_account recover + // safex_account keys + // safex_account create [index=[,,...]] [] [] + // safex_account edit [index=[,,...]] [] [] + + if (args.empty()) + { + // print all the existing accounts + LOCK_IDLE_SCOPE(); + print_safex_accounts(); + return true; + } + + std::vector local_args = args; + std::string command = local_args[0]; + local_args.erase(local_args.begin()); + if (command == "new") + { + if (local_args.size() < 2){ + fail_msg_writer() << tr("usage: safex_account new "); + return true; + } + const std::string &username = local_args[0]; + + if(m_wallet->safex_account_exists(username)) { + fail_msg_writer() << tr("safex account username already exists in the Blockchain"); + return true; + } + + for(auto ch: username){ + if (!(std::islower(ch) || std::isdigit(ch)) && ch!='_' && ch!='-') { + fail_msg_writer() << tr("safex account username can only have lowercase letters, digits, _ and -"); + return true; + } + } + + + std::ostringstream accdata_ostr; + std::copy(local_args.begin() + 1, local_args.end(), ostream_iterator(accdata_ostr, " ")); + const std::string accdata_str = accdata_ostr.str(); + std::vector accdata(accdata_str.begin(), accdata_str.end()-1); + if (accdata.size() == 0) { + fail_msg_writer() << tr("failed to parse account data"); + return true; + } + + auto pass = get_and_verify_password(); + + if(!pass) + return true; + + if (m_wallet->generate_safex_account(username, accdata) && save_safex(pass->password()) ) { + success_msg_writer() << tr("New account created"); + } else { + fail_msg_writer() << tr("Failed to create account"); + } + } + else if (command == "remove") + { + const std::string &username = local_args[0]; + + safex::safex_account sfx_acc; + if (!m_wallet->get_safex_account(username, sfx_acc)) { + fail_msg_writer() << tr("Safex account does not exist: ") << username; + return true; + } + + + auto pass = get_and_verify_password(); + + if(!pass) + return true; + + if (m_wallet->remove_safex_account(username) && save_safex(pass->password()) ) { + success_msg_writer() << tr("Account removed"); + } else { + fail_msg_writer() << tr("Failed to remove account ") << username; + } + } + else if (command == "recover") + { + + if (local_args.size() != 2) { + fail_msg_writer() << tr("Please provide username and secret key for account recovery "); + return true; + } + + const std::string &username = local_args[0]; + const std::string &private_key = local_args[1]; + + + crypto::secret_key skey{}; + epee::string_tools::hex_to_pod(private_key, skey); + + auto pass = get_and_verify_password(); + + if(!pass) + return true; + + if (m_wallet->recover_safex_account(username, skey) && save_safex(pass->password()) ) { + success_msg_writer() << tr("Account recovered"); + } else { + fail_msg_writer() << tr("Failed to recover account ") << username; + } + } + else if (command == "keys") + { + if(local_args.size() != 1){ + fail_msg_writer() << tr("One Safex account username was not given"); + return true; + } + const std::string &username = local_args[0]; + + if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } + + safex::safex_account_keys keys = AUTO_VAL_INIT(keys); + if (m_wallet->get_safex_account_keys(username, keys)) { + success_msg_writer() << tr("Account ") << username<< tr(" keys:"); + success_msg_writer() << tr("Public key: ") << epee::string_tools::pod_to_hex(keys.m_public_key) ; + success_msg_writer() << tr("Secret key: ") << epee::string_tools::pod_to_hex(keys.m_secret_key) ; + + } else { + fail_msg_writer() << tr("Failed to print account keys ") << username; + } + } + else if (command == "create") + { + // create a new safex account transaction + return create_command(CommandType::TransferCreateAccount, local_args); + } + else if (command == "edit") + { + return create_command(CommandType::TransferEditAccount, local_args); + } + else + { + success_msg_writer() << tr("usage:\n" + " safex_account\n" + " safex_account new \n" + " safex_account remove \n" + " safex_account keys \n" + " safex_account recover \n" + " safex_account create [index=[,,...]] [] [] \n" + " safex_account edit [index=[,,...]] [] [] "); + } + return true; + } + + + bool simple_wallet::safex_offer(const std::vector &args){ + // Usage: + // safex_offer + // safex_offer create [index=[,,...]] [] [] + // safex_offer edit [index=[,,...]] [] [] + if (args.empty()) + { + // print all the existing offers + LOCK_IDLE_SCOPE(); + print_my_safex_offers(); + return true; + } + + std::vector local_args = args; + std::string command = local_args[0]; + local_args.erase(local_args.begin()); + if (command == "create") + { + // create a new safex offer transaction + return create_command(CommandType::TransferCreateOffer, local_args); + } + else if (command == "edit") + { + return create_command(CommandType::TransferEditOffer, local_args); + } + else + { + success_msg_writer() << tr("usage:\n" + " safex_offer\n" + " safex_offer create [index=[,,...]] [] [] \n" + " safex_offer edit [index=[,,...]] [] [] "); + + } + return true; + } + + bool simple_wallet::safex_price_peg(const std::vector &args){ + // Usage: + // safex_price_peg + // safex_price_peg create [index=[,,...]] [] [] + // safex_price_peg update [index=[,,...]] [] [] + if (args.empty()) + { + // print all the existing price pegs + LOCK_IDLE_SCOPE(); + print_my_safex_price_pegs(); + return true; + } + + std::vector local_args = args; + std::string command = local_args[0]; + local_args.erase(local_args.begin()); + if (command == "create") + { + // create a new safex price peg transaction + return create_command(CommandType::TransferCreatePricePeg, local_args); + } + else if (command == "update") + { + return create_command(CommandType::TransferUpdatePricePeg, local_args); + } + else + { + success_msg_writer() << tr("usage:\n" + " safex_price_peg\n" + " safex_price_peg create [index=[,,...]] [] [] \n" + " safex_price_peg update [index=[,,...]] [] [] "); + + } + return true; + } + //---------------------------------------------------------------------------------------------------- + void simple_wallet::on_advanced_output_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, const txout_to_script &txout, const cryptonote::subaddress_index& subaddr_index){ + if (txout.output_type == static_cast(tx_out_type::out_safex_account)) { + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string accusername(begin(account.username), end(account.username)); + message_writer(console_color_green, false) << "\r" << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Output of type account, username: ") << accusername << " received, " << + tr("idx ") << subaddr_index; + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_account_update)) { + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string accusername(begin(account.username), end(account.username)); + message_writer(console_color_green, false) << "\r" << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Updated for account, username: ") << accusername << " received, " << + tr("idx ") << subaddr_index; + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer)){ + safex::create_offer_data offer; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, offer); + safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price,offer.description,offer.offer_id, + std::string{offer.seller.begin(),offer.seller.end()},offer.active,offer.seller_address,offer.price_peg_used,offer.price_peg_id,offer.min_sfx_price}; + message_writer(console_color_green, false) << "\r" << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Updated for account, username: ") << sfx_offer.seller << ", " << + tr("Offer title: ") << sfx_offer.title << " received, " << + tr("idx ") << subaddr_index; + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer_update)){ + safex::edit_offer_data offer; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, offer); + safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price, + offer.description,offer.offer_id,std::string{offer.seller.begin(),offer.seller.end()}}; + message_writer(console_color_green, false) << "\r" << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Updated for account, username: ") << sfx_offer.seller << ", " << + tr(" Offer title: ") << sfx_offer.title << " update received, " << + tr("idx ") << subaddr_index; + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_purchase)){ + safex::create_purchase_data purchase_data; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, purchase_data); + safex::safex_offer my_offer = m_wallet->get_my_safex_offer(purchase_data.offer_id); + message_writer(console_color_blue, false) << "\r" << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Updated for account, username: ") << my_offer.seller << ", " << + tr("Purchased offer: ") << my_offer.title << " received, " << + tr("Quantity purchased: ") << purchase_data.quantity << ", " << + tr("idx ") << subaddr_index; + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback_token)){ + safex::create_feedback_token_data feedback_token; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, feedback_token); + message_writer(console_color_blue, false) << "\r" << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Feedback token received for offer: ") << feedback_token.offer_id << " received, " << + tr("idx ") << subaddr_index; + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback)){ + safex::create_feedback_data feedback; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, feedback); + std::string comment{feedback.comment.begin(),feedback.comment.end()}; + message_writer(console_color_blue, false) << "\r" << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Feedback sent received for offer: ") << feedback.offer_id << " received, " << + tr("Stars given: ") << (uint64_t)feedback.stars_given << ", " << + tr("Comment given: ") << comment << ", " << + tr("idx ") << subaddr_index; + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg)){ + safex::create_price_peg_data price_peg; + const cryptonote::blobdata pricepeggblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(pricepeggblob, price_peg); + std::string creator{price_peg.creator.begin(),price_peg.creator.end()}; + std::string title{price_peg.title.begin(),price_peg.title.end()}; + std::string currency{price_peg.currency.begin(),price_peg.currency.end()}; + message_writer(console_color_blue, false) << "\r" << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Price peg creation for account: ") << creator << " received, " << + tr("Price peg ID: ") << price_peg.price_peg_id << ", " << + tr("Price peg rate: ") << print_money(price_peg.rate) << ", " << + tr("Price peg currency: ") << currency << ", " << + tr("idx ") << subaddr_index; + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg_update)){ + safex::update_price_peg_data price_peg; + const cryptonote::blobdata pricepeggblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(pricepeggblob, price_peg); + message_writer(console_color_blue, false) << "\r" << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Price peg update for price peg ID: ") << price_peg.price_peg_id << ", " << + tr("Price peg rate: ") << print_money(price_peg.rate) << ", " << + tr("idx ") << subaddr_index; + } + + + + if (m_auto_refresh_refreshing) + m_cmd_binder.print_prompt(); + else + m_refresh_progress_reporter.update(height, true); + } +//---------------------------------------------------------------------------------------------------- + +} diff --git a/src/wallet/CMakeLists.txt b/src/wallet/CMakeLists.txt index dc5144a47..541c975d8 100644 --- a/src/wallet/CMakeLists.txt +++ b/src/wallet/CMakeLists.txt @@ -34,6 +34,7 @@ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(wallet_sources wallet.cpp + wallet_safex.cpp wallet_args.cpp ringdb.cpp node_rpc_proxy.cpp) @@ -70,7 +71,7 @@ target_link_libraries(wallet ${EXTRA_LIBRARIES}) set(wallet_rpc_sources - wallet_rpc_server.cpp) + wallet_rpc_server.cpp wallet_safex_rpc_server.cpp) set(wallet_rpc_headers) @@ -80,7 +81,7 @@ set(wallet_rpc_private_headers safex_private_headers(wallet_rpc_server ${wallet_rpc_private_headers}) -if (BUILD_WALLET_RPC) +if (NOT IOS) safex_add_executable(wallet_rpc_server ${wallet_rpc_sources} ${wallet_rpc_headers} @@ -117,6 +118,7 @@ if (BUILD_GUI_DEPS) wallet_api wallet multisig + safex_core cryptonote_core cryptonote_basic mnemonics diff --git a/src/wallet/api/CMakeLists.txt b/src/wallet/api/CMakeLists.txt index 15ebc04c4..3408e57c5 100644 --- a/src/wallet/api/CMakeLists.txt +++ b/src/wallet/api/CMakeLists.txt @@ -61,10 +61,22 @@ set(wallet_api_private_headers safex_private_headers(wallet_api ${wallet_api_private_headers}) -safex_add_library(wallet_api + + +if(DEPENDS AND MINGW) + add_library(wallet_api SHARED + ${wallet_api_sources} + ${wallet_api_headers} + ${wallet_api_private_headers}) + + set_target_properties(wallet_api PROPERTIES LINK_FLAGS "-Wl,--export-all-symbols") +else() + safex_add_library(wallet_api ${wallet_api_sources} ${wallet_api_headers} ${wallet_api_private_headers}) +endif() + target_link_libraries(wallet_api PUBLIC wallet @@ -82,8 +94,11 @@ target_link_libraries(wallet_api PRIVATE ${EXTRA_LIBRARIES}) -set_property(TARGET wallet_api PROPERTY EXCLUDE_FROM_ALL TRUE) -set_property(TARGET obj_wallet_api PROPERTY EXCLUDE_FROM_ALL TRUE) + +if(NOT DEPENDS) + set_property(TARGET wallet_api PROPERTY EXCLUDE_FROM_ALL TRUE) + set_property(TARGET obj_wallet_api PROPERTY EXCLUDE_FROM_ALL TRUE) +endif() if(IOS) set(lib_folder lib-${ARCH}) @@ -94,4 +109,7 @@ endif() install(FILES ${wallet_api_headers} DESTINATION include/wallet/api) -add_subdirectory(win_wrapper) \ No newline at end of file +if(DEPENDS AND MINGW) + install(TARGETS wallet_api + ARCHIVE DESTINATION ${lib_folder}) +endif() diff --git a/src/wallet/api/transaction_info.h b/src/wallet/api/transaction_info.h index 680e6c296..5e4f0e2ae 100644 --- a/src/wallet/api/transaction_info.h +++ b/src/wallet/api/transaction_info.h @@ -43,25 +43,25 @@ class TransactionInfoImpl : public TransactionInfo TransactionInfoImpl(); ~TransactionInfoImpl(); //! in/out - virtual int direction() const; + virtual int direction() const override; //! true if hold - virtual bool isPending() const; - virtual bool isFailed() const; - virtual uint64_t amount() const; - virtual uint64_t token_amount() const; + virtual bool isPending() const override; + virtual bool isFailed() const override; + virtual uint64_t amount() const override; + virtual uint64_t token_amount() const override; //! always 0 for incoming txes - virtual uint64_t fee() const; - virtual uint64_t blockHeight() const; - virtual std::set subaddrIndex() const; - virtual uint32_t subaddrAccount() const; - virtual std::string label() const; + virtual uint64_t fee() const override; + virtual uint64_t blockHeight() const override; + virtual std::set subaddrIndex() const override; + virtual uint32_t subaddrAccount() const override; + virtual std::string label() const override; - virtual std::string hash() const; - virtual std::time_t timestamp() const; - virtual std::string paymentId() const; - virtual const std::vector &transfers() const; - virtual uint64_t confirmations() const; - virtual uint64_t unlockTime() const; + virtual std::string hash() const override; + virtual std::time_t timestamp() const override; + virtual std::string paymentId() const override; + virtual const std::vector &transfers() const override; + virtual uint64_t confirmations() const override; + virtual uint64_t unlockTime() const override; virtual TransactionType transactionType() const override; private: diff --git a/src/wallet/api/wallet.cpp b/src/wallet/api/wallet.cpp index 5eac82bbb..80d1546d8 100644 --- a/src/wallet/api/wallet.cpp +++ b/src/wallet/api/wallet.cpp @@ -214,6 +214,127 @@ struct WalletCallbackImpl : public tools::i_wallet_callback } } + virtual void on_advanced_output_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, const cryptonote::txout_to_script &txout, const cryptonote::subaddress_index& subaddr_index) { + + std::string tx_hash = epee::string_tools::pod_to_hex(txid); + + if (txout.output_type == static_cast(tx_out_type::out_safex_account)) { + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string accusername(begin(account.username), end(account.username)); + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Output of type account, username: ") << accusername << " received, " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_account_update)) { + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string accusername(begin(account.username), end(account.username)); + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Updated for account, username: ") << accusername << " received, " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer)){ + safex::create_offer_data offer; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, offer); + safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price,offer.description,offer.offer_id, + std::string{offer.seller.begin(),offer.seller.end()},offer.active,offer.seller_address,offer.price_peg_used,offer.price_peg_id,offer.min_sfx_price}; + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Updated for account, username: ") << sfx_offer.seller << ", " << + tr("Offer title: ") << sfx_offer.title << " received, " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer_update)){ + safex::edit_offer_data offer; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, offer); + safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price, + offer.description,offer.offer_id,std::string{offer.seller.begin(),offer.seller.end()}}; + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Updated for account, username: ") << sfx_offer.seller << ", " << + tr(" Offer title: ") << sfx_offer.title << " update received, " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_purchase)){ + safex::create_purchase_data purchase_data; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, purchase_data); + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Purchased offer: ") << purchase_data.offer_id << " received, " << + tr("Quantity purchased: ") << purchase_data.quantity << ", " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback_token)){ + safex::create_feedback_token_data feedback_token; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, feedback_token); + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Feedback token received for offer: ") << feedback_token.offer_id << " received, " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback)){ + safex::create_feedback_data feedback; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, feedback); + std::string comment{feedback.comment.begin(),feedback.comment.end()}; + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Feedback sent received for offer: ") << feedback.offer_id << " received, " << + tr("Stars given: ") << feedback.stars_given << ", " << + tr("Comment given: ") << comment << ", " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg)){ + safex::create_price_peg_data price_peg; + const cryptonote::blobdata pricepeggblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(pricepeggblob, price_peg); + std::string creator{price_peg.creator.begin(),price_peg.creator.end()}; + std::string title{price_peg.title.begin(),price_peg.title.end()}; + std::string currency{price_peg.currency.begin(),price_peg.currency.end()}; + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Price peg creation for account: ") << creator << " received, " << + tr("Price peg ID: ") << price_peg.price_peg_id << ", " << + tr("Price peg rate: ") << print_money(price_peg.rate) << ", " << + tr("Price peg currency: ") << currency << ", " << + tr("idx ") << subaddr_index); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg_update)){ + safex::update_price_peg_data price_peg; + const cryptonote::blobdata pricepeggblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(pricepeggblob, price_peg); + LOG_PRINT_L3(__FUNCTION__ << + tr("Height ") << height << ", " << + tr("txid ") << txid << ", " << + tr("Price peg update for price peg ID: ") << price_peg.price_peg_id << ", " << + tr("Price peg rate: ") << print_money(price_peg.rate) << ", " << + tr("idx ") << subaddr_index); + } + // do not signal on advanced tx if wallet is not syncronized completely + if (m_listener && m_wallet->synchronized()) + { + m_listener->advancedReceived(tx_hash, static_cast(txout.output_type)); + m_listener->updated(); + } + } + virtual void on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx) { // TODO; @@ -626,6 +747,7 @@ bool WalletImpl::recoverFromKeysWithPassword(const std::string &path, } m_recoveringFromSeed= true; //Slow sync wallet + m_password = password; } catch (const std::exception& e) { @@ -694,6 +816,7 @@ bool WalletImpl::recover(const std::string &path, const std::string &password, c try { m_wallet->set_seed_language(old_language); m_wallet->generate(path, password, recovery_key, true, false); + m_password = password; } catch (const std::exception &e) { m_status = Status_Critical; @@ -913,6 +1036,16 @@ uint64_t WalletImpl::unlockedTokenBalance(uint32_t accountIndex) const return m_wallet->unlocked_token_balance(accountIndex); } +uint64_t WalletImpl::stakedTokenBalance(uint32_t accountIndex) const +{ + return m_wallet->staked_token_balance(accountIndex); +} + +uint64_t WalletImpl::unlockedStakedTokenBalance(uint32_t accountIndex) const +{ + return m_wallet->unlocked_staked_token_balance(accountIndex); +} + uint64_t WalletImpl::blockChainHeight() const { if(m_wallet->light_wallet()) { @@ -1251,13 +1384,15 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const cryptonote::tx_destination_entry de; if (tx_type == TransactionType::TokenTransaction) { - if (!tools::is_whole_coin_amount(*value_amount)) { + if (!tools::is_whole_token_amount(*value_amount)) { THROW_WALLET_EXCEPTION(tools::error::not_whole_token_amount, *value_amount); } de.token_amount = *value_amount; de.token_transaction = true; + de.output_type = cryptonote::tx_out_type::out_token; } else { de.amount = *value_amount; + de.output_type = cryptonote::tx_out_type::out_cash; } de.addr = info.address; @@ -1295,7 +1430,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const m_errorString = (boost::format(tr("failed to get random outputs to mix: %s")) % e.what()).str(); m_status = Status_Error; - } catch (const tools::error::not_enough_unlocked_money& e) { + } catch (const tools::error::not_enough_unlocked_cash& e) { m_status = Status_Error; std::ostringstream writer; @@ -1304,7 +1439,7 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const print_money(e.tx_amount()); m_errorString = writer.str(); - } catch (const tools::error::not_enough_money& e) { + } catch (const tools::error::not_enough_cash& e) { m_status = Status_Error; std::ostringstream writer; @@ -1372,6 +1507,646 @@ PendingTransaction *WalletImpl::createTransaction(const string &dst_addr, const return transaction; } + +bool WalletImpl::createSafexAccount(const std::string& username, const std::vector& description){ + + if(m_wallet->safex_account_exists(username)) { + return false; + } + + if (m_wallet->generate_safex_account(username, description)) { + m_wallet->store_safex(m_password); + return true; + } else { + return false; + } + + return true; +} + +std::vector WalletImpl::getSafexAccounts() { + + std::vector sfx_accounts; + + for (auto& acc: m_wallet->get_safex_accounts()) { + safex::safex_account_keys keys = AUTO_VAL_INIT(keys); + std::string data{acc.account_data.begin(),acc.account_data.end()}; + m_wallet->get_safex_account_keys(acc.username, keys); + std::string pubKey = epee::string_tools::pod_to_hex(keys.m_public_key); + std::string secKey = epee::string_tools::pod_to_hex(keys.m_secret_key); + uint8_t acc_status = m_wallet->get_safex_account_status(acc); + + sfx_accounts.emplace_back(acc.username,data,pubKey,secKey,acc_status); + } + + return sfx_accounts; +} + +SafexAccount WalletImpl::getSafexAccount(const std::string& username){ + + safex::safex_account sfx_account; + safex::safex_account_keys keys = AUTO_VAL_INIT(keys); + + auto res = m_wallet->get_safex_account(username,sfx_account); + if(!res) + return SafexAccount{}; + + std::string data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + m_wallet->get_safex_account_keys(username, keys); + std::string pubKey = epee::string_tools::pod_to_hex(keys.m_public_key); + std::string secKey = epee::string_tools::pod_to_hex(keys.m_secret_key); + uint8_t acc_status = m_wallet->get_safex_account_status(sfx_account); + + return SafexAccount{sfx_account.username,data,pubKey,secKey,acc_status}; + +} + +bool WalletImpl::recoverSafexAccount(const std::string& username, const std::string& private_key){ + + crypto::secret_key skey{}; + epee::string_tools::hex_to_pod(private_key, skey); + + if (m_wallet->recover_safex_account(username, skey)) { + m_wallet->store_safex(m_password); + return true; + } else { + return false; + } + return true; +} + +bool WalletImpl::removeSafexAccount(const std::string& username){ + + if (m_wallet->remove_safex_account(username)) { + m_wallet->store_safex(m_password); + return true; + } + + return false; +} + +std::vector WalletImpl::getMySafexOffers(){ + + auto price_pegs = m_wallet->get_safex_price_pegs(""); + + + std::vector offers; + for(auto &offer: m_wallet->get_my_safex_offers()){ + auto price_peg_id = offer.price_peg_id; + std::string currency = "SFX"; + + auto it = std::find_if(price_pegs.begin(), price_pegs.end(), [price_peg_id](const safex::safex_price_peg &sfx_price_peg) { return price_peg_id == sfx_price_peg.price_peg_id; }); + std::string offerID = epee::string_tools::pod_to_hex(offer.offer_id); + std::string pricePegID = epee::string_tools::pod_to_hex(offer.price_peg_id); + if(it!=price_pegs.end()) + currency = it->currency; + + offers.emplace_back(offer.title,offer.quantity,offer.price,offer.min_sfx_price, std::string{offer.description.begin(),offer.description.end()}, + offer.active, offer.price_peg_used, offerID, offer.seller, pricePegID, currency); + } + + return offers; +} + +std::vector WalletImpl::listSafexOffers(bool active){ + std::vector offers; + std::string currency = "SFX"; + + for (auto &offer: m_wallet->get_safex_offers()) + if(!active || offer.active){ + uint64_t sfx_price; + bool res = m_wallet->calculate_sfx_price(offer,sfx_price); + if(!res) + continue; + std::string offerID = epee::string_tools::pod_to_hex(offer.offer_id); + std::string pricePegID = epee::string_tools::pod_to_hex(offer.price_peg_id); + + offers.emplace_back(offer.title,offer.quantity,sfx_price,offer.min_sfx_price, std::string{offer.description.begin(),offer.description.end()}, + offer.active, offer.price_peg_used, offerID, offer.seller, pricePegID, currency); + } + return offers; +} + +uint64_t WalletImpl::getMyInterest(std::vector>& interest_per_output){ + + return m_wallet->get_current_interest(interest_per_output); +} + + +PendingTransaction * WalletImpl::createAdvancedTransaction(const string &dst_addr, const string &payment_id, optional value_amount, uint32_t mixin_count, + PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices, AdvancedCommand& advancedCommnand){ + + clearStatus(); + // Pause refresh thread while creating transaction + pauseRefresh(); + + + cryptonote::address_parse_info info; + + size_t fake_outs_count = mixin_count > 0 ? mixin_count : m_wallet->default_mixin(); + + uint32_t adjusted_priority = m_wallet->adjust_priority(static_cast(priority)); + + PendingTransactionImpl * transaction = new PendingTransactionImpl(*this); + + do { + + std::vector extra; + // if dst_addr is not an integrated address, parse payment_id + if (!info.has_payment_id && !payment_id.empty()) { + // copy-pasted from simplewallet.cpp:2212 + crypto::hash payment_id_long; + bool r = tools::wallet::parse_long_payment_id(payment_id, payment_id_long); + if (r) { + std::string extra_nonce; + cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id_long); + r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + } else { + r = tools::wallet::parse_short_payment_id(payment_id, info.payment_id); + if (r) { + std::string extra_nonce; + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id); + r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + } + } + + if (!r) { + m_status = Status_Error; + m_errorString = tr("payment id has invalid format, expected 16 or 64 character hex string: ") + payment_id; + break; + } + } + else if (info.has_payment_id) { + std::string extra_nonce; + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id); + bool r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + if (!r) { + m_status = Status_Error; + m_errorString = tr("Failed to add short payment id: ") + epee::string_tools::pod_to_hex(info.payment_id); + break; + } + } + + + //std::vector ptx_vector; + + try { + + vector dsts; + cryptonote::tx_destination_entry de; + safex::safex_account my_safex_account = AUTO_VAL_INIT(my_safex_account); + uint64_t unlock_block = 0; + safex::command_t command = safex::command_t::nop; + + std::string destination_addr = m_wallet->get_subaddress_as_str({subaddr_account, 0}); + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), destination_addr)) { + m_status = Status_Error; + m_errorString = tr("Failed to parse address"); + break; + } + + + if(advancedCommnand.m_transaction_type == TransactionType::CreateAccountTransaction) { + + Safex::CreateAccountCommand sfxAccount = static_cast(advancedCommnand); + + if (!m_wallet->get_safex_account(sfxAccount.m_username, my_safex_account)) { + m_status = Status_Error; + m_errorString = tr("Unknown safex account username"); + break; + }; + if (!crypto::check_key(my_safex_account.pkey)) { + m_status = Status_Error; + m_errorString = tr("Invalid account public key"); + break; + } + cryptonote::tx_destination_entry de_account = create_safex_account_destination(info.address, my_safex_account.username, my_safex_account.pkey, my_safex_account.account_data); + dsts.push_back(de_account); + + //lock tokens for account creation + cryptonote::tx_destination_entry token_create_fee = AUTO_VAL_INIT(token_create_fee); + token_create_fee.addr = info.address; + token_create_fee.is_subaddress = info.is_subaddress; + token_create_fee.token_amount = SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE; + token_create_fee.output_type = tx_out_type::out_token; + dsts.push_back(token_create_fee); + + uint64_t bc_height = m_wallet->get_blockchain_current_height(); + unlock_block = bc_height + safex::get_safex_minumum_account_create_token_lock_period(m_wallet->nettype()); + command = safex::command_t::create_account; + } + else if(advancedCommnand.m_transaction_type == TransactionType::EditAccountTransaction) { + + Safex::EditAccountCommand sfxAccount = static_cast(advancedCommnand); + + if (!m_wallet->get_safex_account(sfxAccount.m_username, my_safex_account)) { + m_status = Status_Error; + m_errorString = tr("Unknown safex account username"); + break; + }; + if (!crypto::check_key(my_safex_account.pkey)) { + m_status = Status_Error; + m_errorString = tr("Invalid account public key"); + break; + } + + std::vector new_accdata(sfxAccount.m_data.begin(), sfxAccount.m_data.end()); + + cryptonote::tx_destination_entry de_account_update = edit_safex_account_destination(info.address, my_safex_account.username, new_accdata); + dsts.push_back(de_account_update); + + command = safex::command_t::edit_account; + } + else if(advancedCommnand.m_transaction_type == TransactionType::CreateOfferTransaction) { + + Safex::CreateOfferCommand sfxOffer = static_cast(advancedCommnand); + if (!m_wallet->get_safex_account(sfxOffer.m_username, my_safex_account)) { + m_status = Status_Error; + m_errorString = tr("Unknown safex account username"); + break; + } + if (!crypto::check_key(my_safex_account.pkey)) { + m_status = Status_Error; + m_errorString = tr("Invalid account public key"); + break; + } + + safex::safex_offer sfx_offer{sfxOffer.m_offer_title, sfxOffer.m_quantity, sfxOffer.m_price, + sfxOffer.m_description, my_safex_account.username, + m_wallet->get_account().get_keys().m_view_secret_key, + m_wallet->get_account().get_keys().m_account_address}; + + if (sfxOffer.m_price_peg_used) { + crypto::hash price_peg_id; + if(!epee::string_tools::hex_to_pod(sfxOffer.m_price_peg_id, price_peg_id)){ + m_status = Status_Error; + m_errorString = tr("Bad price peg ID given"); + break; + } + sfx_offer.set_price_peg(price_peg_id, sfxOffer.m_price, sfxOffer.m_min_sfx_price); + } + + if (sfxOffer.m_min_sfx_price < SAFEX_OFFER_MINIMUM_PRICE) { + m_status = Status_Error; + m_errorString = tr("Wrong minimum SFX price"); + break; + } + + cryptonote::tx_destination_entry de_offer = create_safex_offer_destination(info.address, sfx_offer); + dsts.push_back(de_offer); + + command = safex::command_t::create_offer; + } + else if(advancedCommnand.m_transaction_type == TransactionType::EditOfferTransaction) { + + Safex::EditOfferCommand sfxOffer = static_cast(advancedCommnand); + if (!m_wallet->get_safex_account(sfxOffer.m_username, my_safex_account)) { + m_status = Status_Error; + m_errorString = tr("Unknown safex account username"); + break; + }; + if (!crypto::check_key(my_safex_account.pkey)) { + m_status = Status_Error; + m_errorString = tr("Invalid account public key"); + break; + } + + crypto::hash offer_id_hash; + if(!epee::string_tools::hex_to_pod(sfxOffer.m_offer_id, offer_id_hash)){ + m_status = Status_Error; + m_errorString = tr("Bad offer ID given"); + break; + } + + std::vector new_offerdata(sfxOffer.m_description.begin(), sfxOffer.m_description.end()); + + safex::safex_offer sfx_offer{sfxOffer.m_offer_title, sfxOffer.m_quantity, sfxOffer.m_price, + new_offerdata, offer_id_hash, my_safex_account.username, sfxOffer.m_active, + m_wallet->get_account().get_keys().m_account_address, + m_wallet->get_account().get_keys().m_view_secret_key}; + + if (sfxOffer.m_price_peg_used) { + crypto::hash price_peg_id; + if(!epee::string_tools::hex_to_pod(sfxOffer.m_price_peg_id, price_peg_id)){ + m_status = Status_Error; + m_errorString = tr("Bad price peg ID given"); + break; + } + sfx_offer.set_price_peg(price_peg_id, sfxOffer.m_price, sfxOffer.m_min_sfx_price); + } + + if (sfxOffer.m_min_sfx_price < SAFEX_OFFER_MINIMUM_PRICE) { + m_status = Status_Error; + m_errorString = tr("Wrong minimum SFX price"); + break; + } + + cryptonote::tx_destination_entry de_offer_update = edit_safex_offer_destination(info.address, sfx_offer); + dsts.push_back(de_offer_update); + + command = safex::command_t::edit_offer; + } + else if(advancedCommnand.m_transaction_type == TransactionType::StakeTokenTransaction) { + + Safex::StakeTokenCommand stakeToken = static_cast(advancedCommnand); + if (!tools::is_whole_token_amount(*value_amount)) + { + m_status = Status_Error; + m_errorString = tr("Token amount must be whole number."); + break; + } + + uint64_t minimum_tokens = safex::get_minimum_token_stake_amount(m_wallet->nettype()); + + if (*value_amount < minimum_tokens) + { + m_status = Status_Error; + m_errorString = tr("Token amount must be at least ") + print_money(minimum_tokens); + break; + } + + de.addr = info.address; + de.is_subaddress = info.is_subaddress; + de.token_amount = *value_amount; + de.script_output = true; + de.output_type = tx_out_type::out_staked_token; + dsts.push_back(de); + + command = safex::command_t::token_stake; + } + else if(advancedCommnand.m_transaction_type == TransactionType::UnstakeTokenTransaction) { + + Safex::UnstakeTokenCommand stakeToken = static_cast(advancedCommnand); + if (!tools::is_whole_token_amount(*value_amount)) + { + m_status = Status_Error; + m_errorString = tr("Token amount must be whole number."); + break; + } + + de.addr = info.address; + de.is_subaddress = info.is_subaddress; + de.token_amount = *value_amount; + de.script_output = true; + de.output_type = tx_out_type::out_token; + fake_outs_count = 0; + dsts.push_back(de); + + command = safex::command_t::token_unstake; + } + else if(advancedCommnand.m_transaction_type == TransactionType::CreatePricePegTransaction) { + + Safex::CreatePricePegCommand createPricePeg = static_cast(advancedCommnand); + + const std::string &sfx_username = createPricePeg.m_creator; + if (!m_wallet->get_safex_account(sfx_username, my_safex_account)) { + m_status = Status_Error; + m_errorString = tr("Unknown Safex account username"); + break; + } + + if(createPricePeg.m_currency.length() > SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE){ + m_status = Status_Error; + m_errorString = tr("Currency must be equal or less than ") + std::to_string(SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE) + tr(" characters!"); + break; + } + + uint64_t rate = createPricePeg.m_rate*COIN; + safex::safex_price_peg sfx_price_peg{createPricePeg.m_title,sfx_username,createPricePeg.m_currency,createPricePeg.m_description, rate}; + + cryptonote::tx_destination_entry de_price_peg = create_safex_price_peg_destination(info.address, sfx_price_peg); + dsts.push_back(de_price_peg); + + command = safex::command_t::create_price_peg; + } + else if(advancedCommnand.m_transaction_type == TransactionType::UpdatePricePegTransaction) { + + Safex::UpdatePricePegCommand updatePricePeg = static_cast(advancedCommnand); + crypto::hash price_peg_id; + + if(!epee::string_tools::hex_to_pod(updatePricePeg.m_price_peg_id, price_peg_id)){ + m_status = Status_Error; + m_errorString = tr("Failed to parse price peg id"); + break; + } + + const std::string &sfx_username = updatePricePeg.m_creator; + if (!m_wallet->get_safex_account(sfx_username, my_safex_account)) { + m_status = Status_Error; + m_errorString = tr("Unknown Safex account username"); + break; + } + + if(updatePricePeg.m_currency.length() > SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE){ + m_status = Status_Error; + m_errorString = tr("Currency must be equal or less than ") + std::to_string(SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE) + tr(" characters!"); + break; + } + + uint64_t rate = updatePricePeg.m_rate*COIN; + std::vector description_arg{updatePricePeg.m_description.begin(),updatePricePeg.m_description.end()}; + + safex::safex_price_peg sfx_price_peg{updatePricePeg.m_title,sfx_username,updatePricePeg.m_currency,description_arg,price_peg_id,rate}; + + cryptonote::tx_destination_entry de_price_peg_update = update_safex_price_peg_destination(info.address, sfx_price_peg); + dsts.push_back(de_price_peg_update); + + command = safex::command_t::update_price_peg; + } + else if(advancedCommnand.m_transaction_type == TransactionType::PurchaseTransaction) { + + Safex::PurchaseCommand safexPurchase = static_cast(advancedCommnand); + + crypto::hash purchase_offer_id{}; + std::vector offers = m_wallet->get_safex_offers(); + std::vector::iterator offer_to_purchase; + + uint64_t safex_network_fee = 0; + + if(!epee::string_tools::hex_to_pod(safexPurchase.m_offer_id, purchase_offer_id)){ + m_status = Status_Error; + m_errorString = tr("Bad offer ID given"); + break; + } + + offer_to_purchase = std::find_if(offers.begin(), offers.end(), [purchase_offer_id](safex::safex_offer offer){ + return offer.offer_id == purchase_offer_id;}); + + if(offer_to_purchase==offers.end()) { + m_status = Status_Error; + m_errorString = tr("There is no offer with given id!!"); + break; + } + + uint64_t sfx_price; + bool res = m_wallet->calculate_sfx_price(*offer_to_purchase, sfx_price); + if(!res) { + m_status = Status_Error; + m_errorString = tr("Error calculating SFX price for purchase!!"); + break; + } + + uint64_t total_sfx_to_pay = safexPurchase.m_quantity_to_purchase*sfx_price; + + safex_network_fee = calculate_safex_network_fee(total_sfx_to_pay, m_wallet->nettype(), safex::command_t::simple_purchase); + + de.amount = total_sfx_to_pay - safex_network_fee; + de.output_type = tx_out_type::out_cash; + + cryptonote::tx_destination_entry de_purchase = AUTO_VAL_INIT(de_purchase); + //Purchase + safex::create_purchase_data safex_purchase_output_data{purchase_offer_id, offer_to_purchase->get_hash(), safexPurchase.m_quantity_to_purchase, total_sfx_to_pay}; + blobdata blobdata = cryptonote::t_serializable_object_to_blob(safex_purchase_output_data); + de_purchase = tx_destination_entry{0, offer_to_purchase->seller_address, false, tx_out_type::out_safex_purchase, blobdata}; + dsts.push_back(de_purchase); + + //Feedback token + safex::safex_feedback_token safex_feedback_token_output_data; + safex_feedback_token_output_data.offer_id = purchase_offer_id; + cryptonote::tx_destination_entry de_feedback_token = AUTO_VAL_INIT(de_feedback_token); + de_feedback_token = create_safex_feedback_token_destination(info.address, safex_feedback_token_output_data); + dsts.push_back(de_feedback_token); + + de.addr = offer_to_purchase->seller_address; + + dsts.push_back(de); + + cryptonote::tx_destination_entry de_net_fee = AUTO_VAL_INIT(de_net_fee); + + de_net_fee.addr = info.address; + de_net_fee.is_subaddress = info.is_subaddress; + de_net_fee.amount = safex_network_fee; + de_net_fee.script_output = true; + de_net_fee.output_type = tx_out_type::out_network_fee; + + dsts.push_back(de_net_fee); + + command = safex::command_t::simple_purchase; + } + else if(advancedCommnand.m_transaction_type == TransactionType::FeedbackTransaction) { + + Safex::FeedbackCommand safexFeedback = static_cast(advancedCommnand); + + crypto::hash feedback_offer_id{}; + + if(!epee::string_tools::hex_to_pod(safexFeedback.m_offer_id, feedback_offer_id)){ + m_status = Status_Error; + m_errorString = tr("Bad offer ID given"); + break; + } + + + if(safexFeedback.m_stars_given > 3){ + m_status = Status_Error; + m_errorString = tr("Feedback rating can be from 0 to 3"); + break; + } + + safex::safex_feedback sfx_feedback{(uint8_t)safexFeedback.m_stars_given,safexFeedback.m_comment,feedback_offer_id}; + + tx_destination_entry de_feedback = create_safex_feedback_destination(info.address, sfx_feedback); + dsts.push_back(de_feedback); + + command = safex::command_t::create_feedback; + } + + transaction->m_pending_tx = m_wallet->create_transactions_advanced(command, dsts, fake_outs_count, unlock_block, priority, extra, subaddr_account, subaddr_indices, m_trustedDaemon, my_safex_account); + + } catch (const tools::error::daemon_busy&) { + // TODO: make it translatable with "tr"? + m_errorString = tr("daemon is busy. Please try again later."); + m_status = Status_Error; + } catch (const tools::error::no_connection_to_daemon&) { + m_errorString = tr("no connection to daemon. Please make sure daemon is running."); + m_status = Status_Error; + } catch (const tools::error::wallet_rpc_error& e) { + m_errorString = tr("RPC error: ") + e.to_string(); + m_status = Status_Error; + } catch (const tools::error::not_whole_token_amount &e) { + m_errorString = (boost::format(tr("failed to send token decimal amount: %s")) % e.what()).str(); + m_status = Status_Error; + } catch (const tools::error::get_random_outs_error &e) { + m_errorString = (boost::format(tr("failed to get random outputs to mix: %s")) % e.what()).str(); + m_status = Status_Error; + + } catch (const tools::error::not_enough_unlocked_cash& e) { + m_status = Status_Error; + std::ostringstream writer; + + writer << boost::format(tr("not enough money to transfer, available only %s, sent amount %s")) % + print_money(e.available()) % + print_money(e.tx_amount()); + m_errorString = writer.str(); + + } catch (const tools::error::not_enough_cash& e) { + m_status = Status_Error; + std::ostringstream writer; + + writer << boost::format(tr("not enough money to transfer, overall balance only %s, sent amount %s")) % + print_money(e.available()) % + print_money(e.tx_amount()); + m_errorString = writer.str(); + + } catch (const tools::error::tx_not_possible& e) { + m_status = Status_Error; + std::ostringstream writer; + + writer << boost::format(tr("not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee)")) % + print_money(e.available()) % + print_money(e.tx_amount() + e.fee()) % + print_money(e.tx_amount()) % + print_money(e.fee()); + m_errorString = writer.str(); + + } catch (const tools::error::not_enough_outs_to_mix& e) { + std::ostringstream writer; + writer << tr("not enough outputs for specified ring size") << " = " << (e.mixin_count() + 1) << ":"; + for (const std::pair outs_for_amount : e.scanty_outs()) { + writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.first) << ", " << tr("found outputs to use") << " = " << outs_for_amount.second; + } + writer << "\n" << tr("Please sweep unmixable outputs."); + m_errorString = writer.str(); + m_status = Status_Error; + } catch (const tools::error::tx_not_constructed&) { + m_errorString = tr("transaction was not constructed"); + m_status = Status_Error; + } catch (const tools::error::tx_rejected& e) { + std::ostringstream writer; + writer << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); + m_errorString = writer.str(); + m_status = Status_Error; + } catch (const tools::error::tx_sum_overflow& e) { + m_errorString = e.what(); + m_status = Status_Error; + } catch (const tools::error::zero_destination&) { + m_errorString = tr("one of destinations is zero"); + m_status = Status_Error; + } catch (const tools::error::tx_too_big& e) { + m_errorString = tr("failed to find a suitable way to split transactions"); + m_status = Status_Error; + } catch (const tools::error::transfer_error& e) { + m_errorString = string(tr("unknown transfer error: ")) + e.what(); + m_status = Status_Error; + } catch (const tools::error::wallet_internal_error& e) { + m_errorString = string(tr("internal error: ")) + e.what(); + m_status = Status_Error; + } catch (const std::exception& e) { + m_errorString = string(tr("unexpected error: ")) + e.what(); + m_status = Status_Error; + } catch (...) { + m_errorString = tr("unknown error"); + m_status = Status_Error; + } + } while (false); + + transaction->m_status = m_status; + transaction->m_errorString = m_errorString; + // Resume refresh thread + startRefresh(); + return transaction; + +}; + PendingTransaction *WalletImpl::createSweepUnmixableTransaction() { @@ -1399,7 +2174,7 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction() m_errorString = tr("failed to get random outputs to mix"); m_status = Status_Error; - } catch (const tools::error::not_enough_unlocked_money& e) { + } catch (const tools::error::not_enough_unlocked_cash& e) { m_status = Status_Error; std::ostringstream writer; @@ -1408,7 +2183,7 @@ PendingTransaction *WalletImpl::createSweepUnmixableTransaction() print_money(e.tx_amount()); m_errorString = writer.str(); - } catch (const tools::error::not_enough_money& e) { + } catch (const tools::error::not_enough_cash& e) { m_status = Status_Error; std::ostringstream writer; diff --git a/src/wallet/api/wallet.h b/src/wallet/api/wallet.h index ebfa15466..99f4647e7 100644 --- a/src/wallet/api/wallet.h +++ b/src/wallet/api/wallet.h @@ -58,7 +58,7 @@ class WalletImpl : public Wallet bool create(const std::string &path, const std::string &password, const std::string &language); bool createWatchOnly(const std::string &path, const std::string &password, - const std::string &language) const; + const std::string &language) const override; bool open(const std::string &path, const std::string &password); bool recover(const std::string &path,const std::string &password, const std::string &seed); @@ -78,105 +78,125 @@ class WalletImpl : public Wallet const std::string &viewkey_string, const std::string &spendkey_string = ""); bool close(bool store = true); - std::string seed() const; - std::string getSeedLanguage() const; - void setSeedLanguage(const std::string &arg); + std::string seed() const override; + std::string getSeedLanguage() const override; + void setSeedLanguage(const std::string &arg) override; // void setListener(Listener *) {} - int status() const; - std::string errorString() const; - bool setPassword(const std::string &password); - std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const; - std::string integratedAddress(const std::string &payment_id) const; - std::string secretViewKey() const; - std::string publicViewKey() const; - std::string secretSpendKey() const; - std::string publicSpendKey() const; - std::string path() const; - bool store(const std::string &path); - std::string filename() const; - std::string keysFilename() const; - bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false); - bool connectToDaemon(); - ConnectionStatus connected() const; - void setTrustedDaemon(bool arg); - bool trustedDaemon() const; - uint64_t balance(uint32_t accountIndex = 0) const; - uint64_t unlockedBalance(uint32_t accountIndex = 0) const; - uint64_t tokenBalance(uint32_t accountIndex = 0) const; - uint64_t unlockedTokenBalance(uint32_t accountIndex = 0) const; - uint64_t blockChainHeight() const; - uint64_t approximateBlockChainHeight() const; - uint64_t daemonBlockChainHeight() const; - uint64_t daemonBlockChainTargetHeight() const; - bool synchronized() const; - bool refresh(); - void refreshAsync(); + int status() const override; + std::string errorString() const override; + bool setPassword(const std::string &password) override; + std::string address(uint32_t accountIndex = 0, uint32_t addressIndex = 0) const override; + std::string integratedAddress(const std::string &payment_id) const override; + std::string secretViewKey() const override; + std::string publicViewKey() const override; + std::string secretSpendKey() const override; + std::string publicSpendKey() const override; + std::string path() const override; + bool store(const std::string &path) override; + std::string filename() const override; + std::string keysFilename() const override; + bool init(const std::string &daemon_address, uint64_t upper_transaction_size_limit = 0, const std::string &daemon_username = "", const std::string &daemon_password = "", bool use_ssl = false, bool lightWallet = false) override; + bool connectToDaemon() override; + ConnectionStatus connected() const override; + void setTrustedDaemon(bool arg) override; + bool trustedDaemon() const override; + uint64_t balance(uint32_t accountIndex = 0) const override; + uint64_t unlockedBalance(uint32_t accountIndex = 0) const override; + uint64_t tokenBalance(uint32_t accountIndex = 0) const override; + uint64_t unlockedTokenBalance(uint32_t accountIndex = 0) const override; + uint64_t stakedTokenBalance(uint32_t accountIndex = 0) const override; + uint64_t unlockedStakedTokenBalance(uint32_t accountIndex = 0) const override; + uint64_t blockChainHeight() const override; + uint64_t approximateBlockChainHeight() const override; + uint64_t daemonBlockChainHeight() const override; + uint64_t daemonBlockChainTargetHeight() const override; + bool synchronized() const override; + bool refresh() override; + void refreshAsync() override; bool rescanBlockchain() override; void rescanBlockchainAsync() override; - void setAutoRefreshInterval(int millis); - int autoRefreshInterval() const; - void setRefreshFromBlockHeight(uint64_t refresh_from_block_height); - uint64_t getRefreshFromBlockHeight() const { return m_wallet->get_refresh_from_block_height(); }; - void setRecoveringFromSeed(bool recoveringFromSeed); - bool watchOnly() const; - bool rescanSpent(); - NetworkType nettype() const {return static_cast(m_wallet->nettype());} - void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const; - bool useForkRules(uint8_t version, int64_t early_blocks) const; - - void addSubaddressAccount(const std::string& label); - size_t numSubaddressAccounts() const; - size_t numSubaddresses(uint32_t accountIndex) const; - void addSubaddress(uint32_t accountIndex, const std::string& label); - std::string getSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex) const; - void setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label); + void setAutoRefreshInterval(int millis) override; + int autoRefreshInterval() const override; + void setRefreshFromBlockHeight(uint64_t refresh_from_block_height) override; + uint64_t getRefreshFromBlockHeight() const override{ return m_wallet->get_refresh_from_block_height(); }; + void setRecoveringFromSeed(bool recoveringFromSeed) override; + bool watchOnly() const override; + bool rescanSpent() override; + NetworkType nettype() const override{return static_cast(m_wallet->nettype());} + void hardForkInfo(uint8_t &version, uint64_t &earliest_height) const override; + bool useForkRules(uint8_t version, int64_t early_blocks) const override; + + void addSubaddressAccount(const std::string& label) override; + size_t numSubaddressAccounts() const override; + size_t numSubaddresses(uint32_t accountIndex) const override; + void addSubaddress(uint32_t accountIndex, const std::string& label) override; + std::string getSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex) const override; + void setSubaddressLabel(uint32_t accountIndex, uint32_t addressIndex, const std::string &label) override; PendingTransaction * createTransaction(const std::string &dst_addr, const std::string &payment_id, optional value_amount, uint32_t mixin_count, PendingTransaction::Priority priority = PendingTransaction::Priority_Low, uint32_t subaddr_account = 0, std::set subaddr_indices = {}, - const TransactionType tx_type = TransactionType::CashTransaction); - virtual PendingTransaction * createSweepUnmixableTransaction(); - bool submitTransaction(const std::string &fileName); - virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename); - bool exportKeyImages(const std::string &filename); - bool importKeyImages(const std::string &filename); - - virtual void disposeTransaction(PendingTransaction * t); - virtual TransactionHistory * history(); - virtual AddressBook * addressBook(); - virtual Subaddress * subaddress(); - virtual SubaddressAccount * subaddressAccount(); - virtual void setListener(WalletListener * l); - virtual uint32_t defaultMixin() const; - virtual void setDefaultMixin(uint32_t arg); - virtual bool setUserNote(const std::string &txid, const std::string ¬e); - virtual std::string getUserNote(const std::string &txid) const; - virtual std::string getTxKey(const std::string &txid) const; - virtual bool checkTxKey(const std::string &txid, std::string tx_key, const std::string &address, uint64_t &received_cash, uint64_t &received_token, bool &in_pool, uint64_t &confirmations); - virtual std::string getTxProof(const std::string &txid, const std::string &address, const std::string &message) const; - virtual bool checkTxProof(const std::string &txid, const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &received_cash, uint64_t &received_token, bool &in_pool, uint64_t &confirmations); - virtual std::string getSpendProof(const std::string &txid, const std::string &message) const; - virtual bool checkSpendProof(const std::string &txid, const std::string &message, const std::string &signature, bool &good) const; - virtual std::string getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const; - virtual bool checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent, uint64_t& token_total, uint64_t& token_spent) const; - virtual std::string signMessage(const std::string &message); - virtual bool verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const; - virtual void startRefresh(); - virtual void pauseRefresh(); - virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &cash_amount, uint64_t& token_amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error); - virtual std::string getDefaultDataDir() const; - virtual bool lightWalletLogin(bool &isNewWallet) const; - virtual bool lightWalletImportWalletRequest(std::string &payment_id, uint64_t &fee, bool &new_request, bool &request_fulfilled, std::string &payment_address, std::string &status); - virtual bool blackballOutputs(const std::vector &pubkeys, bool add); - virtual bool unblackballOutput(const std::string &pubkey); - virtual bool getRing(const std::string &key_image, std::vector &ring) const; - virtual bool getRings(const std::string &txid, std::vector>> &rings) const; - virtual bool setRing(const std::string &key_image, const std::vector &ring, bool relative); - virtual void segregatePreForkOutputs(bool segregate); - virtual void segregationHeight(uint64_t height); - virtual void keyReuseMitigation2(bool mitigation); + const TransactionType tx_type = TransactionType::CashTransaction) override; + + + //Safex account realted functions + bool createSafexAccount(const std::string& username, const std::vector& description) override; + std::vector getSafexAccounts() override; + SafexAccount getSafexAccount(const std::string& username) override; + bool recoverSafexAccount(const std::string& username, const std::string& private_key) override; + bool removeSafexAccount(const std::string& username) override; + + //Safex offer realted functions + std::vector getMySafexOffers() override; + std::vector listSafexOffers(bool active) override; + + uint64_t getMyInterest(std::vector>& interest_per_output) override; + + PendingTransaction * createAdvancedTransaction(const std::string &dst_addr, const std::string &payment_id, optional value_amount, uint32_t mixin_count, + PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices, AdvancedCommand& advancedCommnand) override; + + virtual PendingTransaction * createSweepUnmixableTransaction() override; + bool submitTransaction(const std::string &fileName) override; + virtual UnsignedTransaction * loadUnsignedTx(const std::string &unsigned_filename) override; + bool exportKeyImages(const std::string &filename) override; + bool importKeyImages(const std::string &filename) override; + + virtual void disposeTransaction(PendingTransaction * t) override; + virtual TransactionHistory * history() override; + virtual AddressBook * addressBook() override; + virtual Subaddress * subaddress() override; + virtual SubaddressAccount * subaddressAccount() override; + virtual void setListener(WalletListener * l) override; + virtual uint32_t defaultMixin() const override; + virtual void setDefaultMixin(uint32_t arg) override; + virtual bool setUserNote(const std::string &txid, const std::string ¬e) override; + virtual std::string getUserNote(const std::string &txid) const override; + virtual std::string getTxKey(const std::string &txid) const override; + virtual bool checkTxKey(const std::string &txid, std::string tx_key, const std::string &address, uint64_t &received_cash, uint64_t &received_token, bool &in_pool, uint64_t &confirmations) override; + virtual std::string getTxProof(const std::string &txid, const std::string &address, const std::string &message) const override; + virtual bool checkTxProof(const std::string &txid, const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &received_cash, uint64_t &received_token, bool &in_pool, uint64_t &confirmations) override; + virtual std::string getSpendProof(const std::string &txid, const std::string &message) const override; + virtual bool checkSpendProof(const std::string &txid, const std::string &message, const std::string &signature, bool &good) const override; + virtual std::string getReserveProof(bool all, uint32_t account_index, uint64_t amount, const std::string &message) const override; + virtual bool checkReserveProof(const std::string &address, const std::string &message, const std::string &signature, bool &good, uint64_t &total, uint64_t &spent, uint64_t& token_total, uint64_t& token_spent) const override; + virtual std::string signMessage(const std::string &message) override; + virtual bool verifySignedMessage(const std::string &message, const std::string &address, const std::string &signature) const override; + virtual void startRefresh() override; + virtual void pauseRefresh() override; + virtual bool parse_uri(const std::string &uri, std::string &address, std::string &payment_id, uint64_t &cash_amount, uint64_t& token_amount, std::string &tx_description, std::string &recipient_name, std::vector &unknown_parameters, std::string &error) override; + virtual std::string getDefaultDataDir() const override; + virtual bool lightWalletLogin(bool &isNewWallet) const override; + virtual bool lightWalletImportWalletRequest(std::string &payment_id, uint64_t &fee, bool &new_request, bool &request_fulfilled, std::string &payment_address, std::string &status) override; + virtual bool blackballOutputs(const std::vector &pubkeys, bool add) override; + virtual bool unblackballOutput(const std::string &pubkey) override; + virtual bool getRing(const std::string &key_image, std::vector &ring) const override; + virtual bool getRings(const std::string &txid, std::vector>> &rings) const override; + virtual bool setRing(const std::string &key_image, const std::vector &ring, bool relative) override; + virtual void segregatePreForkOutputs(bool segregate) override; + virtual void segregationHeight(uint64_t height) override; + virtual void keyReuseMitigation2(bool mitigation) override; private: void clearStatus() const; diff --git a/src/wallet/api/wallet_api.h b/src/wallet/api/wallet_api.h index 9832ac0b1..e57a41448 100644 --- a/src/wallet/api/wallet_api.h +++ b/src/wallet/api/wallet_api.h @@ -51,7 +51,17 @@ enum NetworkType : uint8_t { enum class TransactionType { CashTransaction = 0, TokenTransaction = 1, - MigrationTransaction = 2 + MigrationTransaction = 2, + StakeTokenTransaction = 3, + UnstakeTokenTransaction = 4, + PurchaseTransaction = 5, + CreateAccountTransaction = 6, + EditAccountTransaction = 7, + CreateOfferTransaction = 8, + EditOfferTransaction = 9, + FeedbackTransaction = 10, + CreatePricePegTransaction = 11, + UpdatePricePegTransaction = 12 }; namespace Utils { @@ -110,6 +120,145 @@ struct PendingTransaction virtual std::vector> subaddrIndices() const = 0; }; + +/** + * @brief Advanced Safex commands + */ +struct AdvancedCommand{ + TransactionType m_transaction_type; +}; + + +struct CreateAccountCommand : public AdvancedCommand +{ +public: + CreateAccountCommand():AdvancedCommand{TransactionType::CreateAccountTransaction}{} + CreateAccountCommand(const std::string& _username):AdvancedCommand{TransactionType::CreateAccountTransaction},m_username{_username}{} + + std::string m_username; +}; + +struct EditAccountCommand : public AdvancedCommand +{ +public: + EditAccountCommand():AdvancedCommand{TransactionType::EditAccountTransaction}{} + EditAccountCommand(const std::string& _username, const std::string& _data):AdvancedCommand{TransactionType::EditAccountTransaction},m_username{_username},m_data{_data}{} + + std::string m_username; + std::string m_data; +}; + +struct CreateOfferCommand : public AdvancedCommand +{ +public: + CreateOfferCommand():AdvancedCommand{TransactionType::CreateOfferTransaction}{} + CreateOfferCommand(const std::string& _username, const std::string& _offer_title, const uint64_t _price, const uint64_t _quantity, const std::string& _descritpion, bool _price_peg_used = false, const std::string& _price_peg_id = "", const uint64_t _min_sfx_price = 0):AdvancedCommand{TransactionType::CreateOfferTransaction}, + m_username{_username},m_offer_title{_offer_title},m_price{_price},m_quantity{_quantity},m_description{_descritpion},m_price_peg_used{_price_peg_used}, m_price_peg_id{_price_peg_id}, m_min_sfx_price{_price}{ + if(_price_peg_used) + m_min_sfx_price = _min_sfx_price; + } + + std::string m_username = ""; + std::string m_offer_title = ""; + uint64_t m_price = 0; + uint64_t m_quantity = 0; + std::string m_description = ""; + bool m_price_peg_used = false; + std::string m_price_peg_id = ""; + uint64_t m_min_sfx_price = 0; +}; + + struct EditOfferCommand : public AdvancedCommand + { + public: + EditOfferCommand():AdvancedCommand{TransactionType::EditOfferTransaction}{} + EditOfferCommand(const std::string& _offer_id, const std::string& _username, bool _active, const std::string& _offer_title, const uint64_t _price, const uint64_t _quantity, const std::string& _descritpion, bool _price_peg_used = false, const std::string& _price_peg_id = "", const uint64_t _min_sfx_price = 0):AdvancedCommand{TransactionType::EditOfferTransaction}, + m_offer_id{_offer_id},m_username{_username},m_active{_active},m_offer_title{_offer_title},m_price{_price},m_quantity{_quantity},m_description{_descritpion},m_price_peg_used{_price_peg_used}, m_price_peg_id{_price_peg_id}, m_min_sfx_price{_price}{ + if(_price_peg_used) + m_min_sfx_price = _min_sfx_price; + } + + std::string m_offer_id = ""; + std::string m_username = ""; + std::string m_offer_title = ""; + uint64_t m_price = 0; + uint64_t m_quantity = 0; + std::string m_description = ""; + bool m_price_peg_used = false; + std::string m_price_peg_id = ""; + uint64_t m_min_sfx_price = 0; + bool m_active = true; + }; + +struct StakeTokenCommand : public AdvancedCommand +{ +public: + StakeTokenCommand():AdvancedCommand{TransactionType::StakeTokenTransaction}{} + StakeTokenCommand(const std::string& _address, const uint64_t _token_amount):AdvancedCommand{TransactionType::StakeTokenTransaction},m_token_amount{_token_amount},m_address{_address}{} + + uint64_t m_token_amount; + std::string m_address; +}; + +struct UnstakeTokenCommand : public AdvancedCommand +{ +public: + UnstakeTokenCommand():AdvancedCommand{TransactionType::UnstakeTokenTransaction}{} + UnstakeTokenCommand(const std::string& _address, const uint64_t _token_amount):AdvancedCommand{TransactionType::UnstakeTokenTransaction},m_token_amount{_token_amount},m_address{_address}{} + + uint64_t m_token_amount; + std::string m_address; +}; + + struct CreatePricePegCommand : public AdvancedCommand + { + public: + CreatePricePegCommand():AdvancedCommand{TransactionType::CreatePricePegTransaction}{} + CreatePricePegCommand(const std::string& _title, const std::string& _creator, const std::string& _description, const std::string& _currency, const double _rate):AdvancedCommand{TransactionType::CreatePricePegTransaction}, + m_title{_title},m_creator{_creator},m_description{_description},m_currency{_currency},m_rate{_rate}{} + + std::string m_title = ""; + std::string m_creator = ""; + std::string m_description = ""; + std::string m_currency = ""; + double m_rate = 0; + }; + +struct UpdatePricePegCommand : public AdvancedCommand +{ +public: + UpdatePricePegCommand():AdvancedCommand{TransactionType::UpdatePricePegTransaction}{} + UpdatePricePegCommand(const std::string& _price_peg_ig, const std::string& _title, const std::string& _creator, const std::string& _description, const std::string& _currency, const double _rate):AdvancedCommand{TransactionType::UpdatePricePegTransaction}, + m_price_peg_id{_price_peg_ig},m_title{_title},m_creator{_creator},m_description{_description},m_currency{_currency},m_rate{_rate}{} + std::string m_price_peg_id = ""; + std::string m_title = ""; + std::string m_creator = ""; + std::string m_description = ""; + std::string m_currency = ""; + double m_rate = 0; +}; + +struct PurchaseCommand : public AdvancedCommand +{ +public: + PurchaseCommand():AdvancedCommand{TransactionType::PurchaseTransaction}{} + PurchaseCommand(const std::string& _offer_id, const uint64_t _quantity__to_purchase):AdvancedCommand{TransactionType::PurchaseTransaction}, + m_offer_id{_offer_id},m_quantity_to_purchase{_quantity__to_purchase}{} + std::string m_offer_id = ""; + uint64_t m_quantity_to_purchase = 0; +}; + +struct FeedbackCommand : public AdvancedCommand +{ +public: + FeedbackCommand():AdvancedCommand{TransactionType::FeedbackTransaction}{} + FeedbackCommand(const std::string& _offer_id, const uint64_t _stars_given, const std::string& _comment):AdvancedCommand{TransactionType::FeedbackTransaction}, + m_offer_id{_offer_id},m_stars_given{_stars_given},m_comment{_comment}{} + std::string m_offer_id = ""; + uint64_t m_stars_given = 0; + std::string m_comment = ""; +}; + /** * @brief Transaction-like interface for sending money */ @@ -197,6 +346,74 @@ struct TransactionHistory virtual void refresh() = 0; }; +struct SafexAccount { +public: + SafexAccount(){} + SafexAccount(const std::string &usr, const std::string &_data, const std::string &_pub_key, const std::string &_sec_key, const uint8_t& _status): + username(usr), + data(_data), + pub_key(_pub_key), + sec_key(_sec_key), + status(_status) {} + +private: + std::string username; + std::string data; + std::string pub_key; + std::string sec_key; + uint8_t status; +public: + std::string getUsername() const {return username;} + std::string getData() const {return data;} + std::string getPubKey() const {return pub_key;} + std::string getSecKey() const {return sec_key;} + uint8_t getStatus() const {return status;} +}; + +struct SafexOffer { +public: + SafexOffer(){} + SafexOffer(const std::string &_title, const uint64_t _quantity, const uint64_t _price, const uint64_t _min_sfx_price, const std::string& _description, + const bool _active, const bool _price_peg_used, const std::string& _offer_id, const std::string& _seller, const std::string& _price_peg_id, const std::string& _currency): + title(_title), + quantity(_quantity), + price(_price), + min_sfx_price(_min_sfx_price), + description(_description), + active(_active), + price_peg_used(_price_peg_used), + offer_id(_offer_id), + price_peg_id(_price_peg_id), + seller(_seller), + currency(_currency){} + +private: + std::string title; + uint64_t quantity; + uint64_t price; + uint64_t min_sfx_price; + std::string description; + bool active; + bool price_peg_used; + std::string offer_id; + std::string price_peg_id; + std::string seller; + std::string currency; +public: + + std::string getTitle() const {return title;}; + uint64_t getQuantity() const {return quantity;}; + uint64_t getPrice() const {return price;}; + uint64_t getMin_sfx_price() const {return min_sfx_price;}; + std::string getDescription() const {return description;}; + bool getActive() const {return active;}; + bool getPrice_peg_used() const {return price_peg_used;}; + std::string getOffer_id() const {return offer_id;}; + std::string getPrice_peg_id() const {return price_peg_id;}; + std::string getSeller() const {return seller;}; + std::string getCurrency() const {return currency;}; +}; + /** * @brief AddressBookRow - provides functions to manage address book */ @@ -349,6 +566,13 @@ struct WalletListener */ virtual void unconfirmedTokensReceived(const std::string &txId, uint64_t token_amount) = 0; + /** + * @brief advancedReceived - called when advanced outputs are received + * @param txId - transaction id + * @param output_type - type of advanced output + */ + virtual void advancedReceived(const std::string &txId, const uint8_t output_type) = 0; + /** * @brief newBlock - called when new block received * @param height - block height @@ -489,6 +713,62 @@ struct Wallet */ virtual void setRefreshFromBlockHeight(uint64_t refresh_from_block_height) = 0; + /*! + * \brief createSafexAccount - Generates keys and creates safex account inside the wallet + * + * \param username - Username of the safex account + * \param description - Description of the safex account + */ + virtual bool createSafexAccount(const std::string& username, const std::vector& description) = 0; + + /*! + * \brief getSafexAccounts - Returns all Safex accounts in the wallet + * + */ + virtual std::vector getSafexAccounts() = 0; + + /*! + * \brief getSafexAccount - Returns requested safex account data + * + * \param username - Username of the specific safex account + */ + virtual SafexAccount getSafexAccount(const std::string& username) = 0; + + /*! + * \brief recoverSafexAccount - Generates safex account that was created before + * + * \param username - Username of the specific safex account + * \param private_key - Private key of the safex account + */ + virtual bool recoverSafexAccount(const std::string& username, const std::string& private_key) = 0; + + /*! + * \brief removeSafexAccount - Removes safex account from the wallet file + * + * \param username - Username of the specific safex account + */ + virtual bool removeSafexAccount(const std::string& username) = 0; + + /*! + * \brief getMySafexOffers - Returns all Safex offers created by safex accounts from whis wallet + * + */ + virtual std::vector getMySafexOffers() = 0; + + /*! + * \brief listSafexOffers - Returns all Safex offers currently in the blockchain + * + * \param active - True if you want to return only offers that can be purchased + */ + virtual std::vector listSafexOffers(bool active) = 0; + + /*! + * \brief getMyInterest - Returns total interest and also interest for each stake token output + * + * \param interest_per_output - Vector of pairs staked token amount and collected fee + */ + virtual uint64_t getMyInterest(std::vector>& interest_per_output) = 0; + /*! * \brief getRestoreHeight - get wallet creation height * @@ -546,6 +826,22 @@ struct Wallet return result; } + virtual uint64_t stakedTokenBalance(uint32_t accountIndex = 0) const = 0; + uint64_t stakedTokenBalanceAll() const { + uint64_t result = 0; + for (uint32_t i = 0; i < numSubaddressAccounts(); ++i) + result += stakedTokenBalance(i); + return result; + } + + virtual uint64_t unlockedStakedTokenBalance(uint32_t accountIndex = 0) const = 0; + uint64_t unlockedStakedTokenBalanceAll() const { + uint64_t result = 0; + for (uint32_t i = 0; i < numSubaddressAccounts(); ++i) + result += unlockedStakedTokenBalance(i); + return result; + } + /** * @brief watchOnly - checks if wallet is watch only * @return - true if watch only @@ -717,6 +1013,10 @@ struct Wallet virtual PendingTransaction * createSweepUnmixableTransaction() = 0; + + virtual PendingTransaction * createAdvancedTransaction(const std::string &dst_addr, const std::string &payment_id, optional value_amount, uint32_t mixin_count, + PendingTransaction::Priority priority, uint32_t subaddr_account, std::set subaddr_indices, AdvancedCommand& advancedCommnand) = 0; + /*! * \brief loadUnsignedTx - creates transaction from unsigned tx file * \return - UnsignedTransaction object. caller is responsible to check UnsignedTransaction::status() diff --git a/src/wallet/api/win_wrapper/windows_wallet_listener.h b/src/wallet/api/win_wrapper/windows_wallet_listener.h deleted file mode 100644 index 481894099..000000000 --- a/src/wallet/api/win_wrapper/windows_wallet_listener.h +++ /dev/null @@ -1,63 +0,0 @@ -// -// Created by stefan on 29.11.18.. -// - -#ifndef SAFEX_WINDOWS_WALLET_LISTENER_H -#define SAFEX_WINDOWS_WALLET_LISTENER_H - -#include "../wallet_api.h" - -struct WinWalletListener : public Safex::WalletListener -{ - void(*moneySpent_)(void*, const char*, uint64_t); - void(*moneyReceived_)(void*,const char*, uint64_t); - void(*unconfirmedMoneyReceived_)(void*,const char*, uint64_t); - void(*tokensSpent_)(void*,const char*, uint64_t); - void(*tokenReceived_)(void*,const char*, uint64_t); - void(*unconfirmedTokenReceived_)(void*,const char*, uint64_t); - void(*newBlock_)(void*,uint64_t); - void(*updated_)(void*); - void(*refreshed_)(void*); - - WinWalletListener(void* up) : ptr_to_up(up) { - - } - - virtual ~WinWalletListener() { - - }; - virtual void moneySpent(const std::string &txId, uint64_t amount) { - //(*moneySpent_)(ptr_to_up, txId.c_str(), amount); - } - virtual void moneyReceived(const std::string &txId, uint64_t amount) { - //(*moneyReceived_)(ptr_to_up, txId.c_str(), amount); - } - virtual void unconfirmedMoneyReceived(const std::string &txId, uint64_t amount) { - //(*unconfirmedMoneyReceived_)(ptr_to_up, txId.c_str(), amount); - } - virtual void tokensSpent(const std::string &txId, uint64_t token_amount) { - //(*tokensSpent_)(ptr_to_up, txId.c_str(), token_amount); - } - virtual void tokensReceived(const std::string &txId, uint64_t token_amount) { - //(*tokenReceived_)(ptr_to_up, txId.c_str(), token_amount); - } - virtual void unconfirmedTokensReceived(const std::string &txId, uint64_t token_amount) { - //(*unconfirmedMoneyReceived_)(ptr_to_up, txId.c_str(), token_amount); - } - virtual void newBlock(uint64_t height) { - //(*newBlock_)(ptr_to_up, height); - } - virtual void updated() { - //(*updated_)(ptr_to_up ); - } - - virtual void refreshed() { - (*refreshed_)(ptr_to_up); - } - -private: - void* ptr_to_up; -}; - - -#endif //SAFEX_WINDOWS_WALLET_LISTENER_H diff --git a/src/wallet/api/win_wrapper/windows_wrapper.cpp b/src/wallet/api/win_wrapper/windows_wrapper.cpp deleted file mode 100644 index d63e33bf7..000000000 --- a/src/wallet/api/win_wrapper/windows_wrapper.cpp +++ /dev/null @@ -1,786 +0,0 @@ -// -// Created by stefan on 28.11.18.. -// - -#include -#include -#include - -#include -#include -#include - -#include "windows_wrapper.h" -#include "../wallet.h" -#include "../pending_transaction.h" -#include "../transaction_info.h" -#include "../wallet_manager.h" -#include "../wallet_api.h" -#include "windows_wallet_listener.h" -#include "../transaction_history.h" - - -char *returnStdString(std::string &&in) -{ - char *dst = (char *) malloc(in.size() * sizeof(char)); - memcpy(dst, in.c_str(), in.size()); - return dst; -} - -extern "C" DLL_MAGIC void win_checkDLL(const char *msg) -{ - printf("Message from below: %s \n", msg); - std::cout << "message bab ba std::cout " << std::endl; - fflush(stdout); - -} - -extern "C" DLL_MAGIC void *win_createWallet(uint8_t nettype) -{ - - printf("Called %s \n", __FUNCTION__); - Safex::WalletImpl *wallet = new Safex::WalletImpl(static_cast(nettype)); - return static_cast(wallet); -} - -extern "C" DLL_MAGIC void win_deleteWallet(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - if (wallet) - { - delete wallet; - } -} - -extern "C" DLL_MAGIC uint8_t win_initB(void *self, const char *daemon_address) -{ - Safex::WalletImpl *wallet = static_cast(self); - return static_cast(wallet->init(daemon_address)); -} - -extern "C" DLL_MAGIC void win_startRefresh(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - wallet->startRefresh(); -} - -extern "C" DLL_MAGIC uint8_t win_storeB(void *self, const char *path) -{ - Safex::WalletImpl *wallet = static_cast(self); - return static_cast(wallet->store(path)); -} - -extern "C" DLL_MAGIC void *win_createTransaction( - void *self, - const char *dst_addr, - const char *payment_id, - uint64_t value_amount, - uint32_t mixin_count, - uint32_t priority, - uint32_t subaddr_account, - uint32_t subaddr_indices, - uint32_t tx_type) -{ - Safex::WalletImpl *wallet = static_cast(self); - Safex::PendingTransaction *pTx = wallet->createTransaction( - dst_addr, - payment_id, - value_amount, - mixin_count, - static_cast(priority), - 0, - {}, - static_cast(tx_type) - ); - - return static_cast(pTx); -} - -extern "C" DLL_MAGIC const char *win_address(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - printf("Called %s \n", __FUNCTION__); - static char buffer[512]; - memset((void *) buffer, 0, sizeof(buffer)); - memcpy((void *) buffer, wallet->address().c_str(), wallet->address().length()); - buffer[wallet->address().length()+1] = '\0'; - return (const char *) buffer; - -} -extern "C" DLL_MAGIC const char *win_seed(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - - static char buffer[1024]; - memset((void *) buffer, 0, sizeof(buffer)); - memcpy((void *) buffer, wallet->seed().c_str(), wallet->seed().length()); - buffer[wallet->seed().length() +1] = '\0'; - return (const char *) buffer; -} -extern "C" DLL_MAGIC const char *win_path(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - static char buffer[1024]; - memset((void *) buffer, 0, sizeof(buffer)); - memcpy((void *) buffer, wallet->path().c_str(), wallet->path().length()); - buffer[wallet->path().length()+1] = '\0'; - return (const char *) buffer; -} -extern "C" DLL_MAGIC uint8_t win_nettype(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - - return static_cast(wallet->nettype()); -} -extern "C" DLL_MAGIC const char *win_secretViewKey(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - static char buffer[128]; - memset((void *) buffer, 0, sizeof(buffer)); - memcpy((void *) buffer, wallet->secretViewKey().c_str(), wallet->secretViewKey().length()); - buffer[wallet->secretViewKey().length() + 1] = '\0'; - return (const char *) buffer; -} -extern "C" DLL_MAGIC const char *win_publicViewKey(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - static char buffer[128]; - memset((void *) buffer, 0, sizeof(buffer)); - memcpy((void *) buffer, wallet->publicViewKey().c_str(), wallet->publicViewKey().length()); - buffer[wallet->publicViewKey().length() + 1] = '\0'; - return (const char *) buffer; -} -extern "C" DLL_MAGIC const char *win_secretSpendKey(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - static char buffer[128]; - memset((void *) buffer, 0, sizeof(buffer)); - memcpy((void *) buffer, wallet->secretSpendKey().c_str(), wallet->secretSpendKey().length()); - buffer[wallet->secretSpendKey().length() + 1] = '\0'; - return (const char *) buffer; -} -extern "C" DLL_MAGIC const char *win_publicSpendKey(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - static char buffer[128]; - memset((void *) buffer, 0, sizeof(buffer)); - memcpy((void *) buffer, wallet->publicSpendKey().c_str(), wallet->publicSpendKey().length()); - buffer[wallet->publicSpendKey().length() + 1] = '\0'; - return (const char *) buffer; -} -extern "C" DLL_MAGIC uint8_t win_setPasswordB(void *self, const char *pass_c) -{ - Safex::WalletImpl *wallet = static_cast(self); - std::string password(pass_c); - - return static_cast(wallet->setPassword(password)); -} -extern "C" DLL_MAGIC const char *win_errorString(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - static char buffer[2048]; - memset((void *) buffer, 0, sizeof(buffer)); - memcpy((void *) buffer, wallet->errorString().c_str(), wallet->errorString().length()); - return (const char *) buffer; -} -extern "C" DLL_MAGIC void win_setRefreshFromBlockHeight(void *self, uint32_t height) -{ - Safex::WalletImpl *wallet = static_cast(self); - wallet->setRefreshFromBlockHeight(height); -} - -extern "C" DLL_MAGIC uint64_t win_getRefreshFromBlockHeight(void* self) { - Safex::WalletImpl *wallet = static_cast(self); - return wallet->getRefreshFromBlockHeight(); -} - -extern "C" DLL_MAGIC uint32_t win_connected(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - - return static_cast(wallet->connected()); -} - -extern "C" DLL_MAGIC uint8_t win_refresh(void* self) { - Safex::WalletImpl *wallet = static_cast(self); - return static_cast(wallet->refresh()); -} - -extern "C" DLL_MAGIC void win_setTrustedDaemon(void *self, uint8_t argB) -{ - Safex::WalletImpl *wallet = static_cast(self); - bool arg = (argB == 0); - wallet->setTrustedDaemon(arg); -} -extern "C" DLL_MAGIC uint8_t win_trustedDaemonB(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - - return static_cast(wallet->trustedDaemon()); -} -extern "C" DLL_MAGIC uint64_t win_balanceAll(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - - return wallet->balanceAll(); -} -extern "C" DLL_MAGIC uint64_t win_unlockedBalanceAll(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - - return wallet->unlockedBalanceAll(); -} -extern "C" DLL_MAGIC uint64_t win_tokenBalanceAll(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - - return wallet->tokenBalanceAll(); -} -extern "C" DLL_MAGIC uint64_t win_unlockedTokenBalanceAll(void *self) -{ - Safex::WalletImpl *wallet = static_cast(self); - - return wallet->unlockedTokenBalanceAll(); -} - -extern "C" DLL_MAGIC uint8_t win_synchronizedB(void* self) { - Safex::WalletImpl *wallet = static_cast(self); - return static_cast(wallet->synchronized()); -} - -extern "C" DLL_MAGIC void win_setAutoRefreshInterval(void* self, uint32_t millis) { - Safex::WalletImpl *wallet = static_cast(self); - wallet->setAutoRefreshInterval(millis); -} - -extern "C" DLL_MAGIC uint8_t win_static_addressValid(const char *address, uint32_t nettype) -{ - return static_cast(Safex::Wallet::addressValid(address, static_cast(nettype))); -} - -extern "C" DLL_MAGIC const char *win_GenPaymentId() -{ - return Safex::Wallet::genPaymentId().c_str(); -} - -extern "C" DLL_MAGIC uint8_t win_PaymentIdValid(const char *pid) -{ - return static_cast(Safex::Wallet::paymentIdValid(pid)); -} - -extern "C" DLL_MAGIC void win_SetListener(void *self, void *listener) -{ - Safex::WalletImpl *wallet = static_cast(self); - WinWalletListener *wlstn = static_cast(listener); - wallet->setListener(wlstn); -} - -extern "C" DLL_MAGIC void win_segregatePreForkOutputs(void *self, uint8_t segregateB) -{ - Safex::WalletImpl *wallet = static_cast(self); - wallet->segregatePreForkOutputs(static_cast(segregateB)); -} - -extern "C" DLL_MAGIC void win_keyReuseMitigation2(void *self, uint8_t mitigationB) -{ - Safex::WalletImpl *wallet = static_cast(self); - wallet->keyReuseMitigation2(static_cast(mitigationB)); -} - -extern "C" DLL_MAGIC const char *win_IntegratedAddress(void *self, const char *paymentId) -{ - Safex::WalletImpl *wallet = static_cast(self); - return wallet->integratedAddress(paymentId).c_str(); -} - -extern "C" DLL_MAGIC uint64_t win_blockChainHeight(void* self) { - Safex::WalletImpl *wallet = static_cast(self); - return wallet->blockChainHeight(); -} - -extern "C" DLL_MAGIC uint64_t win_approximateBlockChainHeight(void* self) { - Safex::WalletImpl *wallet = static_cast(self); - return wallet->approximateBlockChainHeight(); -} - -extern "C" DLL_MAGIC uint64_t win_daemonBlockChainHeight(void* self) { - Safex::WalletImpl *wallet = static_cast(self); - return wallet->daemonBlockChainHeight(); -} - -extern "C" DLL_MAGIC uint64_t win_daemonBlockChainTargetHeight(void* self) { - Safex::WalletImpl *wallet = static_cast(self); - return wallet->daemonBlockChainTargetHeight(); -} - -extern "C" DLL_MAGIC bool win_rescanBlockchain(void* self) { - Safex::WalletImpl *wallet = static_cast(self); - return static_cast(wallet->rescanBlockchain()); -} - -extern "C" DLL_MAGIC void win_rescanBlockchainAsync(void* self) { - Safex::WalletImpl *wallet = static_cast(self); - wallet->rescanBlockchainAsync(); -} - -extern "C" DLL_MAGIC void win_setSeedLanguage(void* self, const char* seedLanguage) { - Safex::WalletImpl *wallet = static_cast(self); - std::string seed(seedLanguage); - wallet->setSeedLanguage(seed); -} - - -extern "C" DLL_MAGIC void* win_history(void* self) { - Safex::WalletImpl *wallet = static_cast(self); - return static_cast(wallet->history()); -} - - -extern "C" DLL_MAGIC const char* win_addrbook_get_all(void* self) { - static std::string result; - Safex::WalletImpl *wallet = static_cast(self); - std::vector rows = wallet->addressBook()->getAll(); - - result.clear(); - result = ""; - std::string delimeter{"$@"}; - for(auto row : rows) { - std::string serialized_row = std::to_string(row->getRowId()) + delimeter; - serialized_row += row->getAddress() + delimeter; - serialized_row += row->getPaymentId() + delimeter; - serialized_row += row->getDescription() + delimeter; - - result += serialized_row; - } - - return result.c_str(); -} - -extern "C" DLL_MAGIC uint8_t win_addrbook_add_row(void* self, const char* addr, const char* pid, const char* desc) { - Safex::WalletImpl *wallet = static_cast(self); - return static_cast(wallet->addressBook()->addRow(addr, pid, desc)); -} - -extern "C" DLL_MAGIC uint8_t win_addrbook_del_row(void* self, uint32_t row_id) { - Safex::WalletImpl *wallet = static_cast(self); - return static_cast(wallet->addressBook()->deleteRow(row_id)); -} - -extern "C" DLL_MAGIC const char* win_addrbook_err_str(void* self) { - Safex::WalletImpl *wallet = static_cast(self); - return wallet->addressBook()->errorString().c_str(); -} - -extern "C" DLL_MAGIC int32_t win_addrbook_look_for_pid(void* self, const char* pid) { - Safex::WalletImpl *wallet = static_cast(self); - return wallet->addressBook()->lookupPaymentID(pid); -} - -/****************************** PENDING TRANSACTION API ***************************************************************/ -extern "C" DLL_MAGIC void *win_pt_create(void *in) -{ - Safex::WalletImpl *wallet = static_cast(in); - Safex::PendingTransactionImpl *ret = new Safex::PendingTransactionImpl(*wallet); - return static_cast(ret); -} - -extern "C" DLL_MAGIC void win_pt_delete(void *self) -{ - Safex::PendingTransaction *ptx = static_cast(self); - if (ptx) - { - delete ptx; - } -} - -extern "C" DLL_MAGIC uint64_t win_pt_amount(void *self) -{ - Safex::PendingTransaction *ptx = static_cast(self); - - return ptx->amount(); -} - -extern "C" DLL_MAGIC uint64_t win_pt_tokenAmount(void *self) -{ - Safex::PendingTransaction *ptx = static_cast(self); - - return ptx->tokenAmount(); -} - -extern "C" DLL_MAGIC uint64_t win_pt_dust(void *self) -{ - Safex::PendingTransaction *ptx = static_cast(self); - - return ptx->dust(); -} - -extern "C" DLL_MAGIC uint64_t win_pt_fee(void *self) -{ - Safex::PendingTransaction *ptx = static_cast(self); - - return ptx->fee(); -} - -extern "C" DLL_MAGIC uint64_t win_pt_txCount(void *self) -{ - Safex::PendingTransaction *ptx = static_cast(self); - - return ptx->txCount(); -} - -extern "C" DLL_MAGIC char *win_pt_txid(void *self) -{ - Safex::PendingTransaction *ptx = static_cast(self); - - std::vector ret = ptx->txid(); - static unsigned char buffer[256*1024]; - memset((void*)buffer, 0, sizeof(buffer)); - - uint64_t offset = 0; - for (auto &tx : ret) - { - memcpy(buffer + offset, tx.c_str(), 64); - offset += 64; - } - - return (char *)buffer; -} - -extern "C" DLL_MAGIC int32_t win_pt_status(void *self) -{ - Safex::PendingTransaction *ptx = static_cast(self); - - return ptx->status(); -} - -extern "C" DLL_MAGIC const char *win_pt_errorString(void *self) -{ - Safex::PendingTransaction *ptx = static_cast(self); - - return ptx->errorString().c_str(); -} - -extern "C" DLL_MAGIC uint8_t win_pt_commit(void *self) -{ - Safex::PendingTransaction *ptx = static_cast(self); - - return static_cast(ptx->commit()); -} - -/****************************** END PENDING TRANSACTION API ***********************************************************/ - - -/****************************** WALLET MANAGER API ********************************************************************/ -extern "C" DLL_MAGIC void win_mng_closeWallet(void *self, void *wallet, uint8_t storeB) -{ - Safex::WalletManagerImpl *mngr = static_cast(self); - Safex::WalletImpl *wllt = static_cast(wallet); - mngr->closeWallet(wllt, static_cast(storeB)); -} - -// @return Safex::WalletImpl -extern "C" DLL_MAGIC void *win_mng_createWallet(void *self, const char *path, const char *password, const char *lang, uint32_t nettype) -{ - Safex::WalletManagerImpl *mngr = static_cast(self); - return static_cast(mngr->createWallet(path, password, lang, static_cast(nettype))); -} - -// @return Safex::WalletImpl -extern "C" DLL_MAGIC void *win_mng_openWallet(void *self, const char *path, const char *password, uint32_t nettype) -{ - Safex::WalletManagerImpl *mngr = static_cast(self); - return static_cast(mngr->openWallet(path, password, static_cast(nettype))); -} - -// @return Safex::WalletImpl -extern "C" DLL_MAGIC void *win_mng_recoveryWallet( - void *self, - const char *path, - const char *password, - const char *mnemonic, - uint32_t nettype, - uint64_t restoreHeight) -{ - Safex::WalletManagerImpl *mngr = static_cast(self); - return static_cast(mngr->recoveryWallet(path, password, mnemonic, static_cast(nettype), restoreHeight)); -} - -extern "C" DLL_MAGIC uint8_t win_mng_walletExists(void *self, const char *path) -{ - Safex::WalletManagerImpl *mngr = static_cast(self); - return static_cast(mngr->walletExists(path)); -} - -extern "C" DLL_MAGIC void *win_mngf_getWalletManager() -{ - Safex::WalletManager *mngr = Safex::WalletManagerFactory::getWalletManager(); - return static_cast(mngr); -} - -extern "C" DLL_MAGIC void* win_mng_createWalletFromKeys(void* self, const char* path, const char* password, const char* language, uint32_t nettype, - uint64_t restoreHeight,const char *addressString, const char* viewKeyString, const char* spendKeyString) { - Safex::WalletManagerImpl *mngr = static_cast(self); - return static_cast(mngr->createWalletFromKeys(path, password, language, static_cast(nettype), restoreHeight, addressString, viewKeyString, spendKeyString)); -} -/****************************** END WALLET MANAGER API ****************************************************************/ -/****************************** TRANSACTIONINFO API *******************************************************************/ -extern "C" DLL_MAGIC void *win_txinfo_createTransactionInfo() -{ - Safex::TransactionInfoImpl *txInfo = new Safex::TransactionInfoImpl(); - return static_cast(txInfo); -} - -extern "C" DLL_MAGIC void win_txinfo_deleteTransactionInfo(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - if (txInfo) - { - delete txInfo; - } -} - -extern "C" DLL_MAGIC int32_t win_txinfo_direction(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - return static_cast(txInfo->direction()); -} - -extern "C" DLL_MAGIC uint8_t win_txinfo_isPendingB(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - return static_cast(txInfo->isPending()); -} - -extern "C" DLL_MAGIC uint8_t win_txinfo_isFailedB(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - return static_cast(txInfo->isFailed()); -} - -extern "C" DLL_MAGIC uint64_t win_txinfo_amount(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - return txInfo->amount(); -} - -extern "C" DLL_MAGIC uint64_t win_txinfo_token_amount(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - return txInfo->token_amount(); -} - -extern "C" DLL_MAGIC uint64_t win_txinfo_fee(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - return txInfo->fee(); -} - -extern "C" DLL_MAGIC uint64_t win_txinfo_blockHeight(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - return txInfo->blockHeight(); -} - -extern "C" DLL_MAGIC const char *win_txinfo_label(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - static unsigned char buffer[512]; - memset((void *) buffer, 0, sizeof(buffer)); - memcpy((void *) buffer, txInfo->label().c_str(),txInfo->label().length()); - buffer[txInfo->label().length()+1] = '\0'; - return (const char *) buffer; -} - -extern "C" DLL_MAGIC const char *win_txinfo_hash(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - static unsigned char buffer[128]; - memset((void *) buffer, 0, sizeof(buffer)); - memcpy((void *) buffer, txInfo->hash().c_str(),txInfo->hash().length()); - buffer[64] = '\0'; - return (const char *) buffer; -} - -extern "C" DLL_MAGIC uint64_t win_txinfo_timestamp(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - return static_cast(txInfo->timestamp()); -} - -extern "C" DLL_MAGIC const char *win_txinfo_paymentId(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - static unsigned char buffer[256]; - memset((void *) buffer, 0, sizeof(buffer)); - memcpy((void *) buffer, txInfo->paymentId().c_str(),txInfo->paymentId().length()); - buffer[txInfo->paymentId().length()+1] = '\0'; - return (const char *) buffer; -} - -extern "C" DLL_MAGIC char *win_txinfo_transfers(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - const std::vector &transfers = txInfo->transfers(); - - static char buffer[2048*1024+sizeof(uint32_t)]; - uint32_t offset = 0; - memset(buffer, 0, sizeof(buffer)); - uint32_t size = static_cast(transfers.size()); - memcpy(buffer+offset, &size, sizeof(uint32_t)); - offset += sizeof(uint32_t); - - for(auto& tx : transfers) { - if(2048 * 1024 - offset <= 128) break; - memcpy(buffer + offset, &(tx.amount), sizeof(uint64_t)); - offset += sizeof(uint64_t); - memcpy(buffer + offset, &(tx.token_amount), sizeof(uint64_t)); - offset += sizeof(uint64_t); - offset++; - } - buffer[2048*1024+sizeof(uint32_t)] = '\0'; - return static_cast(buffer); -} - -extern "C" DLL_MAGIC uint64_t win_txinfo_confirmations(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - return txInfo->confirmations(); -} - -extern "C" DLL_MAGIC uint64_t win_txinfo_unlockTime(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - return static_cast(txInfo->unlockTime()); -} - -extern "C" DLL_MAGIC uint32_t win_txinfo_transactionType(void *self) -{ - Safex::TransactionInfoImpl *txInfo = static_cast(self); - return static_cast(txInfo->transactionType()); -} - -/****************************** END TRANSACTIONINFO API ***************************************************************/ - -/****************************** WALLET LISTENER API ********************************************************************/ -extern "C" DLL_MAGIC void *win_lstn_Create(void *up) -{ - return static_cast(new WinWalletListener(up)); -} -extern "C" DLL_MAGIC void win_lstn_setMoneySpent(void *self, void(*moneySpent_)(void *, const char *, uint64_t)) -{ - WinWalletListener *wlstn = static_cast(self); - wlstn->moneySpent_ = moneySpent_; -} -extern "C" DLL_MAGIC void win_lstn_setMoneyReceived(void *self, void(*moneyReceived_)(void *, const char *, uint64_t)) -{ - WinWalletListener *wlstn = static_cast(self); - wlstn->moneyReceived_ = moneyReceived_; -} - -extern "C" DLL_MAGIC void win_lstn_setUnconfirmedMoneyReceived(void *self, void(*unconfirmedMoneyReceived_)(void *, const char *, uint64_t)) -{ - WinWalletListener *wlstn = static_cast(self); - wlstn->unconfirmedMoneyReceived_ = unconfirmedMoneyReceived_; -} -extern "C" DLL_MAGIC void win_lstn_setTokensSpent(void *self, void(*tokensSpent_)(void *, const char *, uint64_t)) -{ - WinWalletListener *wlstn = static_cast(self); - wlstn->tokensSpent_ = tokensSpent_; -} - -extern "C" DLL_MAGIC void win_lstn_setTokenReceived(void *self, void(*tokenReceived_)(void *, const char *, uint64_t)) -{ - WinWalletListener *wlstn = static_cast(self); - wlstn->tokenReceived_ = tokenReceived_; -} - -extern "C" DLL_MAGIC void win_lstn_setUnconfirmedTokenReceived(void *self, void(*unconfirmedTokenReceived_)(void *, const char *, uint64_t)) -{ - WinWalletListener *wlstn = static_cast(self); - wlstn->unconfirmedTokenReceived_ = unconfirmedTokenReceived_; -} - -extern "C" DLL_MAGIC void win_lstn_setNewBlock(void *self, void(*newBlock_)(void *, uint64_t)) -{ - WinWalletListener *wlstn = static_cast(self); - wlstn->newBlock_ = newBlock_; -} - -extern "C" DLL_MAGIC void win_lstn_setUpdated(void *self, void(*updated_)(void *)) -{ - WinWalletListener *wlstn = static_cast(self); - wlstn->updated_ = updated_; -} -extern "C" DLL_MAGIC void win_lstn_setRefreshed(void *self, void(*refreshed_)(void *)) -{ - WinWalletListener *wlstn = static_cast(self); - wlstn->refreshed_ = refreshed_; -} - -/****************************** END WALLET LISTNER API ****************************************************************/ - -/****************************** OTHER FUNCTIONS ***********************************************************************/ -extern "C" DLL_MAGIC void win_mlog_set_log_levelI(int level) { - mlog_set_log_level(level); -} - -extern "C" DLL_MAGIC void win_mlog_set_log_levelCPtr(const char* log) { - mlog_set_log(log); -} -/****************************** END OTHER FUNCTIONS *******************************************************************/ - -/****************************** TRANSACTION HISTORY API ***************************************************************/ -extern "C" DLL_MAGIC void* _hry_Create(void* wallet) { - Safex::WalletImpl* wlt = static_cast(wallet); - Safex::TransactionHistoryImpl* ret = new Safex::TransactionHistoryImpl(wlt); - return static_cast(ret); -} - -extern "C" DLL_MAGIC void win_txhist_Delete(void* self) { - if (self == nullptr) { return ;} - Safex::TransactionHistoryImpl* txHist = static_cast(self); - delete txHist; -} - -extern "C" DLL_MAGIC uint32_t win_txhist_count(void* self) { - Safex::TransactionHistoryImpl* txHist = static_cast(self); - return txHist->count(); -} - -extern "C" DLL_MAGIC void* win_txhist_transactionInt(void* self, uint32_t index) { - Safex::TransactionHistoryImpl* txHist = static_cast(self); - Safex::TransactionInfo* txInfo = txHist->transaction(index); - return static_cast(txInfo); -} - -extern "C" DLL_MAGIC void* win_txhist_transactionStr(void* self, const char* id) { - Safex::TransactionHistoryImpl* txHist = static_cast(self); - Safex::TransactionInfo* txInfo = txHist->transaction(id); - return static_cast(txInfo); -} - -extern "C" DLL_MAGIC void** win_txhist_getAll(void* self, uint32_t* size) { - Safex::TransactionHistoryImpl* txHist = static_cast(self); - std::vector txInfos = txHist->getAll(); - *size = static_cast(txInfos.size()); - static void* buffer[4096]; - std::sort(txInfos.begin(), txInfos.end(), [](Safex::TransactionInfo* a, Safex::TransactionInfo* b){ - return a->timestamp() > b->timestamp(); - }); - memset(buffer, 0, sizeof(buffer)); - size_t i = 0; - for(auto tx : txInfos) { - if(i >= 4096) break; - buffer[i] = static_cast(tx); - ++i; - } - - return buffer; -} - -extern "C" DLL_MAGIC void win_txhist_refresh(void* self) { - Safex::TransactionHistoryImpl* txHist = static_cast(self); - txHist->refresh(); -} - -/****************************** END TRANSACTION HISTORY API ***********************************************************/ diff --git a/src/wallet/api/win_wrapper/windows_wrapper.h b/src/wallet/api/win_wrapper/windows_wrapper.h deleted file mode 100644 index 0c33dd3ef..000000000 --- a/src/wallet/api/win_wrapper/windows_wrapper.h +++ /dev/null @@ -1,184 +0,0 @@ -// -// Created by stefan on 28.11.18.. -// - -/* - * In order to link wallet library on windows and get portability C API needs to be create - * to avoid name mangling during linkage. - */ - -#ifndef SAFEX_WINDOWS_WRAPPER_H -#define SAFEX_WINDOWS_WRAPPER_H - -#include - -#ifdef DLLIMPORT_SAFEX -#define DLL_MAGIC __declspec(dllimport) -#else -#define DLL_MAGIC __declspec(dllexport) -#endif - -/****************************** WALLET API ****************************************************************************/ -extern "C" DLL_MAGIC void* win_createWallet(uint8_t nettype); -extern "C" DLL_MAGIC void win_deleteWallet(void* self); -extern "C" DLL_MAGIC void win_checkDLL(const char* msg); - -extern "C" DLL_MAGIC uint8_t win_initB(void* self, const char* daemon_address); -extern "C" DLL_MAGIC void win_startRefresh(void* self); -extern "C" DLL_MAGIC uint8_t win_storeB(void* self, const char* path); - -// Returning Safex::PendingTransaction -// @warning subaddr_indices is here uint32_t. Argument will be ignored for time being because Safex doesnt support -// subaddresses. Please be advised to pass integer value instead of initializer_list!!!!! -// Both subaddr fields will be ignored, but are kept here to avoid any serious changes in existing API. -extern "C" DLL_MAGIC void* win_createTransaction( - void* self, - const char* dst_addr, - const char* payment_id, - uint64_t value_amount, - uint32_t mixin_count, - uint32_t priority, - uint32_t subaddr_account, - uint32_t subaddr_indices, - uint32_t tx_type - ); - -extern "C" DLL_MAGIC const char* win_address(void* self); -extern "C" DLL_MAGIC const char* win_seed(void* self); -extern "C" DLL_MAGIC const char* win_path(void* self); -extern "C" DLL_MAGIC uint8_t win_nettype(void* self); -extern "C" DLL_MAGIC const char* win_secretViewKey(void* self); -extern "C" DLL_MAGIC const char* win_publicViewKey(void* self); -extern "C" DLL_MAGIC const char* win_secretSpendKey(void* self); -extern "C" DLL_MAGIC const char* win_publicSpendKey(void* self); -extern "C" DLL_MAGIC uint8_t win_setPasswordB(void* self, const char*); // @todo See if bool is valid in CAPI -extern "C" DLL_MAGIC const char* win_errorString(void* self); -extern "C" DLL_MAGIC void win_setRefreshFromBlockHeight(void* self, uint32_t height); -extern "C" DLL_MAGIC uint64_t win_getRefreshFromBlockHeight(void* self); -extern "C" DLL_MAGIC uint32_t win_connected(void* self); // @todo Enum ConnectionStatus without default type should be uint32_t -extern "C" DLL_MAGIC void win_setTrustedDaemon(void* self, uint8_t argB); -extern "C" DLL_MAGIC uint8_t win_trustedDaemonB(void* self); -extern "C" DLL_MAGIC uint64_t win_balanceAll(void* self); -extern "C" DLL_MAGIC uint64_t win_unlockedBalanceAll(void* self); -extern "C" DLL_MAGIC uint64_t win_tokenBalanceAll(void* self); -extern "C" DLL_MAGIC uint64_t win_unlockedTokenBalanceAll(void* self); - -extern "C" DLL_MAGIC uint8_t win_synchronizedB(void* self); -extern "C" DLL_MAGIC void win_setAutoRefreshInterval(void* self, uint32_t millis); -extern "C" DLL_MAGIC const char* win_GenPaymentId(); -extern "C" DLL_MAGIC uint8_t win_PaymentIdValid(const char* paymentId); -extern "C" DLL_MAGIC void win_SetListener(void* self, void* listener); -extern "C" DLL_MAGIC void win_segregatePreForkOutputs(void* self, uint8_t segregate); -extern "C" DLL_MAGIC void win_keyReuseMitigation2(void* self, uint8_t mitigation); -extern "C" DLL_MAGIC const char* win_IntegratedAddress(void* self, const char* paymentId); -extern "C" DLL_MAGIC uint8_t win_refresh(void* self); - - -extern "C" DLL_MAGIC uint64_t win_blockChainHeight(void* self); -extern "C" DLL_MAGIC uint64_t win_approximateBlockChainHeight(void* self); -extern "C" DLL_MAGIC uint64_t win_daemonBlockChainHeight(void* self); -extern "C" DLL_MAGIC uint64_t win_daemonBlockChainTargetHeight(void* self); - -extern "C" DLL_MAGIC bool win_rescanBlockchain(void* self); -extern "C" DLL_MAGIC void win_rescanBlockchainAsync(void* self); - -extern "C" DLL_MAGIC void win_setSeedLanguage(void* self, const char* seedLanguage); - -extern "C" DLL_MAGIC uint8_t win_static_addressValid(const char* address, uint32_t nettype); -extern "C" DLL_MAGIC void* win_history(void* self); - -extern "C" DLL_MAGIC const char* win_addrbook_get_all(void* self); -extern "C" DLL_MAGIC uint8_t win_addrbook_add_row(void* self, const char* addr, const char* pid, const char* desc); -extern "C" DLL_MAGIC uint8_t win_addrbook_del_row(void* self, uint32_t row_id); -extern "C" DLL_MAGIC const char* win_addrbook_err_str(void* self); -extern "C" DLL_MAGIC int32_t win_addrbook_look_for_pid(void* self, const char* pid); -/****************************** END WALLET API ************************************************************************/ - -/****************************** PENDING TRANSACTION API ***************************************************************/ -extern "C" DLL_MAGIC void* win_pt_create(void* wallet); -extern "C" DLL_MAGIC void win_pt_delete(void* self); -extern "C" DLL_MAGIC uint64_t win_pt_amount(void* self); -extern "C" DLL_MAGIC uint64_t win_pt_tokenAmount(void* self); -extern "C" DLL_MAGIC uint64_t win_pt_dust(void* self); -extern "C" DLL_MAGIC uint64_t win_pt_fee(void* self); -extern "C" DLL_MAGIC uint64_t win_pt_txCount(void* self); -// @warning Last element is nullptr!! Like -extern "C" DLL_MAGIC char* win_pt_txid(void* self); -extern "C" DLL_MAGIC int32_t win_pt_status(void* self); -extern "C" DLL_MAGIC const char* win_pt_errorString(void* self); -extern "C" DLL_MAGIC uint8_t win_pt_commit(void* self); -/****************************** END PENDING TRANSACTION API ***********************************************************/ - - -/****************************** WALLET MANAGER API ********************************************************************/ -extern "C" DLL_MAGIC void* win_mngf_getWalletManager(); -extern "C" DLL_MAGIC void win_mng_closeWallet(void* self, void* wallet, uint8_t storeB); -// @return Safex::WalletImpl -extern "C" DLL_MAGIC void* win_mng_createWallet(void* self, const char* path, const char* password, const char* lang, uint32_t nettype); -// @return Safex::WalletImpl -extern "C" DLL_MAGIC void* win_mng_openWallet(void* self, const char* path, const char* password, uint32_t nettype); -// @return Safex::WalletImpl -extern "C" DLL_MAGIC void* win_mng_recoveryWallet( - void* self, - const char* path, - const char* password, - const char* mnemonic, - uint32_t nettype, - uint64_t restoreHeight); -//@return Safex::WalletManager -extern "C" DLL_MAGIC uint8_t win_mng_walletExists(void* self, const char* path); -extern "C" DLL_MAGIC void* win_mng_createWalletFromKeys(void* self, const char* path, const char* password, const char* language, uint32_t nettype, - uint64_t restoreHeight,const char *addressString, const char* viewKeyString, const char* spendKeyString); -/****************************** END WALLET MANAGER API ****************************************************************/ - -/****************************** TRANSACTIONINFO API *******************************************************************/ -extern "C" DLL_MAGIC void* win_txinfo_createTransactionInfo(); -extern "C" DLL_MAGIC void win_txinfo_deleteTransactionInfo(void* self); -extern "C" DLL_MAGIC int32_t win_txinfo_direction(void* self); -extern "C" DLL_MAGIC uint8_t win_txinfo_isPendingB(void* self); -extern "C" DLL_MAGIC uint8_t win_txinfo_isFailedB(void* self); -extern "C" DLL_MAGIC uint64_t win_txinfo_amount(void* self); -extern "C" DLL_MAGIC uint64_t win_txinfo_token_amount(void* self); -extern "C" DLL_MAGIC uint64_t win_txinfo_fee(void* self); -extern "C" DLL_MAGIC uint64_t win_txinfo_blockHeight(void* self); -extern "C" DLL_MAGIC const char* win_txinfo_label(void* self); -extern "C" DLL_MAGIC const char* win_txinfo_hash(void* self); -extern "C" DLL_MAGIC uint64_t win_txinfo_timestamp(void* self); -extern "C" DLL_MAGIC const char* win_txinfo_paymentId(void* self); -// returns array of Safex::Transfers -extern "C" DLL_MAGIC char* win_txinfo_transfers(void* self); -extern "C" DLL_MAGIC uint64_t win_txinfo_confirmations(void* self); -extern "C" DLL_MAGIC uint64_t win_txinfo_unlockTime(void* self); -extern "C" DLL_MAGIC uint32_t win_txinfo_transactionType(void* self); -/****************************** END TRANSACTIONINFO API ***************************************************************/ - -/****************************** WALLET LISTENER API *******************************************************************/ -extern "C" DLL_MAGIC void* win_lstn_Create(void*); -extern "C" DLL_MAGIC void win_lstn_setMoneySpent(void* self, void(*moneySpent_)(void*,const char*, uint64_t)); -extern "C" DLL_MAGIC void win_lstn_setMoneyReceived(void* self, void(*moneyReceived_)(void*,const char*, uint64_t)); -extern "C" DLL_MAGIC void win_lstn_setUnconfirmedMoneyReceived(void* self, void(*unconfirmedMoneyReceived_)(void*,const char*, uint64_t)); -extern "C" DLL_MAGIC void win_lstn_setTokensSpent(void* self, void(*tokensSpent_)(void*,const char*, uint64_t)); -extern "C" DLL_MAGIC void win_lstn_setTokenReceived(void* self, void(*tokenReceived_)(void*,const char*, uint64_t)); -extern "C" DLL_MAGIC void win_lstn_setUnconfirmedTokenReceived(void* self, void(*unconfirmedTokenReceived_)(void*,const char*, uint64_t)); -extern "C" DLL_MAGIC void win_lstn_setNewBlock(void* self, void(*newBlock_)(void*,uint64_t)); -extern "C" DLL_MAGIC void win_lstn_setUpdated(void* self, void(*updated_)(void*)); -extern "C" DLL_MAGIC void win_lstn_setRefreshed(void* self, void(*refreshed_)(void*)); -/****************************** END WALLET LISTNER API ****************************************************************/ - -/****************************** TRANSACTION HISTORY API ***************************************************************/ -extern "C" DLL_MAGIC void* win_txhist_Create(void* wallet); -extern "C" DLL_MAGIC void win_txhist_Delete(void* self); -extern "C" DLL_MAGIC uint32_t win_txhist_count(void* self); -extern "C" DLL_MAGIC void* win_txhist_transactionInt(void* self, uint32_t index); -extern "C" DLL_MAGIC void* win_txhist_transactionStr(void* self, const char* id); -extern "C" DLL_MAGIC void** win_txhist_getAll(void* self, uint32_t* size); -extern "C" DLL_MAGIC void win_txhist_refresh(void* self); -/****************************** END TRANSACTION HISTORY API ***********************************************************/ - -/****************************** OTHER FUNCTIONS ***********************************************************************/ -extern "C" DLL_MAGIC void win_mlog_set_log_levelI(int level); -extern "C" DLL_MAGIC void win_mlog_set_log_levelCPtr(const char* log); -/****************************** END OTHER FUNCTIONS *******************************************************************/ - -#endif //SAFEX_WINDOWS_WRAPPER_H - diff --git a/src/wallet/node_rpc_proxy.h b/src/wallet/node_rpc_proxy.h index 22411c7bd..9cd15cab8 100644 --- a/src/wallet/node_rpc_proxy.h +++ b/src/wallet/node_rpc_proxy.h @@ -51,7 +51,7 @@ class NodeRPCProxy boost::optional get_target_height(uint64_t &height) const; boost::optional get_earliest_height(uint8_t version, uint64_t &earliest_height) const; boost::optional get_dynamic_per_kb_fee_estimate(uint64_t grace_blocks, uint64_t &fee) const; - + private: epee::net_utils::http::http_simple_client &m_http_client; boost::mutex &m_daemon_rpc_mutex; diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index da4052cd3..df59074a8 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -30,6 +30,7 @@ // Parts of this file are originally copyright (c) 2014-2018 The Monero Project #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include #include +#include #include "include_base_utils.h" using namespace epee; @@ -47,9 +49,7 @@ using namespace epee; #include "rpc/core_rpc_server_commands_defs.h" #include "misc_language.h" #include "cryptonote_basic/cryptonote_basic_impl.h" -#include "multisig/multisig.h" #include "common/boost_serialization_helper.h" -#include "common/command_line.h" #include "common/threadpool.h" #include "profile_tools.h" #include "crypto/crypto.h" @@ -67,9 +67,10 @@ using namespace epee; #include "memwipe.h" #include "common/base58.h" #include "common/dns_utils.h" -#include "ringct/rctSigs.h" #include "ringdb.h" +#include "safex/command.h" + extern "C" { #include "crypto/keccak.h" @@ -93,7 +94,7 @@ using namespace cryptonote; #define UNSIGNED_TX_PREFIX "Safex unsigned tx set\004" #define SIGNED_TX_PREFIX "Safex signed tx set\004" -#define MULTISIG_UNSIGNED_TX_PREFIX "Safex multisig unsigned tx set\001" + #define RECENT_OUTPUT_RATIO (0.5) // 50% of outputs are from the recent zone #define RECENT_OUTPUT_DAYS (1.8) // last 1.8 day makes up the recent zone (taken from monerolink.pdf, Miller et al) @@ -109,62 +110,33 @@ using namespace cryptonote; #define KEY_IMAGE_EXPORT_FILE_MAGIC "Safex key image export\002" -#define MULTISIG_EXPORT_FILE_MAGIC "Safex multisig export\001" - #define SEGREGATION_FORK_HEIGHT 10000000 #define TESTNET_SEGREGATION_FORK_HEIGHT 10000000 #define STAGENET_SEGREGATION_FORK_HEIGHT 10000000 #define SEGREGATION_FORK_VICINITY 1500 /* blocks */ -namespace -{ - std::string get_default_ringdb_path() - { - boost::filesystem::path dir = tools::get_default_data_dir(); - // remove .bitsafex, replace with .shared-ringdb - dir = dir.remove_filename(); - dir /= ".shared-ringdb"; - return dir.string(); - } -} + namespace { -// Create on-demand to prevent static initialization order fiasco issues. -struct options { - const command_line::arg_descriptor daemon_address = {"daemon-address", tools::wallet::tr("Use daemon instance at :"), ""}; - const command_line::arg_descriptor daemon_host = {"daemon-host", tools::wallet::tr("Use daemon instance at host instead of localhost"), ""}; - const command_line::arg_descriptor password = {"password", tools::wallet::tr("Wallet password (escape/quote as needed)"), "", true}; - const command_line::arg_descriptor password_file = {"password-file", tools::wallet::tr("Wallet password file"), "", true}; - const command_line::arg_descriptor daemon_port = {"daemon-port", tools::wallet::tr("Use daemon instance at port instead of 18081"), 0}; - const command_line::arg_descriptor daemon_login = {"daemon-login", tools::wallet::tr("Specify username[:password] for daemon RPC client"), "", true}; - const command_line::arg_descriptor testnet = {"testnet", tools::wallet::tr("For testnet. Daemon must also be launched with --testnet flag"), false}; - const command_line::arg_descriptor stagenet = {"stagenet", tools::wallet::tr("For stagenet. Daemon must also be launched with --stagenet flag"), false}; - const command_line::arg_descriptor restricted = {"restricted-rpc", tools::wallet::tr("Restricts to view-only commands"), false}; - const command_line::arg_descriptor shared_ringdb_dir = { - "shared-ringdb-dir", tools::wallet::tr("Set shared ring database path"), - get_default_ringdb_path(), - testnet, - [](bool testnet, bool defaulted, std::string val)->std::string { - if (testnet) - return (boost::filesystem::path(val) / "testnet").string(); - return val; - } - }; -}; -void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file) + +void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file, std::string& safex_keys_file) { keys_file = file_path; wallet_file = file_path; + safex_keys_file = file_path; boost::system::error_code e; if(string_tools::get_extension(keys_file) == "keys") {//provided keys file name wallet_file = string_tools::cut_off_extension(wallet_file); + safex_keys_file = string_tools::cut_off_extension(wallet_file); + safex_keys_file += ".safex_account_keys"; }else {//provided wallet file name keys_file += ".keys"; + safex_keys_file += ".safex_account_keys"; } } @@ -189,7 +161,7 @@ std::string get_size_string(const cryptonote::blobdata &tx) return get_size_string(tx.size()); } -std::unique_ptr make_basic(const boost::program_options::variables_map& vm, const options& opts, const std::function(const char *, bool)> &password_prompter) +std::unique_ptr make_basic(const boost::program_options::variables_map& vm, const tools::wallet::options& opts, const std::function(const char *, bool)> &password_prompter) { const bool testnet = command_line::get_arg(vm, opts.testnet); const bool stagenet = command_line::get_arg(vm, opts.stagenet); @@ -234,7 +206,7 @@ std::unique_ptr make_basic(const boost::program_options::variable return wallet; } -boost::optional get_password(const boost::program_options::variables_map& vm, const options& opts, const std::function(const char*, bool)> &password_prompter, const bool verify) +boost::optional get_password(const boost::program_options::variables_map& vm, const tools::wallet::options& opts, const std::function(const char*, bool)> &password_prompter, const bool verify) { if (command_line::has_arg(vm, opts.password) && command_line::has_arg(vm, opts.password_file)) { @@ -263,7 +235,7 @@ boost::optional get_password(const boost::program_opt return password_prompter(verify ? tr("Enter a new password for the wallet") : tr("Wallet password"), verify); } -std::unique_ptr generate_from_json(const std::string& json_file, const boost::program_options::variables_map& vm, const options& opts, const std::function(const char *, bool)> &password_prompter) +std::unique_ptr generate_from_json(const std::string& json_file, const boost::program_options::variables_map& vm, const tools::wallet::options& opts, const std::function(const char *, bool)> &password_prompter) { const bool testnet = command_line::get_arg(vm, opts.testnet); const bool stagenet = command_line::get_arg(vm, opts.stagenet); @@ -519,67 +491,11 @@ void drop_from_short_history(std::list &short_chain_history, size_ } } -size_t estimate_rct_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof) -{ - size_t size = 0; - - // tx prefix - - // first few bytes - size += 1 + 6; - - // vin - size += n_inputs * (1+6+(mixin+1)*2+32); - - // vout - size += n_outputs * (6+32); - - // extra - size += extra_size; - - // rct signatures - - // type - size += 1; - - // rangeSigs - if (bulletproof) - size += ((2*6 + 4 + 5)*32 + 3) * n_outputs; - else - size += (2*64*32+32+64*32) * n_outputs; - - // MGs - size += n_inputs * (64 * (mixin+1) + 32); - - // mixRing - not serialized, can be reconstructed - /* size += 2 * 32 * (mixin+1) * n_inputs; */ - - // pseudoOuts - size += 32 * n_inputs; - // ecdhInfo - size += 2 * 32 * n_outputs; - // outPk - only commitment is saved - size += 32 * n_outputs; - // txnFee - size += 4; - - LOG_PRINT_L2("estimated rct tx size for " << n_inputs << " with ring size " << (mixin+1) << " and " << n_outputs << ": " << size << " (" << ((32 * n_inputs/*+1*/) + 2 * 32 * (mixin+1) * n_inputs + 32 * n_outputs) << " saved)"); - return size; -} - -size_t estimate_tx_size(bool use_rct, int n_inputs, int mixin, int n_outputs, size_t extra_size, bool bulletproof) +size_t estimate_tx_size(int n_inputs, int mixin, int n_outputs, size_t extra_size) { - if (use_rct) - return estimate_rct_tx_size(n_inputs, mixin, n_outputs + 1, extra_size, bulletproof); - else return n_inputs * (mixin+1) * APPROXIMATE_INPUT_BYTES + extra_size; } -uint8_t get_bulletproof_fork() -{ - return HF_VERSION_ALLOW_BULLETPROOFS; -} - crypto::hash8 get_short_payment_id(const tools::wallet::pending_tx &ptx, hw::device &hwdev) { crypto::hash8 payment_id8 = null_hash8; @@ -633,14 +549,14 @@ uint32_t get_subaddress_clamped_sum(uint32_t idx, uint32_t extra) namespace tools { // for now, limit to 30 attempts. TODO: discuss a good number to limit to. -const size_t MAX_SPLIT_ATTEMPTS = 30; +const size_t MAX_SPLIT_ATTEMPTS = 10; constexpr const std::chrono::seconds wallet::rpc_timeout; const char* wallet::tr(const char* str) { return i18n_translate(str, "tools::wallet"); } wallet::wallet(network_type nettype, bool restricted): - m_multisig_rescan_info(NULL), - m_multisig_rescan_k(NULL), + m_multisig_rescan_info(NULL), //not used, kept for binary compatibility + m_multisig_rescan_k(NULL), //not used, kept for binary compatibility m_run(true), m_callback(0), m_nettype(nettype), @@ -725,6 +641,7 @@ std::pair, password_container> wallet::make_from_file( const boost::program_options::variables_map& vm, const std::string& wallet_file, const std::function(const char *, bool)> &password_prompter) { const options opts{}; + auto pwd = get_password(vm, opts, password_prompter, false); if (!pwd) { @@ -806,69 +723,6 @@ bool wallet::get_seed(std::string& electrum_words, const epee::wipeable_string & return true; } //---------------------------------------------------------------------------------------------------- -bool wallet::get_multisig_seed(std::string& seed, const epee::wipeable_string &passphrase, bool raw) const -{ - bool ready; - uint32_t threshold, total; - if (!multisig(&ready, &threshold, &total)) - { - std::cout << "This is not a multisig wallet" << std::endl; - return false; - } - if (!ready) - { - std::cout << "This multisig wallet is not yet finalized" << std::endl; - return false; - } - if (!raw && seed_language.empty()) - { - std::cout << "seed_language not set" << std::endl; - return false; - } - - crypto::secret_key skey; - crypto::public_key pkey; - const account_keys &keys = get_account().get_keys(); - std::string data; - data.append((const char*)&threshold, sizeof(uint32_t)); - data.append((const char*)&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; - data.append((const char*)&pkey, sizeof(pkey)); - skey = keys.m_view_secret_key; - data.append((const char*)&skey, sizeof(skey)); - pkey = keys.m_account_address.m_view_public_key; - data.append((const char*)&pkey, sizeof(pkey)); - for (const auto &skey: keys.m_multisig_keys) - data.append((const char*)&skey, sizeof(skey)); - for (const auto &signer: m_multisig_signers) - data.append((const char*)&signer, sizeof(signer)); - - if (!passphrase.empty()) - { - crypto::secret_key key; - crypto::cn_slow_hash(passphrase.data(), passphrase.size(), (crypto::hash&)key); - sc_reduce32((unsigned char*)key.data); - data = encrypt(data, key, true); - } - - if (raw) - { - seed = epee::string_tools::buff_to_hex_nodelimer(data); - } - else - { - if (!crypto::ElectrumWords::bytes_to_words(data.data(), data.size(), seed, seed_language)) - { - std::cout << "Failed to encode seed"; - return false; - } - } - - return true; -} -//---------------------------------------------------------------------------------------------------- /*! * \brief Gets the seed language */ @@ -1012,6 +866,8 @@ void wallet::set_unspent(size_t idx) void wallet::check_acc_out_precomp(const tx_out &o, const crypto::key_derivation &derivation, const std::vector &additional_derivations, size_t i, tx_scan_info_t &tx_scan_info) const { hw::device &hwdev = m_account.get_device(); + + boost::unique_lock hwdev_lock (hwdev); hwdev.set_mode(hw::device::TRANSACTION_PARSE); if (!cryptonote::is_valid_transaction_output_type(o.target)) @@ -1023,66 +879,54 @@ void wallet::check_acc_out_precomp(const tx_out &o, const crypto::key_derivation tx_scan_info.token_transfer = cryptonote::is_token_output(o.target); const crypto::public_key &out_key = *boost::apply_visitor(destination_public_key_visitor(), o.target); - tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, out_key, derivation, additional_derivations, i, hwdev); + if ((cryptonote::get_tx_out_type(o.target) == tx_out_type::out_safex_account) || + (cryptonote::get_tx_out_type(o.target) == tx_out_type::out_safex_account_update) || + (cryptonote::get_tx_out_type(o.target) == tx_out_type::out_safex_offer) || + (cryptonote::get_tx_out_type(o.target) == tx_out_type::out_safex_offer_update) || + (cryptonote::get_tx_out_type(o.target) == tx_out_type::out_safex_price_peg) || + (cryptonote::get_tx_out_type(o.target) == tx_out_type::out_safex_price_peg_update)) + { + boost::optional result = AUTO_VAL_INIT(result); + for (auto &sfx_acc_keys: m_safex_accounts_keys) { + result = is_safex_output_to_acc_precomp(sfx_acc_keys, m_subaddresses, out_key, i, hwdev); + if (result) + { + tx_scan_info.received = result; + break; + } + } + } + else + tx_scan_info.received = is_out_to_acc_precomp(m_subaddresses, out_key, derivation, additional_derivations, i, hwdev); + if(tx_scan_info.received) { - tx_scan_info.money_transfered = o.amount; // may be 0 for ringct outputs + tx_scan_info.money_transfered = o.amount; // may be 0 for token outputs tx_scan_info.token_transfered = o.token_amount; - + tx_scan_info.output_type = cryptonote::get_tx_out_type(o.target); } else { tx_scan_info.money_transfered = 0; tx_scan_info.token_transfered = 0; + tx_scan_info.output_type = cryptonote::tx_out_type::out_invalid; } tx_scan_info.error = false; } -//---------------------------------------------------------------------------------------------------- -static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &derivation, unsigned int i, rct::key & mask, hw::device &hwdev) -{ - crypto::secret_key scalar1; - hwdev.derivation_to_scalar(derivation, i, scalar1); - try - { - switch (rv.type) - { - case rct::RCTTypeSimple: - case rct::RCTTypeSimpleBulletproof: - return rct::decodeRctSimple(rv, rct::sk2rct(scalar1), i, mask, hwdev); - case rct::RCTTypeFull: - case rct::RCTTypeFullBulletproof: - return rct::decodeRct(rv, rct::sk2rct(scalar1), i, mask, hwdev); - default: - LOG_ERROR("Unsupported rct type: " << rv.type); - return 0; - } - } - catch (const std::exception &e) - { - LOG_ERROR("Failed to decode input " << i); - return 0; - } -} + //---------------------------------------------------------------------------------------------------- void wallet::scan_output(const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map &tx_money_got_in_outs, std::unordered_map &tx_tokens_got_in_outs, std::vector &outs) const { THROW_WALLET_EXCEPTION_IF(i >= tx.vout.size(), error::wallet_internal_error, "Invalid vout index"); - if (m_multisig) - { - tx_scan_info.in_ephemeral.pub = boost::get(tx.vout[i].target).key; - tx_scan_info.in_ephemeral.sec = crypto::null_skey; - tx_scan_info.ki = rct::rct2ki(rct::zero()); - } - else - { - //get key - const crypto::public_key &out_key = *boost::apply_visitor(destination_public_key_visitor(), tx.vout[i].target); - bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), out_key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device()); - THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); - THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != out_key, - error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); - } + + //get key + const crypto::public_key &out_key = *boost::apply_visitor(destination_public_key_visitor(), tx.vout[i].target); + bool r = cryptonote::generate_key_image_helper_precomp(m_account.get_keys(), out_key, tx_scan_info.received->derivation, i, tx_scan_info.received->index, tx_scan_info.in_ephemeral, tx_scan_info.ki, m_account.get_device()); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); + THROW_WALLET_EXCEPTION_IF(tx_scan_info.in_ephemeral.pub != out_key, + error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); + const crypto::public_key &temp_out_key = *boost::apply_visitor(destination_public_key_visitor(), tx.vout[i].target); // Preventing adding same output twice in transaction. @@ -1092,17 +936,13 @@ void wallet::scan_output(const cryptonote::transaction &tx, const crypto::public outs.push_back(i); - if (tx_scan_info.token_transfer) + if (tx_scan_info.token_transfered > 0) { tx_tokens_got_in_outs[tx_scan_info.received->index] += tx_scan_info.token_transfered; tx_scan_info.token_amount = tx_scan_info.token_transfered; } else { - if (tx_scan_info.money_transfered == 0) - { - tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_scan_info.received->derivation, i, tx_scan_info.mask, m_account.get_device()); - } tx_money_got_in_outs[tx_scan_info.received->index] += tx_scan_info.money_transfered; tx_scan_info.amount = tx_scan_info.money_transfered; } @@ -1214,6 +1054,19 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: THROW_WALLET_EXCEPTION_IF(tx_scan_info[i].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); if (tx_scan_info[i].received) { + if ((tx_scan_info[i].output_type == tx_out_type::out_safex_account) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_account_update) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_offer) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_offer_update) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_purchase) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_feedback) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_price_peg) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_price_peg_update)){ + outs.push_back(i); + num_vouts_received++; + continue; + } + hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys, derivation, additional_derivations); scan_output(tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, tx_tokens_got_in_outs, outs); } @@ -1237,6 +1090,18 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: THROW_WALLET_EXCEPTION_IF(tx_scan_info[i].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); if (tx_scan_info[i].received) { + if ((tx_scan_info[i].output_type == tx_out_type::out_safex_account) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_account_update) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_offer) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_offer_update) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_purchase) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_feedback) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_price_peg) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_price_peg_update)){ + outs.push_back(i); + num_vouts_received++; + continue; + } hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys, derivation, additional_derivations); scan_output(tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, tx_tokens_got_in_outs, outs); } @@ -1245,22 +1110,36 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: } else { + hwdev_lock.lock(); + hwdev.set_mode(hw::device::NONE); for (size_t i = 0; i < tx.vout.size(); ++i) { check_acc_out_precomp(tx.vout[i], derivation, additional_derivations, i, tx_scan_info[i]); THROW_WALLET_EXCEPTION_IF(tx_scan_info[i].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); if (tx_scan_info[i].received) { - hwdev_lock.lock(); - hwdev.set_mode(hw::device::NONE); + + if ((tx_scan_info[i].output_type == tx_out_type::out_safex_account) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_account_update) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_offer) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_offer_update) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_purchase) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_feedback) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_price_peg) + || (tx_scan_info[i].output_type == tx_out_type::out_safex_price_peg_update)){ + outs.push_back(i); + num_vouts_received++; + continue; + } hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys, derivation, additional_derivations); scan_output(tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, tx_tokens_got_in_outs, outs); - hwdev_lock.unlock(); } } + hwdev_lock.unlock(); } if(!outs.empty() && num_vouts_received > 0) { + //good news - got money! take care about it //usually we have only one transfer for user in transaction if (!pool) @@ -1272,6 +1151,7 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: for(size_t o: outs) { + THROW_WALLET_EXCEPTION_IF(tx.vout.size() <= o, error::wallet_internal_error, "wrong out in transaction: internal index=" + std::to_string(o) + ", total_outs=" + std::to_string(tx.vout.size())); @@ -1280,10 +1160,20 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: error::wallet_internal_error, std::string("Unexpected transfer index from public key: ") + "got " + (kit == m_pub_keys.end() ? "" : boost::lexical_cast(kit->second)) + ", m_transfers.size() is " + boost::lexical_cast(m_transfers.size())); - if (kit == m_pub_keys.end()) + if ((kit == m_pub_keys.end()) + || (kit != m_pub_keys.end() && (cryptonote::get_tx_out_type(tx.vout[o].target) == tx_out_type::out_safex_account_update + || cryptonote::get_tx_out_type(tx.vout[o].target) == tx_out_type::out_safex_account + || cryptonote::get_tx_out_type(tx.vout[o].target) == tx_out_type::out_safex_offer + || cryptonote::get_tx_out_type(tx.vout[o].target) == tx_out_type::out_safex_offer_update + || cryptonote::get_tx_out_type(tx.vout[o].target) == tx_out_type::out_safex_purchase + || cryptonote::get_tx_out_type(tx.vout[o].target) == tx_out_type::out_safex_feedback_token + || cryptonote::get_tx_out_type(tx.vout[o].target) == tx_out_type::out_safex_feedback + || cryptonote::get_tx_out_type(tx.vout[o].target) == tx_out_type::out_safex_price_peg + || cryptonote::get_tx_out_type(tx.vout[o].target) == tx_out_type::out_safex_price_peg_update))) { uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount; uint64_t token_amount = tx.vout[o].token_amount ? tx.vout[o].token_amount : tx_scan_info[o].token_amount; + tx_out_type output_type = cryptonote::get_tx_out_type(tx.vout[o].target); if (!pool) { m_transfers.push_back(boost::value_initialized()); @@ -1294,43 +1184,23 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: td.m_tx = (const cryptonote::transaction_prefix&)tx; td.m_txid = txid; td.m_key_image = tx_scan_info[o].ki; - td.m_key_image_known = !m_watch_only && !m_multisig; + td.m_key_image_known = !m_watch_only; td.m_key_image_partial = m_multisig; td.m_amount = amount; td.m_token_amount = token_amount; td.m_token_transfer = td.m_token_amount > 0; + td.m_output_type = output_type; td.m_pk_index = pk_index - 1; td.m_subaddr_index = tx_scan_info[o].received->index; expand_subaddresses(tx_scan_info[o].received->index); - if ((tx.vout[o].amount == 0) && (tx.vout[o].token_amount == 0)) - { - //ring ct - td.m_mask = tx_scan_info[o].mask; - td.m_amount = tx_scan_info[o].amount; - td.m_token_amount = tx_scan_info[o].token_amount; - td.m_rct = true; - } - else if (miner_tx && tx.version == 2) - { - td.m_mask = rct::identity(); - td.m_rct = true; - } - else - { - td.m_mask = rct::identity(); - td.m_rct = false; - } + + td.m_mask = rct::identity(); + td.m_rct = false; + set_unspent(m_transfers.size()-1); - if (!m_multisig && !m_watch_only) + if (!m_watch_only) m_key_images[td.m_key_image] = m_transfers.size()-1; m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1; - if (m_multisig) - { - THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info, - error::wallet_internal_error, "NULL m_multisig_rescan_k"); - if (m_multisig_rescan_info && m_multisig_rescan_info->front().size() >= m_transfers.size()) - update_multisig_rescan_info(*m_multisig_rescan_k, *m_multisig_rescan_info, m_transfers.size() - 1); - } if (td.m_token_transfer) LOG_PRINT_L0("Received tokens: " << print_money(td.token_amount()) << ", with tx: " << txid); else @@ -1339,10 +1209,18 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: if (0 != m_callback) { if (td.m_token_transfer) m_callback->on_tokens_received(height, txid, tx, td.m_token_amount, td.m_subaddr_index); + else if ((output_type > tx_out_type::out_advanced) && (output_type < tx_out_type::out_invalid)){ + const txout_to_script &txout = boost::get(tx.vout[o].target); + m_callback->on_advanced_output_received(height, txid, tx, txout, td.m_subaddr_index); + } else m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index); } } + if ((output_type > tx_out_type::out_advanced) && (output_type < tx_out_type::out_invalid)){ + const txout_to_script &txout = boost::get(tx.vout[o].target); + process_advanced_output(txout, output_type); + } total_received_1 += amount; total_token_received_1 += token_amount; } @@ -1437,13 +1315,6 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: td.m_mask = rct::identity(); td.m_rct = false; } - if (m_multisig) - { - THROW_WALLET_EXCEPTION_IF(!m_multisig_rescan_k && m_multisig_rescan_info, - error::wallet_internal_error, "NULL m_multisig_rescan_k"); - if (m_multisig_rescan_info && m_multisig_rescan_info->front().size() >= m_transfers.size()) - update_multisig_rescan_info(*m_multisig_rescan_k, *m_multisig_rescan_info, m_transfers.size() - 1); - } THROW_WALLET_EXCEPTION_IF(td.get_public_key() != tx_scan_info[o].in_ephemeral.pub, error::wallet_internal_error, "Inconsistent public keys"); THROW_WALLET_EXCEPTION_IF(td.m_spent, error::wallet_internal_error, "Inconsistent spent status"); @@ -1453,10 +1324,18 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: LOG_PRINT_L0("Received money: " << print_money(td.amount()) << ", with tx: " << txid); if (0 != m_callback) { - if (td.m_token_transfer) - m_callback->on_tokens_received(height, txid, tx, td.m_token_amount, td.m_subaddr_index); - else - m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index); + if (td.m_token_transfer) + m_callback->on_tokens_received(height, txid, tx, td.m_token_amount, td.m_subaddr_index); + else if ((td.m_output_type > tx_out_type::out_advanced) && (td.m_output_type < tx_out_type::out_invalid)){ + const txout_to_script &txout = boost::get(tx.vout[o].target); + m_callback->on_advanced_output_received(height, txid, tx, txout, td.m_subaddr_index); + } + else + m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index); + } + if ((td.m_output_type > tx_out_type::out_advanced) && (td.m_output_type < tx_out_type::out_invalid)){ + const txout_to_script &txout = boost::get(tx.vout[o].target); + process_advanced_output(txout, td.m_output_type); } total_received_1 += extra_amount; total_token_received_1 += extra_token_amount; @@ -1475,16 +1354,17 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: // check all outputs for spending (compare key images) for(auto& in: tx.vin) { - if(!cryptonote::is_valid_transaction_input_type(in)) + if(!cryptonote::is_valid_transaction_input_type(in, tx.version)) continue; const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), in); auto it = m_key_images.find(k_image); - if(it != m_key_images.end()) + if (it != m_key_images.end() && + (in.type() != typeid(txin_to_script) || safex::is_safex_key_image_verification_needed(boost::get(in).command_type))) { transfer_details& td = m_transfers[it->second]; - uint64_t value_amount = *boost::apply_visitor(amount_visitor(), in); + uint64_t value_amount = td.m_token_transfer ? *boost::apply_visitor(token_amount_visitor(), in) : *boost::apply_visitor(amount_visitor(), in); if (td.m_token_transfer) { if (value_amount > 0) @@ -1539,7 +1419,7 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: } } - uint64_t fee = miner_tx ? 0 : tx.version == 1 ? tx_money_spent_in_ins - get_outs_money_amount(tx) : tx.rct_signatures.txnFee; + uint64_t fee = miner_tx ? 0 : tx_money_spent_in_ins - get_outs_cash_amount(tx); if ((tx_money_spent_in_ins > 0 || tx_tokens_spent_in_ins > 0) && !pool) { @@ -1664,6 +1544,7 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: payment.m_unlock_time = tx.unlock_time; payment.m_timestamp = ts; payment.m_subaddr_index = i.first; + payment.m_output_type = get_tx_type(tx.vout); if (pool) { emplace_or_replace(m_unconfirmed_payments, payment_id, pool_payment_details{payment, double_spend_seen}); if (0 != m_callback) @@ -1684,6 +1565,7 @@ void wallet::process_new_transaction(const crypto::hash &txid, const cryptonote: payment.m_unlock_time = tx.unlock_time; payment.m_timestamp = ts; payment.m_subaddr_index = i.first; + payment.m_output_type = get_tx_type(tx.vout); if (pool) { emplace_or_replace(m_unconfirmed_payments, payment_id, pool_payment_details{payment, double_spend_seen}); if (0 != m_callback) @@ -1728,15 +1610,8 @@ void wallet::process_outgoing(const crypto::hash &txid, const cryptonote::transa // we only see 0 input amounts, so have to deduce amount out from other parameters. entry.first->second.m_amount_in = spent; entry.first->second.m_token_amount_in = tokens_spent; - if (tx.version == 1) - { - entry.first->second.m_amount_out = get_outs_money_amount(tx); - entry.first->second.m_token_amount_out = get_outs_token_amount(tx); - } - else - { - entry.first->second.m_amount_out = spent - tx.rct_signatures.txnFee; - } + entry.first->second.m_amount_out = get_outs_cash_amount(tx); + entry.first->second.m_token_amount_out = get_outs_token_amount(tx); entry.first->second.m_change = received; entry.first->second.m_token_change = tokens_received; @@ -1752,6 +1627,9 @@ void wallet::process_outgoing(const crypto::hash &txid, const cryptonote::transa entry.first->second.m_subaddr_indices = subaddr_indices; } + entry.first->second.m_output_type = get_tx_type(tx.vout); + + for (const auto &in: tx.vin) { if ((in.type() != typeid(txin_to_key)) && (in.type() != typeid(txin_token_to_key))) @@ -1779,7 +1657,7 @@ void wallet::process_new_blockchain_entry(const cryptonote::block& b, const cryp //handle transactions from new block //optimization: seeking only for blocks that are not older then the wallet creation time plus 1 day. 1 day is for possible user incorrect time setup - if(b.timestamp + 60*60*24 > m_account.get_createtime() && height >= m_refresh_from_block_height) + if((b.timestamp + 60*60*24 > m_account.get_createtime() && height >= m_refresh_from_block_height) || m_refresh_from_block_height == 0) { TIME_MEASURE_START(miner_tx_handle_time); process_new_transaction(get_transaction_hash(b.miner_tx), b.miner_tx, o_indices.indices[txidx++].indices, height, b.timestamp, true, false, false); @@ -2727,6 +2605,9 @@ bool wallet::clear() m_local_bc_height = 1; m_subaddresses.clear(); m_subaddress_labels.clear(); + m_safex_feedback_tokens.clear(); + m_safex_offers.clear(); + m_safex_price_pegs.clear(); return true; } @@ -2775,13 +2656,6 @@ bool wallet::store_keys(const std::string& keys_file_name, const epee::wipeable_ value2.SetUint(m_multisig_threshold); json.AddMember("multisig_threshold", value2, json.GetAllocator()); - if (m_multisig) - { - bool r = ::serialization::dump_binary(m_multisig_signers, multisig_signers); - CHECK_AND_ASSERT_MES(r, false, "failed to serialize wallet multisig signers"); - value.SetString(multisig_signers.c_str(), multisig_signers.length()); - json.AddMember("multisig_signers", value, json.GetAllocator()); - } value2.SetInt(m_always_confirm_transfers ? 1 :0); json.AddMember("always_confirm_transfers", value2, json.GetAllocator()); @@ -2881,6 +2755,59 @@ bool wallet::store_keys(const std::string& keys_file_name, const epee::wipeable_ return true; } //---------------------------------------------------------------------------------------------------- + +/*! + * \brief Stores wallet safex information to file. + * \param safex_keys_file_name Name of wallet safex keys file + * \param password Password of wallet file + * \return Whether it was successful. + */ + bool wallet::store_safex_keys(const std::string& safex_keys_file_name, const epee::wipeable_string& password) + { + + std::string safex_keys_data; + bool r; + wallet::keys_file_data safex_keys_file_data = boost::value_initialized(); + + // Create a JSON object + rapidjson::Document json; + json.SetObject(); + + for(unsigned i = 0; i < m_safex_accounts.size(); ++i){ + rapidjson::Value value(rapidjson::kStringType); + auto pkey = m_safex_accounts[i].pkey; + auto safex_keys = find_if(m_safex_accounts_keys.begin(),m_safex_accounts_keys.end(),[&pkey](const safex::safex_account_keys& it){ + return it.get_public_key() == pkey; + }); + CHECK_AND_ASSERT_MES(safex_keys != m_safex_accounts_keys.end(), false, "failed to generate wallet safex account keys file " << safex_keys_file_name); + value.SetString(safex_keys->m_secret_key.data, sizeof(safex_keys->m_secret_key.data)); + rapidjson::Value name(m_safex_accounts[i].username.c_str(), json.GetAllocator()); + json.AddMember(name.Move(), value, json.GetAllocator()); + } + + // Serialize the JSON object + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + json.Accept(writer); + safex_keys_data = buffer.GetString(); + + // Encrypt the entire JSON object. + crypto::chacha_key key; + crypto::generate_chacha_key(password.data(), password.size(), key); + std::string cipher; + cipher.resize(safex_keys_data.size()); + safex_keys_file_data.iv = crypto::rand(); + crypto::chacha20(safex_keys_data.data(), safex_keys_data.size(), key, safex_keys_file_data.iv, &cipher[0]); + safex_keys_file_data.account_data = cipher; + + std::string buf; + r = ::serialization::dump_binary(safex_keys_file_data, buf); + r = r && epee::file_io_utils::save_string_to_file(safex_keys_file_name, buf); //and never touch wallet_keys_file again, only read + CHECK_AND_ASSERT_MES(r, false, "failed to generate wallet safex account keys file " << safex_keys_file_name); + + return true; + } +//---------------------------------------------------------------------------------------------------- /*! * \brief Load wallet information from wallet file. * \param keys_file_name Name of wallet file @@ -2964,31 +2891,10 @@ bool wallet::load_keys(const std::string& keys_file_name, const epee::wipeable_s } GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, watch_only, int, Int, false, false); m_watch_only = field_watch_only; - GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, multisig, int, Int, false, false); - m_multisig = field_multisig; - GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, multisig_threshold, unsigned int, Uint, m_multisig, 0); - m_multisig_threshold = field_multisig_threshold; - if (m_multisig) - { - if (!json.HasMember("multisig_signers")) - { - LOG_ERROR("Field multisig_signers not found in JSON"); - return false; - } - if (!json["multisig_signers"].IsString()) - { - LOG_ERROR("Field multisig_signers found in JSON, but not String"); - return false; - } - const char *field_multisig_signers = json["multisig_signers"].GetString(); - std::string multisig_signers = std::string(field_multisig_signers, field_multisig_signers + json["multisig_signers"].GetStringLength()); - r = ::serialization::parse_binary(multisig_signers, m_multisig_signers); - if (!r) - { - LOG_ERROR("Field multisig_signers found in JSON, but failed to parse"); - return false; - } - } + + m_multisig = false; + m_multisig_threshold = 0; + GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, always_confirm_transfers, int, Int, false, true); m_always_confirm_transfers = field_always_confirm_transfers; GET_FIELD_FROM_JSON_RETURN_ON_ERROR(json, print_ring_members, int, Int, false, true); @@ -3087,6 +2993,42 @@ bool wallet::load_keys(const std::string& keys_file_name, const epee::wipeable_s return true; } +bool wallet::load_safex_keys(const std::string& safex_keys_file_name, const epee::wipeable_string& password) +{ + rapidjson::Document json; + wallet::keys_file_data safex_keys_file_data; + std::string buf; + if(!epee::file_io_utils::load_file_to_string(safex_keys_file_name, buf)) + return false; + + // Decrypt the contents + bool r = ::serialization::parse_binary(buf, safex_keys_file_data); + THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "internal error: failed to deserialize \"" + safex_keys_file_name + '\"'); + crypto::chacha_key key; + crypto::generate_chacha_key(password.data(), password.size(), key); + std::string account_data; + account_data.resize(safex_keys_file_data.account_data.size()); + crypto::chacha20(safex_keys_file_data.account_data.data(), safex_keys_file_data.account_data.size(), key, safex_keys_file_data.iv, &account_data[0]); + if (json.Parse(account_data.c_str()).HasParseError() || !json.IsObject()) + crypto::chacha8(safex_keys_file_data.account_data.data(), safex_keys_file_data.account_data.size(), key, safex_keys_file_data.iv, &account_data[0]); + + if(json.IsObject()) { + const char *username, *secret_key; + for (rapidjson::Value::MemberIterator M = json.MemberBegin(); M != json.MemberEnd(); M++) { + username = M->name.GetString(); + secret_key = M->value.GetString(); + + if (username != nullptr && secret_key != nullptr) { + crypto::secret_key skey{}; + memcpy(skey.data,secret_key,sizeof(skey.data)); + recover_safex_account(username,skey); + } + } + return true; + } + return false; +} + /*! * \brief verify password for default wallet keys file. * \param password Password to verify @@ -3099,7 +3041,7 @@ bool wallet::load_keys(const std::string& keys_file_name, const epee::wipeable_s */ bool wallet::verify_password(const epee::wipeable_string& password) const { - return verify_password(m_keys_file, password, m_watch_only || m_multisig, m_account.get_device()); + return verify_password(m_keys_file, password, m_watch_only, m_account.get_device()); } /*! @@ -3155,100 +3097,6 @@ bool wallet::verify_password(const std::string& keys_file_name, const epee::wipe return r; } -/*! - * \brief Generates a wallet or restores one. - * \param wallet_ Name of wallet file - * \param password Password of wallet file - * \param multisig_data The multisig restore info and keys - */ -void wallet::generate(const std::string& wallet_, const epee::wipeable_string& password, - const std::string& multisig_data, bool create_address_file) -{ - clear(); - prepare_file_names(wallet_); - - if (!wallet_.empty()) - { - boost::system::error_code ignored_ec; - THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_wallet_file, ignored_ec), error::file_exists, m_wallet_file); - THROW_WALLET_EXCEPTION_IF(boost::filesystem::exists(m_keys_file, ignored_ec), error::file_exists, m_keys_file); - } - - m_account.generate(rct::rct2sk(rct::zero()), true, false); - - THROW_WALLET_EXCEPTION_IF(multisig_data.size() < 32, error::invalid_multisig_seed); - size_t offset = 0; - uint32_t threshold = *(uint32_t*)(multisig_data.data() + offset); - offset += sizeof(uint32_t); - uint32_t total = *(uint32_t*)(multisig_data.data() + offset); - offset += sizeof(uint32_t); - THROW_WALLET_EXCEPTION_IF(threshold < 2, error::invalid_multisig_seed); - THROW_WALLET_EXCEPTION_IF(total != threshold && total != threshold + 1, error::invalid_multisig_seed); - const size_t n_multisig_keys = total == threshold ? 1 : threshold; - THROW_WALLET_EXCEPTION_IF(multisig_data.size() != 8 + 32 * (4 + n_multisig_keys + total), error::invalid_multisig_seed); - - std::vector multisig_keys; - std::vector multisig_signers; - crypto::secret_key spend_secret_key = *(crypto::secret_key*)(multisig_data.data() + offset); - offset += sizeof(crypto::secret_key); - crypto::public_key spend_public_key = *(crypto::public_key*)(multisig_data.data() + offset); - offset += sizeof(crypto::public_key); - crypto::secret_key view_secret_key = *(crypto::secret_key*)(multisig_data.data() + offset); - offset += sizeof(crypto::secret_key); - crypto::public_key view_public_key = *(crypto::public_key*)(multisig_data.data() + offset); - offset += sizeof(crypto::public_key); - for (size_t n = 0; n < n_multisig_keys; ++n) - { - multisig_keys.push_back(*(crypto::secret_key*)(multisig_data.data() + offset)); - offset += sizeof(crypto::secret_key); - } - for (size_t n = 0; n < total; ++n) - { - multisig_signers.push_back(*(crypto::public_key*)(multisig_data.data() + offset)); - offset += sizeof(crypto::public_key); - } - - crypto::public_key calculated_view_public_key; - THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(view_secret_key, calculated_view_public_key), error::invalid_multisig_seed); - THROW_WALLET_EXCEPTION_IF(view_public_key != calculated_view_public_key, error::invalid_multisig_seed); - crypto::public_key local_signer; - THROW_WALLET_EXCEPTION_IF(!crypto::secret_key_to_public_key(spend_secret_key, local_signer), error::invalid_multisig_seed); - THROW_WALLET_EXCEPTION_IF(std::find(multisig_signers.begin(), multisig_signers.end(), local_signer) == multisig_signers.end(), error::invalid_multisig_seed); - rct::key skey = rct::zero(); - for (const auto &msk: multisig_keys) - sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes); - THROW_WALLET_EXCEPTION_IF(!(rct::rct2sk(skey) == spend_secret_key), error::invalid_multisig_seed); - - m_account.make_multisig(view_secret_key, spend_secret_key, spend_public_key, multisig_keys); - m_account.finalize_multisig(spend_public_key); - - m_account_public_address = m_account.get_keys().m_account_address; - m_watch_only = false; - m_multisig = true; - m_multisig_threshold = threshold; - m_multisig_signers = multisig_signers; - m_key_on_device = false; - - if (!wallet_.empty()) - { - bool r = store_keys(m_keys_file, password, false); - THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); - - if (m_nettype != MAINNET || create_address_file) - { - r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); - if(!r) MERROR("String with address text not saved"); - } - } - - cryptonote::block b; - generate_genesis(b); - m_blockchain.push_back(get_block_hash(b)); - add_subaddress_account(tr("Primary account")); - - if (!wallet_.empty()) - store(); -} /*! * \brief Generates a wallet or restores one. @@ -3490,350 +3338,12 @@ void wallet::restore(const std::string& wallet_, const epee::wipeable_string& pa } } -std::string wallet::make_multisig(const epee::wipeable_string &password, - const std::vector &view_keys, - const std::vector &spend_keys, - uint32_t threshold) -{ - CHECK_AND_ASSERT_THROW_MES(!view_keys.empty(), "empty view keys"); - CHECK_AND_ASSERT_THROW_MES(view_keys.size() == spend_keys.size(), "Mismatched view/spend key sizes"); - CHECK_AND_ASSERT_THROW_MES(threshold > 1 && threshold <= spend_keys.size() + 1, "Invalid threshold"); - CHECK_AND_ASSERT_THROW_MES(threshold == spend_keys.size() || threshold == spend_keys.size() + 1, "Unsupported threshold case"); - - std::string extra_multisig_info; - crypto::hash hash; - - clear(); - - MINFO("Creating spend key..."); - std::vector multisig_keys; - rct::key spend_pkey, spend_skey; - if (threshold == spend_keys.size() + 1) - { - cryptonote::generate_multisig_N_N(get_account().get_keys(), spend_keys, multisig_keys, spend_skey, spend_pkey); - } - else if (threshold == spend_keys.size()) - { - cryptonote::generate_multisig_N1_N(get_account().get_keys(), spend_keys, multisig_keys, spend_skey, spend_pkey); - - // We need an extra step, so we package all the composite public keys - // we know about, and make a signed string out of them - std::string data; - crypto::public_key signer; - CHECK_AND_ASSERT_THROW_MES(crypto::secret_key_to_public_key(rct::rct2sk(spend_skey), signer), "Failed to derive public spend key"); - data += std::string((const char *)&signer, sizeof(crypto::public_key)); - - for (const auto &msk: multisig_keys) - { - rct::key pmsk = rct::scalarmultBase(rct::sk2rct(msk)); - data += std::string((const char *)&pmsk, sizeof(crypto::public_key)); - } - - data.resize(data.size() + sizeof(crypto::signature)); - crypto::cn_fast_hash(data.data(), data.size() - sizeof(signature), hash); - crypto::signature &signature = *(crypto::signature*)&data[data.size() - sizeof(crypto::signature)]; - crypto::generate_signature(hash, signer, rct::rct2sk(spend_skey), signature); - - extra_multisig_info = std::string("MultisigxV1") + tools::base58::encode(data); - } - else - { - CHECK_AND_ASSERT_THROW_MES(false, "Unsupported threshold case"); - } - // the multisig view key is shared by all, make one all can derive - MINFO("Creating view key..."); - crypto::secret_key view_skey = cryptonote::generate_multisig_view_secret_key(get_account().get_keys().m_view_secret_key, view_keys); +bool wallet::multisig(bool *ready, uint32_t *threshold, uint32_t *total) const +{ + return false; +} - MINFO("Creating multisig address..."); - CHECK_AND_ASSERT_THROW_MES(m_account.make_multisig(view_skey, rct::rct2sk(spend_skey), rct::rct2pk(spend_pkey), multisig_keys), - "Failed to create multisig wallet due to bad keys"); - - m_account_public_address = m_account.get_keys().m_account_address; - m_watch_only = false; - m_multisig = true; - m_multisig_threshold = threshold; - m_key_on_device = false; - - if (threshold == spend_keys.size() + 1) - { - m_multisig_signers = spend_keys; - m_multisig_signers.push_back(get_multisig_signer_public_key()); - } - else - { - m_multisig_signers = std::vector(spend_keys.size() + 1, crypto::null_pkey); - } - - if (!m_wallet_file.empty()) - { - bool r = store_keys(m_keys_file, password, false); - THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); - - if (boost::filesystem::exists(m_wallet_file + ".address.txt")) - { - r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); - if(!r) MERROR("String with address text not saved"); - } - } - - cryptonote::block b; - generate_genesis(b); - m_blockchain.push_back(get_block_hash(b)); - add_subaddress_account(tr("Primary account")); - - if (!m_wallet_file.empty()) - store(); - - return extra_multisig_info; -} - -std::string wallet::make_multisig(const epee::wipeable_string &password, - const std::vector &info, - uint32_t threshold) -{ - // parse all multisig info - std::vector secret_keys(info.size()); - std::vector public_keys(info.size()); - for (size_t i = 0; i < info.size(); ++i) - { - THROW_WALLET_EXCEPTION_IF(!verify_multisig_info(info[i], secret_keys[i], public_keys[i]), - error::wallet_internal_error, "Bad multisig info: " + info[i]); - } - - // remove duplicates - for (size_t i = 0; i < secret_keys.size(); ++i) - { - for (size_t j = i + 1; j < secret_keys.size(); ++j) - { - if (rct::sk2rct(secret_keys[i]) == rct::sk2rct(secret_keys[j])) - { - MDEBUG("Duplicate key found, ignoring"); - secret_keys[j] = secret_keys.back(); - public_keys[j] = public_keys.back(); - secret_keys.pop_back(); - public_keys.pop_back(); - --j; - } - } - } - - // people may include their own, weed it out - const crypto::secret_key local_skey = cryptonote::get_multisig_blinded_secret_key(get_account().get_keys().m_view_secret_key); - const crypto::public_key local_pkey = get_multisig_signer_public_key(get_account().get_keys().m_spend_secret_key); - for (size_t i = 0; i < secret_keys.size(); ++i) - { - if (secret_keys[i] == local_skey) - { - MDEBUG("Local key is present, ignoring"); - secret_keys[i] = secret_keys.back(); - public_keys[i] = public_keys.back(); - secret_keys.pop_back(); - public_keys.pop_back(); - --i; - } - else - { - THROW_WALLET_EXCEPTION_IF(public_keys[i] == local_pkey, error::wallet_internal_error, - "Found local spend public key, but not local view secret key - something very weird"); - } - } - - return make_multisig(password, secret_keys, public_keys, threshold); -} - -bool wallet::finalize_multisig(const epee::wipeable_string &password, std::unordered_set pkeys, std::vector signers) -{ - CHECK_AND_ASSERT_THROW_MES(!pkeys.empty(), "empty pkeys"); - - // add ours if not included - crypto::public_key local_signer; - CHECK_AND_ASSERT_THROW_MES(crypto::secret_key_to_public_key(get_account().get_keys().m_spend_secret_key, local_signer), - "Failed to derive public spend key"); - if (std::find(signers.begin(), signers.end(), local_signer) == signers.end()) - { - signers.push_back(local_signer); - for (const auto &msk: get_account().get_multisig_keys()) - { - pkeys.insert(rct::rct2pk(rct::scalarmultBase(rct::sk2rct(msk)))); - } - } - - CHECK_AND_ASSERT_THROW_MES(signers.size() == m_multisig_signers.size(), "Bad signers size"); - - crypto::public_key spend_public_key = cryptonote::generate_multisig_N1_N_spend_public_key(std::vector(pkeys.begin(), pkeys.end())); - m_account_public_address.m_spend_public_key = spend_public_key; - m_account.finalize_multisig(spend_public_key); - - m_multisig_signers = signers; - std::sort(m_multisig_signers.begin(), m_multisig_signers.end(), [](const crypto::public_key &e0, const crypto::public_key &e1){ return memcmp(&e0, &e1, sizeof(e0)); }); - - if (!m_wallet_file.empty()) - { - bool r = store_keys(m_keys_file, password, false); - THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); - - if (boost::filesystem::exists(m_wallet_file + ".address.txt")) - { - r = file_io_utils::save_string_to_file(m_wallet_file + ".address.txt", m_account.get_public_address_str(m_nettype)); - if(!r) MERROR("String with address text not saved"); - } - } - - m_subaddresses.clear(); - m_subaddress_labels.clear(); - add_subaddress_account(tr("Primary account")); - - if (!m_wallet_file.empty()) - store(); - - return true; -} - -bool wallet::finalize_multisig(const epee::wipeable_string &password, const std::vector &info) -{ - // parse all multisig info - std::unordered_set public_keys; - std::vector signers(info.size(), crypto::null_pkey); - for (size_t i = 0; i < info.size(); ++i) - { - if (!verify_extra_multisig_info(info[i], public_keys, signers[i])) - { - MERROR("Bad multisig info"); - return false; - } - } - return finalize_multisig(password, public_keys, signers); -} - -std::string wallet::get_multisig_info() const -{ - // It's a signed package of private view key and public spend key - const crypto::secret_key skey = cryptonote::get_multisig_blinded_secret_key(get_account().get_keys().m_view_secret_key); - const crypto::public_key pkey = get_multisig_signer_public_key(get_account().get_keys().m_spend_secret_key); - crypto::hash hash; - - std::string data; - data += std::string((const char *)&skey, sizeof(crypto::secret_key)); - data += std::string((const char *)&pkey, sizeof(crypto::public_key)); - - data.resize(data.size() + sizeof(crypto::signature)); - crypto::cn_fast_hash(data.data(), data.size() - sizeof(signature), hash); - crypto::signature &signature = *(crypto::signature*)&data[data.size() - sizeof(crypto::signature)]; - crypto::generate_signature(hash, pkey, get_multisig_blinded_secret_key(get_account().get_keys().m_spend_secret_key), signature); - - return std::string("MultisigV1") + tools::base58::encode(data); -} - -bool wallet::verify_multisig_info(const std::string &data, crypto::secret_key &skey, crypto::public_key &pkey) -{ - const size_t header_len = strlen("MultisigV1"); - if (data.size() < header_len || data.substr(0, header_len) != "MultisigV1") - { - MERROR("Multisig info header check error"); - return false; - } - std::string decoded; - if (!tools::base58::decode(data.substr(header_len), decoded)) - { - MERROR("Multisig info decoding error"); - return false; - } - if (decoded.size() != sizeof(crypto::secret_key) + sizeof(crypto::public_key) + sizeof(crypto::signature)) - { - MERROR("Multisig info is corrupt"); - return false; - } - - size_t offset = 0; - skey = *(const crypto::secret_key*)(decoded.data() + offset); - offset += sizeof(skey); - pkey = *(const crypto::public_key*)(decoded.data() + offset); - offset += sizeof(pkey); - const crypto::signature &signature = *(const crypto::signature*)(decoded.data() + offset); - - crypto::hash hash; - crypto::cn_fast_hash(decoded.data(), decoded.size() - sizeof(signature), hash); - if (!crypto::check_signature(hash, pkey, signature)) - { - MERROR("Multisig info signature is invalid"); - return false; - } - - return true; -} - -bool wallet::verify_extra_multisig_info(const std::string &data, std::unordered_set &pkeys, crypto::public_key &signer) -{ - const size_t header_len = strlen("MultisigxV1"); - if (data.size() < header_len || data.substr(0, header_len) != "MultisigxV1") - { - MERROR("Multisig info header check error"); - return false; - } - std::string decoded; - if (!tools::base58::decode(data.substr(header_len), decoded)) - { - MERROR("Multisig info decoding error"); - return false; - } - if (decoded.size() < sizeof(crypto::public_key) + sizeof(crypto::signature)) - { - MERROR("Multisig info is corrupt"); - return false; - } - if ((decoded.size() - (sizeof(crypto::public_key) + sizeof(crypto::signature))) % sizeof(crypto::public_key)) - { - MERROR("Multisig info is corrupt"); - return false; - } - - const size_t n_keys = (decoded.size() - (sizeof(crypto::public_key) + sizeof(crypto::signature))) / sizeof(crypto::public_key); - size_t offset = 0; - signer = *(const crypto::public_key*)(decoded.data() + offset); - offset += sizeof(signer); - const crypto::signature &signature = *(const crypto::signature*)(decoded.data() + offset + n_keys * sizeof(crypto::public_key)); - - crypto::hash hash; - crypto::cn_fast_hash(decoded.data(), decoded.size() - sizeof(signature), hash); - if (!crypto::check_signature(hash, signer, signature)) - { - MERROR("Multisig info signature is invalid"); - return false; - } - - for (size_t n = 0; n < n_keys; ++n) - { - crypto::public_key mspk = *(const crypto::public_key*)(decoded.data() + offset); - pkeys.insert(mspk); - offset += sizeof(mspk); - } - - return true; -} - -bool wallet::multisig(bool *ready, uint32_t *threshold, uint32_t *total) const -{ - if (!m_multisig) - return false; - if (threshold) - *threshold = m_multisig_threshold; - if (total) - *total = m_multisig_signers.size(); - if (ready) - *ready = !(get_account().get_keys().m_account_address.m_spend_public_key == rct::rct2pk(rct::identity())); - return true; -} - -bool wallet::has_multisig_partial_key_images() const -{ - if (!m_multisig) - return false; - for (const auto &td: m_transfers) - if (td.m_key_image_partial) - return true; - return false; -} /*! * \brief Rewrites to the wallet file for wallet upgrade (doesn't generate key, assumes it's already there) @@ -3849,6 +3359,8 @@ void wallet::rewrite(const std::string& wallet_name, const epee::wipeable_string THROW_WALLET_EXCEPTION_IF(!boost::filesystem::exists(m_keys_file, ignored_ec), error::file_not_found, m_keys_file); bool r = store_keys(m_keys_file, password, m_watch_only); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); + r = store_safex_keys(m_safex_keys_file, password); + THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_safex_keys_file); } /*! * \brief Writes to a file named based on the normal wallet (doesn't generate key, assumes it's already there) @@ -3868,8 +3380,8 @@ void wallet::write_watch_only_wallet(const std::string& wallet_name, const epee: //---------------------------------------------------------------------------------------------------- void wallet::wallet_exists(const std::string& file_path, bool& keys_file_exists, bool& wallet_file_exists) { - std::string keys_file, wallet_file; - do_prepare_file_names(file_path, keys_file, wallet_file); + std::string keys_file, wallet_file, safex_keys_file; + do_prepare_file_names(file_path, keys_file, wallet_file, safex_keys_file); boost::system::error_code ignore; keys_file_exists = boost::filesystem::exists(keys_file, ignore); @@ -3923,7 +3435,7 @@ bool wallet::parse_payment_id(const std::string& payment_id_str, crypto::hash& p //---------------------------------------------------------------------------------------------------- bool wallet::prepare_file_names(const std::string& file_path) { - do_prepare_file_names(file_path, m_keys_file, m_wallet_file); + do_prepare_file_names(file_path, m_keys_file, m_wallet_file, m_safex_keys_file); return true; } //---------------------------------------------------------------------------------------------------- @@ -4066,6 +3578,11 @@ void wallet::load(const std::string& wallet_, const epee::wipeable_string& passw error::wallet_files_doesnt_correspond, m_keys_file, m_wallet_file); } + if (!load_safex_keys(m_safex_keys_file, password)) + { + LOG_PRINT_L0("No safex accounts found in : " << m_safex_keys_file); + } + cryptonote::block genesis; generate_genesis(genesis); crypto::hash genesis_hash = get_block_hash(genesis); @@ -4142,12 +3659,28 @@ std::string wallet::path() const { return m_wallet_file; } + +boost::optional password_prompter(const char *prompt, bool verify) +{ + auto pwd_container = tools::password_container::prompt(verify, prompt); + if (!pwd_container) + { + MERROR("failed to read wallet password"); + } + return pwd_container; +} //---------------------------------------------------------------------------------------------------- void wallet::store() { store_to("", epee::wipeable_string()); } //---------------------------------------------------------------------------------------------------- +void wallet::store_safex(const epee::wipeable_string &password) +{ + bool r = store_safex_keys(m_safex_keys_file, password); + THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_safex_keys_file); +} +//---------------------------------------------------------------------------------------------------- void wallet::store_to(const std::string &path, const epee::wipeable_string &password) { trim_hashchain(); @@ -4163,7 +3696,7 @@ void wallet::store_to(const std::string &path, const epee::wipeable_string &pass #ifdef WIN32 //boost canonical messes with linux gnu #else - if (!path.empty()) + if (!path.empty() && boost::filesystem::exists(m_wallet_file)) { std::string canonical_path = boost::filesystem::canonical(m_wallet_file).string(); size_t pos = canonical_path.find(path); @@ -4202,8 +3735,10 @@ void wallet::store_to(const std::string &path, const epee::wipeable_string &pass cache_file_data.cache_data = cipher; const std::string new_file = same_file ? m_wallet_file + ".new" : path; + const std::string new_safex_keys_file = same_file ? m_safex_keys_file + ".new" : path; const std::string old_file = m_wallet_file; const std::string old_keys_file = m_keys_file; + const std::string old_safex_keys_file = m_safex_keys_file; const std::string old_address_file = m_wallet_file + ".address.txt"; // save keys to the new file @@ -4212,6 +3747,8 @@ void wallet::store_to(const std::string &path, const epee::wipeable_string &pass prepare_file_names(path); bool r = store_keys(m_keys_file, password, false); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); + r = store_safex_keys(m_safex_keys_file, password); + THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_safex_keys_file); if (boost::filesystem::exists(old_address_file)) { // save address to the new file @@ -4229,6 +3766,11 @@ void wallet::store_to(const std::string &path, const epee::wipeable_string &pass if (!r) { LOG_ERROR("error removing file: " << old_keys_file); } + // remove old safex keys file + r = boost::filesystem::remove(old_safex_keys_file); + if (!r) { + LOG_ERROR("error removing file: " << old_safex_keys_file); + } // remove old address file r = boost::filesystem::remove(old_address_file); if (!r) { @@ -4254,7 +3796,6 @@ void wallet::store_to(const std::string &path, const epee::wipeable_string &pass ostr.close(); THROW_WALLET_EXCEPTION_IF(!success || !ostr.good(), error::file_save_error, new_file); #endif - // here we have "*.new" file, we need to rename it to be without ".new" std::error_code e = tools::replace_file(new_file, m_wallet_file); THROW_WALLET_EXCEPTION_IF(e, error::file_save_error, m_wallet_file, e); @@ -4306,6 +3847,10 @@ std::map wallet::balance_per_subaddress(uint32_t index_major std::map amount_per_subaddr; for (const auto& td: m_transfers) { + if(td.m_output_type != cryptonote::tx_out_type::out_cash) { + continue; + } + if (td.m_subaddr_index.major == index_major && !td.m_spent) { auto found = amount_per_subaddr.find(td.m_subaddr_index.minor); @@ -4317,6 +3862,10 @@ std::map wallet::balance_per_subaddress(uint32_t index_major } for (const auto& utx: m_unconfirmed_txs) { + if( utx.second.m_output_type != cryptonote::tx_out_type::out_cash) { + continue; + } + if (utx.second.m_subaddr_account == index_major && utx.second.m_state != wallet::unconfirmed_transfer_details::failed) { // all changes go to 0-th subaddress (in the current subaddress account) @@ -4335,6 +3884,10 @@ std::map wallet::unlocked_balance_per_subaddress(uint32_t in std::map amount_per_subaddr; for(const transfer_details& td: m_transfers) { + if(td.m_output_type != cryptonote::tx_out_type::out_cash) { + continue; + } + if(td.m_subaddr_index.major == index_major && !td.m_spent && is_transfer_unlocked(td)) { auto found = amount_per_subaddr.find(td.m_subaddr_index.minor); @@ -4346,23 +3899,31 @@ std::map wallet::unlocked_balance_per_subaddress(uint32_t in } return amount_per_subaddr; } + //---------------------------------------------------------------------------------------------------- std::map wallet::token_balance_per_subaddress(uint32_t index_major) const { std::map token_amount_per_subaddr; for (const auto& td: m_transfers) { + if(td.m_output_type != cryptonote::tx_out_type::out_token) { + continue; + } + if (td.m_subaddr_index.major == index_major && !td.m_spent) { auto found = token_amount_per_subaddr.find(td.m_subaddr_index.minor); if (found == token_amount_per_subaddr.end()) - token_amount_per_subaddr[td.m_subaddr_index.minor] = td.token_amount(); + token_amount_per_subaddr[td.m_subaddr_index.minor] = td.get_out_type() == tx_out_type::out_token ? td.token_amount():0; else - found->second += td.token_amount(); + found->second += td.get_out_type() == tx_out_type::out_token ? td.token_amount() : 0; } } for (const auto& utx: m_unconfirmed_txs) { + if( utx.second.m_output_type != cryptonote::tx_out_type::out_token) { + continue; + } if (utx.second.m_subaddr_account == index_major && utx.second.m_state != wallet::unconfirmed_transfer_details::failed) { // all changes go to 0-th subaddress (in the current subaddress account) @@ -4375,19 +3936,26 @@ std::map wallet::token_balance_per_subaddress(uint32_t index } return token_amount_per_subaddr; } + +//---------------------------------------------------------------------------------------------------- + //---------------------------------------------------------------------------------------------------- std::map wallet::unlocked_token_balance_per_subaddress(uint32_t index_major) const { std::map token_amount_per_subaddr; for(const transfer_details& td: m_transfers) { + if(td.m_output_type != cryptonote::tx_out_type::out_token) { + continue; + } + if(td.m_subaddr_index.major == index_major && !td.m_spent && is_token_transfer_unlocked(td)) { auto found = token_amount_per_subaddr.find(td.m_subaddr_index.minor); if (found == token_amount_per_subaddr.end()) - token_amount_per_subaddr[td.m_subaddr_index.minor] = td.token_amount(); + token_amount_per_subaddr[td.m_subaddr_index.minor] = td.m_output_type == tx_out_type::out_token ? td.token_amount() : 0; else - found->second += td.token_amount(); + found->second += td.m_output_type == tx_out_type::out_token ? td.token_amount() : 0; } } return token_amount_per_subaddr; @@ -4575,7 +4143,14 @@ bool wallet::is_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) c //---------------------------------------------------------------------------------------------------- bool wallet::is_token_transfer_unlocked(const transfer_details& td) const { - return is_token_transfer_unlocked(td.m_tx.unlock_time, td.m_block_height); + + auto block_height = td.m_block_height; + + if(td.token_amount()== SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE && is_create_account_token_fee(td)){ + block_height += safex::get_safex_minumum_account_create_token_lock_period(m_nettype); + } + + return is_token_transfer_unlocked(td.m_tx.unlock_time, block_height); } //---------------------------------------------------------------------------------------------------- bool wallet::is_token_transfer_unlocked(uint64_t unlock_time, uint64_t block_height) const @@ -4696,13 +4271,17 @@ float wallet::get_output_relatedness(const transfer_details &td0, const transfer return 0.0f; } //---------------------------------------------------------------------------------------------------- -size_t wallet::pop_best_value_from(const transfer_container &transfers, std::vector &unused_indices, const std::vector& selected_transfers, bool smallest, bool token_transfer) const +size_t wallet::pop_best_value_from(const transfer_container &transfers, std::vector &unused_indices, const std::vector& selected_transfers, bool smallest, const cryptonote::tx_out_type out_type, const uint64_t needed_cash_for_purchase) const { std::vector candidates; float best_relatedness = 1.0f; + + bool largest = false; + for (size_t n = 0; n < unused_indices.size(); ++n) { const transfer_details &candidate = transfers[unused_indices[n]]; + if (candidate.get_out_type() != out_type || (needed_cash_for_purchase > 0 && needed_cash_for_purchase > candidate.amount())) continue; float relatedness = 0.0f; for (std::vector::const_iterator i = selected_transfers.begin(); i != selected_transfers.end(); ++i) { @@ -4725,6 +4304,43 @@ size_t wallet::pop_best_value_from(const transfer_container &transfers, std::vec candidates.push_back(n); } + if(!candidates.empty() && needed_cash_for_purchase > 0) + smallest = true; + + if(candidates.empty() && needed_cash_for_purchase > 0) + largest = true; + + if(candidates.empty()){ + float best_relatedness = 1.0f; + for (size_t n = 0; n < unused_indices.size(); ++n) + { + const transfer_details &candidate = transfers[unused_indices[n]]; + if (candidate.get_out_type() != out_type) continue; + float relatedness = 0.0f; + for (std::vector::const_iterator i = selected_transfers.begin(); i != selected_transfers.end(); ++i) + { + float r = get_output_relatedness(candidate, transfers[*i]); + if (r > relatedness) + { + relatedness = r; + if (relatedness == 1.0f) + break; + } + } + + if (relatedness < best_relatedness) + { + best_relatedness = relatedness; + candidates.clear(); + } + + if (relatedness == best_relatedness) + candidates.push_back(n); + } + } + + + THROW_WALLET_EXCEPTION_IF(candidates.empty(), error::no_matching_available_outputs); // we have all the least related outputs in candidates, so we can pick either // the smallest, or a random one, depending on request size_t idx; @@ -4734,18 +4350,34 @@ size_t wallet::pop_best_value_from(const transfer_container &transfers, std::vec for (size_t n = 0; n < candidates.size(); ++n) { const transfer_details &td = transfers[unused_indices[candidates[n]]]; - if (token_transfer) + if (out_type == tx_out_type::out_token && td.get_out_type() == out_type) { if (td.token_amount() < transfers[unused_indices[candidates[idx]]].token_amount()) idx = n; } - else + else if (out_type == tx_out_type::out_cash && td.get_out_type() == out_type) { if (td.amount() < transfers[unused_indices[candidates[idx]]].amount()) idx = n; } + else if (out_type == tx_out_type::out_staked_token && td.get_out_type() == out_type) + { + if (td.token_amount() == transfers[unused_indices[candidates[idx]]].token_amount()) + idx = n; + } } } + else if (largest) + { + idx = 0; + for (size_t n = 0; n < candidates.size(); ++n) + { + const transfer_details &td = transfers[unused_indices[candidates[n]]]; + + if (td.amount() > transfers[unused_indices[candidates[idx]]].amount()) + idx = n; + } + } else { idx = crypto::rand() % candidates.size(); @@ -4753,37 +4385,193 @@ size_t wallet::pop_best_value_from(const transfer_container &transfers, std::vec return pop_index (unused_indices, candidates[idx]); } //---------------------------------------------------------------------------------------------------- -size_t wallet::pop_best_value(std::vector &unused_indices, const std::vector& selected_transfers, bool smallest, bool token_transfer) const -{ - return pop_best_value_from(m_transfers, unused_indices, selected_transfers, smallest, token_transfer); -} -//---------------------------------------------------------------------------------------------------- -// Select random input sources for transaction. -// returns: -// direct return: amount of money found -// modified reference: selected_transfers, a list of iterators/indices of input sources -uint64_t wallet::select_transfers(uint64_t needed_money, std::vector unused_transfers_indices, std::vector& selected_transfers, bool trusted_daemon) const -{ - uint64_t found_money = 0; - selected_transfers.reserve(unused_transfers_indices.size()); - while (found_money < needed_money && !unused_transfers_indices.empty()) + size_t wallet::pop_ideal_value_from(const transfer_container &transfers, std::vector &unused_indices, const std::vector &selected_transfers, const cryptonote::tx_out_type out_type, const uint64_t cash_amount, + const uint64_t token_amount) const { - size_t idx = pop_best_value(unused_transfers_indices, selected_transfers); + std::vector candidates; + float best_relatedness = 1.0f; + uint64_t oldest_output = get_blockchain_current_height(); + for (size_t n = 0; n < unused_indices.size(); ++n) + { + const transfer_details &candidate = transfers[unused_indices[n]]; + if ((candidate.get_out_type() != out_type) || (candidate.token_amount() != token_amount) || (candidate.amount() != cash_amount)) continue; - const transfer_container::const_iterator it = m_transfers.begin() + idx; - selected_transfers.push_back(idx); - found_money += it->amount(); - } + //in case of staked token outputs with the same amount, select the oldest one + if (candidate.get_out_type() == tx_out_type::out_staked_token) + { + if (candidate.m_block_height < oldest_output) + { + candidates.clear(); + oldest_output = candidate.m_block_height; + candidates.push_back(n); + } + } + else + { + float relatedness = 0.0f; + for (std::vector::const_iterator i = selected_transfers.begin(); i != selected_transfers.end(); ++i) + { + float r = get_output_relatedness(candidate, transfers[*i]); + if (r > relatedness) + { + relatedness = r; + if (relatedness == 1.0f) + break; + } + } - return found_money; -} -//---------------------------------------------------------------------------------------------------- - void wallet::add_unconfirmed_tx(const cryptonote::transaction &tx, uint64_t amount_in, uint64_t token_amount_in, const std::vector &dests, const crypto::hash &payment_id, uint64_t change_amount, - uint64_t token_change_amount, uint32_t subaddr_account, const std::set &subaddr_indices) -{ - unconfirmed_transfer_details& utd = m_unconfirmed_txs[cryptonote::get_transaction_hash(tx)]; - utd.m_amount_in = amount_in; - utd.m_token_amount_in = token_amount_in; + + if (relatedness < best_relatedness) + { + best_relatedness = relatedness; + candidates.clear(); + } + + if (relatedness == best_relatedness) + candidates.push_back(n); + } + } + + + THROW_WALLET_EXCEPTION_IF(candidates.empty(), error::no_matching_available_outputs); + + size_t idx; + idx = crypto::rand() % candidates.size(); + + return pop_index(unused_indices, candidates[idx]); + } + //---------------------------------------------------------------------------------------------------- + size_t wallet::pop_advanced_output_from(const transfer_container &transfers,const std::vector& selected_transfers, const std::string &acc_username, const cryptonote::tx_out_type out_type) const + { + std::vector candidates; + for (size_t n = 0; n < transfers.size(); ++n) + { + const transfer_details &candidate = transfers[n]; + if (candidate.get_out_type() != out_type) continue; + candidates.push_back(n); + } + + + THROW_WALLET_EXCEPTION_IF(candidates.empty(), error::safex_unknown_account); + + int idx = -1; + for (size_t n = 0; n < candidates.size(); ++n) + { + const transfer_details &td = transfers[candidates[n]]; + const txout_to_script ¤t = boost::get(td.m_tx.vout[td.m_internal_output_index].target); + const cryptonote::blobdata blobdata1(begin(current.data), end(current.data)); + std::string current_username; + + if (out_type == tx_out_type::out_safex_account && td.get_out_type() == tx_out_type::out_safex_account) + { + safex::create_account_data account_output_data; + parse_and_validate_object_from_blob(blobdata1, account_output_data); + current_username = std::string(begin(account_output_data.username), end(account_output_data.username)); + } + if (current_username == acc_username && td.m_block_height+ CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= m_local_bc_height) + idx = (int)n; + } + + THROW_WALLET_EXCEPTION_IF(idx == -1, error::safex_unknown_account); + + return candidates[idx]; + } + + size_t wallet::pop_advanced_output_from(const transfer_container &transfers, const std::vector& selected_transfers, const crypto::hash& out_id, const cryptonote::tx_out_type out_type) const + { + std::vector candidates; + for (size_t n = 0; n < transfers.size(); ++n) + { + const transfer_details &candidate = transfers[n]; + if (candidate.get_out_type() != out_type) continue; + candidates.push_back(n); + } + + + THROW_WALLET_EXCEPTION_IF(candidates.empty(), error::safex_unknown_id); + + int idx = -1; + for (size_t n = 0; n < candidates.size(); ++n) + { + const transfer_details &td = transfers[candidates[n]]; + const txout_to_script ¤t = boost::get(td.m_tx.vout[td.m_internal_output_index].target); + const cryptonote::blobdata blobdata1(begin(current.data), end(current.data)); + + if (out_type == tx_out_type::out_safex_feedback_token && td.get_out_type() == tx_out_type::out_safex_feedback_token && !td.m_spent) + { + safex::create_feedback_token_data feedback_token_output_data; + parse_and_validate_object_from_blob(blobdata1, feedback_token_output_data); + if (out_id == feedback_token_output_data.offer_id && td.m_block_height+ CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= m_local_bc_height) + idx = (int)n; + } else if (out_type == tx_out_type::out_safex_offer && td.get_out_type() == tx_out_type::out_safex_offer) + { + safex::create_offer_data offer_output_data; + parse_and_validate_object_from_blob(blobdata1, offer_output_data); + if (out_id == offer_output_data.offer_id && td.m_block_height+ CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= m_local_bc_height) + idx = (int)n; + } + else if (out_type == tx_out_type::out_safex_price_peg && td.get_out_type() == tx_out_type::out_safex_price_peg) + { + safex::create_price_peg_data price_peg_output_data; + parse_and_validate_object_from_blob(blobdata1, price_peg_output_data); + if (out_id == price_peg_output_data.price_peg_id && td.m_block_height+ CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= m_local_bc_height) + idx = (int)n; + + } + } + + THROW_WALLET_EXCEPTION_IF(idx == -1, error::safex_unknown_id); + + return candidates[idx]; + } +//---------------------------------------------------------------------------------------------------- +size_t wallet::pop_best_value(std::vector &unused_indices, const std::vector& selected_transfers, bool smallest, const cryptonote::tx_out_type out_type, const uint64_t needed_cash_for_purchase) const +{ + return pop_best_value_from(m_transfers, unused_indices, selected_transfers, smallest, out_type, needed_cash_for_purchase); +} +//---------------------------------------------------------------------------------------------------- +size_t wallet::pop_ideal_value(std::vector &unused_indices, const std::vector& selected_transfers, const cryptonote::tx_out_type out_type, const uint64_t cash_amount, const uint64_t token_amount) const +{ + return pop_ideal_value_from(m_transfers, unused_indices, selected_transfers, out_type, cash_amount, token_amount); +} +//---------------------------------------------------------------------------------------------------- + size_t wallet::pop_advanced_output(const std::vector& selected_transfers, const std::vector &acc_username, const cryptonote::tx_out_type out_type) const + { + const std::string acc_username_str(acc_username.begin(), acc_username.end()); + return pop_advanced_output_from(m_transfers, selected_transfers, acc_username_str, out_type); + } + + size_t wallet::pop_advanced_output(const std::vector& selected_transfers, const crypto::hash& out_id, const cryptonote::tx_out_type out_type) const + { + return pop_advanced_output_from(m_transfers, selected_transfers, out_id, out_type); + } +//---------------------------------------------------------------------------------------------------- +// Select random input sources for transaction. +// returns: +// direct return: amount of money found +// modified reference: selected_transfers, a list of iterators/indices of input sources +uint64_t wallet::select_transfers(uint64_t needed_money, std::vector unused_transfers_indices, std::vector& selected_transfers, bool trusted_daemon) const +{ + uint64_t found_money = 0; + selected_transfers.reserve(unused_transfers_indices.size()); + while (found_money < needed_money && !unused_transfers_indices.empty()) + { + size_t idx = pop_best_value(unused_transfers_indices, selected_transfers); + + const transfer_container::const_iterator it = m_transfers.begin() + idx; + selected_transfers.push_back(idx); + found_money += it->amount(); + } + + return found_money; +} +//---------------------------------------------------------------------------------------------------- + void wallet::add_unconfirmed_tx(const cryptonote::transaction &tx, uint64_t amount_in, uint64_t token_amount_in, const std::vector &dests, const crypto::hash &payment_id, uint64_t change_amount, + uint64_t token_change_amount, uint32_t subaddr_account, const std::set &subaddr_indices) +{ + unconfirmed_transfer_details& utd = m_unconfirmed_txs[cryptonote::get_transaction_hash(tx)]; + utd.m_amount_in = amount_in; + utd.m_token_amount_in = token_amount_in; utd.m_amount_out = 0; utd.m_token_amount_out = 0; for (const auto &d: dests) @@ -4842,7 +4630,7 @@ void wallet::transfer_migration( // throw if attempting a transaction with no destinations THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination); - THROW_WALLET_EXCEPTION_IF(m_multisig, error::wallet_internal_error, "Multisig wallets cannot spend non rct outputs"); + THROW_WALLET_EXCEPTION_IF(m_multisig, error::wallet_internal_error, "Multisig is not supported"); uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit(); uint64_t needed_money = fee; @@ -4864,7 +4652,7 @@ void wallet::transfer_migration( // throw if requested send amount is greater than (unlocked) amount available to send std::vector selected_transfers; uint64_t found_money = select_transfers(needed_money, unused_transfers_indices, selected_transfers, trusted_daemon); - THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee); + THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_cash, found_money, needed_money - fee, fee); uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major; for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i) { @@ -4923,9 +4711,7 @@ void wallet::transfer_migration( const transfer_details& td = m_transfers[idx]; src.amount = td.amount(); src.token_amount = 0; - src.token_transaction = false; - src.migration = false; - src.rct = false; + src.referenced_output_type = tx_out_type::out_cash; //paste mixin transaction if(!daemon_resp.outs.empty()) { @@ -4957,7 +4743,6 @@ void wallet::transfer_migration( src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx); src.real_output = interted_it - src.outputs.begin(); src.real_output_in_tx_index = td.m_internal_output_index; - src.multisig_kLRki = rct::multisig_kLRki({rct::zero(), rct::zero(), rct::zero(), rct::zero()}); detail::print_source_entry(src); ++i; } @@ -4974,9 +4759,7 @@ void wallet::transfer_migration( auto output = cryptonote::generate_migration_bitcoin_transaction_output(m_account.get_keys(), bitcoin_transaction_hash, dt.token_amount); src.outputs.push_back(output); src.token_amount = dt.token_amount; - src.rct = false; - src.token_transaction = true; - src.migration = true; + src.referenced_output_type = tx_out_type::out_bitcoin_migration; detail::print_token_source_entry(src); } } @@ -5003,7 +4786,7 @@ void wallet::transfer_migration( splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust, d.is_subaddress)); if (d.token_transaction) - splitted_dsts.push_back(cryptonote::tx_destination_entry(d.token_amount, dust_policy.addr_for_dust, d.is_subaddress, true)); + splitted_dsts.push_back(cryptonote::tx_destination_entry(d.token_amount, dust_policy.addr_for_dust, d.is_subaddress, cryptonote::tx_out_type::out_token)); dust += d.amount; token_dust += d.token_amount; @@ -5011,9 +4794,8 @@ void wallet::transfer_migration( crypto::secret_key tx_key = AUTO_VAL_INIT(tx_key); std::vector additional_tx_keys; - rct::multisig_out msout = AUTO_VAL_INIT(msout); - 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, false, m_multisig ? &msout : NULL); + 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); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); @@ -5356,11 +5138,9 @@ bool wallet::sign_tx(unsigned_tx_set &exported_txs, const std::string &signed_fi LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, ring size " << sd.sources[0].outputs.size()); signed_txes.ptx.push_back(pending_tx()); tools::wallet::pending_tx &ptx = signed_txes.ptx.back(); - bool bulletproof = sd.use_rct && !ptx.tx.rct_signatures.p.bulletproofs.empty(); crypto::secret_key tx_key; std::vector additional_tx_keys; - rct::multisig_out msout; - 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, bulletproof, m_multisig ? &msout : NULL); + 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); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, 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, @@ -5550,295 +5330,9 @@ bool wallet::load_tx(const std::string &signed_filename, std::vector& ptx_vector) -{ - multisig_tx_set txs; - txs.m_ptx = ptx_vector; - - for (const auto &msk: get_account().get_multisig_keys()) - { - crypto::public_key pkey = get_multisig_signing_public_key(msk); - for (auto &ptx: txs.m_ptx) for (auto &sig: ptx.multisig_sigs) sig.signing_keys.insert(pkey); - } - - txs.m_signers.insert(get_multisig_signer_public_key()); - - return save_multisig_tx(txs); -} -//---------------------------------------------------------------------------------------------------- -bool wallet::save_multisig_tx(const std::vector& ptx_vector, const std::string &filename) -{ - std::string ciphertext = save_multisig_tx(ptx_vector); - if (ciphertext.empty()) - return false; - return epee::file_io_utils::save_string_to_file(filename, ciphertext); -} -//---------------------------------------------------------------------------------------------------- -bool wallet::load_multisig_tx(cryptonote::blobdata s, multisig_tx_set &exported_txs, std::function accept_func) -{ - const size_t magiclen = strlen(MULTISIG_UNSIGNED_TX_PREFIX); - if (strncmp(s.c_str(), MULTISIG_UNSIGNED_TX_PREFIX, magiclen)) - { - LOG_PRINT_L0("Bad magic from multisig tx data"); - return false; - } - try - { - s = decrypt_with_view_secret_key(std::string(s, magiclen)); - } - catch (const std::exception &e) - { - LOG_PRINT_L0("Failed to decrypt multisig tx data: " << e.what()); - return false; - } - try - { - std::istringstream iss(s); - boost::archive::portable_binary_iarchive ar(iss); - ar >> exported_txs; - } - catch (...) - { - LOG_PRINT_L0("Failed to parse multisig tx data"); - return false; - } - - // sanity checks - for (const auto &ptx: exported_txs.m_ptx) - { - CHECK_AND_ASSERT_MES(ptx.selected_transfers.size() == ptx.tx.vin.size(), false, "Mismatched selected_transfers/vin sizes"); - for (size_t idx: ptx.selected_transfers) - CHECK_AND_ASSERT_MES(idx < m_transfers.size(), false, "Transfer index out of range"); - CHECK_AND_ASSERT_MES(ptx.construction_data.selected_transfers.size() == ptx.tx.vin.size(), false, "Mismatched cd selected_transfers/vin sizes"); - for (size_t idx: ptx.construction_data.selected_transfers) - CHECK_AND_ASSERT_MES(idx < m_transfers.size(), false, "Transfer index out of range"); - CHECK_AND_ASSERT_MES(ptx.construction_data.sources.size() == ptx.tx.vin.size(), false, "Mismatched sources/vin sizes"); - } - - LOG_PRINT_L1("Loaded multisig tx unsigned data from binary: " << exported_txs.m_ptx.size() << " transactions"); - for (auto &ptx: exported_txs.m_ptx) LOG_PRINT_L0(cryptonote::obj_to_json_str(ptx.tx)); - - if (accept_func && !accept_func(exported_txs)) - { - LOG_PRINT_L1("Transactions rejected by callback"); - return false; - } - - const bool is_signed = exported_txs.m_signers.size() >= m_multisig_threshold; - if (is_signed) - { - for (const auto &ptx: exported_txs.m_ptx) - { - const crypto::hash txid = get_transaction_hash(ptx.tx); - if (store_tx_info()) - { - m_tx_keys.insert(std::make_pair(txid, ptx.tx_key)); - m_additional_tx_keys.insert(std::make_pair(txid, ptx.additional_tx_keys)); - } - } - } - - return true; -} -//---------------------------------------------------------------------------------------------------- -bool wallet::load_multisig_tx_from_file(const std::string &filename, multisig_tx_set &exported_txs, std::function accept_func) -{ - std::string s; - boost::system::error_code errcode; - - if (!boost::filesystem::exists(filename, errcode)) - { - LOG_PRINT_L0("File " << filename << " does not exist: " << errcode); - return false; - } - if (!epee::file_io_utils::load_file_to_string(filename.c_str(), s)) - { - LOG_PRINT_L0("Failed to load from " << filename); - return false; - } - - if (!load_multisig_tx(s, exported_txs, accept_func)) - { - LOG_PRINT_L0("Failed to parse multisig tx data from " << filename); - return false; - } - return true; -} -//---------------------------------------------------------------------------------------------------- -bool wallet::sign_multisig_tx(multisig_tx_set &exported_txs, std::vector &txids) -{ - THROW_WALLET_EXCEPTION_IF(exported_txs.m_ptx.empty(), error::wallet_internal_error, "No tx found"); - - const crypto::public_key local_signer = get_multisig_signer_public_key(); - - THROW_WALLET_EXCEPTION_IF(exported_txs.m_signers.find(local_signer) != exported_txs.m_signers.end(), - error::wallet_internal_error, "Transaction already signed by this private key"); - THROW_WALLET_EXCEPTION_IF(exported_txs.m_signers.size() > m_multisig_threshold, - error::wallet_internal_error, "Transaction was signed by too many signers"); - THROW_WALLET_EXCEPTION_IF(exported_txs.m_signers.size() == m_multisig_threshold, - error::wallet_internal_error, "Transaction is already fully signed"); - - txids.clear(); - - // sign the transactions - for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n) - { - tools::wallet::pending_tx &ptx = exported_txs.m_ptx[n]; - THROW_WALLET_EXCEPTION_IF(ptx.multisig_sigs.empty(), error::wallet_internal_error, "No signatures found in multisig tx"); - tools::wallet::tx_construction_data &sd = ptx.construction_data; - LOG_PRINT_L1(" " << (n+1) << ": " << sd.sources.size() << " inputs, mixin " << (sd.sources[0].outputs.size()-1) << - ", signed by " << exported_txs.m_signers.size() << "/" << m_multisig_threshold); - cryptonote::transaction tx; - rct::multisig_out msout = ptx.multisig_sigs.front().msout; - auto sources = sd.sources; - const bool bulletproof = sd.use_rct && (ptx.tx.rct_signatures.type == rct::RCTTypeFullBulletproof || ptx.tx.rct_signatures.type == rct::RCTTypeSimpleBulletproof); - bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources, sd.splitted_dsts, ptx.change_dts.addr, sd.extra, tx, sd.unlock_time, ptx.tx_key, ptx.additional_tx_keys, sd.use_rct, bulletproof, &msout, false); - THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sd.sources, sd.splitted_dsts, sd.unlock_time, m_nettype); - - THROW_WALLET_EXCEPTION_IF(get_transaction_prefix_hash (tx) != get_transaction_prefix_hash(ptx.tx), - error::wallet_internal_error, "Transaction prefix does not match data"); - - // Tests passed, sign - std::vector indices; - for (const auto &source: sources) - indices.push_back(source.real_output); - - for (auto &sig: ptx.multisig_sigs) - { - if (sig.ignore != local_signer) - { - ptx.tx.rct_signatures = sig.sigs; - - rct::keyV k; - for (size_t idx: sd.selected_transfers) - k.push_back(get_multisig_k(idx, sig.used_L)); - - rct::key skey = rct::zero(); - for (const auto &msk: get_account().get_multisig_keys()) - { - crypto::public_key pmsk = get_multisig_signing_public_key(msk); - - if (sig.signing_keys.find(pmsk) == sig.signing_keys.end()) - { - sc_add(skey.bytes, skey.bytes, rct::sk2rct(msk).bytes); - sig.signing_keys.insert(pmsk); - } - } - THROW_WALLET_EXCEPTION_IF(!rct::signMultisig(ptx.tx.rct_signatures, indices, k, sig.msout, skey), - error::wallet_internal_error, "Failed signing, transaction likely malformed"); - - sig.sigs = ptx.tx.rct_signatures; - } - } - - const bool is_last = exported_txs.m_signers.size() + 1 >= m_multisig_threshold; - if (is_last) - { - // when the last signature on a multisig tx is made, we select the right - // signature to plug into the final tx - bool found = false; - for (const auto &sig: ptx.multisig_sigs) - { - if (sig.ignore != local_signer && exported_txs.m_signers.find(sig.ignore) == exported_txs.m_signers.end()) - { - THROW_WALLET_EXCEPTION_IF(found, error::wallet_internal_error, "More than one transaction is final"); - ptx.tx.rct_signatures = sig.sigs; - found = true; - } - } - THROW_WALLET_EXCEPTION_IF(!found, error::wallet_internal_error, - "Final signed transaction not found: this transaction was likely made without our export data, so we cannot sign it"); - const crypto::hash txid = get_transaction_hash(ptx.tx); - if (store_tx_info()) - { - m_tx_keys.insert(std::make_pair(txid, ptx.tx_key)); - m_additional_tx_keys.insert(std::make_pair(txid, ptx.additional_tx_keys)); - } - txids.push_back(txid); - } - } - - // txes generated, get rid of used k values - for (size_t n = 0; n < exported_txs.m_ptx.size(); ++n) - for (size_t idx: exported_txs.m_ptx[n].construction_data.selected_transfers) - m_transfers[idx].m_multisig_k.clear(); - - exported_txs.m_signers.insert(get_multisig_signer_public_key()); - - return true; -} -//---------------------------------------------------------------------------------------------------- -bool wallet::sign_multisig_tx_to_file(multisig_tx_set &exported_txs, const std::string &filename, std::vector &txids) -{ - bool r = sign_multisig_tx(exported_txs, txids); - if (!r) - return false; - return save_multisig_tx(exported_txs, filename); -} -//---------------------------------------------------------------------------------------------------- -bool wallet::sign_multisig_tx_from_file(const std::string &filename, std::vector &txids, std::function accept_func) -{ - multisig_tx_set exported_txs; - if(!load_multisig_tx_from_file(filename, exported_txs)) - return false; - - if (accept_func && !accept_func(exported_txs)) - { - LOG_PRINT_L1("Transactions rejected by callback"); - return false; - } - return sign_multisig_tx_to_file(exported_txs, filename, txids); -} -//---------------------------------------------------------------------------------------------------- uint64_t wallet::get_fee_multiplier(uint32_t priority, int fee_algorithm) const { - static const uint64_t multipliers[3] = {1, 2, 3}; + static const uint64_t multipliers[4] = {1, 2, 3, 4}; if (fee_algorithm == -1) fee_algorithm = get_fee_algorithm(); @@ -5855,7 +5349,7 @@ uint64_t wallet::get_fee_multiplier(uint32_t priority, int fee_algorithm) const } // 1 to 3 are allowed as priorities - uint32_t max_priority = 3; + uint32_t max_priority = 4; if (priority >= 1 && priority <= max_priority) { switch (fee_algorithm) @@ -6018,7 +5512,7 @@ std::vector wallet::create_transactions(std::vector> &o if (fake_outputs_count > 0) { + std::vector cash_token_selected_transfers; + + for(size_t idx: selected_transfers) + { + if (m_transfers[idx].m_output_type == cryptonote::tx_out_type::out_safex_account || + m_transfers[idx].m_output_type == cryptonote::tx_out_type::out_safex_account_update || + m_transfers[idx].m_output_type == cryptonote::tx_out_type::out_safex_offer || + m_transfers[idx].m_output_type == cryptonote::tx_out_type::out_safex_offer_update || + m_transfers[idx].m_output_type == cryptonote::tx_out_type::out_safex_price_peg || + m_transfers[idx].m_output_type == cryptonote::tx_out_type::out_safex_price_peg_update || + m_transfers[idx].m_output_type == cryptonote::tx_out_type::out_safex_feedback_token || + m_transfers[idx].m_output_type == cryptonote::tx_out_type::out_safex_feedback) //no fake outputs count for accounts and offers + continue; + + cash_token_selected_transfers.push_back(idx); + + } + + uint64_t segregation_fork_height = get_segregation_fork_height(); // check whether we're shortly after the fork uint64_t height; @@ -6451,14 +5964,14 @@ void wallet::get_outs(std::vector> &o cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response resp_t = AUTO_VAL_INIT(resp_t); m_daemon_rpc_mutex.lock(); - for(size_t idx: selected_transfers) + for(size_t idx: cash_token_selected_transfers) { - if (m_transfers[idx].m_token_transfer && out_type == tx_out_type::out_token) - req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].token_amount()); + if (out_type == tx_out_type::out_token) + req_t.amounts.push_back(m_transfers[idx].token_amount()); - if (!m_transfers[idx].m_token_transfer && out_type == tx_out_type::out_cash) - req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount()); + if (out_type == tx_out_type::out_cash) + req_t.amounts.push_back(m_transfers[idx].amount()); } std::sort(req_t.amounts.begin(), req_t.amounts.end()); auto end = std::unique(req_t.amounts.begin(), req_t.amounts.end()); @@ -6478,13 +5991,13 @@ void wallet::get_outs(std::vector> &o { cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::request req_t = AUTO_VAL_INIT(req_t); cryptonote::COMMAND_RPC_GET_OUTPUT_DISTRIBUTION::response resp_t = AUTO_VAL_INIT(resp_t); - for(size_t idx: selected_transfers) + for(size_t idx: cash_token_selected_transfers) { - if (m_transfers[idx].m_token_transfer && out_type == tx_out_type::out_token) - req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].token_amount()); + if (out_type == tx_out_type::out_token) + req_t.amounts.push_back(m_transfers[idx].token_amount()); - if (!m_transfers[idx].m_token_transfer && out_type == tx_out_type::out_cash) - req_t.amounts.push_back(m_transfers[idx].is_rct() ? 0 : m_transfers[idx].amount()); + if (out_type == tx_out_type::out_cash) + req_t.amounts.push_back(m_transfers[idx].amount()); } std::sort(req_t.amounts.begin(), req_t.amounts.end()); auto end = std::unique(req_t.amounts.begin(), req_t.amounts.end()); @@ -6501,14 +6014,11 @@ void wallet::get_outs(std::vector> &o THROW_WALLET_EXCEPTION_IF(resp_t.status != CORE_RPC_STATUS_OK, error::get_output_distribution, resp_t.status); // check we got all data - for(size_t idx: selected_transfers) + for(size_t idx: cash_token_selected_transfers) { - //skip cash outputs if getting token outputs or other way round - if ((!m_transfers[idx].m_token_transfer && out_type == tx_out_type::out_token) - || (m_transfers[idx].m_token_transfer && out_type == tx_out_type::out_cash)) - continue; - const uint64_t value_amount = m_transfers[idx].is_rct() ? 0 : (m_transfers[idx].m_token_transfer ? m_transfers[idx].token_amount() : m_transfers[idx].amount()); + const uint64_t value_amount = (out_type == tx_out_type::out_token ? m_transfers[idx].token_amount() : m_transfers[idx].amount()); + if (value_amount == 0) continue; //skip this outputs bool found = false; for (const auto &d: resp_t.distributions) { @@ -6541,16 +6051,14 @@ void wallet::get_outs(std::vector> &o req.out_type = out_type; size_t num_selected_transfers = 0; - for(size_t idx: selected_transfers) + for(size_t idx: cash_token_selected_transfers) { - //skip cash outputs if getting token outputs or other way round - if ((!m_transfers[idx].m_token_transfer && out_type == tx_out_type::out_token) - || (m_transfers[idx].m_token_transfer && out_type == tx_out_type::out_cash)) - continue; - ++num_selected_transfers; const transfer_details &td = m_transfers[idx]; - const uint64_t value_amount = td.is_rct() ? 0 : (td.m_token_transfer ? td.token_amount(): td.amount()); + const uint64_t value_amount = (out_type == tx_out_type::out_token ? td.token_amount(): td.amount()); + if (value_amount == 0) continue; + + ++num_selected_transfers; std::unordered_set seen_indices; // request more for rct in base recent (locked) coinbases are picked, since they're locked for longer size_t requested_outputs_count = base_requested_outputs_count + (td.is_rct() ? CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW - CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE : 0); @@ -6804,7 +6312,7 @@ void wallet::get_outs(std::vector> &o std::unordered_map scanty_outs; size_t base = 0; outs.reserve(num_selected_transfers); - for(size_t idx: selected_transfers) + for(size_t idx: cash_token_selected_transfers) { //skip cash outputs if getting token outputs or other way round if ((!m_transfers[idx].m_token_transfer && out_type == tx_out_type::out_token) @@ -6924,13 +6432,12 @@ void wallet::get_outs(std::vector> &o { const transfer_details &td = m_transfers[idx]; //skip cash outputs if getting token outputs or other way round - if ((!m_transfers[idx].m_token_transfer && out_type == tx_out_type::out_token) - || (m_transfers[idx].m_token_transfer && out_type == tx_out_type::out_cash)) + if (td.m_output_type != out_type) continue; std::vector v; - const uint64_t value_amount = td.is_rct() ? 0 : (td.m_token_transfer ? td.token_amount(): td.amount()); - const rct::key mask = td.is_rct() ? rct::commit(value_amount, td.m_mask) : rct::zeroCommit(value_amount); + const uint64_t value_amount = td.m_token_transfer ? td.token_amount(): td.amount(); + const rct::key mask = rct::zeroCommit(value_amount); v.push_back(std::make_tuple(td.m_global_output_index, td.get_public_key(), mask)); outs.push_back(v); } @@ -6946,7 +6453,7 @@ void wallet::transfer_selected(const std::vector 0; - src.rct = td.is_rct(); + src.referenced_output_type = (src.token_amount > 0) ? tx_out_type::out_token: tx_out_type::out_cash; //paste keys (fake and real) for (size_t n = 0; n < fake_outputs_count + 1; ++n) @@ -7043,7 +6549,6 @@ void wallet::transfer_selected(const std::vector additional_tx_keys; - rct::multisig_out msout = AUTO_VAL_INIT(msout); 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, false, m_multisig ? &msout : NULL); + 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); LOG_PRINT_L2("constructed tx, r="< dsts, const std::vector& selected_transfers, size_t fake_outputs_count, - std::vector> &outs, - uint64_t unlock_time, uint64_t fee, const std::vector& extra, cryptonote::transaction& tx, pending_tx &ptx, bool bulletproof) + +template +void wallet::transfer_advanced(safex::command_t command_type, const std::vector& dsts, const std::vector& selected_transfers, + size_t fake_outputs_count, std::vector> &outs, + uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, + cryptonote::transaction& tx, pending_tx &ptx, const safex::safex_account &sfx_acc) { using namespace cryptonote; // throw if attempting a transaction with no destinations THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination); + THROW_WALLET_EXCEPTION_IF(m_multisig, error::wallet_internal_error, "Multisig wallets not supported"); + uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit(); uint64_t needed_money = fee; - LOG_PRINT_L2("transfer_selected_rct: starting with fee " << print_money (needed_money)); - LOG_PRINT_L2("selected transfers: " << strjoin(selected_transfers, " ")); + uint64_t needed_tokens = 0; + uint64_t needed_staked_tokens = 0; + LOG_PRINT_L2("transfer: starting with fee " << print_money (needed_money)); + + safex::safex_account_keys my_safex_keys = AUTO_VAL_INIT(my_safex_keys); // calculate total amount being sent to all destinations // throw if total amount overflows uint64_t for(auto& dt: dsts) { - THROW_WALLET_EXCEPTION_IF(0 == dt.amount, error::zero_destination); needed_money += dt.amount; - LOG_PRINT_L2("transfer: adding " << print_money(dt.amount) << ", for a total of " << print_money (needed_money)); - THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee, m_nettype); - } - - // if this is a multisig wallet, create a list of multisig signers we can use - std::deque multisig_signers; - size_t n_multisig_txes = 0; - if (m_multisig && !m_transfers.empty()) - { - const crypto::public_key local_signer = get_multisig_signer_public_key(); - size_t n_available_signers = 1; - for (const crypto::public_key &signer: m_multisig_signers) + if (command_type == safex::command_t::token_unstake) { - if (signer == local_signer) - continue; - multisig_signers.push_front(signer); - for (const auto &i: m_transfers[0].m_multisig_info) - { - if (i.m_signer == signer) - { - multisig_signers.pop_front(); - multisig_signers.push_back(signer); - ++n_available_signers; - break; - } - } + needed_staked_tokens += dt.token_amount; + THROW_WALLET_EXCEPTION_IF(needed_staked_tokens < dt.token_amount, error::tx_sum_overflow, dsts, fee, m_nettype); + } + else + { + needed_tokens += dt.token_amount; + THROW_WALLET_EXCEPTION_IF(needed_tokens < dt.token_amount, error::tx_sum_overflow, dsts, fee, m_nettype); } - multisig_signers.push_back(local_signer); - MDEBUG("We can use " << n_available_signers << "/" << m_multisig_signers.size() << " other signers"); - THROW_WALLET_EXCEPTION_IF(n_available_signers+1 < m_multisig_threshold, error::multisig_import_needed); - n_multisig_txes = n_available_signers == m_multisig_signers.size() ? m_multisig_threshold : 1; - MDEBUG("We will create " << n_multisig_txes << " txes"); + + LOG_PRINT_L2("advanced transfer: adding " << print_money(dt.token_amount) << " tokens, for a total of " << print_money (needed_tokens) << + " tokens and " << print_money(dt.amount) << " cash, for a total of " << print_money (needed_money) << " cash"); + THROW_WALLET_EXCEPTION_IF(needed_money < dt.amount, error::tx_sum_overflow, dsts, fee, m_nettype); + } uint64_t found_money = 0; + uint64_t found_tokens = 0; + uint64_t found_staked_tokens = 0; for(size_t idx: selected_transfers) { found_money += m_transfers[idx].amount(); + found_tokens += m_transfers[idx].m_output_type == tx_out_type::out_token ? m_transfers[idx].token_amount() : 0; + found_staked_tokens += m_transfers[idx].m_output_type == tx_out_type::out_staked_token ? m_transfers[idx].token_amount() : 0; } - LOG_PRINT_L2("wanted " << print_money(needed_money) << ", found " << print_money(found_money) << ", fee " << print_money(fee)); - THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee); + LOG_PRINT_L2("wanted tokens:" << print_money(needed_tokens) << ", found tokens: " << print_money(found_tokens) << " wanted cash:" << + print_money(needed_money) << ", found cash:" << print_money(found_money) << ", fee " << print_money(fee) << " cash"); + THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_cash, found_money, needed_money - fee, fee); + THROW_WALLET_EXCEPTION_IF(found_tokens < needed_tokens, error::not_enough_unlocked_tokens, found_tokens, needed_tokens); + THROW_WALLET_EXCEPTION_IF(found_staked_tokens < needed_staked_tokens, error::not_enough_unlocked_staked_tokens, found_staked_tokens, needed_staked_tokens); uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major; for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i) THROW_WALLET_EXCEPTION_IF(subaddr_account != m_transfers[*i].m_subaddr_index.major, error::wallet_internal_error, "the tx uses funds from multiple accounts"); - if (outs.empty()) - get_outs(outs, selected_transfers, fake_outputs_count, cryptonote::tx_out_type::out_cash); // may throw + if (outs.empty()) { + if ((command_type == safex::command_t::token_stake || command_type == safex::command_t::create_account)) + get_outs(outs, selected_transfers, fake_outputs_count, tx_out_type::out_token); // may throw + else if (command_type == safex::command_t::donate_network_fee || command_type == safex::command_t::simple_purchase) + get_outs(outs, selected_transfers, fake_outputs_count, tx_out_type::out_cash); // may throw + else if (command_type == safex::command_t::token_unstake) + get_outs(outs, selected_transfers, fake_outputs_count, tx_out_type::out_staked_token); // may throw + else if (command_type == safex::command_t::edit_account) + get_outs(outs, selected_transfers, 0, tx_out_type::out_safex_account); // may throw + else if (command_type == safex::command_t::create_offer) + get_outs(outs, selected_transfers, 0, tx_out_type::out_safex_account); // may throw + else if (command_type == safex::command_t::edit_offer) + get_outs(outs, selected_transfers, 0, tx_out_type::out_safex_offer); // may throw + else if (command_type == safex::command_t::create_feedback) + get_outs(outs, selected_transfers, 0, tx_out_type::out_safex_feedback_token); // may throw + else if (command_type == safex::command_t::create_price_peg) + get_outs(outs, selected_transfers, 0, tx_out_type::out_safex_account); // may throw + else if (command_type == safex::command_t::update_price_peg) + get_outs(outs, selected_transfers, 0, tx_out_type::out_safex_price_peg); // may throw + } + + + if ((command_type == safex::command_t::token_stake) || (command_type == safex::command_t::token_unstake) + || (command_type == safex::command_t::create_account) || (command_type == safex::command_t::edit_account) + || (command_type == safex::command_t::create_offer) || (command_type == safex::command_t::edit_offer) + || (command_type == safex::command_t::create_price_peg) || (command_type == safex::command_t::update_price_peg) + || (command_type == safex::command_t::create_feedback)) + { + //find also outputs for cash fee payment in case of token transaction + std::vector> cash_fee_outs = AUTO_VAL_INIT(cash_fee_outs); + get_outs(cash_fee_outs, selected_transfers, fake_outputs_count, cryptonote::tx_out_type::out_cash); + for (auto out: cash_fee_outs) + outs.push_back(out); + } + else if (command_type == safex::command_t::donate_network_fee || command_type == safex::command_t::simple_purchase) + { + //do nothing + } + else { + THROW_WALLET_EXCEPTION(tools::error::command_not_supported); + } //prepare inputs LOG_PRINT_L2("preparing outputs"); + typedef cryptonote::tx_source_entry::output_entry tx_output_entry; size_t i = 0, out_index = 0; std::vector sources; - std::unordered_set used_L; + std::vector additional_sources; //advanced command inputs + + auto find_matching_advanced_output = [&](const tx_out_type out_type) { + for (const cryptonote::tx_destination_entry& dt: dsts ) + if (dt.output_type == out_type) return dt; + + THROW_WALLET_EXCEPTION(tools::error::safex_missing_outputs_error); + return cryptonote::tx_destination_entry{}; + }; + + bool command_input_creted = false; for(size_t idx: selected_transfers) { - sources.resize(sources.size()+1); - cryptonote::tx_source_entry& src = sources.back(); - const transfer_details& td = m_transfers[idx]; + sources.resize(sources.size() + 1); + cryptonote::tx_source_entry &src = sources.back(); + const transfer_details &td = m_transfers[idx]; src.amount = td.amount(); - src.rct = td.is_rct(); - //paste mixin transaction - - THROW_WALLET_EXCEPTION_IF(outs.size() < out_index + 1 , error::wallet_internal_error, "outs.size() < out_index + 1"); - THROW_WALLET_EXCEPTION_IF(outs[out_index].size() < fake_outputs_count , error::wallet_internal_error, "fake_outputs_count > random outputs found"); + src.token_amount = td.token_amount(); + if (td.get_out_type() != tx_out_type::out_invalid && td.get_out_type() != tx_out_type::out_cash) + src.referenced_output_type = td.get_out_type(); + else + src.referenced_output_type = (src.token_amount > 0) ? tx_out_type::out_token : tx_out_type::out_cash; - typedef cryptonote::tx_source_entry::output_entry tx_output_entry; - for (size_t n = 0; n < fake_outputs_count + 1; ++n) + //paste keys (fake and real) + const size_t fake_outputs_count_revised = (src.referenced_output_type == tx_out_type::out_safex_account || src.referenced_output_type == tx_out_type::out_safex_offer + || src.referenced_output_type == tx_out_type::out_safex_feedback_token || src.referenced_output_type == tx_out_type::out_safex_price_peg) ? 0 : fake_outputs_count; + for (size_t n = 0; n < fake_outputs_count_revised + 1; ++n) { - tx_output_entry oe; + tx_output_entry oe = AUTO_VAL_INIT(oe); oe.first = std::get<0>(outs[out_index][n]); oe.second.dest = rct::pk2rct(std::get<1>(outs[out_index][n])); oe.second.mask = std::get<2>(outs[out_index][n]); + src.outputs.push_back(oe); + ++i; } - ++i; //paste real transaction to the random index - auto it_to_replace = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a) + auto it_to_replace = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry &a) { return a.first == td.m_global_output_index; }); THROW_WALLET_EXCEPTION_IF(it_to_replace == src.outputs.end(), error::wallet_internal_error, - "real output not found"); + "real output not found"); - tx_output_entry real_oe; + tx_output_entry real_oe = AUTO_VAL_INIT(real_oe); real_oe.first = td.m_global_output_index; - real_oe.second.dest = rct::pk2rct(td.get_public_key()); - real_oe.second.mask = rct::commit(td.amount(), td.m_mask); + real_oe.second.dest = rct::pk2rct(*boost::apply_visitor(destination_public_key_visitor(), td.m_tx.vout[td.m_internal_output_index].target)); *it_to_replace = real_oe; src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx, td.m_pk_index); src.real_out_additional_tx_keys = get_additional_tx_pub_keys_from_extra(td.m_tx); src.real_output = it_to_replace - src.outputs.begin(); src.real_output_in_tx_index = td.m_internal_output_index; - src.mask = td.m_mask; - if (m_multisig) + + //set command type + if (command_type == safex::command_t::token_stake && src.referenced_output_type == tx_out_type::out_token) + src.command_type = safex::command_t::token_stake; + else if (command_type == safex::command_t::simple_purchase && (!command_input_creted)) { - crypto::public_key ignore = m_multisig_threshold == m_multisig_signers.size() ? crypto::null_pkey : multisig_signers.front(); - src.multisig_kLRki = get_multisig_composite_kLRki(idx, ignore, used_L, used_L); + src.command_type = safex::command_t::simple_purchase; + src.referenced_output_type = cryptonote::tx_out_type::out_cash; + command_input_creted = true; + const cryptonote::tx_destination_entry &dt_purchase = find_matching_advanced_output(tx_out_type::out_safex_purchase); + src.command_safex_data = dt_purchase.output_data; } - else - src.multisig_kLRki = rct::multisig_kLRki({rct::zero(), rct::zero(), rct::zero(), rct::zero()}); + else if (command_type == safex::command_t::token_unstake && src.referenced_output_type == tx_out_type::out_staked_token) + { + src.command_type = safex::command_t::token_unstake; + + src.amount = get_interest_for_transfer(td); + + } + else if (command_type == safex::command_t::create_account && (!command_input_creted)) + { + const cryptonote::tx_destination_entry &dt_account = find_matching_advanced_output(tx_out_type::out_safex_account); + src.command_safex_data = dt_account.output_data; + src.command_type = safex::command_t::create_account; + command_input_creted = true; + bool res = get_safex_account_keys(sfx_acc.username, my_safex_keys); + THROW_WALLET_EXCEPTION_IF(!res, error::wallet_internal_error, "safex account keys missing"); + } + else if (command_type == safex::command_t::edit_account && m_transfers[idx].m_output_type == tx_out_type::out_safex_account) + { + const cryptonote::tx_destination_entry &dt_account = find_matching_advanced_output(tx_out_type::out_safex_account_update); + src.command_safex_data = dt_account.output_data; + src.command_type = safex::command_t::edit_account; + bool res = get_safex_account_keys(sfx_acc.username, my_safex_keys); + THROW_WALLET_EXCEPTION_IF(!res, error::wallet_internal_error, "safex account keys missing"); + } + else if (command_type == safex::command_t::create_offer && m_transfers[idx].m_output_type == tx_out_type::out_safex_account) + { + const cryptonote::tx_destination_entry &dt_account = find_matching_advanced_output(tx_out_type::out_safex_offer); + src.command_safex_data = dt_account.output_data; + src.command_type = safex::command_t::create_offer; + bool res = get_safex_account_keys(sfx_acc.username, my_safex_keys); + THROW_WALLET_EXCEPTION_IF(!res, error::wallet_internal_error, "safex account keys missing"); + } + else if (command_type == safex::command_t::edit_offer && m_transfers[idx].m_output_type == tx_out_type::out_safex_offer) + { + const cryptonote::tx_destination_entry &dt_account = find_matching_advanced_output(tx_out_type::out_safex_offer_update); + src.command_safex_data = dt_account.output_data; + src.command_type = safex::command_t::edit_offer; + bool res = get_safex_account_keys(sfx_acc.username, my_safex_keys); + THROW_WALLET_EXCEPTION_IF(!res, error::wallet_internal_error, "safex account keys missing"); + } + else if (command_type == safex::command_t::create_feedback && m_transfers[idx].m_output_type == tx_out_type::out_safex_feedback_token) + { + const cryptonote::tx_destination_entry &dt_account = find_matching_advanced_output(tx_out_type::out_safex_feedback); + src.command_safex_data = dt_account.output_data; + src.command_type = safex::command_t::create_feedback; + } + else if (command_type == safex::command_t::create_price_peg && m_transfers[idx].m_output_type == tx_out_type::out_safex_account) + { + const cryptonote::tx_destination_entry &dt_account = find_matching_advanced_output(tx_out_type::out_safex_price_peg); + src.command_safex_data = dt_account.output_data; + src.command_type = safex::command_t::create_price_peg; + bool res = get_safex_account_keys(sfx_acc.username, my_safex_keys); + THROW_WALLET_EXCEPTION_IF(!res, error::wallet_internal_error, "safex account keys missing"); + } + else if (command_type == safex::command_t::update_price_peg && m_transfers[idx].m_output_type == tx_out_type::out_safex_price_peg) + { + const cryptonote::tx_destination_entry &dt_account = find_matching_advanced_output(tx_out_type::out_safex_price_peg_update); + src.command_safex_data = dt_account.output_data; + src.command_type = safex::command_t::update_price_peg; + bool res = get_safex_account_keys(sfx_acc.username, my_safex_keys); + THROW_WALLET_EXCEPTION_IF(!res, error::wallet_internal_error, "safex account keys missing"); + } + detail::print_source_entry(src); ++out_index; } + + if (additional_sources.size() > 0) std::copy(additional_sources.begin(), additional_sources.end(), std::back_inserter(sources)); + LOG_PRINT_L2("outputs prepared"); - // we still keep a copy, since we want to keep dsts free of change for user feedback purposes - std::vector splitted_dsts = dsts; cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts); - change_dts.amount = found_money - needed_money; - if (change_dts.amount == 0) + cryptonote::tx_destination_entry change_token_dts = AUTO_VAL_INIT(change_token_dts); + + if (needed_money < found_money) { - if (splitted_dsts.size() == 1) - { - // If the change is 0, send it to a random address, to avoid confusing - // the sender with a 0 amount output. We send a 0 amount in order to avoid - // letting the destination be able to work out which of the inputs is the - // real one in our rings - LOG_PRINT_L2("generating dummy address for 0 change"); - cryptonote::account_base dummy; - dummy.generate(); - change_dts.addr = dummy.get_keys().m_account_address; - LOG_PRINT_L2("generated dummy address for 0 change"); - splitted_dsts.push_back(change_dts); - } + change_dts.addr = get_subaddress({subaddr_account, 0}); + change_dts.amount = found_money - needed_money; } - else + + if (needed_tokens < found_tokens) { - change_dts.addr = get_subaddress({subaddr_account, 0}); - splitted_dsts.push_back(change_dts); + change_token_dts.addr = get_subaddress({subaddr_account, 0}); + change_token_dts.token_amount = found_tokens - needed_tokens; + } + + std::vector splitted_dsts, dust_dsts; + uint64_t dust = 0; + destination_split_strategy(dsts, change_dts, change_token_dts, dust_policy.dust_threshold, splitted_dsts, dust_dsts); + for(auto& d: dust_dsts) { + THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.amount, error::wallet_internal_error, "invalid dust value: dust = " + + std::to_string(d.amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); + THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < d.token_amount, error::wallet_internal_error, "invalid token dust value: dust = " + + std::to_string(d.token_amount) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); + } + for(auto& d: dust_dsts) { + if ((!dust_policy.add_to_fee)) + splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust, d.is_subaddress, cryptonote::tx_out_type::out_cash)); + + dust += d.amount; } - crypto::secret_key tx_key; + crypto::secret_key tx_key = AUTO_VAL_INIT(tx_key); std::vector additional_tx_keys; - rct::multisig_out msout; LOG_PRINT_L2("constructing tx"); - auto sources_copy = sources; - 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, bulletproof, m_multisig ? &msout : NULL); + + + + 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, my_safex_keys); LOG_PRINT_L2("constructed tx, r="< ins_order; - for (size_t n = 0; n < sources.size(); ++n) + std::string key_images; + bool all_are_valid_input = std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool { - for (size_t idx = 0; idx < sources_copy.size(); ++idx) + if ((s_e.type() == typeid(txin_to_key)) || (s_e.type() == typeid(txin_token_to_key)) || (s_e.type() == typeid(txin_to_script)) ) { - THROW_WALLET_EXCEPTION_IF((size_t)sources_copy[idx].real_output >= sources_copy[idx].outputs.size(), - error::wallet_internal_error, "Invalid real_output"); - if (sources_copy[idx].outputs[sources_copy[idx].real_output].second.dest == sources[n].outputs[sources[n].real_output].second.dest) - ins_order.push_back(idx); + const crypto::key_image &k_image = *boost::apply_visitor(key_image_visitor(), s_e); + key_images += boost::to_string(k_image) + " "; + return true; } - } - THROW_WALLET_EXCEPTION_IF(ins_order.size() != sources.size(), error::wallet_internal_error, "Failed to work out sources permutation"); - - std::vector multisig_sigs; - if (m_multisig) - { - crypto::public_key ignore = m_multisig_threshold == m_multisig_signers.size() ? crypto::null_pkey : multisig_signers.front(); - multisig_sigs.push_back({tx.rct_signatures, ignore, used_L, std::unordered_set(), msout}); - - if (m_multisig_threshold < m_multisig_signers.size()) - { - const crypto::hash prefix_hash = cryptonote::get_transaction_prefix_hash(tx); - - // create the other versions, one for every other participant (the first one's already done above) - for (size_t signer_index = 1; signer_index < n_multisig_txes; ++signer_index) - { - std::unordered_set new_used_L; - size_t src_idx = 0; - THROW_WALLET_EXCEPTION_IF(selected_transfers.size() != sources.size(), error::wallet_internal_error, "mismatched selected_transfers and sources sixes"); - for(size_t idx: selected_transfers) - { - cryptonote::tx_source_entry& src = sources[src_idx]; - src.multisig_kLRki = get_multisig_composite_kLRki(idx, multisig_signers[signer_index], used_L, new_used_L); - ++src_idx; - } + else + return false; + }); + THROW_WALLET_EXCEPTION_IF(!all_are_valid_input, error::unexpected_txin_type, tx); - LOG_PRINT_L2("Creating supplementary multisig transaction"); - cryptonote::transaction ms_tx; - auto sources_copy_copy = sources_copy; - bool r = cryptonote::construct_tx_with_tx_key(m_account.get_keys(), m_subaddresses, sources_copy_copy, splitted_dsts, change_dts.addr, extra, ms_tx, unlock_time,tx_key, additional_tx_keys, true, bulletproof, &msout, false); - LOG_PRINT_L2("constructed tx, r="<(), msout}); - ms_tx.rct_signatures = tx.rct_signatures; - THROW_WALLET_EXCEPTION_IF(cryptonote::get_transaction_hash(ms_tx) != cryptonote::get_transaction_hash(tx), error::wallet_internal_error, "Multisig txes differ by more than the signatures"); - } - } - } + bool dust_sent_elsewhere = (dust_policy.addr_for_dust.m_view_public_key != change_dts.addr.m_view_public_key + || dust_policy.addr_for_dust.m_spend_public_key != change_dts.addr.m_spend_public_key); - LOG_PRINT_L2("gathering key images"); - std::string key_images; - bool all_are_txin_to_key = std::all_of(tx.vin.begin(), tx.vin.end(), [&](const txin_v& s_e) -> bool - { - CHECKED_GET_SPECIFIC_VARIANT(s_e, const txin_to_key, in, false); - key_images += boost::to_string(in.k_image) + " "; - return true; - }); - THROW_WALLET_EXCEPTION_IF(!all_are_txin_to_key, error::unexpected_txin_type, tx); - LOG_PRINT_L2("gathered key images"); + if (dust_policy.add_to_fee || dust_sent_elsewhere) change_dts.amount -= dust; ptx.key_images = key_images; - ptx.fee = fee; - ptx.dust = 0; - ptx.dust_added_to_fee = false; + ptx.fee = (dust_policy.add_to_fee ? fee+dust : fee); + ptx.dust = ((dust_policy.add_to_fee || dust_sent_elsewhere) ? dust : 0); + ptx.dust_added_to_fee = dust_policy.add_to_fee; ptx.tx = tx; ptx.change_dts = change_dts; + ptx.change_token_dts = change_token_dts; ptx.selected_transfers = selected_transfers; - tools::apply_permutation(ins_order, ptx.selected_transfers); ptx.tx_key = tx_key; ptx.additional_tx_keys = additional_tx_keys; ptx.dests = dsts; - ptx.multisig_sigs = multisig_sigs; - ptx.construction_data.sources = sources_copy; + ptx.construction_data.sources = sources; ptx.construction_data.change_dts = change_dts; ptx.construction_data.splitted_dsts = splitted_dsts; - ptx.construction_data.selected_transfers = ptx.selected_transfers; + ptx.construction_data.selected_transfers = selected_transfers; ptx.construction_data.extra = tx.extra; ptx.construction_data.unlock_time = unlock_time; - ptx.construction_data.use_rct = true; + ptx.construction_data.use_rct = false; ptx.construction_data.dests = dsts; // record which subaddress indices are being used as inputs ptx.construction_data.subaddr_account = subaddr_account; ptx.construction_data.subaddr_indices.clear(); for (size_t idx: selected_transfers) ptx.construction_data.subaddr_indices.insert(m_transfers[idx].m_subaddr_index.minor); - LOG_PRINT_L2("transfer_selected_rct done"); -} - - -std::vector wallet::pick_preferred_rct_inputs(uint64_t needed_money, uint32_t subaddr_account, const std::set &subaddr_indices) const -{ - std::vector picks; - float current_output_relatdness = 1.0f; - - LOG_PRINT_L2("pick_preferred_rct_inputs: needed_money " << print_money(needed_money)); - - // try to find a rct input of enough size - for (size_t i = 0; i < m_transfers.size(); ++i) - { - const transfer_details& td = m_transfers[i]; - if (!td.m_spent && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1) - { - LOG_PRINT_L2("We can use " << i << " alone: " << print_money(td.amount())); - picks.push_back(i); - return picks; - } - } - - // then try to find two outputs - // this could be made better by picking one of the outputs to be a small one, since those - // are less useful since often below the needed money, so if one can be used in a pair, - // it gets rid of it for the future - for (size_t i = 0; i < m_transfers.size(); ++i) - { - const transfer_details& td = m_transfers[i]; - if (!td.m_spent && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1) - { - LOG_PRINT_L2("Considering input " << i << ", " << print_money(td.amount())); - for (size_t j = i + 1; j < m_transfers.size(); ++j) - { - const transfer_details& td2 = m_transfers[j]; - if (!td2.m_spent && !td.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index) - { - // update our picks if those outputs are less related than any we - // already found. If the same, don't update, and oldest suitable outputs - // will be used in preference. - float relatedness = get_output_relatedness(td, td2); - LOG_PRINT_L2(" with input " << j << ", " << print_money(td2.amount()) << ", relatedness " << relatedness); - if (relatedness < current_output_relatdness) - { - // reset the current picks with those, and return them directly - // if they're unrelated. If they are related, we'll end up returning - // them if we find nothing better - picks.clear(); - picks.push_back(i); - picks.push_back(j); - LOG_PRINT_L0("we could use " << i << " and " << j); - if (relatedness == 0.0f) - return picks; - current_output_relatdness = relatedness; - } - } - } - } - } - - return picks; -} - -bool wallet::should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector &unused_transfers_indices, const std::vector &unused_dust_indices) const -{ - if (!use_rct) - return false; - if (n_transfers > 1) - return false; - if (unused_dust_indices.empty() && unused_transfers_indices.empty()) - return false; - // we want at least one free rct output to avoid a corner case where - // we'd choose a non rct output which doesn't have enough "siblings" - // value-wise on the chain, and thus can't be mixed - bool found = false; - for (auto i: unused_dust_indices) - { - if (m_transfers[i].is_rct()) - { - found = true; - break; - } - } - if (!found) for (auto i: unused_transfers_indices) - { - if (m_transfers[i].is_rct()) - { - found = true; - break; - } - } - if (!found) - return false; - return true; + LOG_PRINT_L2("transfer_selected done"); } -std::vector wallet::get_only_rct(const std::vector &unused_dust_indices, const std::vector &unused_transfers_indices) const -{ - std::vector indices; - for (size_t n: unused_dust_indices) - if (m_transfers[n].is_rct()) - indices.push_back(n); - for (size_t n: unused_transfers_indices) - if (m_transfers[n].is_rct()) - indices.push_back(n); - return indices; -} static uint32_t get_count_above(const std::vector &transfers, const std::vector &indices, uint64_t threshold) { @@ -7648,7 +7127,7 @@ void wallet::light_wallet_get_unspent_outs() add_tx_pub_key_to_extra(td.m_tx, tx_pub_key); td.m_key_image = unspent_key_image; - td.m_key_image_known = !m_watch_only && !m_multisig; + td.m_key_image_known = !m_watch_only; td.m_key_image_partial = m_multisig; td.m_amount = o.amount; td.m_pk_index = 0; @@ -8080,8 +7559,6 @@ std::vector wallet::create_transactions_2(std::vector wallet::create_transactions_2(std::vector balance_subtotal, error::not_enough_money, + THROW_WALLET_EXCEPTION_IF(needed_money > balance_subtotal, error::not_enough_cash, balance_subtotal, needed_money, 0); // first check overall balance is enough, then unlocked one, so we throw distinct exceptions - THROW_WALLET_EXCEPTION_IF(needed_money > unlocked_balance_subtotal, error::not_enough_unlocked_money, + THROW_WALLET_EXCEPTION_IF(needed_money > unlocked_balance_subtotal, error::not_enough_unlocked_cash, unlocked_balance_subtotal, needed_money, 0); for (uint32_t i : subaddr_indices) @@ -8136,7 +7613,9 @@ std::vector wallet::create_transactions_2(std::vector>& x) { return x.first == index_minor; }; @@ -8195,50 +7674,6 @@ std::vector wallet::create_transactions_2(std::vector preferred_inputs; - uint64_t rct_outs_needed = 2 * (fake_outs_count + 1); - rct_outs_needed += 100; // some fudge factor since we don't know how many are locked - if (use_rct) - { - // this is used to build a tx that's 1 or 2 inputs, and 2 outputs, which - // will get us a known fee. - uint64_t estimated_fee = calculate_fee(fee_per_kb, estimate_rct_tx_size(2, fake_outs_count, 2, extra.size(), bulletproof), fee_multiplier); - preferred_inputs = pick_preferred_rct_inputs(needed_money + estimated_fee, subaddr_account, subaddr_indices); - if (!preferred_inputs.empty()) - { - string s; - for (auto i: preferred_inputs) s += boost::lexical_cast(i) + " (" + print_money(m_transfers[i].amount()) + ") "; - LOG_PRINT_L1("Found preferred rct inputs for rct tx: " << s); - - // bring the list of available outputs stored by the same subaddress index to the front of the list - uint32_t index_minor = m_transfers[preferred_inputs[0]].m_subaddr_index.minor; - for (size_t i = 1; i < unused_transfers_indices_per_subaddr.size(); ++i) - { - if (unused_transfers_indices_per_subaddr[i].first == index_minor) - { - std::swap(unused_transfers_indices_per_subaddr[0], unused_transfers_indices_per_subaddr[i]); - break; - } - } - for (size_t i = 1; i < unused_dust_indices_per_subaddr.size(); ++i) - { - if (unused_dust_indices_per_subaddr[i].first == index_minor) - { - std::swap(unused_dust_indices_per_subaddr[0], unused_dust_indices_per_subaddr[i]); - break; - } - } - } - } - LOG_PRINT_L2("done checking preferred"); - - std::vector txes; txes.push_back(TX()); // start with an empty tx @@ -8259,14 +7694,14 @@ std::vector wallet::create_transactions_2(std::vector* unused_dust_indices = &unused_dust_indices_per_subaddr[0].second; hwdev.set_mode(hw::device::TRANSACTION_CREATE_FAKE); - while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_transfers_indices, *unused_dust_indices)) { + while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee) { TX &tx = txes.back(); LOG_PRINT_L2("Start of loop with " << unused_transfers_indices->size() << " " << unused_dust_indices->size()); - LOG_PRINT_L2("unused_transfers_indices: " << strjoin(*unused_transfers_indices, " ")); - LOG_PRINT_L2("unused_dust_indices: " << strjoin(*unused_dust_indices, " ")); + LOG_PRINT_L2("unused_transfers_indices: " << (unused_transfers_indices->size() < 100 ? strjoin(*unused_transfers_indices, " ") : "too big to print")); + LOG_PRINT_L2("unused_dust_indices: " << (unused_dust_indices->size() < 100 ? strjoin(*unused_dust_indices, " ") : "too big to print")); LOG_PRINT_L2("dsts size " << dsts.size() << ", first " << (dsts.empty() ? "-" : cryptonote::print_money(dsts[0].amount))); - LOG_PRINT_L2("adding_fee " << adding_fee << ", use_rct " << use_rct); + LOG_PRINT_L2("adding_fee " << adding_fee); // if we need to spend money and don't have any left, we fail if (unused_dust_indices->empty() && unused_transfers_indices->empty()) { @@ -8277,14 +7712,10 @@ std::vector wallet::create_transactions_2(std::vector indices = get_only_rct(*unused_dust_indices, *unused_transfers_indices); - idx = pop_best_value(indices, tx.selected_transfers, true); + std::vector indices; + idx = pop_best_value(indices, tx.selected_transfers, true, tx_out_type::out_cash); // we might not want to add it if it's a large output and we don't have many left if (m_transfers[idx].amount() >= m_min_output_value) { @@ -8305,7 +7736,7 @@ std::vector wallet::create_transactions_2(std::vectorempty() ? *unused_dust_indices : *unused_transfers_indices, tx.selected_transfers); + idx = pop_best_value(unused_transfers_indices->empty() ? *unused_dust_indices : *unused_transfers_indices, tx.selected_transfers, false, tx_out_type::out_cash); const transfer_details &td = m_transfers[idx]; LOG_PRINT_L2("Picking output " << idx << ", amount " << print_money(td.amount()) << ", ki " << td.m_key_image); @@ -8325,7 +7756,7 @@ std::vector wallet::create_transactions_2(std::vector wallet::create_transactions_2(std::vector 0 && !dsts.empty() && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof) < TX_SIZE_TARGET(upper_transaction_size_limit)) { + if (available_amount > 0 && !dsts.empty() && estimate_tx_size(tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size()) < TX_SIZE_TARGET(upper_transaction_size_limit)) { // we can partially fill that destination LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << " for " << print_money(available_amount) << "/" << print_money(dsts[0].amount)); @@ -8351,26 +7782,24 @@ std::vector wallet::create_transactions_2(std::vector= needed_fee; - } - else - { - const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof); - try_tx = dsts.empty() || (estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit)); - } + /* might not actually be enough if adding this output bumps size to next kB, but we need to try */ + try_tx = available_for_fee >= needed_fee; } + else + { + const size_t estimated_rct_tx_size = estimate_tx_size(tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size()); + try_tx = dsts.empty() || (estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit)); + } + if (try_tx) { cryptonote::transaction test_tx = AUTO_VAL_INIT(test_tx); pending_tx test_ptx = AUTO_VAL_INIT(test_ptx); - const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof); + const size_t estimated_tx_size = estimate_tx_size(tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size()); needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier); uint64_t inputs = 0, outputs = needed_fee; @@ -8386,11 +7815,7 @@ std::vector wallet::create_transactions_2(std::vector wallet::create_transactions_2(std::vector test_ptx.fee) { - if (use_rct) - transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, - test_tx, test_ptx, bulletproof); - else - transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), test_tx, test_ptx); txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); @@ -8493,19 +7915,8 @@ std::vector wallet::create_transactions_2(std::vector dsts,*/ - tx.selected_transfers, /* const std::list selected_transfers */ - fake_outs_count, /* CONST size_t fake_outputs_count, */ - tx.outs, /* MOD std::vector> &outs, */ - unlock_time, /* CONST uint64_t unlock_time, */ - tx.ptx.fee, /* CONST uint64_t fee, */ - extra, /* const std::vector& extra, */ - test_tx, /* OUT cryptonote::transaction& tx, */ - test_ptx, /* OUT cryptonote::transaction& tx, */ - bulletproof); - } else { - transfer_selected(tx.dsts, + + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, @@ -8516,7 +7927,7 @@ std::vector wallet::create_transactions_2(std::vector wallet::create_transactions_token(std::vector> outs; - void add(const account_public_address &addr, bool is_subaddress, bool is_token_transaction, uint64_t amount, unsigned int original_output_index, bool merge_destinations) { + void add(const account_public_address &addr, bool is_subaddress, cryptonote::tx_out_type output_type, uint64_t amount, unsigned int original_output_index, bool merge_destinations) { if (merge_destinations) { std::vector::iterator i; i = std::find_if(dsts.begin(), dsts.end(), [&](const cryptonote::tx_destination_entry &d) { return !memcmp (&d.addr, &addr, sizeof(addr)); }); if (i == dsts.end()) { - dsts.emplace_back(0, addr, is_subaddress, is_token_transaction); + dsts.emplace_back(0, addr, is_subaddress, output_type); i = dsts.end() - 1; } - if (is_token_transaction) + if (output_type == cryptonote::tx_out_type::out_token) { - THROW_WALLET_EXCEPTION_IF(!tools::is_whole_coin_amount(amount), error::wallet_internal_error, "Token amount must be whole number."); + THROW_WALLET_EXCEPTION_IF(!tools::is_whole_token_amount(amount), error::wallet_internal_error, "Token amount must be whole number."); i->token_amount += amount; } else @@ -8593,11 +8004,11 @@ std::vector wallet::create_transactions_token(std::vector dsts.size(), error::wallet_internal_error, std::string("original_output_index too large: ") + std::to_string(original_output_index) + " > " + std::to_string(dsts.size())); if (original_output_index == dsts.size()) - dsts.emplace_back(0,addr,is_subaddress,is_token_transaction); + dsts.emplace_back(0,addr,is_subaddress, output_type); THROW_WALLET_EXCEPTION_IF(memcmp(&dsts[original_output_index].addr, &addr, sizeof(addr)), error::wallet_internal_error, "Mismatched destination address"); - if (is_token_transaction) + if (output_type == cryptonote::tx_out_type::out_token) { - THROW_WALLET_EXCEPTION_IF(!tools::is_whole_coin_amount(amount), error::wallet_internal_error, "Token amount must be whole number."); + THROW_WALLET_EXCEPTION_IF(!tools::is_whole_token_amount(amount), error::wallet_internal_error, "Token amount must be whole number."); dsts[original_output_index].token_amount += amount; } else @@ -8609,8 +8020,6 @@ std::vector wallet::create_transactions_token(std::vector wallet::create_transactions_token(std::vector wallet::create_transactions_token(std::vector>& x) { return x.first == index_minor; }; - if (td.m_token_transfer) + if (td.m_token_transfer && td.get_out_type() == tx_out_type::out_token ) { //for token payments - if ((td.is_rct()) || is_valid_decomposed_amount(td.token_amount())) + auto found = std::find_if(unused_token_transfers_indices_per_subaddr.begin(), unused_token_transfers_indices_per_subaddr.end(), find_predicate); + if (found == unused_token_transfers_indices_per_subaddr.end()) { - auto found = std::find_if(unused_token_transfers_indices_per_subaddr.begin(), unused_token_transfers_indices_per_subaddr.end(), find_predicate); - if (found == unused_token_transfers_indices_per_subaddr.end()) - { - unused_token_transfers_indices_per_subaddr.push_back({index_minor, {i}}); - } - else - { - found->second.push_back(i); - } - ++num_nondust_token_outputs; + unused_token_transfers_indices_per_subaddr.push_back({index_minor, {i}}); } else { - auto found = std::find_if(unused_token_dust_indices_per_subaddr.begin(), unused_token_dust_indices_per_subaddr.end(), find_predicate); - if (found == unused_token_dust_indices_per_subaddr.end()) - { - unused_token_dust_indices_per_subaddr.push_back({index_minor, {i}}); - } - else - { - found->second.push_back(i); - } - ++num_dust_token_outputs; + found->second.push_back(i); } + ++num_nondust_token_outputs; } else { @@ -8765,7 +8158,7 @@ std::vector wallet::create_transactions_token(std::vector wallet::create_transactions_token(std::vector txes; txes.push_back(TOKEN_TX()); - uint64_t needed_fee = 0, available_for_fee = 0; //this is safex cash - uint64_t accumulated_fee = 0, accumulated_outputs = 0, accumulated_change = 0; + uint64_t needed_cash_fee = 0, available_for_fee = 0; //this is safex cash + uint64_t accumulated_fee = 0, accumulated_cash_outputs = 0, accumulated_cash_change = 0; uint64_t accumulated_token_outputs = 0, accumulated_token_change = 0; bool adding_fee = false; // true if new outputs go towards fee, rather than destinations std::vector> outs; - // for rct, since we don't see the amounts, we will try to make all transactions - // look the same, with 1 or 2 inputs, and 2 outputs. One input is preferable, as - // this prevents linking to another by provenance analysis, but two is ok if we - // try to pick outputs not from the same block. We will get two outputs, one for - // the destination, and one for change. - LOG_PRINT_L2("checking preferred"); - std::vector preferred_inputs; - uint64_t rct_outs_needed = 2 * (fake_outs_count + 1); - rct_outs_needed += 100; // some fudge factor since we don't know how many are locked - if (use_rct) - { - // this is used to build a tx that's 1 or 2 inputs, and 2 outputs, which - // will get us a known fee. - uint64_t estimated_fee = calculate_fee(fee_per_kb, estimate_rct_tx_size(2, fake_outs_count, 2, extra.size(), bulletproof), fee_multiplier); - preferred_inputs = pick_preferred_rct_inputs(needed_money + estimated_fee, subaddr_account, subaddr_indices); - if (!preferred_inputs.empty()) - { - string s; - for (auto i: preferred_inputs) s += boost::lexical_cast(i) + " (" + print_money(m_transfers[i].amount()) + ") "; - LOG_PRINT_L1("Found preferred rct inputs for rct tx: " << s); - - // bring the list of available outputs stored by the same subaddress index to the front of the list - uint32_t index_minor = m_transfers[preferred_inputs[0]].m_subaddr_index.minor; - for (size_t i = 1; i < unused_token_transfers_indices_per_subaddr.size(); ++i) - { - if (unused_token_transfers_indices_per_subaddr[i].first == index_minor) - { - std::swap(unused_token_transfers_indices_per_subaddr[0], unused_token_transfers_indices_per_subaddr[i]); - break; - } - } - for (size_t i = 1; i < unused_token_dust_indices_per_subaddr.size(); ++i) - { - if (unused_token_dust_indices_per_subaddr[i].first == index_minor) - { - std::swap(unused_token_dust_indices_per_subaddr[0], unused_token_dust_indices_per_subaddr[i]); - break; - } - } - } - } - LOG_PRINT_L2("done checking preferred"); - // while: // - we have something to send // - or we need to gather more fee - // - or we have just one input in that tx, which is rct (to try and make all/most rct txes 2/2) unsigned int original_output_index = 0; std::vector* unused_token_transfers_indices = &unused_token_transfers_indices_per_subaddr[0].second; - std::vector* unused_token_dust_indices = &unused_token_dust_indices_per_subaddr[0].second; std::vector* unused_transfers_indices = &unused_transfers_indices_per_subaddr[0].second; std::vector* unused_dust_indices = &unused_dust_indices_per_subaddr[0].second; hwdev.set_mode(hw::device::TRANSACTION_CREATE_FAKE); - while ((!dsts.empty() && dsts[0].token_amount > 0) || adding_fee || !preferred_inputs.empty() || should_pick_a_second_output(use_rct, txes.back().selected_transfers.size(), *unused_token_transfers_indices, *unused_token_dust_indices)) { + while ((!dsts.empty() && dsts[0].token_amount > 0) || adding_fee) { TOKEN_TX &tx = txes.back(); - LOG_PRINT_L2("Start of loop with " << unused_token_transfers_indices->size() << " " << unused_token_dust_indices->size()); + LOG_PRINT_L2("Start of loop with " << unused_token_transfers_indices->size()); LOG_PRINT_L2("unused_token_transfers_indices: " << strjoin(*unused_token_transfers_indices, " ")); - LOG_PRINT_L2("unused_token_dust_indices: " << strjoin(*unused_token_dust_indices, " ")); LOG_PRINT_L2("unused_transfers_indices: " << strjoin(*unused_transfers_indices, " ")); LOG_PRINT_L2("unused_dust_indices: " << strjoin(*unused_dust_indices, " ")); LOG_PRINT_L2("dsts size " << dsts.size() << ", first " << (dsts.empty() ? "-" : cryptonote::print_money(dsts[0].token_amount))); - LOG_PRINT_L2("adding_fee " << adding_fee << ", use_rct " << use_rct); + LOG_PRINT_L2("adding_fee " << adding_fee); // if we need to spend money for fee and don't have any left, we fail if (adding_fee && (unused_dust_indices->empty() && unused_transfers_indices->empty())) { LOG_PRINT_L2("No more cash outputs to choose from"); - THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account), needed_money , accumulated_fee + needed_fee); + THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account), needed_money , accumulated_fee + needed_cash_fee); } // if we need to spend tokens and don't have any left, we fail - else if (!adding_fee && unused_token_dust_indices->empty() && unused_token_transfers_indices->empty()) + else if (!adding_fee && unused_token_transfers_indices->empty()) { LOG_PRINT_L2("No more token outputs to choose from"); - THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_token_balance(subaddr_account), needed_tokens, accumulated_fee + needed_fee); + THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_token_balance(subaddr_account), needed_tokens, accumulated_fee + needed_cash_fee); } // get a random unspent token output and use it to pay part (or all) of the current destination (and maybe next one, etc) // This could be more clever, but maybe at the cost of making probabilistic inferences easier size_t idx; - if (!preferred_inputs.empty()) { - idx = pop_back(preferred_inputs); - pop_if_present(*unused_token_transfers_indices, idx); - pop_if_present(*unused_token_dust_indices, idx); - } else if ((dsts.empty() || dsts[0].token_amount == 0) && !adding_fee) { + if ((dsts.empty() || dsts[0].token_amount == 0) && !adding_fee) { // the "make rct txes 2/2" case - we pick a small value output to "clean up" the wallet too - std::vector indices = get_only_rct(*unused_token_dust_indices, *unused_token_transfers_indices); - idx = pop_best_value(indices, tx.selected_transfers, true, true); + std::vector indices; + idx = pop_best_value(indices, tx.selected_transfers, true, tx_out_type::out_token); // we might not want to add it if it's a large output and we don't have many left if (m_transfers[idx].token_amount() >= m_min_output_value) { @@ -8904,13 +8247,14 @@ std::vector wallet::create_transactions_token(std::vectorempty() ? *unused_dust_indices : *unused_transfers_indices, tx.selected_transfers); + idx = pop_best_value(unused_transfers_indices->empty() ? *unused_dust_indices : *unused_transfers_indices, tx.selected_transfers, false, tx_out_type::out_cash); } else - idx = pop_best_value(unused_token_transfers_indices->empty() ? *unused_token_dust_indices : *unused_token_transfers_indices, tx.selected_transfers, true); + { + idx = pop_best_value(*unused_token_transfers_indices, tx.selected_transfers, true, tx_out_type::out_token); + } const transfer_details &td = m_transfers[idx]; if (adding_fee) @@ -8922,7 +8266,7 @@ std::vector wallet::create_transactions_token(std::vector wallet::create_transactions_token(std::vector 0 && !dsts.empty() && estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof) < TX_SIZE_TARGET(upper_transaction_size_limit)) + if (available_token_amount > 0 && !dsts.empty() && estimate_tx_size(tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size()) < TX_SIZE_TARGET(upper_transaction_size_limit)) { // we can partially fill that destination LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << " for " << print_money(available_token_amount) << "/" << print_money(dsts[0].token_amount)); - tx.add(dsts[0].addr, dsts[0].is_subaddress, true, available_token_amount, original_output_index, m_merge_destinations); + tx.add(dsts[0].addr, dsts[0].is_subaddress, cryptonote::tx_out_type::out_token, available_token_amount, original_output_index, m_merge_destinations); dsts[0].token_amount -= available_token_amount; available_token_amount = 0; } @@ -8962,19 +8306,17 @@ std::vector wallet::create_transactions_token(std::vector= needed_fee; - } - else - { - const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof); - try_tx = dsts.empty() || (estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit)); - } + /* might not actually be enough if adding this output bumps size to next kB, but we need to try */ + try_tx = available_for_fee >= needed_cash_fee; } + else + { + const size_t estimated_tx_size = estimate_tx_size(tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size()); + try_tx = dsts.empty() || (estimated_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit)); + } + if (try_tx) { cryptonote::transaction test_tx = AUTO_VAL_INIT(test_tx); @@ -8982,10 +8324,10 @@ std::vector wallet::create_transactions_token(std::vector wallet::create_transactions_token(std::vector(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_cash_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), test_tx, test_ptx); auto txBlob = t_serializable_object_to_blob(test_ptx.tx); - needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); + needed_cash_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); available_for_fee = test_ptx.fee + test_ptx.change_dts.amount + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0); LOG_PRINT_L2("Made a " << get_size_string(txBlob) << " tx, with " << print_money(available_for_fee) << " available for fee (" << - print_money(needed_fee) << " needed)"); + print_money(needed_cash_fee) << " needed)"); - if (needed_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0) + if (needed_cash_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0) { // we don't have enough for the fee, but we've only partially paid the current address, // so we can take the fee from the paid amount, since we'll have to make another tx anyway @@ -9024,20 +8362,20 @@ std::vector wallet::create_transactions_token(std::vectoramount > needed_fee) + if (i->amount > needed_cash_fee) { - uint64_t new_paid_amount = i->amount /*+ test_ptx.fee*/ - needed_fee; + uint64_t new_paid_amount = i->amount /*+ test_ptx.fee*/ - needed_cash_fee; LOG_PRINT_L2("Adjusting amount paid to " << get_account_address_as_str(m_nettype, i->is_subaddress, i->addr) << " from " << print_money(i->amount) << " to " << print_money(new_paid_amount) << " to accommodate " << - print_money(needed_fee) << " fee"); + print_money(needed_cash_fee) << " fee"); dsts[0].amount += i->amount - new_paid_amount; i->amount = new_paid_amount; - test_ptx.fee = needed_fee; - available_for_fee = needed_fee; + test_ptx.fee = needed_cash_fee; + available_for_fee = needed_cash_fee; } } - if (needed_fee > available_for_fee) + if (needed_cash_fee > available_for_fee) { LOG_PRINT_L2("We could not make a tx, switching to fee accumulation"); @@ -9045,16 +8383,12 @@ std::vector wallet::create_transactions_token(std::vector test_ptx.fee) { - if (use_rct) - transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, - test_tx, test_ptx, bulletproof); - else - transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + LOG_PRINT_L2("We made a tx, adjusting fee and saving it, we need " << print_money(needed_cash_fee) << " and we have " << print_money(test_ptx.fee)); + while (needed_cash_fee > test_ptx.fee) { + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_cash_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), test_tx, test_ptx); txBlob = t_serializable_object_to_blob(test_ptx.tx); - needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); + needed_cash_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); LOG_PRINT_L2("Made an attempt at a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << " fee and " << print_money(test_ptx.change_dts.amount) << " cash change and" << print_money(test_ptx.change_token_dts.token_amount) << " token change"); } @@ -9067,14 +8401,14 @@ std::vector wallet::create_transactions_token(std::vector wallet::create_transactions_token(std::vectorempty() && unused_token_dust_indices_per_subaddr.size() > 1) + if (unused_token_dust_indices_per_subaddr.size() > 1) { unused_token_dust_indices_per_subaddr.erase(unused_token_dust_indices_per_subaddr.begin()); - unused_token_dust_indices = &unused_token_dust_indices_per_subaddr[0].second; } } @@ -9115,11 +8448,11 @@ std::vector wallet::create_transactions_token(std::vector::iterator i = txes.begin(); i != txes.end(); ++i) @@ -9127,30 +8460,19 @@ std::vector wallet::create_transactions_token(std::vector dsts,*/ - tx.selected_transfers, /* const std::list selected_transfers */ - fake_outs_count, /* CONST size_t fake_outputs_count, */ - tx.outs, /* MOD std::vector> &outs, */ - unlock_time, /* CONST uint64_t unlock_time, */ - tx.ptx.fee, /* CONST uint64_t fee, */ - extra, /* const std::vector& extra, */ - test_tx, /* OUT cryptonote::transaction& tx, */ - test_ptx, /* OUT cryptonote::transaction& tx, */ - bulletproof); - } else { - transfer_selected(tx.dsts, - tx.selected_transfers, - fake_outs_count, - tx.outs, - unlock_time, - tx.ptx.fee, - extra, - detail::digit_split_strategy, - tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), - test_tx, - test_ptx); - } + + transfer_selected(tx.dsts, + tx.selected_transfers, + fake_outs_count, + tx.outs, + unlock_time, + tx.ptx.fee, + extra, + detail::digit_split_strategy, + tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), + test_tx, + test_ptx); + auto txBlob = t_serializable_object_to_blob(test_ptx.tx); tx.tx = test_tx; tx.ptx = test_ptx; @@ -9182,7 +8504,6 @@ std::vector wallet::create_transactions_all(uint64_t below, { std::vector unused_transfers_indices; std::vector unused_dust_indices; - const bool use_rct = use_fork_rules(HF_VERSION_ENFORCE_RCT, 0); THROW_WALLET_EXCEPTION_IF(unlocked_balance(subaddr_account) == 0, error::wallet_internal_error, "No unlocked balance in the entire wallet"); @@ -9193,7 +8514,7 @@ std::vector wallet::create_transactions_all(uint64_t below, for (size_t i = 0; i < m_transfers.size(); ++i) { const transfer_details& td = m_transfers[i]; - if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1)) + if (!td.m_spent && !td.m_key_image_partial && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1)) { fund_found = true; if (below == 0 || td.amount() < below) @@ -9236,12 +8557,11 @@ std::vector wallet::create_transactions_single(const crypto: { std::vector unused_transfers_indices; std::vector unused_dust_indices; - const bool use_rct = use_fork_rules(HF_VERSION_ENFORCE_RCT, 0); // find output with the given key image for (size_t i = 0; i < m_transfers.size(); ++i) { const transfer_details& td = m_transfers[i]; - if (td.m_key_image_known && td.m_key_image == ki && !td.m_spent && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td)) + if (td.m_key_image_known && td.m_key_image == ki && !td.m_spent && is_transfer_unlocked(td)) { if (td.is_rct() || is_valid_decomposed_amount(td.amount())) unused_transfers_indices.push_back(i); @@ -9260,14 +8580,20 @@ std::vector wallet::create_transactions_migration( bool mark_as_spent) { const size_t fake_outs_count = 0; - const std::vector unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, true, trusted_daemon, cryptonote::tx_out_type::out_cash); - const uint64_t fee_per_kb = get_per_kb_fee(); const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm()); + const uint64_t needed_cash = [&]() { + uint64_t tmp = 0; + for (auto &dt: dsts) { + tmp += dt.amount; + THROW_WALLET_EXCEPTION_IF(tmp < dt.amount, error::tx_sum_overflow, dsts, 0, m_nettype); + } + return tmp;}(); + + // failsafe split attempt counter size_t attempt_count = 0; - for (attempt_count = 1;; attempt_count++) { size_t num_tx = 1; @@ -9287,82 +8613,1017 @@ std::vector wallet::create_transactions_migration( { cryptonote::transaction tx; pending_tx ptx = AUTO_VAL_INIT(ptx); + std::vector unused_transfers_indices = select_available_outputs_from_histogram(fake_outs_count + 1, true, true, false, trusted_daemon, cryptonote::tx_out_type::out_cash); + + size_t idx; + uint64_t found_cash = 0; + uint64_t min_needed_cash = needed_cash; + bool adding_fee = false; + uint64_t needed_fee = 0; + std::vector selected_transfers; + while (found_cash < min_needed_cash && !adding_fee) { + //Select cash inputs for migration cash distribution + idx = pop_best_value(unused_transfers_indices, selected_transfers, false, tx_out_type::out_cash); + const transfer_details &td = m_transfers[idx]; + + found_cash += td.amount(); + selected_transfers.push_back(idx); + if (found_cash > min_needed_cash && !adding_fee) { + adding_fee = true; + const size_t estimated_tx_size = estimate_tx_size(selected_transfers.size(), fake_outs_count, dst_vector.size(), extra.size()); + needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier); + min_needed_cash += needed_fee; + } + } + + do + { + transfer_migration(dst_vector, bitcoin_transaction_hash, fake_outs_count, selected_transfers, + unlock_time, needed_fee, extra, tx, ptx, trusted_daemon); + auto txBlob = t_serializable_object_to_blob(ptx.tx); + needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); + } while (ptx.fee < needed_fee); + + ptx_vector.push_back(ptx); + + // mark transfers to be used as "spent" + for(size_t idx: ptx.selected_transfers) + { + set_spent(idx, 0); + } + } + + // if we made it this far, we've selected our transactions. committing them will mark them spent, + // so this is a failsafe in case they don't go through + // unmark pending tx transfers as spent + if (!mark_as_spent) { + for (auto &ptx : ptx_vector) { + // mark transfers to be used as not spent + for (size_t idx2: ptx.selected_transfers) { + set_unspent(idx2); + } + + } + } + + // if we made it this far, we're OK to actually send the transactions + return ptx_vector; + + } + // only catch this here, other exceptions need to pass through to the calling function + catch (const tools::error::tx_too_big& e) + { + + // unmark pending tx transfers as spent + for (auto & ptx : ptx_vector) + { + // mark transfers to be used as not spent + for(size_t idx2: ptx.selected_transfers) + { + set_unspent(idx2); + } + } + + if (attempt_count >= MAX_SPLIT_ATTEMPTS) + { + throw; + } + } + catch (...) + { + // in case of some other exception, make sure any tx in queue are marked unspent again + + // unmark pending tx transfers as spent + for (auto & ptx : ptx_vector) + { + // mark transfers to be used as not spent + for(size_t idx2: ptx.selected_transfers) + { + set_unspent(idx2); + } + } + + throw; + } + } +} + + +std::vector wallet::create_transactions_advanced(safex::command_t command_type, std::vector dsts, + const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector &extra, + uint32_t subaddr_account, std::set subaddr_indices, bool trusted_daemon, const safex::safex_account &sfx_acc) + { + //ensure device is let in NONE mode in any case + hw::device &hwdev = m_account.get_device(); + boost::unique_lock hwdev_lock(hwdev); + hw::reset_mode rst(hwdev); + + THROW_WALLET_EXCEPTION_IF(m_light_wallet, error::not_supported); + + std::vector>> unused_token_transfers_indices_per_subaddr; + std::vector>> unused_cash_transfers_indices_per_subaddr; + std::vector>> unused_cash_dust_indices_per_subaddr; + std::vector>> unused_staked_token_transfers_indices_per_subaddr; + + struct ADVANCED_TX + { + std::vector selected_transfers; + std::vector dsts; + cryptonote::transaction tx; + pending_tx ptx = AUTO_VAL_INIT(ptx); + size_t bytes = 0; + std::vector> outs; + + void add(const account_public_address &addr, bool is_subaddress, cryptonote::tx_out_type output_type, uint64_t amount, uint64_t token_amount, + unsigned int original_output_index, bool merge_destinations, const cryptonote::blobdata& output_data={}) + { + if (merge_destinations) + { + std::vector::iterator i; + i = std::find_if(dsts.begin(), dsts.end(), [&](const cryptonote::tx_destination_entry &d) + { return !memcmp(&d.addr, &addr,sizeof(addr)) && (d.output_type == tx_out_type::out_cash || d.output_type == tx_out_type::out_token); }); //merge only cash and token outputs + + if (i == dsts.end()) + { + dsts.emplace_back(0, addr, is_subaddress, output_type, output_data); + i = dsts.end() - 1; + } + + THROW_WALLET_EXCEPTION_IF((output_type == cryptonote::tx_out_type::out_token) && !tools::is_whole_token_amount(amount), error::wallet_internal_error, "Token amount must be whole number."); + i->token_amount += token_amount; + i->amount += amount; + + } + else + { + THROW_WALLET_EXCEPTION_IF(original_output_index > dsts.size(), error::wallet_internal_error, + std::string("original_output_index too large: ") + std::to_string(original_output_index) + " > " + std::to_string(dsts.size())); + if (original_output_index == dsts.size()) + dsts.emplace_back(0, addr, is_subaddress, output_type, output_data); + THROW_WALLET_EXCEPTION_IF(memcmp(&dsts[original_output_index].addr, &addr, sizeof(addr)), error::wallet_internal_error, "Mismatched destination address"); + THROW_WALLET_EXCEPTION_IF((output_type == cryptonote::tx_out_type::out_token) && !tools::is_whole_token_amount(amount), error::wallet_internal_error, + "Token amount must be whole number."); + dsts[original_output_index].token_amount += token_amount; + dsts[original_output_index].amount += amount; + } + } + }; + + uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit(); + + const uint64_t fee_per_kb = get_per_kb_fee(); + const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm()); + + // throw if attempting a transaction with no destinations + THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination); + + + // calculate total amount being sent to all destinations + // throw if total amount overflows uint64_t + uint64_t needed_cash = 0; + uint64_t needed_tokens = 0; + uint64_t needed_staked_tokens = 0; + uint64_t needed_cash_for_purchase = 0; + for (auto &dt: dsts) + { + if ((command_type == safex::command_t::token_stake) || (command_type == safex::command_t::token_unstake)) + { + THROW_WALLET_EXCEPTION_IF(0 == dt.token_amount, error::zero_destination); + THROW_WALLET_EXCEPTION_IF(!tools::is_whole_token_amount(dt.token_amount), error::wallet_internal_error, "Token amount must be a round number."); + + if (command_type == safex::command_t::token_stake) + { + LOG_PRINT_L2("transfer: adding " << print_money(dt.token_amount) << " tokens for token staking, for a total of " << print_money(needed_tokens)) << " tokens"; + needed_tokens += dt.token_amount; + THROW_WALLET_EXCEPTION_IF(needed_tokens < dt.token_amount, error::tx_sum_overflow, dsts, 0, m_nettype); + } + else + { + LOG_PRINT_L2("transfer: adding " << print_money(dt.token_amount) << " tokens for token unstaking, for a total of " << print_money(needed_tokens)) << " staked tokens"; + needed_staked_tokens += dt.token_amount; + THROW_WALLET_EXCEPTION_IF(needed_staked_tokens < dt.token_amount, error::tx_sum_overflow, dsts, 0, m_nettype); + } + + } + else if (command_type == safex::command_t::simple_purchase) { + if (dt.script_output == false || dt.output_type == tx_out_type::out_network_fee || dt.output_type == tx_out_type::out_safex_feedback_token) { + needed_cash += dt.amount; + THROW_WALLET_EXCEPTION_IF(needed_cash < dt.amount, error::tx_sum_overflow, dsts, 0, m_nettype); + } else { + THROW_WALLET_EXCEPTION_IF(dt.output_type != tx_out_type::out_safex_purchase, error::safex_invalid_output_error); + } + + if(dt.output_type == tx_out_type::out_safex_purchase){ + safex::create_purchase_data purchase{}; + + if (!cryptonote::parse_and_validate_from_blob(dt.output_data, purchase)) + { + THROW_WALLET_EXCEPTION(error::wallet_internal_error, "Error parsing purchase output"); + } + needed_cash_for_purchase = purchase.price; + } + + } + else if (command_type == safex::command_t::create_account) + { + if (dt.script_output == false) { + THROW_WALLET_EXCEPTION_IF(dt.token_amount != SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE, error::zero_destination); + needed_tokens += dt.token_amount; + LOG_PRINT_L2("creting account: locking " << print_money(dt.token_amount) << " safex token" << " cash"); + THROW_WALLET_EXCEPTION_IF(needed_tokens < dt.token_amount, error::tx_sum_overflow, dsts, 0, m_nettype); + } else { + THROW_WALLET_EXCEPTION_IF(dt.output_type != tx_out_type::out_safex_account, error::safex_invalid_output_error); + } + + } + else if (command_type == safex::command_t::edit_account) + { + THROW_WALLET_EXCEPTION_IF(dt.output_type != tx_out_type::out_safex_account_update, error::safex_invalid_output_error); + } + else if (command_type == safex::command_t::create_offer) + { + THROW_WALLET_EXCEPTION_IF(dt.output_type != tx_out_type::out_safex_offer, error::safex_invalid_output_error); + } + else if (command_type == safex::command_t::edit_offer) + { + THROW_WALLET_EXCEPTION_IF(dt.output_type != tx_out_type::out_safex_offer_update, error::safex_invalid_output_error); + } + else if (command_type == safex::command_t::create_price_peg) + { + THROW_WALLET_EXCEPTION_IF(dt.output_type != tx_out_type::out_safex_price_peg, error::safex_invalid_output_error); + } + else if (command_type == safex::command_t::update_price_peg) + { + THROW_WALLET_EXCEPTION_IF(dt.output_type != tx_out_type::out_safex_price_peg_update, error::safex_invalid_output_error); + } + else + { + THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination); + } + } + + // throw if attempting a transaction with no money + THROW_WALLET_EXCEPTION_IF((command_type == safex::command_t::token_stake || command_type == safex::command_t::create_account) && needed_tokens == 0, error::zero_destination); + THROW_WALLET_EXCEPTION_IF(command_type == safex::command_t::token_unstake && needed_staked_tokens == 0, error::zero_destination); + THROW_WALLET_EXCEPTION_IF(command_type == safex::command_t::donate_network_fee && needed_cash == 0, error::zero_destination); + + std::map unlocked_cash_balance_per_subaddr = unlocked_balance_per_subaddress(subaddr_account); + std::map cash_balance_per_subaddr = balance_per_subaddress(subaddr_account); + std::map unlocked_token_balance_per_subaddr = unlocked_token_balance_per_subaddress(subaddr_account); + std::map token_balance_per_subaddr = token_balance_per_subaddress(subaddr_account); + std::map unlocked_staked_token_balance_per_subaddr = unlocked_staked_token_balance_per_subaddress(subaddr_account); + std::map staked_token_balance_per_subaddr = staked_token_balance_per_subaddress(subaddr_account); + + if (subaddr_indices.empty()) // "index=[,,...]" wasn't specified -> use all the indices with non-zero unlocked balance + { + for (const auto &i : token_balance_per_subaddr) + subaddr_indices.insert(i.first); + for (const auto &i : staked_token_balance_per_subaddr) + subaddr_indices.insert(i.first); + for (const auto &i : cash_balance_per_subaddr) + subaddr_indices.insert(i.first); + } + + uint64_t cash_balance_subtotal = 0; + uint64_t unlocked_cash_balance_subtotal = 0; + for (uint32_t index_minor : subaddr_indices) + { + cash_balance_subtotal += cash_balance_per_subaddr[index_minor]; + unlocked_cash_balance_subtotal += unlocked_cash_balance_per_subaddr[index_minor]; + } + + // early out if we know we can't make it anyway + // we could also check for being within FEE_PER_KB, but if the fee calculation + // ever changes, this might be missed, so let this go through + uint64_t token_balance_subtotal = 0; + uint64_t unlocked_token_balance_subtotal = 0; + for (uint32_t index_minor : subaddr_indices) + { + token_balance_subtotal += token_balance_per_subaddr[index_minor]; + unlocked_token_balance_subtotal += unlocked_token_balance_per_subaddr[index_minor]; + } + + uint64_t staked_token_balance_subtotal = 0; + uint64_t unlocked_staked_token_balance_subtotal = 0; //funny name + if (command_type == safex::command_t::token_unstake) //relevant only for this command + { + for (uint32_t index_minor : subaddr_indices) + { + staked_token_balance_subtotal += staked_token_balance_per_subaddr[index_minor]; + unlocked_staked_token_balance_subtotal += unlocked_staked_token_balance_per_subaddr[index_minor]; + } + + THROW_WALLET_EXCEPTION_IF(needed_staked_tokens > staked_token_balance_subtotal, error::not_enough_staked_tokens, staked_token_balance_subtotal, needed_staked_tokens); + THROW_WALLET_EXCEPTION_IF(needed_staked_tokens > unlocked_staked_token_balance_subtotal, error::not_enough_unlocked_tokens, unlocked_staked_token_balance_subtotal, needed_staked_tokens); + } + + + THROW_WALLET_EXCEPTION_IF(needed_cash > cash_balance_subtotal, error::not_enough_cash, cash_balance_subtotal, needed_cash, 0); + THROW_WALLET_EXCEPTION_IF(needed_cash > unlocked_cash_balance_subtotal, error::not_enough_unlocked_cash, unlocked_cash_balance_subtotal, needed_cash, 0); + THROW_WALLET_EXCEPTION_IF(needed_tokens > token_balance_subtotal, error::not_enough_tokens, token_balance_subtotal, needed_tokens); + THROW_WALLET_EXCEPTION_IF(needed_tokens > unlocked_token_balance_subtotal, error::not_enough_unlocked_tokens, unlocked_token_balance_subtotal, needed_tokens); + + + for (uint32_t i : subaddr_indices) + LOG_PRINT_L2("Candidate subaddress index for spending: " << i); + + // gather all dust and non-dust outputs belonging to specified subaddresses + size_t num_nondust_outputs = 0; + size_t num_dust_outputs = 0; + size_t num_nondust_token_outputs = 0; + size_t num_nondust_staked_token_outputs = 0; + for (size_t i = 0; i < m_transfers.size(); ++i) + { + const transfer_details &td = m_transfers[i]; + if (!td.m_spent && !td.m_key_image_partial && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1) + { + const uint32_t index_minor = td.m_subaddr_index.minor; + auto find_predicate = [&index_minor](const std::pair> &x) + { return x.first == index_minor; }; + + if ((command_type == safex::command_t::token_unstake) && td.m_output_type == cryptonote::tx_out_type::out_staked_token) + { + auto found = std::find_if(unused_staked_token_transfers_indices_per_subaddr.begin(), unused_staked_token_transfers_indices_per_subaddr.end(), find_predicate); + if (found == unused_staked_token_transfers_indices_per_subaddr.end()) + { + unused_staked_token_transfers_indices_per_subaddr.push_back({index_minor, {i}}); + } + else + { + found->second.push_back(i); + } + ++num_nondust_staked_token_outputs; + } + else if (td.token_amount() > 0 && td.m_output_type == cryptonote::tx_out_type::out_token && is_token_transfer_unlocked(td)) + { + auto found = std::find_if(unused_token_transfers_indices_per_subaddr.begin(), unused_token_transfers_indices_per_subaddr.end(), find_predicate); + if (found == unused_token_transfers_indices_per_subaddr.end()) + { + unused_token_transfers_indices_per_subaddr.push_back({index_minor, {i}}); + } + else + { + found->second.push_back(i); + } + ++num_nondust_token_outputs; + } + + //for cash fee payment + if (td.amount() > 0 && td.m_output_type == cryptonote::tx_out_type::out_cash) + { + if (is_valid_decomposed_amount(td.amount())) + { + auto found = std::find_if(unused_cash_transfers_indices_per_subaddr.begin(), unused_cash_transfers_indices_per_subaddr.end(), find_predicate); + if (found == unused_cash_transfers_indices_per_subaddr.end()) + { + unused_cash_transfers_indices_per_subaddr.push_back({index_minor, {i}}); + } + else + { + found->second.push_back(i); + } + ++num_nondust_outputs; + } + else + { + auto found = std::find_if(unused_cash_dust_indices_per_subaddr.begin(), unused_cash_dust_indices_per_subaddr.end(), find_predicate); + if (found == unused_cash_dust_indices_per_subaddr.end()) + { + unused_cash_dust_indices_per_subaddr.push_back({index_minor, {i}}); + } + else + { + found->second.push_back(i); + } + ++num_dust_outputs; + } + } + } + } + + // shuffle & sort output indices + { + std::random_device rd; + std::mt19937 g(rd()); + + if (command_type == safex::command_t::token_unstake) { + //staked token outputs + std::shuffle(unused_staked_token_transfers_indices_per_subaddr.begin(), unused_staked_token_transfers_indices_per_subaddr.end(), g); + auto sort_token_predicate = [&unlocked_staked_token_balance_per_subaddr](const std::pair> &x, const std::pair> &y) + { + return unlocked_staked_token_balance_per_subaddr[x.first] > unlocked_staked_token_balance_per_subaddr[y.first]; + }; + std::sort(unused_staked_token_transfers_indices_per_subaddr.begin(), unused_staked_token_transfers_indices_per_subaddr.end(), sort_token_predicate); + + if (unused_staked_token_transfers_indices_per_subaddr.empty()) + return std::vector(); + + } else if (command_type == safex::command_t::token_stake || command_type == safex::command_t::token_collect || command_type == safex::command_t::create_account) { + //shuffle common token outputs + std::shuffle(unused_token_transfers_indices_per_subaddr.begin(), unused_token_transfers_indices_per_subaddr.end(), g); + auto sort_token_predicate = [&unlocked_token_balance_per_subaddr](const std::pair> &x, const std::pair> &y) + { + return unlocked_token_balance_per_subaddr[x.first] > unlocked_token_balance_per_subaddr[y.first]; + }; + std::sort(unused_token_transfers_indices_per_subaddr.begin(), unused_token_transfers_indices_per_subaddr.end(), sort_token_predicate); + + if (unused_token_transfers_indices_per_subaddr.empty()) + return std::vector(); + } + + //cash outputs + std::shuffle(unused_cash_transfers_indices_per_subaddr.begin(), unused_cash_transfers_indices_per_subaddr.end(), g); + std::shuffle(unused_cash_dust_indices_per_subaddr.begin(), unused_cash_dust_indices_per_subaddr.end(), g); + auto sort_cash_predicate = [&unlocked_cash_balance_per_subaddr](const std::pair> &x, const std::pair> &y) + { + return unlocked_cash_balance_per_subaddr[x.first] > unlocked_cash_balance_per_subaddr[y.first]; + }; + std::sort(unused_cash_transfers_indices_per_subaddr.begin(), unused_cash_transfers_indices_per_subaddr.end(), sort_cash_predicate); + std::sort(unused_cash_dust_indices_per_subaddr.begin(), unused_cash_dust_indices_per_subaddr.end(), sort_cash_predicate); + } + + LOG_PRINT_L2("Starting with " << num_nondust_token_outputs << " token non-dust outputs and " << + num_nondust_outputs << " non-dust cash outputs and " << num_dust_outputs << " dust cash outputs"); + + + if (unused_cash_dust_indices_per_subaddr.empty() && unused_cash_transfers_indices_per_subaddr.empty()) + return std::vector(); + + // if empty, put dummy entry so that the front can be referenced later in the loop + if (unused_token_transfers_indices_per_subaddr.empty()) + unused_token_transfers_indices_per_subaddr.push_back({}); + if (unused_cash_dust_indices_per_subaddr.empty()) + unused_cash_dust_indices_per_subaddr.push_back({}); + if (unused_cash_transfers_indices_per_subaddr.empty()) + unused_cash_transfers_indices_per_subaddr.push_back({}); + if (unused_staked_token_transfers_indices_per_subaddr.empty()) + unused_staked_token_transfers_indices_per_subaddr.push_back({}); + + // start with an empty tx + std::vector txes; + txes.push_back(ADVANCED_TX()); + + uint64_t needed_fee = 0, available_for_fee = 0; //this is safex cash + uint64_t accumulated_cash_fee = 0, accumulated_cash_outputs = 0, accumulated_cash_change = 0; + uint64_t accumulated_token_outputs = 0, accumulated_token_change = 0; + uint64_t accumulated_staked_token_outputs = 0; + + bool adding_fee = false; // true if new outputs go towards fee, rather than destinations + bool purchase_init = false; + + std::vector> outs; + + // while: + // - we have something to send + // - or we need to gather more fee + unsigned int original_output_index = 0; + std::vector *unused_token_transfers_indices = &unused_token_transfers_indices_per_subaddr[0].second; + std::vector *unused_cash_transfers_indices = &unused_cash_transfers_indices_per_subaddr[0].second; + std::vector *unused_cash_dust_indices = &unused_cash_dust_indices_per_subaddr[0].second; + std::vector *unused_staked_token_transfers_indices = &unused_staked_token_transfers_indices_per_subaddr[0].second; + + + hwdev.set_mode(hw::device::TRANSACTION_CREATE_FAKE); + while ((!dsts.empty() && (dsts[0].token_amount > 0 || dsts[0].amount > 0 + || dsts[0].output_type == tx_out_type::out_safex_account + || dsts[0].output_type == tx_out_type::out_safex_account_update + || dsts[0].output_type == tx_out_type::out_safex_offer + || dsts[0].output_type == tx_out_type::out_safex_offer_update + || dsts[0].output_type == tx_out_type::out_safex_purchase + || dsts[0].output_type == tx_out_type::out_safex_feedback + || dsts[0].output_type == tx_out_type::out_safex_price_peg + || dsts[0].output_type == tx_out_type::out_safex_price_peg_update)) || adding_fee) + { + ADVANCED_TX &tx = txes.back(); + + LOG_PRINT_L2("Start of loop with tokens: " << unused_token_transfers_indices->size() << " staked_tokens: " << unused_staked_token_transfers_indices->size()); + LOG_PRINT_L2("unused_token_transfers_indices: " << (unused_token_transfers_indices->size() < 100 ? strjoin(*unused_token_transfers_indices, " ") : " too big to print")); + LOG_PRINT_L2("unused_staked_token_transfers_indices: " << (unused_staked_token_transfers_indices->size() < 100 ? strjoin(*unused_staked_token_transfers_indices, " ") : "too big to print")); + LOG_PRINT_L2("unused_cash_transfers_indices: " << (unused_cash_transfers_indices->size() < 100 ? strjoin(*unused_cash_transfers_indices, "too big to print") : " ")); + LOG_PRINT_L2("unused_cash_dust_indices: " << (unused_cash_dust_indices->size() < 100 ? strjoin(*unused_cash_dust_indices, " ") : "too big to print")); + LOG_PRINT_L2("dsts size " << dsts.size() << ", first " << (dsts.empty() ? "-" : cryptonote::print_money(dsts[0].token_amount))); + LOG_PRINT_L2("adding_fee " << adding_fee); + + const bool advanced_output_reference = (dsts[0].output_type == tx_out_type::out_safex_account_update || dsts[0].output_type == tx_out_type::out_safex_offer + || dsts[0].output_type == tx_out_type::out_safex_offer_update || dsts[0].output_type == tx_out_type::out_safex_feedback + || dsts[0].output_type == tx_out_type::out_safex_price_peg || dsts[0].output_type == tx_out_type::out_safex_price_peg_update); + + + // if we need to spend cash and don't have any left, we fail + if ((adding_fee || needed_cash>0) && (unused_cash_dust_indices->empty() && unused_cash_transfers_indices->empty())) + { + LOG_PRINT_L2("No more cash outputs to choose from"); + THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account), needed_cash, accumulated_cash_fee + needed_fee); + + } + // if we need to spend tokens and don't have any left, we fail + else if (!adding_fee && needed_tokens > 0 && unused_token_transfers_indices->empty()) + { + LOG_PRINT_L2("No more token outputs to choose from"); + THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_token_balance(subaddr_account), needed_tokens, accumulated_cash_fee + needed_fee); + } + else if (!adding_fee && needed_staked_tokens > 0 && unused_staked_token_transfers_indices->empty()) + { + LOG_PRINT_L2("No more staked token outputs to choose from"); + THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_staked_token_balance(subaddr_account), needed_staked_tokens, accumulated_cash_fee + needed_fee); + } + + if (dsts[0].output_type == tx_out_type::out_safex_account) { + //safex account is created from create command referencing token output, but does not directly references tokens locked for its creation (there is separate locked token output) + + LOG_PRINT_L2("Adding advanced output" << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << + " with blobdata: " << dsts[0].output_data); + + tx.add(dsts[0].addr, dsts[0].is_subaddress, dsts[0].output_type, dsts[0].amount, dsts[0].token_amount, original_output_index, false, dsts[0].output_data); + + pop_index(dsts, 0); + ++original_output_index; + if (dsts[0].output_type == tx_out_type::out_safex_account) continue; //no need to match any index + } + if (dsts[0].output_type == tx_out_type::out_safex_purchase) { + //safex purchase is created from create command referencing cash output, but does not directly references cash used for its creation (there is separate cash out output) + + LOG_PRINT_L2("Adding advanced output" << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << + " with blobdata: " << dsts[0].output_data); + + tx.add(dsts[0].addr, dsts[0].is_subaddress, dsts[0].output_type, dsts[0].amount, dsts[0].token_amount, original_output_index, false, dsts[0].output_data); + + pop_index(dsts, 0); + ++original_output_index; + if (dsts[0].output_type == tx_out_type::out_safex_purchase) continue; //no need to match any index + } + + // get a random unspent cash, token or advanced output and use it to pay part (or all) of the current destination (and maybe next one, etc) + // This could be more clever, but maybe at the cost of making probabilistic inferences easier + size_t idx = 0; + if ((dsts.empty() || ((needed_tokens > 0 && dsts[0].token_amount == 0) || (needed_cash > 0 && dsts[0].amount == 0) || (needed_staked_tokens > 0 && dsts[0].token_amount == 0))) + && !adding_fee && !advanced_output_reference) + { + std::vector indices; + + if (dsts[0].output_type == tx_out_type::out_staked_token) + idx = pop_ideal_value(indices, tx.selected_transfers, dsts[0].output_type, dsts[0].amount, dsts[0].token_amount); + else + idx = pop_best_value(indices, tx.selected_transfers, true, dsts[0].output_type); + + // we might not want to add it if it's a large output and we don't have many left + if (needed_staked_tokens > 0 && m_transfers[idx].token_amount() >= m_min_output_value && m_transfers[idx].get_out_type() == tx_out_type::out_staked_token) + { + if (get_count_above(m_transfers, *unused_staked_token_transfers_indices, m_min_output_value) < m_min_output_count) + { + LOG_PRINT_L2("Second staked token output was not strictly needed, and we're running out of outputs above " << print_money(m_min_output_value) << ", not adding"); + break; + } + } + + // we might not want to add it if it's a large output and we don't have many left + if (needed_tokens > 0 && m_transfers[idx].token_amount() >= m_min_output_value && m_transfers[idx].get_out_type() == tx_out_type::out_token) + { + if (get_count_above(m_transfers, *unused_token_transfers_indices, m_min_output_value) < m_min_output_count) + { + LOG_PRINT_L2("Second token output was not strictly needed, and we're running out of outputs above " << print_money(m_min_output_value) << ", not adding"); + break; + } + } + + if (needed_cash > 0 && m_transfers[idx].amount() >= m_min_output_value && m_transfers[idx].get_out_type() == tx_out_type::out_cash) + { + if (get_count_above(m_transfers, *unused_cash_transfers_indices, m_min_output_value) < + m_min_output_count) + { + LOG_PRINT_L2("Second token output was not strictly needed, and we're running out of outputs above " + << print_money(m_min_output_value) << ", not adding"); + break; + } + } + + // since we're trying to add a second output which is not strictly needed, + // we only add it if it's unrelated enough to the first one + float relatedness = get_output_relatedness(m_transfers[idx], m_transfers[tx.selected_transfers.front()]); + if (relatedness > SECOND_OUTPUT_RELATEDNESS_THRESHOLD) + { + LOG_PRINT_L2("Second output was not strictly needed, and relatedness " << relatedness << ", not adding"); + break; + } + + if (needed_staked_tokens > 0) + { + pop_if_present(*unused_staked_token_transfers_indices, idx); + } + else if (needed_tokens > 0) + { + pop_if_present(*unused_token_transfers_indices, idx); + } + else if (dsts[0].output_type == tx_out_type::out_safex_purchase) { + idx = pop_best_value(unused_cash_transfers_indices->empty() ? *unused_cash_dust_indices : *unused_cash_transfers_indices, tx.selected_transfers, false, tx_out_type::out_cash); + } + else if (needed_cash > 0) + { + pop_if_present(*unused_cash_transfers_indices, idx); + pop_if_present(*unused_cash_dust_indices, idx); + } + else if (dsts[0].output_type == tx_out_type::out_safex_account_update) { + safex::edit_account_data account; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, account); + //find account output + idx = pop_advanced_output(tx.selected_transfers, account.username, tx_out_type::out_safex_account); + } + else if (dsts[0].output_type == tx_out_type::out_safex_offer) { + safex::create_offer_data offer; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, offer); + //find offer output + idx = pop_advanced_output(tx.selected_transfers, offer.seller, tx_out_type::out_safex_account); + } + else if (dsts[0].output_type == tx_out_type::out_safex_offer_update) { + safex::edit_offer_data offer; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, offer); + //find offer output + idx = pop_advanced_output(tx.selected_transfers, offer.offer_id, tx_out_type::out_safex_offer); + } + else if (dsts[0].output_type == tx_out_type::out_safex_feedback) { + safex::create_feedback_data feedback; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, feedback); + //find feedback_token output + idx = pop_advanced_output(tx.selected_transfers, feedback.offer_id, tx_out_type::out_safex_feedback_token); + } + else if (dsts[0].output_type == tx_out_type::out_safex_price_peg) { + safex::create_price_peg_data price_peg; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, price_peg); + //find price peg output + idx = pop_advanced_output(tx.selected_transfers, price_peg.creator, tx_out_type::out_safex_account); + } + else if (dsts[0].output_type == tx_out_type::out_safex_price_peg_update) { + safex::update_price_peg_data price_peg; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, price_peg); + //find price peg output + idx = pop_advanced_output(tx.selected_transfers, price_peg.price_peg_id, tx_out_type::out_safex_price_peg); + } + } + else if (adding_fee) + { + idx = pop_best_value(unused_cash_transfers_indices->empty() ? *unused_cash_dust_indices : *unused_cash_transfers_indices, tx.selected_transfers, false, tx_out_type::out_cash); + } + else + { + if (needed_staked_tokens > 0) + { + idx = pop_ideal_value(*unused_staked_token_transfers_indices, tx.selected_transfers, tx_out_type::out_staked_token, 0, needed_staked_tokens); + } + else if (needed_tokens > 0) + { + idx = pop_best_value(*unused_token_transfers_indices, tx.selected_transfers, true, tx_out_type::out_token); + } + else if(command_type == safex::command_t::simple_purchase && !purchase_init) { + purchase_init = true; + idx = pop_best_value(unused_cash_transfers_indices->empty() ? *unused_cash_dust_indices : *unused_cash_transfers_indices, tx.selected_transfers, false, tx_out_type::out_cash, needed_cash_for_purchase); + } + else if (needed_cash > 0) + { + idx = pop_best_value(unused_cash_transfers_indices->empty() ? *unused_cash_dust_indices : *unused_cash_transfers_indices, tx.selected_transfers, true, tx_out_type::out_cash); + } + else if (dsts[0].output_type == tx_out_type::out_safex_account_update) { + safex::edit_account_data account; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, account); + //find account output + idx = pop_advanced_output(tx.selected_transfers, account.username, tx_out_type::out_safex_account); + } + else if (dsts[0].output_type == tx_out_type::out_safex_offer) { + safex::create_offer_data offer; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, offer); + //find offer output + idx = pop_advanced_output(tx.selected_transfers, offer.seller, tx_out_type::out_safex_account); + } + else if (dsts[0].output_type == tx_out_type::out_safex_offer_update) { + safex::edit_offer_data offer; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, offer); + //find offer output + idx = pop_advanced_output(tx.selected_transfers, offer.offer_id, tx_out_type::out_safex_offer); + } + else if (dsts[0].output_type == tx_out_type::out_safex_feedback) { + safex::create_feedback_data feedback; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, feedback); + //find feedback_token output + idx = pop_advanced_output(tx.selected_transfers, feedback.offer_id, tx_out_type::out_safex_feedback_token); + } + else if (dsts[0].output_type == tx_out_type::out_safex_price_peg) { + safex::create_price_peg_data price_peg; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, price_peg); + //find price peg output + idx = pop_advanced_output(tx.selected_transfers, price_peg.creator, tx_out_type::out_safex_account); + } + else if (dsts[0].output_type == tx_out_type::out_safex_price_peg_update) { + safex::update_price_peg_data price_peg; + cryptonote::parse_and_validate_from_blob(dsts[0].output_data, price_peg); + //find price peg output + idx = pop_advanced_output(tx.selected_transfers, price_peg.price_peg_id, tx_out_type::out_safex_price_peg); + } else { + THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Cannot find idx")); + } + } + + + const transfer_details &td = m_transfers[idx]; + if (adding_fee || needed_cash > 0) + LOG_PRINT_L2("Picking output " << idx << ", cash amount " << print_money(td.amount()) << ", ki " << td.m_key_image); + else if (needed_tokens > 0) + LOG_PRINT_L2("Picking output " << idx << ", token amount " << print_money(td.token_amount()) << ", ki " << td.m_key_image); + else if (needed_staked_tokens > 0) + LOG_PRINT_L2("Picking output " << idx << ", staked token amount " << print_money(td.token_amount()) << ", ki " << td.m_key_image); + + // add this output to the list to spend + uint64_t available_cash_amount = td.amount(); + uint64_t available_token_amount = td.get_out_type() == tx_out_type::out_token ? td.token_amount() : 0; + uint64_t available_staked_token_amount = td.get_out_type() == tx_out_type::out_staked_token ? td.token_amount() : 0; + + tx.selected_transfers.push_back(idx); + accumulated_cash_outputs += available_cash_amount; + accumulated_token_outputs += available_token_amount; + accumulated_staked_token_outputs += available_staked_token_amount; + + // clear any fake outs we'd already gathered, since we'll need a new set + outs.clear(); + + const size_t input_with_0_mixin = (command_type == safex::command_t::token_unstake || command_type == safex::command_t::create_feedback || + command_type == safex::command_t::create_offer || command_type == safex::command_t::create_price_peg || + command_type == safex::command_t::edit_account || command_type == safex::command_t::edit_offer || + command_type == safex::command_t::update_price_peg || command_type == safex::command_t::simple_purchase) ? 1 : 0; //count into estimation safex network fee distribution inputs + + + if (adding_fee) + { + LOG_PRINT_L2("We need more fee, adding it to fee"); + available_for_fee += available_cash_amount; + } + else + { + while (!dsts.empty() && (((dsts[0].token_amount <= available_token_amount) || ( command_type == safex::command_t::token_unstake && dsts[0].token_amount <= available_staked_token_amount)) + && (dsts[0].amount <= available_cash_amount)) && + estimate_tx_size(tx.selected_transfers.size() - input_with_0_mixin, fake_outs_count, tx.dsts.size(), extra.size()) < TX_SIZE_TARGET(upper_transaction_size_limit)) + { + // we can fully pay that destination + LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << + " for " << print_money(dsts[0].amount)<<" cash " << print_money(dsts[0].output_type == tx_out_type::out_token && dsts[0].token_amount)<<" tokens" + << print_money(dsts[0].output_type == tx_out_type::out_staked_token && dsts[0].token_amount)<<" staked tokens"); + + tx.add(dsts[0].addr, dsts[0].is_subaddress, dsts[0].output_type, dsts[0].amount, dsts[0].token_amount, original_output_index, m_merge_destinations, dsts[0].output_data); + if (command_type == safex::command_t::token_unstake) + available_staked_token_amount -= dsts[0].token_amount; + else + available_token_amount -= dsts[0].token_amount; + + available_cash_amount -= dsts[0].amount; + dsts[0].token_amount = 0; + dsts[0].amount = 0; + pop_index(dsts, 0); + ++original_output_index; + } + + if ((needed_staked_tokens > 0 && available_staked_token_amount > 0) && !dsts.empty() && dsts[0].token_amount == available_staked_token_amount + && estimate_tx_size(tx.selected_transfers.size() - input_with_0_mixin, fake_outs_count, tx.dsts.size(), extra.size()) < TX_SIZE_TARGET(upper_transaction_size_limit)) + { + // we can partially fill that destination + LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << + " for " << print_money(available_staked_token_amount) << "/" << print_money(dsts[0].token_amount)); + tx.add(dsts[0].addr, dsts[0].is_subaddress, dsts[0].output_type, 0, available_staked_token_amount, original_output_index, m_merge_destinations, dsts[0].output_data); + dsts[0].token_amount -= available_staked_token_amount; + available_staked_token_amount = 0; + } + + if ((needed_tokens > 0 && available_token_amount > 0) && !dsts.empty() && estimate_tx_size(tx.selected_transfers.size() - input_with_0_mixin, fake_outs_count, + tx.dsts.size(), extra.size()) + < TX_SIZE_TARGET(upper_transaction_size_limit)) + { + // we can partially fill that destination + LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << + " for " << print_money(available_token_amount) << "/" << print_money(dsts[0].token_amount)); + tx.add(dsts[0].addr, dsts[0].is_subaddress, dsts[0].output_type, 0, available_token_amount, original_output_index, m_merge_destinations, dsts[0].output_data); + dsts[0].token_amount -= available_token_amount; + available_token_amount = 0; + } + + if ((needed_cash > 0 && available_cash_amount > 0) && !dsts.empty() && estimate_tx_size(tx.selected_transfers.size() - input_with_0_mixin, fake_outs_count, + tx.dsts.size(), extra.size()) < TX_SIZE_TARGET(upper_transaction_size_limit)) + { + // we can partially fill that destination + LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << + " for " << print_money(available_cash_amount) << "/" << print_money(dsts[0].amount)); + tx.add(dsts[0].addr, dsts[0].is_subaddress, dsts[0].output_type, available_cash_amount, 0, original_output_index, m_merge_destinations, dsts[0].output_data); + dsts[0].amount -= available_cash_amount; + available_cash_amount = 0; + } + } + + // here, check if we need to sent tx and start a new one + LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit " << upper_transaction_size_limit); + bool try_tx = false; + // if we have preferred picks, but haven't yet used all of them, continue + if (adding_fee) + { + /* might not actually be enough if adding this output bumps size to next kB, but we need to try */ + try_tx = available_for_fee >= needed_fee; + } + else + { + const size_t estimated_tx_size = estimate_tx_size(tx.selected_transfers.size() - input_with_0_mixin, fake_outs_count, + tx.dsts.size(), extra.size()); + try_tx = dsts.empty() || (estimated_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit)); + } + + + if (try_tx) + { + cryptonote::transaction test_tx = AUTO_VAL_INIT(test_tx); + pending_tx test_ptx = AUTO_VAL_INIT(test_ptx); - // loop until fee is met without increasing tx size to next KB boundary. - //todo ATANA update estimate_tx_size to include migration transaction - const size_t estimated_tx_size = estimate_tx_size(false, unused_transfers_indices.size(), fake_outs_count, dst_vector.size(), extra.size(), false); - uint64_t needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier); - do + //Now, we can calculate fee, and go back one more round to select cash + //inputs to pay that fee + const size_t estimated_tx_size = estimate_tx_size(tx.selected_transfers.size() - input_with_0_mixin, fake_outs_count, + tx.dsts.size(), extra.size()); + needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier); + + uint64_t inputs = 0, outputs = needed_fee; + for (size_t idx: tx.selected_transfers) { - transfer_migration(dst_vector, bitcoin_transaction_hash, fake_outs_count, unused_transfers_indices, - unlock_time, needed_fee, extra, tx, ptx, trusted_daemon); - auto txBlob = t_serializable_object_to_blob(ptx.tx); - needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); - } while (ptx.fee < needed_fee); + inputs += m_transfers[idx].amount(); + } + for (const auto &o: tx.dsts) + { + outputs += o.amount; + } - ptx_vector.push_back(ptx); + if (inputs == 0 || inputs < outputs) + { + LOG_PRINT_L2("Switching to adding_fee mode for advanced transaction"); + adding_fee = true; + goto skip_tx; + } - // mark transfers to be used as "spent" - for(size_t idx: ptx.selected_transfers) + LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " outputs and " << + tx.selected_transfers.size() << " inputs"); + transfer_advanced(command_type, tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, + needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), test_tx, test_ptx, sfx_acc); + + auto txBlob = t_serializable_object_to_blob(test_ptx.tx); + needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); + available_for_fee = test_ptx.fee + test_ptx.change_dts.amount + (!test_ptx.dust_added_to_fee ? test_ptx.dust : 0); + LOG_PRINT_L2("Made a " << get_size_string(txBlob) << " tx, with " << print_money(available_for_fee) << " available for fee (" << + print_money(needed_fee) << " needed)"); + + if (needed_fee > available_for_fee && !dsts.empty() && dsts[0].amount > 0) { - set_spent(idx, 0); + // we don't have enough for the fee, but we've only partially paid the current address, + // so we can take the fee from the paid amount, since we'll have to make another tx anyway + std::vector::iterator i; + i = std::find_if(tx.dsts.begin(), tx.dsts.end(), + [&](const cryptonote::tx_destination_entry &d) + { return !memcmp(&d.addr, &dsts[0].addr, sizeof(dsts[0].addr)); }); + THROW_WALLET_EXCEPTION_IF(i == tx.dsts.end(), error::wallet_internal_error, "paid address not found in outputs"); + if (i->amount > needed_fee) + { + uint64_t new_paid_amount = i->amount /*+ test_ptx.fee*/ - needed_fee; + LOG_PRINT_L2("Adjusting amount paid to " << get_account_address_as_str(m_nettype, i->is_subaddress, i->addr) << " from " << + print_money(i->amount) << " to " << print_money(new_paid_amount) << " to accommodate " << + print_money(needed_fee) << " fee"); + dsts[0].amount += i->amount - new_paid_amount; + i->amount = new_paid_amount; + test_ptx.fee = needed_fee; + available_for_fee = needed_fee; + } } - } - // if we made it this far, we've selected our transactions. committing them will mark them spent, - // so this is a failsafe in case they don't go through - // unmark pending tx transfers as spent - if (!mark_as_spent) { - for (auto &ptx : ptx_vector) { - // mark transfers to be used as not spent - for (size_t idx2: ptx.selected_transfers) { - set_unspent(idx2); + if (needed_fee > available_for_fee) + { + LOG_PRINT_L2("We could not make a tx, switching to fee accumulation"); + + adding_fee = true; + } + 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)); + while (needed_fee > test_ptx.fee) + { + transfer_advanced(command_type, tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), test_tx, test_ptx, sfx_acc); + txBlob = t_serializable_object_to_blob(test_ptx.tx); + needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); + LOG_PRINT_L2("Made an attempt at a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << + " fee and " << print_money(test_ptx.change_dts.amount) << " cash change and" << print_money(test_ptx.change_token_dts.token_amount) << " token change"); } + LOG_PRINT_L2("Made a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << + " fee and " << print_money(test_ptx.change_dts.amount) << " cash change and" << print_money(test_ptx.change_token_dts.token_amount) << " token change"); + + tx.tx = test_tx; + tx.ptx = test_ptx; + tx.bytes = txBlob.size(); + tx.outs = outs; + accumulated_cash_fee += test_ptx.fee; + accumulated_cash_change += test_ptx.change_dts.amount; + accumulated_token_change += test_ptx.change_token_dts.token_amount; + adding_fee = false; + if (!dsts.empty()) + { + THROW_WALLET_EXCEPTION(error::wallet_internal_error, std::string("Advanced tx too big. Create bigger input.")); + } } } - // if we made it this far, we're OK to actually send the transactions - return ptx_vector; - - } - // only catch this here, other exceptions need to pass through to the calling function - catch (const tools::error::tx_too_big& e) - { - - // unmark pending tx transfers as spent - for (auto & ptx : ptx_vector) + skip_tx: + // if unused_*_indices is empty while unused_*_indices_per_subaddr has multiple elements, and if we still have something to pay, + // pop front of unused_*_indices_per_subaddr and have unused_*_indices point to the front of unused_*_indices_per_subaddr + if (!dsts.empty() && (dsts[0].token_amount > 0) && (!adding_fee)) { - // mark transfers to be used as not spent - for(size_t idx2: ptx.selected_transfers) + if (command_type == safex::command_t::token_unstake) { - set_unspent(idx2); + if (unused_staked_token_transfers_indices->empty() && unused_staked_token_transfers_indices_per_subaddr.size() > 1) + { + unused_staked_token_transfers_indices_per_subaddr.erase(unused_staked_token_transfers_indices_per_subaddr.begin()); + unused_staked_token_transfers_indices = &unused_staked_token_transfers_indices_per_subaddr[0].second; + } + } + else + { + if (unused_token_transfers_indices->empty() && unused_token_transfers_indices_per_subaddr.size() > 1) + { + unused_token_transfers_indices_per_subaddr.erase(unused_token_transfers_indices_per_subaddr.begin()); + unused_token_transfers_indices = &unused_token_transfers_indices_per_subaddr[0].second; + } } } - if (attempt_count >= MAX_SPLIT_ATTEMPTS) + //Cash indices, for fee + if ((dsts[0].amount > 0) || (adding_fee)) { - throw; + if (unused_cash_transfers_indices->empty() && unused_cash_transfers_indices_per_subaddr.size() > 1) + { + unused_cash_transfers_indices_per_subaddr.erase(unused_cash_transfers_indices_per_subaddr.begin()); + unused_cash_transfers_indices = &unused_cash_transfers_indices_per_subaddr[0].second; + } + if (unused_cash_dust_indices->empty() && unused_cash_dust_indices_per_subaddr.size() > 1) + { + unused_cash_dust_indices_per_subaddr.erase(unused_cash_dust_indices_per_subaddr.begin()); + unused_cash_dust_indices = &unused_cash_dust_indices_per_subaddr[0].second; + } } } - catch (...) + + if (adding_fee) { - // in case of some other exception, make sure any tx in queue are marked unspent again + LOG_PRINT_L1("We ran out of outputs while trying to gather final fee"); + THROW_WALLET_EXCEPTION_IF(1, error::tx_not_possible, unlocked_balance(subaddr_account), needed_cash, accumulated_cash_fee + needed_fee); + } - // unmark pending tx transfers as spent - for (auto & ptx : ptx_vector) - { - // mark transfers to be used as not spent - for(size_t idx2: ptx.selected_transfers) - { - set_unspent(idx2); - } - } + LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_money(accumulated_cash_fee) << + " total fee, " << print_money(accumulated_cash_change) << " total cash change and " << print_money(accumulated_token_change) << " total token change"); - throw; + hwdev.set_mode(hw::device::TRANSACTION_CREATE_REAL); + for (std::vector::iterator i = txes.begin(); i != txes.end(); ++i) + { + ADVANCED_TX &tx = *i; + cryptonote::transaction test_tx = AUTO_VAL_INIT(test_tx); + pending_tx test_ptx = AUTO_VAL_INIT(test_ptx); + + transfer_advanced(command_type, + tx.dsts, + tx.selected_transfers, + fake_outs_count, + tx.outs, + unlock_time, + tx.ptx.fee, + extra, + detail::digit_split_strategy, + tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), + test_tx, + test_ptx, + sfx_acc); + + auto txBlob = t_serializable_object_to_blob(test_ptx.tx); + tx.tx = test_tx; + tx.ptx = test_ptx; + tx.bytes = txBlob.size(); } + + std::vector ptx_vector; + for (std::vector::iterator i = txes.begin(); i != txes.end(); ++i) + { + ADVANCED_TX &tx = *i; + uint64_t tx_money = 0; + uint64_t tx_tokens = 0; + for (size_t idx: tx.selected_transfers) + tx_money += m_transfers[idx].amount(); + for (size_t idx: tx.selected_transfers) + tx_tokens += m_transfers[idx].token_amount(); + LOG_PRINT_L1(" Transaction " << (1 + std::distance(txes.begin(), i)) << "/" << txes.size() << + ": " << get_size_string(tx.bytes) << ", sending " << print_money(tx_tokens) << " tokens and" ", sending " << print_money(tx_money) << " cash in " << tx.selected_transfers.size() << + " outputs to " << tx.dsts.size() << " destination(s), including " << + print_money(tx.ptx.fee) << " fee, " << print_money(tx.ptx.change_token_dts.token_amount) << " token change and " << print_money(tx.ptx.change_dts.amount) << " cash change"); + ptx_vector.push_back(tx.ptx); + } + + // if we made it this far, we're OK to actually send the transactions + return ptx_vector; } -} + std::vector wallet::create_transactions_from(const cryptonote::account_public_address &address, bool is_subaddress, std::vector unused_transfers_indices, std::vector unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector& extra, bool trusted_daemon) { @@ -9385,8 +9646,6 @@ std::vector wallet::create_transactions_from(const cryptonot uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit(); std::vector> outs; - const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0); - const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0); const uint64_t fee_per_kb = get_per_kb_fee(); const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm()); @@ -9424,28 +9683,25 @@ std::vector wallet::create_transactions_from(const cryptonot outs.clear(); // here, check if we need to sent tx and start a new one - LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit " - << upper_transaction_size_limit); - const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1, extra.size(), bulletproof); - bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit)); + LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit " << upper_transaction_size_limit); + const size_t estimated_tmp_tx_size = estimate_tx_size(tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1, extra.size()); + bool try_tx = (unused_dust_indices.empty() && unused_transfers_indices.empty()) || ( estimated_tmp_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit)); if (try_tx) { cryptonote::transaction test_tx = AUTO_VAL_INIT(test_tx); pending_tx test_ptx; - const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof); + const size_t estimated_tx_size = estimate_tx_size(tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size()); needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier); tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress)); 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, unlock_time, needed_fee, extra, - test_tx, test_ptx, bulletproof); - else - transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), test_tx, test_ptx); + auto txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); available_for_fee = test_ptx.fee + test_ptx.dests[0].amount + test_ptx.change_dts.amount; @@ -9457,12 +9713,10 @@ std::vector wallet::create_transactions_from(const cryptonot do { LOG_PRINT_L2("We made a tx, adjusting fee and saving it"); tx.dsts[0].amount = available_for_fee - needed_fee; - if (use_rct) - transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, - test_tx, test_ptx, bulletproof); - else - transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), test_tx, test_ptx); + txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); LOG_PRINT_L2("Made an attempt at a final " << get_size_string(txBlob) << " tx, with " << print_money(test_ptx.fee) << @@ -9495,13 +9749,10 @@ std::vector wallet::create_transactions_from(const cryptonot TX &tx = *i; cryptonote::transaction test_tx = AUTO_VAL_INIT(test_tx); pending_tx test_ptx; - if (use_rct) { - transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, needed_fee, extra, - test_tx, test_ptx, bulletproof); - } else { - transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, needed_fee, extra, + + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), test_tx, test_ptx); - } + auto txBlob = t_serializable_object_to_blob(test_ptx.tx); tx.tx = test_tx; tx.ptx = test_ptx; @@ -9547,8 +9798,6 @@ std::vector wallet::create_transactions_token_from(const cry uint64_t upper_transaction_size_limit = get_upper_transaction_size_limit(); std::vector> outs; - const bool use_rct = fake_outs_count > 0 && use_fork_rules(4, 0); - const bool bulletproof = use_fork_rules(get_bulletproof_fork(), 0); const uint64_t fee_per_kb = get_per_kb_fee(); const uint64_t fee_multiplier = get_fee_multiplier(priority, get_fee_algorithm()); @@ -9576,12 +9825,12 @@ std::vector wallet::create_transactions_token_from(const cry TOKEN_TX &tx = txes.back(); LOG_PRINT_L2("Start of loop with " << unused_token_transfers_indices.size() << " " << unused_token_dust_indices.size()); - LOG_PRINT_L2("unused_token_transfers_indices: " << strjoin(unused_token_transfers_indices, " ")); - LOG_PRINT_L2("unused_token_dust_indices: " << strjoin(unused_token_dust_indices, " ")); - LOG_PRINT_L2("unused_transfers_indices: " << strjoin(unused_transfers_indices, " ")); - LOG_PRINT_L2("unused_dust_indices: " << strjoin(unused_dust_indices, " ")); + LOG_PRINT_L2("unused_token_transfers_indices: " << (unused_token_transfers_indices.size() < 100 ? strjoin(unused_token_transfers_indices, " ") : " too big to print")); + LOG_PRINT_L2("unused_token_dust_indices: " << (unused_token_dust_indices.size() < 100 ? strjoin(unused_token_dust_indices, " ") : " too big to print")); + LOG_PRINT_L2("unused_transfers_indices: " << (unused_transfers_indices.size()?strjoin(unused_transfers_indices, " "):"too big to print")); + LOG_PRINT_L2("unused_dust_indices: " << (unused_dust_indices.size() ? strjoin(unused_dust_indices, " ") : " ")); LOG_PRINT_L2("dsts size " << tx.dsts.size() << ", first token " << (tx.dsts.empty() ? "-" : cryptonote::print_money(tx.dsts[0].token_amount))); - LOG_PRINT_L2("adding_fee " << adding_fee << ", use_rct " << use_rct); + LOG_PRINT_L2("adding_fee " << adding_fee); size_t idx; @@ -9589,18 +9838,18 @@ std::vector wallet::create_transactions_token_from(const cry if (adding_fee) { //get cash output for fee; - idx = unused_transfers_indices.empty() ? pop_best_value(unused_dust_indices, tx.selected_transfers) : unused_dust_indices.empty() ? pop_best_value(unused_transfers_indices, tx.selected_transfers) : - ((tx.selected_transfers.size() & 1) || accumulated_outputs > fee_per_kb * fee_multiplier * (upper_transaction_size_limit + 1023) / 1024) ? pop_best_value(unused_dust_indices, tx.selected_transfers) : - pop_best_value(unused_transfers_indices, tx.selected_transfers); + idx = unused_transfers_indices.empty() ? pop_best_value(unused_dust_indices, tx.selected_transfers, false, tx_out_type::out_cash) : unused_dust_indices.empty() ? pop_best_value(unused_transfers_indices, tx.selected_transfers, false, tx_out_type::out_cash) : + ((tx.selected_transfers.size() & 1) || accumulated_outputs > fee_per_kb * fee_multiplier * (upper_transaction_size_limit + 1023) / 1024) ? pop_best_value(unused_dust_indices, tx.selected_transfers, false, tx_out_type::out_cash) : + pop_best_value(unused_transfers_indices, tx.selected_transfers, false, tx_out_type::out_cash); } else { // get a random unspent output and use it to pay next chunk. We try to alternate // dust and non dust to ensure we never get with only dust, from which we might // get a tx that can't pay for itself - idx = unused_token_transfers_indices.empty() ? pop_best_value(unused_token_dust_indices, tx.selected_transfers, false, true) : - unused_token_dust_indices.empty() ? pop_best_value(unused_token_transfers_indices, tx.selected_transfers, true) : - (tx.selected_transfers.size() & 1) ? pop_best_value(unused_token_dust_indices, tx.selected_transfers, false, true) : pop_best_value(unused_token_transfers_indices, tx.selected_transfers, true); + idx = unused_token_transfers_indices.empty() ? pop_best_value(unused_token_dust_indices, tx.selected_transfers, false, tx_out_type::out_token) : + unused_token_dust_indices.empty() ? pop_best_value(unused_token_transfers_indices, tx.selected_transfers, true, tx_out_type::out_token) : + (tx.selected_transfers.size() & 1) ? pop_best_value(unused_token_dust_indices, tx.selected_transfers, false, tx_out_type::out_token) : pop_best_value(unused_token_transfers_indices, tx.selected_transfers, true, tx_out_type::out_token); } const transfer_details &td = m_transfers[idx]; @@ -9618,7 +9867,7 @@ std::vector wallet::create_transactions_token_from(const cry // here, check if we need to sent tx and start a new one LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit " << upper_transaction_size_limit); - const size_t estimated_rct_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1, extra.size(), bulletproof); + const size_t estimated_rct_tx_size = estimate_tx_size(tx.selected_transfers.size(), fake_outs_count, tx.dsts.size() + 1, extra.size()); bool try_tx = (unused_token_dust_indices.empty() && unused_token_transfers_indices.empty()) || (estimated_rct_tx_size >= TX_SIZE_TARGET(upper_transaction_size_limit)) || adding_fee; if (try_tx) @@ -9626,7 +9875,7 @@ std::vector wallet::create_transactions_token_from(const cry cryptonote::transaction test_tx = AUTO_VAL_INIT(test_tx); pending_tx test_ptx = AUTO_VAL_INIT(test_ptx); - const size_t estimated_tx_size = estimate_tx_size(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size(), bulletproof); + const size_t estimated_tx_size = estimate_tx_size(tx.selected_transfers.size(), fake_outs_count, tx.dsts.size(), extra.size()); needed_fee = calculate_fee(fee_per_kb, estimated_tx_size, fee_multiplier); if (needed_fee > 0 && accumulated_fee == 0 && accumulated_outputs == 0) @@ -9639,11 +9888,8 @@ std::vector wallet::create_transactions_token_from(const cry tx.dsts.push_back(tx_destination_entry(1, address, is_subaddress)); 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, unlock_time, needed_fee, extra, - test_tx, test_ptx, bulletproof); - else - transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), test_tx, test_ptx); auto txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); @@ -9656,11 +9902,8 @@ std::vector wallet::create_transactions_token_from(const cry { LOG_PRINT_L2("We made a tx, adjusting fee and saving it"); tx.dsts[0].amount = available_for_fee - needed_fee; - if (use_rct) - transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, - test_tx, test_ptx, bulletproof); - else - transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, + + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, outs, unlock_time, needed_fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), test_tx, test_ptx); txBlob = t_serializable_object_to_blob(test_ptx.tx); needed_fee = calculate_fee(fee_per_kb, txBlob, fee_multiplier); @@ -9697,15 +9940,10 @@ std::vector wallet::create_transactions_token_from(const cry TOKEN_TX &tx = *i; cryptonote::transaction test_tx = AUTO_VAL_INIT(test_tx); pending_tx test_ptx = AUTO_VAL_INIT(test_ptx); - if (use_rct) - { - transfer_selected_rct(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, tx.ptx.fee, extra, - test_tx, test_ptx, bulletproof); - } else - { - transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, tx.ptx.fee, extra, + + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, tx.outs, unlock_time, tx.ptx.fee, extra, detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD, ::config::DEFAULT_TOKEN_DUST_THRESHOLD), test_tx, test_ptx); - } + auto txBlob = t_serializable_object_to_blob(test_ptx.tx); tx.tx = test_tx; tx.ptx = test_ptx; @@ -9792,7 +10030,7 @@ std::vector wallet::get_unspent_amounts_vector() const for (const auto &td: m_transfers) { if (!td.m_spent) - set.insert(td.is_rct() ? 0 : td.amount()); + set.insert(td.amount()); } std::vector vector; vector.reserve(set.size()); @@ -9811,7 +10049,7 @@ std::vector wallet::select_available_outputs_from_histogram(uint64_t cou if (trusted_daemon) req_t.amounts = get_unspent_amounts_vector(); req_t.min_count = count; - req_t.max_count = 0; + req_t.unlocked = unlocked; req_t.out_type = out_type; bool r = net_utils::invoke_http_json_rpc("/json_rpc", "get_output_histogram", req_t, resp_t, m_http_client, rpc_timeout); @@ -9830,13 +10068,13 @@ std::vector wallet::select_available_outputs_from_histogram(uint64_t cou if (!allow_rct && td.is_rct()) return false; uint64_t value_amount; - if (out_type == cryptonote::tx_out_type::out_token && td.m_token_transfer) + if (out_type == cryptonote::tx_out_type::out_token) { - value_amount = td.is_rct() ? 0 : td.token_amount(); + value_amount = td.token_amount(); } - else if (out_type == cryptonote::tx_out_type::out_cash && (!td.m_token_transfer)) + else if (out_type == cryptonote::tx_out_type::out_cash) { - value_amount = td.is_rct() ? 0 : td.amount(); + value_amount = td.amount(); } else { @@ -9915,7 +10153,7 @@ std::vector wallet::create_unmixable_sweep_transactions(bool std::vector unmixable_transfer_outputs, unmixable_dust_outputs; for (auto n: unmixable_outputs) { - if (!m_transfers[n].m_token_transfer) + if (m_transfers[n].get_out_type() == cryptonote::tx_out_type::out_cash) { if (m_transfers[n].amount() < fee_per_kb) unmixable_dust_outputs.push_back(n); @@ -9938,7 +10176,7 @@ std::vector wallet::create_unmixable_sweep_transactions(bool for (auto n: unmixable_token_outputs) { - if (m_transfers[n].m_token_transfer) + if (m_transfers[n].get_out_type() == cryptonote::tx_out_type::out_token) { if (m_transfers[n].token_amount() < fee_per_kb) unmixable_token_dust_outputs.push_back(n); @@ -9947,9 +10185,10 @@ std::vector wallet::create_unmixable_sweep_transactions(bool } } - if (num_dust_outputs == 0) + { - //in case of sweeping tokens, we will need some mixable cash outputs (if there are no unmixable) for fee + //in case of sweeping tokens, we will need mixable cash outputs for fee + //TODO: Add logic to use full ring size for mixable cash outputs std::vector mixable_outputs; mixable_outputs = select_available_mixable_outputs(trusted_daemon, cryptonote::tx_out_type::out_cash); @@ -9963,7 +10202,7 @@ std::vector wallet::create_unmixable_sweep_transactions(bool std::vector mixable_transfer_outputs, mixable_dust_outputs; for (auto n: mixable_outputs) { - if (!m_transfers[n].m_token_transfer) + if (m_transfers[n].get_out_type() == cryptonote::tx_out_type::out_cash) { if (m_transfers[n].amount() < fee_per_kb) mixable_dust_outputs.push_back(n); @@ -9974,11 +10213,7 @@ std::vector wallet::create_unmixable_sweep_transactions(bool return create_transactions_token_from(m_account_public_address, false, unmixable_token_transfer_outputs, unmixable_token_dust_outputs, mixable_transfer_outputs, mixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector(), trusted_daemon); } - else - { - return create_transactions_token_from(m_account_public_address, false, unmixable_token_transfer_outputs, unmixable_token_dust_outputs, - unmixable_transfer_outputs, unmixable_dust_outputs, 0 /*fake_outs_count */, 0 /* unlock_time */, 1 /*priority */, std::vector(), trusted_daemon); - } + } @@ -10601,7 +10836,7 @@ bool wallet::check_tx_proof(const crypto::hash &txid, const cryptonote::account_ std::string wallet::get_reserve_proof(const boost::optional> &account_minreserve, const std::string &message, bool token) { - THROW_WALLET_EXCEPTION_IF(m_watch_only || m_multisig, error::wallet_internal_error, "Reserve proof can only be generated by a full wallet"); + THROW_WALLET_EXCEPTION_IF(m_watch_only, error::wallet_internal_error, "Reserve proof can only be generated by a full wallet"); if(!token) { THROW_WALLET_EXCEPTION_IF(balance_all() == 0, error::wallet_internal_error, "Zero balance"); THROW_WALLET_EXCEPTION_IF(account_minreserve && balance(account_minreserve->first) < account_minreserve->second, error::wallet_internal_error, @@ -11342,7 +11577,7 @@ uint64_t wallet::import_key_images(const std::vectorm_tx.vin) { - if (cryptonote::is_valid_transaction_input_type(in)) + if (cryptonote::is_valid_transaction_input_type(in, it->m_tx.version)) { auto k_image_opt = boost::apply_visitor(key_image_visitor(), in); if (k_image_opt && td.m_key_image == *k_image_opt) @@ -11422,12 +11657,8 @@ uint64_t wallet::import_key_images(const std::vectorderivation, output_index, mask, hwdev); - } tx_money_got_in_outs += tx_scan_info.money_transfered; + tx_tokens_got_in_outs += tx_scan_info.output_type == tx_out_type::out_token ? tx_scan_info.token_transfered : 0; } ++output_index; } @@ -11439,7 +11670,7 @@ uint64_t wallet::import_key_images(const std::vector subaddr_indices; for (const cryptonote::txin_v& in : spent_tx.vin) { - if (!cryptonote::is_valid_transaction_input_type(in)) + if (!cryptonote::is_valid_transaction_input_type(in, spent_tx.version)) continue; const auto k_image_opt = boost::apply_visitor(key_image_visitor(), in); @@ -11447,7 +11678,8 @@ uint64_t wallet::import_key_images(const std::vector(in).command_type))) { const transfer_details& td = m_transfers[it->second]; uint64_t value_amount = *boost::apply_visitor(amount_visitor(), in); @@ -11460,13 +11692,13 @@ uint64_t wallet::import_key_images(const std::vector(); // spent txid is unknown, so hypothetically set to random @@ -11629,287 +11862,6 @@ size_t wallet::import_outputs(const std::vector return m_transfers.size(); } //---------------------------------------------------------------------------------------------------- -crypto::public_key wallet::get_multisig_signer_public_key(const crypto::secret_key &spend_skey) const -{ - crypto::public_key pkey; - crypto::secret_key_to_public_key(get_multisig_blinded_secret_key(spend_skey), pkey); - return pkey; -} -//---------------------------------------------------------------------------------------------------- -crypto::public_key wallet::get_multisig_signer_public_key() const -{ - CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig"); - crypto::public_key signer; - CHECK_AND_ASSERT_THROW_MES(crypto::secret_key_to_public_key(get_account().get_keys().m_spend_secret_key, signer), "Failed to generate signer public key"); - return signer; -} -//---------------------------------------------------------------------------------------------------- -crypto::public_key wallet::get_multisig_signing_public_key(const crypto::secret_key &msk) const -{ - CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig"); - crypto::public_key pkey; - CHECK_AND_ASSERT_THROW_MES(crypto::secret_key_to_public_key(msk, pkey), "Failed to derive public key"); - return pkey; -} -//---------------------------------------------------------------------------------------------------- -crypto::public_key wallet::get_multisig_signing_public_key(size_t idx) const -{ - CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig"); - CHECK_AND_ASSERT_THROW_MES(idx < get_account().get_multisig_keys().size(), "Multisig signing key index out of range"); - return get_multisig_signing_public_key(get_account().get_multisig_keys()[idx]); -} -//---------------------------------------------------------------------------------------------------- -rct::key wallet::get_multisig_k(size_t idx, const std::unordered_set &used_L) const -{ - CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig"); - CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "idx out of range"); - for (const auto &k: m_transfers[idx].m_multisig_k) - { - rct::key L; - rct::scalarmultBase(L, k); - if (used_L.find(L) != used_L.end()) - return k; - } - THROW_WALLET_EXCEPTION(tools::error::multisig_export_needed); - return rct::zero(); -} -//---------------------------------------------------------------------------------------------------- -rct::multisig_kLRki wallet::get_multisig_kLRki(size_t n, const rct::key &k) const -{ - CHECK_AND_ASSERT_THROW_MES(n < m_transfers.size(), "Bad m_transfers index"); - rct::multisig_kLRki kLRki; - kLRki.k = k; - cryptonote::generate_multisig_LR(m_transfers[n].get_public_key(), rct::rct2sk(kLRki.k), (crypto::public_key&)kLRki.L, (crypto::public_key&)kLRki.R); - kLRki.ki = rct::ki2rct(m_transfers[n].m_key_image); - return kLRki; -} -//---------------------------------------------------------------------------------------------------- -rct::multisig_kLRki wallet::get_multisig_composite_kLRki(size_t n, const crypto::public_key &ignore, std::unordered_set &used_L, std::unordered_set &new_used_L) const -{ - CHECK_AND_ASSERT_THROW_MES(n < m_transfers.size(), "Bad transfer index"); - - const transfer_details &td = m_transfers[n]; - rct::multisig_kLRki kLRki = get_multisig_kLRki(n, rct::skGen()); - - // pick a L/R pair from every other participant but one - size_t n_signers_used = 1; - for (const auto &p: m_transfers[n].m_multisig_info) - { - if (p.m_signer == ignore) - continue; - for (const auto &lr: p.m_LR) - { - if (used_L.find(lr.m_L) != used_L.end()) - continue; - used_L.insert(lr.m_L); - new_used_L.insert(lr.m_L); - rct::addKeys(kLRki.L, kLRki.L, lr.m_L); - rct::addKeys(kLRki.R, kLRki.R, lr.m_R); - ++n_signers_used; - break; - } - } - CHECK_AND_ASSERT_THROW_MES(n_signers_used >= m_multisig_threshold, "LR not found for enough participants"); - - return kLRki; -} -//---------------------------------------------------------------------------------------------------- -crypto::key_image wallet::get_multisig_composite_key_image(size_t n) const -{ - CHECK_AND_ASSERT_THROW_MES(n < m_transfers.size(), "Bad output index"); - - const transfer_details &td = m_transfers[n]; - const crypto::public_key tx_key = get_tx_pub_key_from_received_outs(td); - const std::vector additional_tx_keys = cryptonote::get_additional_tx_pub_keys_from_extra(td.m_tx); - crypto::key_image ki; - std::vector pkis; - for (const auto &info: td.m_multisig_info) - for (const auto &pki: info.m_partial_key_images) - pkis.push_back(pki); - bool r = cryptonote::generate_multisig_composite_key_image(get_account().get_keys(), m_subaddresses, td.get_public_key(), tx_key, additional_tx_keys, td.m_internal_output_index, pkis, ki); - THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image"); - return ki; -} -//---------------------------------------------------------------------------------------------------- -cryptonote::blobdata wallet::export_multisig() -{ - std::vector info; - - const crypto::public_key signer = get_multisig_signer_public_key(); - - info.resize(m_transfers.size()); - for (size_t n = 0; n < m_transfers.size(); ++n) - { - transfer_details &td = m_transfers[n]; - const std::vector additional_tx_pub_keys = get_additional_tx_pub_keys_from_extra(td.m_tx); - crypto::key_image ki; - td.m_multisig_k.clear(); - info[n].m_LR.clear(); - info[n].m_partial_key_images.clear(); - - for (size_t m = 0; m < get_account().get_multisig_keys().size(); ++m) - { - // we want to export the partial key image, not the full one, so we can't use td.m_key_image - bool r = generate_multisig_key_image(get_account().get_keys(), m, td.get_public_key(), ki); - CHECK_AND_ASSERT_THROW_MES(r, "Failed to generate key image"); - info[n].m_partial_key_images.push_back(ki); - } - - size_t nlr = m_multisig_threshold < m_multisig_signers.size() ? m_multisig_threshold - 1 : 1; - for (size_t m = 0; m < nlr; ++m) - { - td.m_multisig_k.push_back(rct::skGen()); - const rct::multisig_kLRki kLRki = get_multisig_kLRki(n, td.m_multisig_k.back()); - info[n].m_LR.push_back({kLRki.L, kLRki.R}); - } - - info[n].m_signer = signer; - } - - std::stringstream oss; - boost::archive::portable_binary_oarchive ar(oss); - ar << info; - - std::string magic(MULTISIG_EXPORT_FILE_MAGIC, strlen(MULTISIG_EXPORT_FILE_MAGIC)); - const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address; - std::string header; - header += std::string((const char *)&keys.m_spend_public_key, sizeof(crypto::public_key)); - header += std::string((const char *)&keys.m_view_public_key, sizeof(crypto::public_key)); - header += std::string((const char *)&signer, sizeof(crypto::public_key)); - std::string ciphertext = encrypt_with_view_secret_key(header + oss.str()); - - return MULTISIG_EXPORT_FILE_MAGIC + ciphertext; -} -//---------------------------------------------------------------------------------------------------- -void wallet::update_multisig_rescan_info(const std::vector> &multisig_k, const std::vector> &info, size_t n) -{ - CHECK_AND_ASSERT_THROW_MES(n < m_transfers.size(), "Bad index in update_multisig_info"); - CHECK_AND_ASSERT_THROW_MES(multisig_k.size() >= m_transfers.size(), "Mismatched sizes of multisig_k and info"); - - MDEBUG("update_multisig_rescan_info: updating index " << n); - transfer_details &td = m_transfers[n]; - td.m_multisig_info.clear(); - for (const auto &pi: info) - { - CHECK_AND_ASSERT_THROW_MES(n < pi.size(), "Bad pi size"); - td.m_multisig_info.push_back(pi[n]); - } - m_key_images.erase(td.m_key_image); - td.m_key_image = get_multisig_composite_key_image(n); - td.m_key_image_known = true; - td.m_key_image_partial = false; - td.m_multisig_k = multisig_k[n]; - m_key_images[td.m_key_image] = n; -} -//---------------------------------------------------------------------------------------------------- -size_t wallet::import_multisig(std::vector blobs) -{ - CHECK_AND_ASSERT_THROW_MES(m_multisig, "Wallet is not multisig"); - - std::vector> info; - std::unordered_set seen; - for (cryptonote::blobdata &data: blobs) - { - const size_t magiclen = strlen(MULTISIG_EXPORT_FILE_MAGIC); - THROW_WALLET_EXCEPTION_IF(data.size() < magiclen || memcmp(data.data(), MULTISIG_EXPORT_FILE_MAGIC, magiclen), - error::wallet_internal_error, "Bad multisig info file magic in "); - - data = decrypt_with_view_secret_key(std::string(data, magiclen)); - - const size_t headerlen = 3 * sizeof(crypto::public_key); - THROW_WALLET_EXCEPTION_IF(data.size() < headerlen, error::wallet_internal_error, "Bad data size"); - - const crypto::public_key &public_spend_key = *(const crypto::public_key*)&data[0]; - const crypto::public_key &public_view_key = *(const crypto::public_key*)&data[sizeof(crypto::public_key)]; - const crypto::public_key &signer = *(const crypto::public_key*)&data[2*sizeof(crypto::public_key)]; - const cryptonote::account_public_address &keys = get_account().get_keys().m_account_address; - THROW_WALLET_EXCEPTION_IF(public_spend_key != keys.m_spend_public_key || public_view_key != keys.m_view_public_key, - error::wallet_internal_error, "Multisig info is for a different account"); - if (get_multisig_signer_public_key() == signer) - { - MINFO("Multisig info from this wallet ignored"); - continue; - } - if (seen.find(signer) != seen.end()) - { - MINFO("Duplicate multisig info ignored"); - continue; - } - seen.insert(signer); - - std::string body(data, headerlen); - std::istringstream iss(body); - std::vector i; - boost::archive::portable_binary_iarchive ar(iss); - ar >> i; - MINFO(boost::format("%u outputs found") % boost::lexical_cast(i.size())); - info.push_back(std::move(i)); - } - - CHECK_AND_ASSERT_THROW_MES(info.size() + 1 <= m_multisig_signers.size() && info.size() + 1 >= m_multisig_threshold, "Wrong number of multisig sources"); - - std::vector> k; - k.reserve(m_transfers.size()); - for (const auto &td: m_transfers) - k.push_back(td.m_multisig_k); - - // how many outputs we're going to update - size_t n_outputs = m_transfers.size(); - for (const auto &pi: info) - if (pi.size() < n_outputs) - n_outputs = pi.size(); - - if (n_outputs == 0) - return 0; - - // check signers are consistent - for (const auto &pi: info) - { - CHECK_AND_ASSERT_THROW_MES(std::find(m_multisig_signers.begin(), m_multisig_signers.end(), pi[0].m_signer) != m_multisig_signers.end(), - "Signer is not a member of this multisig wallet"); - for (size_t n = 1; n < n_outputs; ++n) - CHECK_AND_ASSERT_THROW_MES(pi[n].m_signer == pi[0].m_signer, "Mismatched signers in imported multisig info"); - } - - // trim data we don't have info for from all participants - for (auto &pi: info) - pi.resize(n_outputs); - - // sort by signer - if (!info.empty() && !info.front().empty()) - { - std::sort(info.begin(), info.end(), [](const std::vector &i0, const std::vector &i1){ return memcmp(&i0[0].m_signer, &i1[0].m_signer, sizeof(i0[0].m_signer)); }); - } - - // first pass to determine where to detach the blockchain - for (size_t n = 0; n < n_outputs; ++n) - { - const transfer_details &td = m_transfers[n]; - if (!td.m_key_image_partial) - continue; - MINFO("Multisig info importing from block height " << td.m_block_height); - detach_blockchain(td.m_block_height); - break; - } - - for (size_t n = 0; n < n_outputs && n < m_transfers.size(); ++n) - { - update_multisig_rescan_info(k, info, n); - } - - m_multisig_rescan_k = &k; - m_multisig_rescan_info = &info; - try - { - refresh(); - } - catch (...) {} - m_multisig_rescan_info = NULL; - m_multisig_rescan_k = NULL; - - return n_outputs; -} -//---------------------------------------------------------------------------------------------------- std::string wallet::encrypt(const std::string &plaintext, const crypto::secret_key &skey, bool authenticated) const { crypto::chacha_key key; @@ -12339,6 +12291,9 @@ uint64_t wallet::get_segregation_fork_height() const } return SEGREGATION_FORK_HEIGHT; } + + + //---------------------------------------------------------------------------------------------------- void wallet::generate_genesis(cryptonote::block& b) const { if (m_nettype == TESTNET) diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 6cb1de99b..d462a5cb8 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -34,11 +34,13 @@ #include #include +#include #include #include #include #include #include +#include #include "include_base_utils.h" #include "cryptonote_basic/account.h" @@ -55,11 +57,16 @@ #include "ringct/rctTypes.h" #include "ringct/rctOps.h" #include "checkpoints/checkpoints.h" +#include "safex/safex_core.h" +#include "safex/safex_account.h" +#include "common/command_line.h" +#include "safex/safex_offer.h" #include "wallet_errors.h" #include "common/password.h" #include "node_rpc_proxy.h" + #undef SAFEX_DEFAULT_LOG_CATEGORY #define SAFEX_DEFAULT_LOG_CATEGORY "wallet.wallet" @@ -77,6 +84,7 @@ namespace tools virtual void on_new_block(uint64_t height, const cryptonote::block& block) {} virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) {} virtual void on_tokens_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t token_amount, const cryptonote::subaddress_index& subaddr_index) {} + virtual void on_advanced_output_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, const cryptonote::txout_to_script &txout, const cryptonote::subaddress_index& subaddr_index){} virtual void on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index) {} virtual void on_unconfirmed_tokens_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t token_amount, const cryptonote::subaddress_index& subaddr_index) {} virtual void on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index) {} @@ -217,8 +225,10 @@ namespace tools bool error; bool token_transfer; boost::optional received; + cryptonote::tx_out_type output_type; - tx_scan_info_t(): in_ephemeral(AUTO_VAL_INIT(in_ephemeral)), ki(AUTO_VAL_INIT(ki)), mask(AUTO_VAL_INIT(mask)), amount(0), token_amount(0), money_transfered(0), token_transfered(0), error(true), token_transfer(false) {} + tx_scan_info_t(): in_ephemeral(AUTO_VAL_INIT(in_ephemeral)), ki(AUTO_VAL_INIT(ki)), mask(AUTO_VAL_INIT(mask)), amount(0), token_amount(0), + money_transfered(0), token_transfered(0), error(true), token_transfer(false), output_type(cryptonote::tx_out_type::out_invalid) {} }; struct transfer_details @@ -242,10 +252,12 @@ namespace tools bool m_key_image_partial; std::vector m_multisig_k; std::vector m_multisig_info; // one per other participant + cryptonote::tx_out_type m_output_type = cryptonote::tx_out_type::out_cash; //cash outputs by default bool is_rct() const { return m_rct; } + cryptonote::tx_out_type get_out_type() const { return m_output_type;} uint64_t amount() const { return m_amount; } - uint64_t token_amount() const { return m_token_amount; } + uint64_t token_amount() const { return m_token_amount;} const crypto::public_key &get_public_key() const { return *boost::apply_visitor(cryptonote::destination_public_key_visitor(), m_tx.vout[m_internal_output_index].target); @@ -271,6 +283,7 @@ namespace tools FIELD(m_key_image_partial) FIELD(m_multisig_k) FIELD(m_multisig_info) + FIELD(m_output_type) END_SERIALIZE() }; @@ -285,6 +298,7 @@ namespace tools uint64_t m_timestamp; cryptonote::subaddress_index m_subaddr_index; bool m_token_transaction = false; + cryptonote::tx_out_type m_output_type = cryptonote::tx_out_type::out_invalid; }; struct address_tx : payment_details @@ -317,6 +331,7 @@ namespace tools uint32_t m_subaddr_account; // subaddress account of your wallet to be used in this transfer std::set m_subaddr_indices; // set of address indices used as inputs in this transfer std::vector>> m_rings; // relative + cryptonote::tx_out_type m_output_type = cryptonote::tx_out_type::out_invalid; }; struct confirmed_transfer_details @@ -335,6 +350,7 @@ namespace tools uint32_t m_subaddr_account; // subaddress account of your wallet to be used in this transfer std::set m_subaddr_indices; // set of address indices used as inputs in this transfer std::vector>> m_rings; // relative + cryptonote::tx_out_type m_output_type = cryptonote::tx_out_type::out_invalid; confirmed_transfer_details(): m_amount_in(0), m_amount_out(0), m_change((uint64_t)-1), m_token_amount_in(0), m_token_amount_out(0), m_token_change((uint64_t)-1), m_block_height(0), m_payment_id(crypto::null_hash), m_timestamp(0), m_unlock_time(0), m_subaddr_account((uint32_t)-1) {} @@ -539,53 +555,6 @@ namespace tools */ void restore(const std::string& wallet_, const epee::wipeable_string& password, const std::string &device_name); - /*! - * \brief Creates a multisig wallet - * \return empty if done, non empty if we need to send another string - * to other participants - */ - std::string make_multisig(const epee::wipeable_string &password, - const std::vector &info, - uint32_t threshold); - /*! - * \brief Creates a multisig wallet - * \return empty if done, non empty if we need to send another string - * to other participants - */ - std::string make_multisig(const epee::wipeable_string &password, - const std::vector &view_keys, - const std::vector &spend_keys, - uint32_t threshold); - /*! - * \brief Finalizes creation of a multisig wallet - */ - bool finalize_multisig(const epee::wipeable_string &password, const std::vector &info); - /*! - * \brief Finalizes creation of a multisig wallet - */ - bool finalize_multisig(const epee::wipeable_string &password, std::unordered_set pkeys, std::vector signers); - /*! - * Get a packaged multisig information string - */ - std::string get_multisig_info() const; - /*! - * Verifies and extracts keys from a packaged multisig information string - */ - static bool verify_multisig_info(const std::string &data, crypto::secret_key &skey, crypto::public_key &pkey); - /*! - * Verifies and extracts keys from a packaged multisig information string - */ - static bool verify_extra_multisig_info(const std::string &data, std::unordered_set &pkeys, crypto::public_key &signer); - /*! - * Export multisig info - * This will generate and remember new k values - */ - cryptonote::blobdata export_multisig(); - /*! - * Import a set of multisig info from multisig partners - * \return the number of inputs which were imported - */ - size_t import_multisig(std::vector info); /*! * \brief Rewrites to the wallet file for wallet upgrade (doesn't generate key, assumes it's already there) * \param wallet_name Name of wallet file (should exist) @@ -595,6 +564,7 @@ namespace tools void write_watch_only_wallet(const std::string& wallet_name, const epee::wipeable_string& password, std::string &new_keys_filename); void load(const std::string& wallet, const epee::wipeable_string& password); void store(); + void store_safex(const epee::wipeable_string &password); /*! * \brief store_to - stores wallet to another file(s), deleting old ones * \param path - path to the wallet file (keys and address filenames will be generated based on this filename) @@ -602,6 +572,7 @@ namespace tools */ void store_to(const std::string &path, const epee::wipeable_string &password); + std::string path() const; /*! @@ -687,8 +658,6 @@ namespace tools bool restricted() const { return m_restricted; } bool watch_only() const { return m_watch_only; } bool multisig(bool *ready = NULL, uint32_t *threshold = NULL, uint32_t *total = NULL) const; - bool has_multisig_partial_key_images() const; - bool get_multisig_seed(std::string& seed, const epee::wipeable_string &passphrase = std::string(), bool raw = true) const; bool key_on_device() const { return m_key_on_device; } // locked & unlocked balance of given or current subaddress account @@ -696,12 +665,25 @@ namespace tools uint64_t unlocked_balance(uint32_t subaddr_index_major) const; uint64_t token_balance(uint32_t subaddr_index_major) const; uint64_t unlocked_token_balance(uint32_t subaddr_index_major) const; + + + uint64_t staked_token_balance(uint32_t subaddr_index_major) const; + std::map staked_token_balance_per_subaddress(uint32_t subaddr_index_major) const; + + + uint64_t unlocked_staked_token_balance(uint32_t subaddr_index_major) const; + std::map unlocked_staked_token_balance_per_subaddress(uint32_t subaddr_index_major) const; + // locked & unlocked balance per subaddress of given or current subaddress account std::map balance_per_subaddress(uint32_t subaddr_index_major) const; std::map unlocked_balance_per_subaddress(uint32_t subaddr_index_major) const; // all locked & unlocked balances of all subaddress accounts std::map token_balance_per_subaddress(uint32_t subaddr_index_major) const; std::map unlocked_token_balance_per_subaddress(uint32_t subaddr_index_major) const; + + uint64_t staked_token_balance_all() const; + uint64_t unlocked_staked_token_balance_all() const; + uint64_t balance_all() const; uint64_t unlocked_balance_all() const; uint64_t token_balance_all() const; @@ -717,17 +699,17 @@ namespace tools void transfer_selected(const std::vector& dsts, const std::vector& selected_transfers, size_t fake_outputs_count, std::vector> &outs, uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, cryptonote::transaction& tx, pending_tx &ptx); - void transfer_selected_rct(std::vector dsts, const std::vector& selected_transfers, size_t fake_outputs_count, - std::vector> &outs, - uint64_t unlock_time, uint64_t fee, const std::vector& extra, cryptonote::transaction& tx, pending_tx &ptx, bool bulletproof); + + template + void transfer_advanced(safex::command_t command_type, const std::vector& dsts, const std::vector& selected_transfers, + size_t fake_outputs_count, std::vector> &outs, + uint64_t unlock_time, uint64_t fee, const std::vector& extra, T destination_split_strategy, const tx_dust_policy& dust_policy, + cryptonote::transaction& tx, pending_tx &ptx, const safex::safex_account &safexacc = safex::safex_account{}); void commit_tx(pending_tx& ptx_vector); void commit_tx(std::vector& ptx_vector); bool save_tx(const std::vector& ptx_vector, const std::string &filename) const; - std::string save_multisig_tx(multisig_tx_set txs); - bool save_multisig_tx(const multisig_tx_set &txs, const std::string &filename); - std::string save_multisig_tx(const std::vector& ptx_vector); - bool save_multisig_tx(const std::vector& ptx_vector, const std::string &filename); + // load unsigned tx from file and sign it. Takes confirmation callback as argument. Used by the cli wallet bool sign_tx(const std::string &unsigned_filename, const std::string &signed_filename, std::vector &ptx, std::function accept_func = NULL, bool export_raw = false); // sign unsigned tx. Takes unsigned_tx_set as argument. Used by GUI @@ -745,11 +727,7 @@ namespace tools std::vector unused_transfers_indices, std::vector unused_dust_indices, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector &extra, bool trusted_daemon); std::vector create_transactions_migration(std::vector dsts, crypto::hash bitcoin_transaction_hash, uint64_t unlock_time, uint32_t priority, const std::vector& extra, bool trusted_daemon, bool mark_as_spent=false); - bool load_multisig_tx(cryptonote::blobdata blob, multisig_tx_set &exported_txs, std::function accept_func = NULL); - bool load_multisig_tx_from_file(const std::string &filename, multisig_tx_set &exported_txs, std::function accept_func = NULL); - bool sign_multisig_tx_from_file(const std::string &filename, std::vector &txids, std::function accept_func); - bool sign_multisig_tx(multisig_tx_set &exported_txs, std::vector &txids); - bool sign_multisig_tx_to_file(multisig_tx_set &exported_txs, const std::string &filename, std::vector &txids); + std::vector create_transactions_advanced(safex::command_t command_type, std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices, bool trusted_daemon, const safex::safex_account &sfx_acc = safex::safex_account{}); std::vector create_unmixable_sweep_transactions(bool trusted_daemon, cryptonote::tx_out_type out_type); bool check_connection(uint32_t *version = NULL, uint32_t timeout = 200000); void get_transfers(wallet::transfer_container& incoming_transfers) const; @@ -794,8 +772,51 @@ namespace tools a & m_unconfirmed_payments; a & m_account_tags; a & m_ring_history_saved; + + if (ver < 1) return; + + a & m_safex_accounts; + + a & m_safex_offers; + + a & m_safex_feedback_tokens; + + a & m_safex_price_pegs; + } + static std::string get_default_ringdb_path() + { + boost::filesystem::path dir = tools::get_default_data_dir(); + // remove .bitsafex, replace with .shared-ringdb + dir = dir.remove_filename(); + dir /= ".shared-ringdb"; + return dir.string(); + } + + // Create on-demand to prevent static initialization order fiasco issues. + struct options { + const command_line::arg_descriptor daemon_address = {"daemon-address", tools::wallet::tr("Use daemon instance at :"), ""}; + const command_line::arg_descriptor daemon_host = {"daemon-host", tools::wallet::tr("Use daemon instance at host instead of localhost"), ""}; + const command_line::arg_descriptor password = {"password", tools::wallet::tr("Wallet password (escape/quote as needed)"), "", true}; + const command_line::arg_descriptor password_file = {"password-file", tools::wallet::tr("Wallet password file"), "", true}; + const command_line::arg_descriptor daemon_port = {"daemon-port", tools::wallet::tr("Use daemon instance at port instead of 18081"), 0}; + const command_line::arg_descriptor daemon_login = {"daemon-login", tools::wallet::tr("Specify username[:password] for daemon RPC client"), "", true}; + const command_line::arg_descriptor testnet = {"testnet", tools::wallet::tr("For testnet. Daemon must also be launched with --testnet flag"), false}; + const command_line::arg_descriptor stagenet = {"stagenet", tools::wallet::tr("For stagenet. Daemon must also be launched with --stagenet flag"), false}; + const command_line::arg_descriptor restricted = {"restricted-rpc", tools::wallet::tr("Restricts to view-only commands"), false}; + const command_line::arg_descriptor shared_ringdb_dir = { + "shared-ringdb-dir", tools::wallet::tr("Set shared ring database path"), + get_default_ringdb_path(), + testnet, + [](bool _testnet, bool defaulted, std::string val)->std::string { + if (_testnet) + return (boost::filesystem::path(val) / "testnet").string(); + return val; + } + }; + }; + /*! * \brief Check if wallet keys and bin files exist * \param file_path Wallet file path @@ -914,8 +935,14 @@ namespace tools std::vector select_available_unmixable_outputs(bool trusted_daemon, cryptonote::tx_out_type out_type); std::vector select_available_mixable_outputs(bool trusted_daemon, cryptonote::tx_out_type out_type); - size_t pop_best_value_from(const transfer_container &transfers, std::vector &unused_dust_indices, const std::vector& selected_transfers, bool smallest = false, bool token_transfer = false) const; - size_t pop_best_value(std::vector &unused_dust_indices, const std::vector& selected_transfers, bool smallest = false, bool token_transfer = false) const; + size_t pop_best_value_from(const transfer_container &transfers, std::vector &unused_dust_indices, const std::vector& selected_transfers, bool smallest = false, const cryptonote::tx_out_type out_type = cryptonote::tx_out_type::out_cash, const uint64_t needed_cash_for_purchase = 0) const; + size_t pop_ideal_value_from(const transfer_container &transfers, std::vector &unused_indices, const std::vector& selected_transfers, const cryptonote::tx_out_type out_type, const uint64_t cash_amount, const uint64_t token_amount) const; + size_t pop_advanced_output_from(const transfer_container &transfers, const std::vector& selected_transfers, const std::string &acc_username, const cryptonote::tx_out_type out_type) const; + size_t pop_best_value(std::vector &unused_dust_indices, const std::vector& selected_transfers, bool smallest = false, const cryptonote::tx_out_type out_type = cryptonote::tx_out_type::out_cash, const uint64_t needed_cash_for_purchase = 0) const; + size_t pop_ideal_value(std::vector &unused_indices, const std::vector& selected_transfers, const cryptonote::tx_out_type out_type, const uint64_t cash_amount, const uint64_t token_amount) const; + size_t pop_advanced_output(const std::vector& selected_transfers, const std::vector &acc_username, const cryptonote::tx_out_type out_type) const; + size_t pop_advanced_output(const std::vector& selected_transfers, const crypto::hash& out_id, const cryptonote::tx_out_type out_type) const; + size_t pop_advanced_output_from(const transfer_container &transfers, const std::vector& selected_transfers, const crypto::hash& out_id, const cryptonote::tx_out_type out_type) const; void set_tx_note(const crypto::hash &txid, const std::string ¬e); std::string get_tx_note(const crypto::hash &txid) const; @@ -1017,11 +1044,6 @@ namespace tools void set_attribute(const std::string &key, const std::string &value); std::string get_attribute(const std::string &key) const; - crypto::public_key get_multisig_signer_public_key(const crypto::secret_key &spend_skey) const; - crypto::public_key get_multisig_signer_public_key() const; - crypto::public_key get_multisig_signing_public_key(size_t idx) const; - crypto::public_key get_multisig_signing_public_key(const crypto::secret_key &skey) const; - template inline bool invoke_http_json(const boost::string_ref uri, const t_request& req, t_response& res, std::chrono::milliseconds timeout = std::chrono::seconds(15), const boost::string_ref http_method = "GET") { @@ -1053,6 +1075,45 @@ namespace tools bool unblackball_output(const crypto::public_key &output); bool is_output_blackballed(const crypto::public_key &output) const; + + std::map get_interest_map(const uint64_t start_interval, const uint64_t end_interval); + uint64_t get_interest_for_transfer(const transfer_details& td); + uint64_t get_current_interest(std::vector>& interest_per_output); + + bool generate_safex_account(const std::string &username, const std::vector &account_data); + bool remove_safex_account(const std::string &username); + bool get_safex_account(const std::string &username, safex::safex_account &acc); + bool get_safex_account_keys(const std::string &username, safex::safex_account_keys &acckeys); + std::vector get_safex_accounts(); + bool recover_safex_account(const std::string &username, const crypto::secret_key &secret_key); + bool update_safex_account_data(const std::string &username, const std::vector accdata); + bool safex_account_exists(const std::string& username); + + uint8_t get_safex_account_status(const safex::safex_account& sfx_account) const; + + bool is_safex_account_unlocked(const std::string& username) const; + bool is_create_account_token_fee(const transfer_details& td) const; + + bool add_safex_offer(const safex::safex_offer& offer); + bool update_safex_offer(const safex::safex_offer& offer); + bool update_safex_offer(const safex::create_purchase_data& purchase); + bool add_safex_feedback_token(const safex::create_feedback_token_data& feedback_token); + bool remove_safex_feedback_token(const crypto::hash& offer_id); + bool add_safex_price_peg(const safex::safex_price_peg& price_peg); + bool update_safex_price_peg(const crypto::hash &price_peg_id, const uint64_t& rate); + + bool calculate_sfx_price(const safex::safex_offer& sfx_offer, uint64_t& sfx_price); + + void process_advanced_output(const cryptonote::txout_to_script &txout, const cryptonote::tx_out_type& output_type); + + std::vector get_safex_offers(); + std::vector get_safex_ratings(const crypto::hash& offer_id); + std::vector get_my_safex_offers(); + std::vector get_my_safex_feedbacks_to_give(); + safex::safex_offer get_my_safex_offer(crypto::hash& offer_id); + std::vector get_safex_price_pegs(const std::string& currency = ""); + std::vector get_my_safex_price_pegs(); + private: /*! * \brief Stores wallet information to wallet file. @@ -1062,12 +1123,15 @@ namespace tools * \return Whether it was successful. */ bool store_keys(const std::string& keys_file_name, const epee::wipeable_string& password, bool watch_only = false); + + bool store_safex_keys(const std::string& safex_keys_file_name, const epee::wipeable_string& password); /*! * \brief Load wallet information from wallet file. * \param keys_file_name Name of wallet file * \param password Password of wallet file */ bool load_keys(const std::string& keys_file_name, const epee::wipeable_string& password); + bool load_safex_keys(const std::string& safex_keys_file_name, const epee::wipeable_string& password); void process_new_transaction(const crypto::hash &txid, const cryptonote::transaction& tx, const std::vector &o_indices, uint64_t height, uint64_t ts, bool miner_tx, bool pool, bool double_spend_seen); void process_new_blockchain_entry(const cryptonote::block& b, const cryptonote::block_complete_entry& bche, const crypto::hash& bl_id, uint64_t height, const cryptonote::COMMAND_RPC_GET_BLOCKS_FAST::block_output_indices &o_indices); void detach_blockchain(uint64_t height); @@ -1106,11 +1170,6 @@ namespace tools void scan_output(const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map &tx_money_got_in_outs, std::unordered_map &tx_token_got_in_outs, std::vector &outs) const; void trim_hashchain(); - crypto::key_image get_multisig_composite_key_image(size_t n) const; - rct::multisig_kLRki get_multisig_composite_kLRki(size_t n, const crypto::public_key &ignore, std::unordered_set &used_L, std::unordered_set &new_used_L) const; - rct::multisig_kLRki get_multisig_kLRki(size_t n, const rct::key &k) const; - rct::key get_multisig_k(size_t idx, const std::unordered_set &used_L) const; - void update_multisig_rescan_info(const std::vector> &multisig_k, const std::vector> &info, size_t n); bool add_rings(const crypto::chacha_key &key, const cryptonote::transaction_prefix &tx); bool add_rings(const cryptonote::transaction_prefix &tx); bool remove_rings(const cryptonote::transaction_prefix &tx); @@ -1122,11 +1181,20 @@ namespace tools uint64_t get_segregation_fork_height() const; + /*************************** SAFEX MARKETPLACE FUNCTIONALITIES ******************************************/ + + std::vector create_lock_transaction(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices, bool trusted_daemon); // pass subaddr_indices by value on purpose + std::vector create_unlock_transaction(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices, bool trusted_daemon); // pass subaddr_indices by value on purpose + std::vector create_donation_transaction(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint32_t priority, const std::vector& extra, uint32_t subaddr_account, std::set subaddr_indices, bool trusted_daemon); // pass subaddr_indices by value on purpose + + /********************************************************************************************************/ + cryptonote::account_base m_account; boost::optional m_daemon_login; std::string m_daemon_address; std::string m_wallet_file; std::string m_keys_file; + std::string m_safex_keys_file; epee::net_utils::http::http_simple_client m_http_client; hashchain m_blockchain; std::atomic m_local_bc_height; //temporary workaround @@ -1163,8 +1231,8 @@ namespace tools std::string seed_language; /*!< Language of the mnemonics (seed). */ bool is_old_file_format; /*!< Whether the wallet file is of an old file format */ bool m_watch_only; /*!< no spend key */ - bool m_multisig; /*!< if > 1 spend secret key will not match spend public key */ - uint32_t m_multisig_threshold; + bool m_multisig = false; /*!< if > 1 spend secret key will not match spend public key */ + uint32_t m_multisig_threshold = 0; std::vector m_multisig_signers; bool m_always_confirm_transfers; bool m_print_ring_members; @@ -1215,18 +1283,27 @@ namespace tools bool m_ring_history_saved; std::unique_ptr m_ringdb; - bool problematic_output(crypto::public_key key); + bool problematic_output(crypto::public_key key); + + std::vector m_safex_accounts; + std::vector m_safex_accounts_keys; + + std::vector m_safex_offers; + + std::vector m_safex_feedback_tokens; + + std::vector m_safex_price_pegs; }; } -BOOST_CLASS_VERSION(tools::wallet, 0) -BOOST_CLASS_VERSION(tools::wallet::transfer_details, 0) +BOOST_CLASS_VERSION(tools::wallet, 1) +BOOST_CLASS_VERSION(tools::wallet::transfer_details, 1) BOOST_CLASS_VERSION(tools::wallet::multisig_info, 0) BOOST_CLASS_VERSION(tools::wallet::multisig_info::LR, 0) BOOST_CLASS_VERSION(tools::wallet::multisig_tx_set, 0) -BOOST_CLASS_VERSION(tools::wallet::payment_details, 0) +BOOST_CLASS_VERSION(tools::wallet::payment_details, 1) BOOST_CLASS_VERSION(tools::wallet::pool_payment_details, 0) -BOOST_CLASS_VERSION(tools::wallet::unconfirmed_transfer_details, 0) -BOOST_CLASS_VERSION(tools::wallet::confirmed_transfer_details, 0) +BOOST_CLASS_VERSION(tools::wallet::unconfirmed_transfer_details, 1) +BOOST_CLASS_VERSION(tools::wallet::confirmed_transfer_details, 1) BOOST_CLASS_VERSION(tools::wallet::address_book_row, 0) BOOST_CLASS_VERSION(tools::wallet::reserve_proof_entry, 0) BOOST_CLASS_VERSION(tools::wallet::unsigned_tx_set, 0) @@ -1234,6 +1311,9 @@ BOOST_CLASS_VERSION(tools::wallet::signed_tx_set, 0) BOOST_CLASS_VERSION(tools::wallet::tx_construction_data, 0) BOOST_CLASS_VERSION(tools::wallet::pending_tx, 0) BOOST_CLASS_VERSION(tools::wallet::multisig_sig, 0) +BOOST_CLASS_VERSION(safex::safex_account, 0) +BOOST_CLASS_VERSION(safex::safex_account_keys, 0) +BOOST_CLASS_VERSION(safex::safex_account_key_handler, 0) namespace boost { @@ -1270,6 +1350,10 @@ namespace boost a & x.m_multisig_info; a & x.m_multisig_k; a & x.m_key_image_partial; + + if (ver < 1) return; + + a & x.m_output_type; } template @@ -1312,6 +1396,8 @@ namespace boost a & x.m_subaddr_account; a & x.m_subaddr_indices; a & x.m_rings; + if (ver < 1) return; + a & x.m_output_type; } template @@ -1331,6 +1417,8 @@ namespace boost a & x.m_subaddr_account; a & x.m_subaddr_indices; a & x.m_rings; + if (ver < 1) return; + a & x.m_output_type; } template @@ -1345,6 +1433,8 @@ namespace boost a & x.m_timestamp; a & x.m_subaddr_index; a & x.m_token_transaction; + if (ver < 1) return; + a & x.m_output_type; } template @@ -1430,6 +1520,7 @@ namespace boost a & x.construction_data; a & x.multisig_sigs; } + } } @@ -1453,24 +1544,37 @@ namespace tools for(auto& de: dsts) { - if (de.token_transaction) { - cryptonote::decompose_amount_into_digits(de.token_amount, 0, - [&](uint64_t chunk) { splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, de.addr, de.is_subaddress, true)); }, - [&](uint64_t a_dust) { splitted_dsts.push_back(cryptonote::tx_destination_entry(a_dust, de.addr, de.is_subaddress, true)); } ); - } else { - cryptonote::decompose_amount_into_digits(de.amount, 0, - [&](uint64_t chunk) { splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, de.addr, de.is_subaddress)); }, - [&](uint64_t a_dust) { splitted_dsts.push_back(cryptonote::tx_destination_entry(a_dust, de.addr, de.is_subaddress)); } ); - } + if (de.output_type == cryptonote::tx_out_type::out_token) + { + cryptonote::decompose_amount_into_digits(de.token_amount, 0, + [&](uint64_t chunk) + { splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, de.addr, de.is_subaddress, cryptonote::tx_out_type::out_token)); }, + [&](uint64_t a_dust) + { splitted_dsts.push_back(cryptonote::tx_destination_entry(a_dust, de.addr, de.is_subaddress, cryptonote::tx_out_type::out_token)); }); + + } + else if (de.output_type == cryptonote::tx_out_type::out_cash) + { + cryptonote::decompose_amount_into_digits(de.amount, 0, + [&](uint64_t chunk) + { splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, de.addr, de.is_subaddress, cryptonote::tx_out_type::out_cash)); }, + [&](uint64_t a_dust) + { splitted_dsts.push_back(cryptonote::tx_destination_entry(a_dust, de.addr, de.is_subaddress, cryptonote::tx_out_type::out_cash)); }); + } + else { + //do nothing + splitted_dsts.push_back(de); + } + } //for cash cryptonote::decompose_amount_into_digits(change_dst.amount, 0, [&](uint64_t chunk) { if (chunk <= dust_threshold) - dust_dsts.push_back(cryptonote::tx_destination_entry(chunk, change_dst.addr, false)); + dust_dsts.push_back(cryptonote::tx_destination_entry(chunk, change_dst.addr, false, cryptonote::tx_out_type::out_cash)); else - splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, change_dst.addr, false)); + splitted_dsts.push_back(cryptonote::tx_destination_entry(chunk, change_dst.addr, false, cryptonote::tx_out_type::out_cash)); }, [&](uint64_t a_dust) { dust_dsts.push_back(cryptonote::tx_destination_entry(a_dust, change_dst.addr, false)); } ); @@ -1478,11 +1582,11 @@ namespace tools cryptonote::decompose_amount_into_digits(change_token_dst.token_amount, 0, [&](uint64_t token_chunk) { if (token_chunk <= dust_threshold) - dust_dsts.push_back(cryptonote::tx_destination_entry(token_chunk, change_token_dst.addr, false, true /*token destination*/)); + dust_dsts.push_back(cryptonote::tx_destination_entry(token_chunk, change_token_dst.addr, false, cryptonote::tx_out_type::out_token)); else - splitted_dsts.push_back(cryptonote::tx_destination_entry(token_chunk, change_token_dst.addr, false, true)); + splitted_dsts.push_back(cryptonote::tx_destination_entry(token_chunk, change_token_dst.addr, false, cryptonote::tx_out_type::out_token)); }, - [&](uint64_t a_token_dust) { dust_dsts.push_back(cryptonote::tx_destination_entry(a_token_dust, change_token_dst.addr, false, true)); } ); + [&](uint64_t a_token_dust) { dust_dsts.push_back(cryptonote::tx_destination_entry(a_token_dust, change_token_dst.addr, false, cryptonote::tx_out_type::out_token)); } ); } //---------------------------------------------------------------------------------------------------- inline void null_split_strategy(const std::vector& dsts, @@ -1502,7 +1606,7 @@ namespace tools if (0 != token_change) { - splitted_dsts.push_back(cryptonote::tx_destination_entry(token_change, change_token_dst.addr, false, true)); + splitted_dsts.push_back(cryptonote::tx_destination_entry(token_change, change_token_dst.addr, false, cryptonote::tx_out_type::out_token)); } } //---------------------------------------------------------------------------------------------------- @@ -1510,7 +1614,9 @@ namespace tools { std::string indexes; std::for_each(src.outputs.begin(), src.outputs.end(), [&](const cryptonote::tx_source_entry::output_entry& s_e) { indexes += boost::to_string(s_e.first) + " "; }); - LOG_PRINT_L0("amount=" << cryptonote::print_money(src.amount) << ", real_output=" < selected_transfers; uint64_t found_money = select_transfers(needed_money, unused_transfers_indices, selected_transfers, trusted_daemon); - THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_money, found_money, needed_money - fee, fee); + THROW_WALLET_EXCEPTION_IF(found_money < needed_money, error::not_enough_unlocked_cash, found_money, needed_money - fee, fee); uint32_t subaddr_account = m_transfers[*selected_transfers.begin()].m_subaddr_index.major; for (auto i = ++selected_transfers.begin(); i != selected_transfers.end(); ++i) @@ -1610,7 +1716,6 @@ namespace tools cryptonote::tx_source_entry& src = sources.back(); const transfer_details& td = m_transfers[idx]; src.amount = td.amount(); - src.rct = false; //paste mixin transaction if(daemon_resp.outs.size()) { @@ -1643,7 +1748,6 @@ namespace tools src.real_out_tx_key = get_tx_pub_key_from_extra(td.m_tx); src.real_output = interted_it - src.outputs.begin(); src.real_output_in_tx_index = td.m_internal_output_index; - src.multisig_kLRki = rct::multisig_kLRki({rct::zero(), rct::zero(), rct::zero(), rct::zero()}); detail::print_source_entry(src); ++i; } @@ -1670,7 +1774,7 @@ namespace tools splitted_dsts.push_back(cryptonote::tx_destination_entry(d.amount, dust_policy.addr_for_dust, d.is_subaddress)); if (d.token_transaction) - splitted_dsts.push_back(cryptonote::tx_destination_entry(d.token_amount, dust_policy.addr_for_dust, d.is_subaddress, true)); + splitted_dsts.push_back(cryptonote::tx_destination_entry(d.token_amount, dust_policy.addr_for_dust, d.is_subaddress, cryptonote::tx_out_type::out_token)); dust += d.amount; token_dust += d.token_amount; @@ -1678,8 +1782,7 @@ namespace tools crypto::secret_key tx_key = AUTO_VAL_INIT(tx_key); std::vector additional_tx_keys; - rct::multisig_out msout = AUTO_VAL_INIT(msout); - 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, false, m_multisig ? &msout : NULL); + 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); THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_nettype); THROW_WALLET_EXCEPTION_IF(upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, upper_transaction_size_limit); diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index ccd3e547b..459777621 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -73,9 +73,9 @@ namespace tools // get_tx_pool_error // transfer_error * // get_random_outs_general_error - // not_enough_unlocked_money + // not_enough_unlocked_cash // not_enough_unlocked_tokens - // not_enough_money + // not_enough_cash // not_enough_tokens // tx_not_possible // not_enough_outs_to_mix @@ -195,19 +195,20 @@ namespace tools } }; //---------------------------------------------------------------------------------------------------- - struct multisig_export_needed : public wallet_runtime_error + struct not_supported : public wallet_internal_error { - explicit multisig_export_needed(std::string&& loc) - : wallet_runtime_error(std::move(loc), "This signature was made with stale data: export fresh multisig data, which other participants must then use") + explicit not_supported(std::string&& loc) + : wallet_internal_error(std::move(loc), "wallet operation not supported") { } }; //---------------------------------------------------------------------------------------------------- - struct multisig_import_needed : public wallet_runtime_error + struct command_not_supported : public wallet_internal_error { - explicit multisig_import_needed(std::string&& loc) - : wallet_runtime_error(std::move(loc), "Not enough multisig data was found to sign: import multisig data from more other participants") + explicit command_not_supported(std::string&& loc) + : wallet_internal_error(std::move(loc), "wallet operation not supported") { + } }; //---------------------------------------------------------------------------------------------------- @@ -412,10 +413,10 @@ namespace tools //---------------------------------------------------------------------------------------------------- typedef failed_rpc_request get_random_outs_error; //---------------------------------------------------------------------------------------------------- - struct not_enough_unlocked_money : public transfer_error + struct not_enough_unlocked_cash : public transfer_error { - explicit not_enough_unlocked_money(std::string&& loc, uint64_t available, uint64_t tx_amount, uint64_t fee) - : transfer_error(std::move(loc), "not enough unlocked money") + explicit not_enough_unlocked_cash(std::string&& loc, uint64_t available, uint64_t tx_amount, uint64_t fee) + : transfer_error(std::move(loc), "not enough unlocked cash") , m_available(available) , m_tx_amount(tx_amount) { @@ -464,10 +465,36 @@ namespace tools uint64_t m_tx_token_amount; }; //---------------------------------------------------------------------------------------------------- - struct not_enough_money : public transfer_error + struct not_enough_unlocked_staked_tokens : public transfer_error + { + explicit not_enough_unlocked_staked_tokens(std::string&& loc, uint64_t token_available, uint64_t tx_token_amount) + : transfer_error(std::move(loc), "not enough unlocked staked tokens") + , m_staked_token_available(token_available) + , m_tx_token_amount(tx_token_amount) + { + } + + uint64_t token_available() const { return m_staked_token_available; } + uint64_t tx_token_amount() const { return m_tx_token_amount; } + + std::string to_string() const + { + std::ostringstream ss; + ss << transfer_error::to_string() << + ", unlocked staked token available = " << cryptonote::print_money(m_staked_token_available) << + ", tx token amount = " << cryptonote::print_money(m_tx_token_amount); + return ss.str(); + } + + private: + uint64_t m_staked_token_available; + uint64_t m_tx_token_amount; + }; + //---------------------------------------------------------------------------------------------------- + struct not_enough_cash : public transfer_error { - explicit not_enough_money(std::string&& loc, uint64_t available, uint64_t tx_amount, uint64_t fee) - : transfer_error(std::move(loc), "not enough money") + explicit not_enough_cash(std::string&& loc, uint64_t available, uint64_t tx_amount, uint64_t fee) + : transfer_error(std::move(loc), "not enough cash") , m_available(available) , m_tx_amount(tx_amount) { @@ -516,6 +543,32 @@ namespace tools uint64_t m_tx_token_amount; }; //---------------------------------------------------------------------------------------------------- + struct not_enough_staked_tokens : public transfer_error + { + explicit not_enough_staked_tokens(std::string&& loc, uint64_t token_available, uint64_t tx_token_amount) + : transfer_error(std::move(loc), "not enough staked tokens") + , m_staked_token_available(token_available) + , m_tx_token_amount(tx_token_amount) + { + } + + uint64_t staked_token_available() const { return m_staked_token_available; } + uint64_t tx_token_amount() const { return m_tx_token_amount; } + + std::string to_string() const + { + std::ostringstream ss; + ss << transfer_error::to_string() << + ", staked token available = " << cryptonote::print_money(m_staked_token_available) << + ", tx token amount = " << cryptonote::print_money(m_tx_token_amount); + return ss.str(); + } + + private: + uint64_t m_staked_token_available; + uint64_t m_tx_token_amount; + }; + //---------------------------------------------------------------------------------------------------- struct not_whole_token_amount : public transfer_error { explicit not_whole_token_amount(std::string&& loc, uint64_t tx_token_amount) @@ -778,6 +831,14 @@ namespace tools } }; //---------------------------------------------------------------------------------------------------- + struct no_matching_available_outputs : public transfer_error + { + explicit no_matching_available_outputs(std::string&& loc) + : transfer_error(std::move(loc), "there are no matching available outputs") + { + } + }; + //---------------------------------------------------------------------------------------------------- struct wallet_rpc_error : public wallet_logic_error { const std::string& request() const { return m_request; } @@ -876,7 +937,63 @@ namespace tools { } }; + //---------------------------------------------------------------------------------------------------- + struct insufficient_token_lock_amount : public transfer_error + { + explicit insufficient_token_lock_amount(std::string&& loc) + : transfer_error(std::move(loc), "minumum token amount to lock is"+std::to_string(safex::get_minimum_token_stake_amount()/SAFEX_TOKEN)) + { + } + }; + //---------------------------------------------------------------------------------------------------- + struct create_account_fee_error : public transfer_error + { + explicit create_account_fee_error(std::string&& loc) + : transfer_error(std::move(loc), "invalid token create account lock fee") + { + } + }; + //---------------------------------------------------------------------------------------------------- + struct safex_invalid_output_error : public transfer_error + { + explicit safex_invalid_output_error(std::string&& loc) + : transfer_error(std::move(loc), "invalid output type") + { + } + }; + //---------------------------------------------------------------------------------------------------- + struct safex_unsuported_command_error : public transfer_error + { + explicit safex_unsuported_command_error(std::string&& loc) + : transfer_error(std::move(loc), "unsupported safex command") + { + } + }; + //---------------------------------------------------------------------------------------------------- + struct safex_missing_outputs_error : public transfer_error + { + explicit safex_missing_outputs_error(std::string&& loc) + : transfer_error(std::move(loc), "missing advanced output") + { + } + }; + //---------------------------------------------------------------------------------------------------- + struct safex_unknown_account : public transfer_error + { + explicit safex_unknown_account(std::string&& loc) + : transfer_error(std::move(loc), "account does not exist or is still locked") + { + } + }; + //---------------------------------------------------------------------------------------------------- + struct safex_unknown_id : public transfer_error + { + explicit safex_unknown_id(std::string&& loc) + : transfer_error(std::move(loc), "ID does not exist or is still locked") + { + } + }; #if !defined(_MSC_VER) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index cc80e6ba9..e79ce9f27 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -43,7 +43,6 @@ using namespace epee; #include "cryptonote_config.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_basic/account.h" -#include "multisig/multisig.h" #include "wallet_rpc_server_commands_defs.h" #include "misc_language.h" #include "string_coding.h" @@ -86,9 +85,7 @@ const char* wallet_rpc_server::tr(const char* str) } //------------------------------------------------------------------------------------------------------------------------------ -wallet_rpc_server::wallet_rpc_server():m_wallet(NULL), rpc_login_file(), m_stop(false), m_trusted_daemon(false), m_vm(NULL) -{ -} +wallet_rpc_server::wallet_rpc_server():m_wallet(NULL), rpc_login_file(), m_stop(false), m_trusted_daemon(false), m_vm(NULL){} //------------------------------------------------------------------------------------------------------------------------------ wallet_rpc_server::~wallet_rpc_server() { @@ -345,11 +342,15 @@ bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE: res.unlocked_balance = m_wallet->unlocked_balance(req.account_index); res.token_balance = m_wallet->token_balance(req.account_index); res.unlocked_token_balance = m_wallet->unlocked_token_balance(req.account_index); - res.multisig_import_needed = m_wallet->multisig() && m_wallet->has_multisig_partial_key_images(); + res.staked_tokens = m_wallet->staked_token_balance(req.account_index); + res.unlocked_staked_tokens = m_wallet->unlocked_staked_token_balance(req.account_index); + res.multisig_import_needed = false; std::map balance_per_subaddress = m_wallet->balance_per_subaddress(req.account_index); std::map token_balance_per_subaddress = m_wallet->token_balance_per_subaddress(req.account_index); std::map unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(req.account_index); std::map unlocked_token_balance_per_subaddress = m_wallet->unlocked_token_balance_per_subaddress(req.account_index); + std::map staked_token_balance_per_subaddress = m_wallet->staked_token_balance_per_subaddress(req.account_index); + std::map unlocked_staked_token_balance_per_subaddress = m_wallet->unlocked_staked_token_balance_per_subaddress(req.account_index); std::vector transfers; m_wallet->get_transfers(transfers); for (const auto& i : balance_per_subaddress) @@ -362,6 +363,8 @@ bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE: info.unlocked_balance = unlocked_balance_per_subaddress[i.first]; info.token_balance = token_balance_per_subaddress[i.first]; info.unlocked_token_balance = unlocked_token_balance_per_subaddress[i.first]; + info.staked_tokens = staked_token_balance_per_subaddress[i.first]; + info.unlocked_staked_tokens = unlocked_staked_token_balance_per_subaddress[i.first]; info.label = m_wallet->get_subaddress_label(index); info.num_unspent_outputs = static_cast(std::count_if( transfers.begin(), transfers.end(), @@ -652,17 +655,19 @@ bool wallet_rpc_server::validate_transfer( if (is_token) { de.amount = 0; // check if the amount is whole - if (!tools::is_whole_coin_amount(destination.amount)) { + if (!tools::is_whole_token_amount(destination.amount)) { er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; er.message = std::string("WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE: token amount not whole number"); return true; } de.token_amount = destination.amount; de.token_transaction = true; + de.output_type = cryptonote::tx_out_type::out_token; } else { de.amount = destination.amount; de.token_amount = 0; de.token_transaction = false; + de.output_type = cryptonote::tx_out_type::out_cash; } dsts.push_back(de); @@ -727,7 +732,172 @@ bool wallet_rpc_server::validate_transfer( } return true; } -//------------------------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------------------------< +bool wallet_rpc_server::validate_transfer_advanced( + const std::list &destinations, + const std::string &payment_id, + std::vector &dsts, + std::vector &extra, + bool at_least_one_destination, + epee::json_rpc::error &er, + safex::command_t cmd_type) +{ + crypto::hash8 integrated_payment_id {crypto::null_hash8}; + std::string extra_nonce; + uint64_t safex_network_fee = 0; + for (const auto &destination : destinations) { + cryptonote::address_parse_info info {}; + cryptonote::tx_destination_entry de {}; + er.message = ""; + if(!get_account_address_from_str_or_url(info, m_wallet->nettype(), destination.address, + [&er](const std::string &url, const std::vector &addresses, bool dnssec_valid)->std::string { + if (!dnssec_valid) + { + er.message = std::string("Invalid DNSSEC for ") + url; + return {}; + } + if (addresses.empty()) + { + er.message = std::string("No Safex address found at ") + url; + return {}; + } + return addresses[0]; + })) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; + if (er.message.empty()) + er.message = std::string("WALLET_RPC_ERROR_CODE_WRONG_ADDRESS: ") + destination.address; + return false; + } + + de.addr = info.address; + de.is_subaddress = info.is_subaddress; + + if (cmd_type == safex::command_t::token_stake) + { + if (!tools::is_whole_token_amount(destination.amount)) + { + er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; + er.message = std::string("WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE: token amount not whole number"); + return true; + } + de.token_amount = destination.amount; + de.token_transaction = true; + de.output_type = cryptonote::tx_out_type::out_staked_token; + } + else if (cmd_type == safex::command_t::token_unstake) + { + if (!tools::is_whole_token_amount(destination.amount)) + { + er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; + er.message = std::string("WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE: token amount not whole number"); + return true; + } + de.token_amount = destination.amount; + de.script_output = false; + de.output_type = cryptonote::tx_out_type::out_token; + } + else if (cmd_type == safex::command_t::donate_network_fee) { + de.amount = destination.amount; + de.script_output = true; + de.output_type = cryptonote::tx_out_type::out_network_fee; + } + // Allow to collect outputs for regular SFX transaction. + else if(cmd_type == safex::command_t::simple_purchase) { + uint64_t network_fee = calculate_safex_network_fee(destination.amount, m_wallet->nettype(), safex::command_t::simple_purchase); + safex_network_fee += network_fee; + de.amount = destination.amount - network_fee; + } + + dsts.push_back(de); + + if (info.has_payment_id) + { + if (!payment_id.empty() || integrated_payment_id != crypto::null_hash8) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; + er.message = "A single payment id is allowed per transaction"; + return false; + } + integrated_payment_id = info.payment_id; + cryptonote::set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, integrated_payment_id); + + /* Append Payment ID data into extra */ + if (!cryptonote::add_extra_nonce_to_tx_extra(extra, extra_nonce)) { + er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; + er.message = "Something went wrong with integrated payment_id."; + return false; + } + } + + + } + + // If its demo purchase, make special destination_entry for network fee. + if(cmd_type == safex::command_t::simple_purchase) { + cryptonote::tx_destination_entry de_net_fee = AUTO_VAL_INIT(de_net_fee); + std::string destination_addr = m_wallet->get_subaddress_as_str({0, 0}); + + cryptonote::address_parse_info info = AUTO_VAL_INIT(info); + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), destination_addr)) + { + er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; + er.message = "Wrong address parsing!!"; + return true; + } + + de_net_fee.addr = info.address; + de_net_fee.is_subaddress = info.is_subaddress; + de_net_fee.amount = safex_network_fee; + de_net_fee.script_output = true; + de_net_fee.output_type = cryptonote::tx_out_type::out_network_fee; + + dsts.push_back(de_net_fee); + } + + if (at_least_one_destination && dsts.empty()) + { + er.code = WALLET_RPC_ERROR_CODE_ZERO_DESTINATION; + er.message = "No destinations for this transfer"; + return false; + } + + if (!payment_id.empty()) + { + + /* Just to clarify */ + const std::string& payment_id_str = payment_id; + + crypto::hash long_payment_id {}; + crypto::hash8 short_payment_id {}; + + /* Parse payment ID */ + if (wallet::parse_long_payment_id(payment_id_str, long_payment_id)) { + cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, long_payment_id); + } + /* or short payment ID */ + else if (wallet::parse_short_payment_id(payment_id_str, short_payment_id)) { + cryptonote::set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, short_payment_id); + } + else { + er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; + er.message = "Payment id has invalid format: \"" + payment_id_str + "\", expected 16 or 64 character string"; + return false; + } + + /* Append Payment ID data into extra */ + if (!cryptonote::add_extra_nonce_to_tx_extra(extra, extra_nonce)) { + er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; + er.message = "Something went wrong with payment_id. Please check its format: \"" + payment_id_str + "\", expected 64-character string"; + return false; + } + + } + return true; +} +//------------------------------------------------------------------------------------------------------------------------------< + + static std::string ptx_to_string(const tools::wallet::pending_tx &ptx) { std::ostringstream oss; @@ -793,35 +963,23 @@ bool wallet_rpc_server::fill_response(std::vector &pt fill(fee, ptx.fee); } - if (m_wallet->multisig()) + if (!do_not_relay) + m_wallet->commit_tx(ptx_vector); + + // populate response with tx hashes + for (auto & ptx : ptx_vector) { - multisig_txset = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(ptx_vector)); - if (multisig_txset.empty()) + bool r = fill(tx_hash, epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); + r = r && (!get_tx_hex || fill(tx_blob, epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx)))); + r = r && (!get_tx_metadata || fill(tx_metadata, ptx_to_string(ptx))); + if (!r) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save multisig tx set after creation"; + er.message = "Failed to save tx info"; return false; } } - else - { - if (!do_not_relay) - m_wallet->commit_tx(ptx_vector); - // populate response with tx hashes - for (auto & ptx : ptx_vector) - { - bool r = fill(tx_hash, epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); - r = r && (!get_tx_hex || fill(tx_blob, epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx)))); - r = r && (!get_tx_metadata || fill(tx_metadata, ptx_to_string(ptx))); - if (!r) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Failed to save tx info"; - return false; - } - } - } return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -2656,14 +2814,14 @@ void wallet_rpc_server::handle_rpc_exception(const std::exception_ptr& e, epee:: er.code = WALLET_RPC_ERROR_CODE_ZERO_DESTINATION; er.message = e.what(); } - catch (const tools::error::not_enough_money& e) + catch (const tools::error::not_enough_cash& e) { - er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY; + er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_CASH; er.message = e.what(); } - catch (const tools::error::not_enough_unlocked_money& e) + catch (const tools::error::not_enough_unlocked_cash& e) { - er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_UNLOCKED_MONEY; + er.code = WALLET_RPC_ERROR_CODE_NOT_ENOUGH_UNLOCKED_CASH; er.message = e.what(); } catch (const tools::error::tx_not_possible& e) @@ -2720,555 +2878,437 @@ bool wallet_rpc_server::on_is_multisig(const wallet_rpc::COMMAND_RPC_IS_MULTISIG return true; } //------------------------------------------------------------------------------------------------------------------------------ -bool wallet_rpc_server::on_prepare_multisig(const wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG::response& res, epee::json_rpc::error& er) +bool wallet_rpc_server::on_migrate_view_only( + const tools::wallet_rpc::COMMAND_RPC_MIGRATE_VIEW_ONLY::request &req, + tools::wallet_rpc::COMMAND_RPC_MIGRATE_VIEW_ONLY::response &res, + epee::json_rpc::error &er) { if (!m_wallet) return not_open(er); - if (m_wallet->restricted()) - { + + if (!m_wallet->watch_only()) { er.code = WALLET_RPC_ERROR_CODE_DENIED; - er.message = "Command unavailable in restricted mode."; - return false; - } - if (m_wallet->multisig()) - { - er.code = WALLET_RPC_ERROR_CODE_ALREADY_MULTISIG; - er.message = "This wallet is already multisig"; - return false; - } - if (m_wallet->watch_only()) - { - er.code = WALLET_RPC_ERROR_CODE_WATCH_ONLY; - er.message = "wallet is watch-only and cannot be made multisig"; + er.message = "Command unavailable in regular mode. Only view mode."; return false; } - res.multisig_info = m_wallet->get_multisig_info(); - return true; -} -//------------------------------------------------------------------------------------------------------------------------------ -bool wallet_rpc_server::on_make_multisig(const wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::response& res, epee::json_rpc::error& er) -{ - if (!m_wallet) return not_open(er); - if (m_wallet->restricted()) - { + if (m_wallet->restricted()) { er.code = WALLET_RPC_ERROR_CODE_DENIED; er.message = "Command unavailable in restricted mode."; return false; } - if (m_wallet->multisig()) - { - er.code = WALLET_RPC_ERROR_CODE_ALREADY_MULTISIG; - er.message = "This wallet is already multisig"; + + cryptonote::address_parse_info info = AUTO_VAL_INIT(info); + cryptonote::tx_destination_entry token_destination = AUTO_VAL_INIT(token_destination); + if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), req.address)) { + er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; + er.message = "Invalid address: " + req.address; return false; } - if (m_wallet->watch_only()) - { - er.code = WALLET_RPC_ERROR_CODE_WATCH_ONLY; - er.message = "wallet is watch-only and cannot be made multisig"; + token_destination.addr = info.address; + token_destination.is_subaddress = info.is_subaddress; + token_destination.token_transaction = true; + token_destination.token_amount = req.amount * SAFEX_CASH_COIN; + token_destination.output_type = cryptonote::tx_out_type::out_token; + + //parse bitcoin transaction hash + cryptonote::blobdata expected_bitcoin_hash_data; + if (!epee::string_tools::parse_hexstr_to_binbuff(req.bitcoin_hash, expected_bitcoin_hash_data) || + expected_bitcoin_hash_data.size() != sizeof(crypto::hash)) { + er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; + er.message = "Invalid address: " + req.address; return false; } + const crypto::hash bitcoin_burn_transaction = *reinterpret_cast(expected_bitcoin_hash_data.data()); - try - { - res.multisig_info = m_wallet->make_multisig(req.password, req.multisig_info, req.threshold); - res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype()); + //airdrop reward calculation + cryptonote::tx_destination_entry airdrop_destination = AUTO_VAL_INIT(airdrop_destination); + airdrop_destination.addr = info.address; + airdrop_destination.is_subaddress = info.is_subaddress; + airdrop_destination.token_transaction = false; + airdrop_destination.amount = cryptonote::get_airdrop_cash(token_destination.token_amount); + airdrop_destination.output_type = cryptonote::tx_out_type::out_cash; + + std::vector dsts; + dsts.push_back(token_destination); + dsts.push_back(airdrop_destination); + + + //for migration transaction, extra nonce is so far not used + std::vector extra; + + cryptonote::add_bitcoin_hash_to_extra(extra, bitcoin_burn_transaction); + + try { + // figure out what tx will be necessary + std::vector ptx_vector; + std::string err; + + ptx_vector = m_wallet->create_transactions_migration( + dsts, bitcoin_burn_transaction, 0 /* unlock_time */, 0 /* priority, 0 == default */, + extra, m_trusted_daemon, true); + + if (ptx_vector.empty()) { + er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; + er.message = "No outputs found, or daemon is not ready"; + return false; + } + + // ugly hack... used bitcoin_hash noy saved in sources + for (auto &ptx : ptx_vector) { + cryptonote::add_bitcoin_hash_to_extra(ptx.construction_data.extra, bitcoin_burn_transaction); + } + + std::string path = req.filename; + bool is_saved = m_wallet->save_tx(ptx_vector, path); + + if (!is_saved) { + er.code = WALLET_RPC_ERROR_CODE_COULD_NOT_SAVE_FILE; + er.message = "Could not save to file"; + return false; + } else { + res.filename = req.filename; + } } - catch (const std::exception &e) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = e.what(); - return false; + catch (...) { + er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; } - return true; } -//------------------------------------------------------------------------------------------------------------------------------ -bool wallet_rpc_server::on_export_multisig(const wallet_rpc::COMMAND_RPC_EXPORT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_EXPORT_MULTISIG::response& res, epee::json_rpc::error& er) + +bool wallet_rpc_server::on_sign_migration( + const tools::wallet_rpc::COMMAND_RPC_SIGN_MIGRATION::request &req, + tools::wallet_rpc::COMMAND_RPC_SIGN_MIGRATION::response &res, + epee::json_rpc::error &er) { if (!m_wallet) return not_open(er); - if (m_wallet->restricted()) - { + + if (m_wallet->watch_only()) { er.code = WALLET_RPC_ERROR_CODE_DENIED; - er.message = "Command unavailable in restricted mode."; - return false; - } - bool ready; - if (!m_wallet->multisig(&ready)) - { - er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; - er.message = "This wallet is not multisig"; - return false; - } - if (!ready) - { - er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; - er.message = "This wallet is multisig, but not yet finalized"; + er.message = "Command unavailable in view only mode. Must be able to sign transactions."; return false; } - cryptonote::blobdata info; - try - { - info = m_wallet->export_multisig(); - } - catch (const std::exception &e) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = e.what(); + if (m_wallet->restricted()) { + er.code = WALLET_RPC_ERROR_CODE_DENIED; + er.message = "Command unavailable in restricted mode."; return false; } - res.info = epee::string_tools::buff_to_hex_nodelimer(info); - - return true; -} -//------------------------------------------------------------------------------------------------------------------------------ -bool wallet_rpc_server::on_import_multisig(const wallet_rpc::COMMAND_RPC_IMPORT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_IMPORT_MULTISIG::response& res, epee::json_rpc::error& er) -{ - if (!m_wallet) return not_open(er); - if (m_wallet->restricted()) - { + if (m_wallet->key_on_device()) { er.code = WALLET_RPC_ERROR_CODE_DENIED; er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) - { - er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; - er.message = "This wallet is not multisig"; - return false; - } - if (!ready) - { - er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; - er.message = "This wallet is multisig, but not yet finalized"; + if (m_wallet->multisig()) { + er.code = WALLET_RPC_ERROR_CODE_DENIED; + er.message = "This is a multisig wallet, it can only sign with sign_multisig"; return false; } - if (req.info.size() < threshold - 1) - { - er.code = WALLET_RPC_ERROR_CODE_THRESHOLD_NOT_REACHED; - er.message = "Needs multisig export info from more participants"; - return false; - } + std::vector ptx; + try { + bool success = m_wallet->sign_tx( + req.unsigned_filename, req.signed_filename, + ptx, [&](const tools::wallet::unsigned_tx_set &tx) { + return true; + }, false); - std::vector info; - info.resize(req.info.size()); - for (size_t n = 0; n < info.size(); ++n) - { - if (!epee::string_tools::parse_hexstr_to_binbuff(req.info[n], info[n])) - { - er.code = WALLET_RPC_ERROR_CODE_BAD_HEX; - er.message = "Failed to parse hex."; + if (!success) { + er.code = WALLET_RPC_ERROR_CODE_COULD_NOT_SAVE_FILE; + er.message = "Failed to sign transaction"; return false; } } - - try - { - res.n_outputs = m_wallet->import_multisig(info); - } - catch (const std::exception &e) - { + catch (const std::exception &e) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Error calling import_multisig"; + er.message = std::string("Failed to sign transaction: ") + e.what(); return false; } - - if (m_trusted_daemon) - { - try - { - m_wallet->rescan_spent(); - } - catch (const std::exception &e) - { - er.message = std::string("Success, but failed to update spent status after import multisig info: ") + e.what(); - } - } - else - { - er.message = "Success, but cannot update spent status after import multisig info as daemon is untrusted"; - } - + res.signed_filename = req.signed_filename; return true; } -//------------------------------------------------------------------------------------------------------------------------------ -bool wallet_rpc_server::on_finalize_multisig(const wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::response& res, epee::json_rpc::error& er) -{ - if (!m_wallet) return not_open(er); - if (m_wallet->restricted()) - { - er.code = WALLET_RPC_ERROR_CODE_DENIED; - er.message = "Command unavailable in restricted mode."; - return false; - } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) - { - er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; - er.message = "This wallet is not multisig"; - return false; - } - if (ready) - { - er.code = WALLET_RPC_ERROR_CODE_ALREADY_MULTISIG; - er.message = "This wallet is multisig, and already finalized"; - return false; - } - if (req.multisig_info.size() < threshold - 1) +bool wallet_rpc_server::on_submit_migration( + const tools::wallet_rpc::COMMAND_RPC_SUBMIT_MIGRATION::request &req, + tools::wallet_rpc::COMMAND_RPC_SUBMIT_MIGRATION::response &res, + epee::json_rpc::error &er) +{ + if (m_wallet->key_on_device()) { - er.code = WALLET_RPC_ERROR_CODE_THRESHOLD_NOT_REACHED; - er.message = "Needs multisig info from more participants"; + er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; + er.message = "Command not supported by HW wallet"; return false; } try { - if (!m_wallet->finalize_multisig(req.password, req.multisig_info)) + std::vector pending_transactions; + bool is_loading_successful = m_wallet->load_tx(req.signed_filename, pending_transactions, + [&](const tools::wallet::signed_tx_set &tx) { + return true; + }); + if (!is_loading_successful) { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Error calling finalize_multisig"; + er.code = WALLET_RPC_ERROR_CODE_COULD_NOT_LOAD_SIGNED_TX; + er.message = "Could not load signed transaction"; return false; } + + m_wallet->commit_tx(pending_transactions); + res.signed_filename = req.signed_filename; } - catch (const std::exception &e) + catch (const std::exception& e) { er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = std::string("Error calling finalize_multisig: ") + e.what(); + er.message = std::string("Could not submit transaction: ") + e.what(); return false; } - res.address = m_wallet->get_account().get_public_address_str(m_wallet->nettype()); return true; } -//------------------------------------------------------------------------------------------------------------------------------ -bool wallet_rpc_server::on_sign_multisig(const wallet_rpc::COMMAND_RPC_SIGN_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_SIGN_MULTISIG::response& res, epee::json_rpc::error& er) +bool wallet_rpc_server::on_stake_token(const wallet_rpc::COMMAND_RPC_STAKE_TOKEN::request& req, wallet_rpc::COMMAND_RPC_STAKE_TOKEN::response& res, epee::json_rpc::error& er) { + std::vector dsts; + std::vector extra; + + LOG_PRINT_L3("on_transfer starts"); if (!m_wallet) return not_open(er); - if (m_wallet->restricted()) - { + if (m_wallet->restricted()) { er.code = WALLET_RPC_ERROR_CODE_DENIED; er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) - { - er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; - er.message = "This wallet is not multisig"; - return false; - } - if (!ready) - { - er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; - er.message = "This wallet is multisig, but not yet finalized"; - return false; - } - cryptonote::blobdata blob; - if (!epee::string_tools::parse_hexstr_to_binbuff(req.tx_data_hex, blob)) - { - er.code = WALLET_RPC_ERROR_CODE_BAD_HEX; - er.message = "Failed to parse hex."; + // validate the transfer requested and populate dsts & extra + if (!validate_transfer_advanced(req.destinations, req.payment_id, dsts, extra, true, er, safex::command_t::token_stake)) { return false; } - tools::wallet::multisig_tx_set txs; - bool r = m_wallet->load_multisig_tx(blob, txs, NULL); - if (!r) - { - er.code = WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA; - er.message = "Failed to parse multisig tx data."; - return false; - } + try { + uint64_t mixin; + if (req.ring_size != 0) { + mixin = m_wallet->adjust_mixin(req.ring_size - 1); + } else { + mixin = m_wallet->adjust_mixin(req.mixin); - std::vector txids; - try - { - bool r = m_wallet->sign_multisig_tx(txs, txids); - if (!r) - { - er.code = WALLET_RPC_ERROR_CODE_MULTISIG_SIGNATURE; - er.message = "Failed to sign multisig tx"; + } + + uint32_t priority = m_wallet->adjust_priority(req.priority); + std::vector ptx_vector = m_wallet->create_transactions_advanced(safex::command_t::token_stake, + dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon); + + if (ptx_vector.empty()) { + er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; + er.message = "No transaction created"; return false; } + + // reject proposed transactions if there are more than one. see on_transfer_split below. + if (ptx_vector.size() != 1) { + er.code = WALLET_RPC_ERROR_CODE_TX_TOO_LARGE; + er.message = "Transaction would be too large. try /transfer_split."; + return false; + } + + return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.token_amount, res.fee, res.multisig_txset, + req.do_not_relay, res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, + res.tx_metadata, er, true); } - catch (const std::exception &e) - { - er.code = WALLET_RPC_ERROR_CODE_MULTISIG_SIGNATURE; - er.message = std::string("Failed to sign multisig tx: ") + e.what(); + catch (const std::exception &e) { + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR); return false; } - - res.tx_data_hex = epee::string_tools::buff_to_hex_nodelimer(m_wallet->save_multisig_tx(txs)); - if (!txids.empty()) - { - for (const crypto::hash &txid: txids) - res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(txid)); - } - return true; } -//------------------------------------------------------------------------------------------------------------------------------ -bool wallet_rpc_server::on_submit_multisig(const wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG::response& res, epee::json_rpc::error& er) + +bool wallet_rpc_server::on_donate_safex_fee(const wallet_rpc::COMMAND_RPC_DONATE_SAFEX_FEE::request& req, wallet_rpc::COMMAND_RPC_DONATE_SAFEX_FEE::response& res, epee::json_rpc::error& er) { + std::vector dsts; + std::vector extra; + + LOG_PRINT_L3("on_transfer starts"); if (!m_wallet) return not_open(er); - if (m_wallet->restricted()) - { + if (m_wallet->restricted()) { er.code = WALLET_RPC_ERROR_CODE_DENIED; er.message = "Command unavailable in restricted mode."; return false; } - bool ready; - uint32_t threshold, total; - if (!m_wallet->multisig(&ready, &threshold, &total)) - { - er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; - er.message = "This wallet is not multisig"; - return false; - } - if (!ready) - { - er.code = WALLET_RPC_ERROR_CODE_NOT_MULTISIG; - er.message = "This wallet is multisig, but not yet finalized"; - return false; - } - cryptonote::blobdata blob; - if (!epee::string_tools::parse_hexstr_to_binbuff(req.tx_data_hex, blob)) - { - er.code = WALLET_RPC_ERROR_CODE_BAD_HEX; - er.message = "Failed to parse hex."; + // validate the transfer requested and populate dsts & extra + if (!validate_transfer_advanced(req.destinations, req.payment_id, dsts, extra, true, er, safex::command_t::donate_network_fee)) { return false; } - tools::wallet::multisig_tx_set txs; - bool r = m_wallet->load_multisig_tx(blob, txs, NULL); - if (!r) - { - er.code = WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA; - er.message = "Failed to parse multisig tx data."; - return false; - } + try { + uint64_t mixin; + if (req.ring_size != 0) { + mixin = m_wallet->adjust_mixin(req.ring_size - 1); + } else { + mixin = m_wallet->adjust_mixin(req.mixin); - if (txs.m_signers.size() < threshold) - { - er.code = WALLET_RPC_ERROR_CODE_THRESHOLD_NOT_REACHED; - er.message = "Not enough signers signed this transaction."; - return false; - } + } - try - { - for (auto &ptx: txs.m_ptx) - { - m_wallet->commit_tx(ptx); - res.tx_hash_list.push_back(epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(ptx.tx))); + uint32_t priority = m_wallet->adjust_priority(req.priority); + std::vector ptx_vector = m_wallet->create_transactions_advanced(safex::command_t::donate_network_fee, + dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon); + + if (ptx_vector.empty()) { + er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; + er.message = "No transaction created"; + return false; } + + // reject proposed transactions if there are more than one. see on_transfer_split below. + if (ptx_vector.size() != 1) { + er.code = WALLET_RPC_ERROR_CODE_TX_TOO_LARGE; + er.message = "Transaction would be too large. try /transfer_split."; + return false; + } + + return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.token_amount, res.fee, res.multisig_txset, + req.do_not_relay, res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, + res.tx_metadata, er, true); } - catch (const std::exception &e) - { - er.code = WALLET_RPC_ERROR_CODE_MULTISIG_SUBMISSION; - er.message = std::string("Failed to submit multisig tx: ") + e.what(); + catch (const std::exception &e) { + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR); return false; } - return true; } -//------------------------------------------------------------------------------------------------------------------------------ -bool wallet_rpc_server::on_migrate_view_only( - const tools::wallet_rpc::COMMAND_RPC_MIGRATE_VIEW_ONLY::request &req, - tools::wallet_rpc::COMMAND_RPC_MIGRATE_VIEW_ONLY::response &res, - epee::json_rpc::error &er) -{ - if (!m_wallet) return not_open(er); - if (!m_wallet->watch_only()) { - er.code = WALLET_RPC_ERROR_CODE_DENIED; - er.message = "Command unavailable in regular mode. Only view mode."; - return false; - } +bool wallet_rpc_server::on_unstake_token(const wallet_rpc::COMMAND_RPC_UNSTAKE_TOKEN::request& req, wallet_rpc::COMMAND_RPC_UNSTAKE_TOKEN::response& res, epee::json_rpc::error& er) +{ + std::vector dsts; + std::vector extra; + LOG_PRINT_L3("on_transfer starts"); + if (!m_wallet) return not_open(er); if (m_wallet->restricted()) { er.code = WALLET_RPC_ERROR_CODE_DENIED; er.message = "Command unavailable in restricted mode."; return false; } - cryptonote::address_parse_info info = AUTO_VAL_INIT(info); - cryptonote::tx_destination_entry token_destination = AUTO_VAL_INIT(token_destination); - if (!cryptonote::get_account_address_from_str(info, m_wallet->nettype(), req.address)) { - er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; - er.message = "Invalid address: " + req.address; - return false; - } - token_destination.addr = info.address; - token_destination.is_subaddress = info.is_subaddress; - token_destination.token_transaction = true; - token_destination.token_amount = req.amount * SAFEX_CASH_COIN; - - //parse bitcoin transaction hash - cryptonote::blobdata expected_bitcoin_hash_data; - if (!epee::string_tools::parse_hexstr_to_binbuff(req.bitcoin_hash, expected_bitcoin_hash_data) || - expected_bitcoin_hash_data.size() != sizeof(crypto::hash)) { - er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; - er.message = "Invalid address: " + req.address; + // validate the transfer requested and populate dsts & extra + if (!validate_transfer_advanced(req.destinations, req.payment_id, dsts, extra, true, er, safex::command_t::token_unstake)) { return false; } - const crypto::hash bitcoin_burn_transaction = *reinterpret_cast(expected_bitcoin_hash_data.data()); - - //airdrop reward calculation - cryptonote::tx_destination_entry airdrop_destination = AUTO_VAL_INIT(airdrop_destination); - airdrop_destination.addr = info.address; - airdrop_destination.is_subaddress = info.is_subaddress; - airdrop_destination.token_transaction = false; - airdrop_destination.amount = cryptonote::get_airdrop_cash(token_destination.token_amount); - - std::vector dsts; - dsts.push_back(token_destination); - dsts.push_back(airdrop_destination); - - - //for migration transaction, extra nonce is so far not used - std::vector extra; - - cryptonote::add_bitcoin_hash_to_extra(extra, bitcoin_burn_transaction); try { - // figure out what tx will be necessary - std::vector ptx_vector; - std::string err; + uint64_t mixin; + if (req.ring_size != 0) { + mixin = m_wallet->adjust_mixin(req.ring_size - 1); + } else { + mixin = m_wallet->adjust_mixin(req.mixin); - ptx_vector = m_wallet->create_transactions_migration( - dsts, bitcoin_burn_transaction, 0 /* unlock_time */, 0 /* priority, 0 == default */, - extra, m_trusted_daemon, true); + } + + uint32_t priority = m_wallet->adjust_priority(req.priority); + std::vector ptx_vector = m_wallet->create_transactions_advanced(safex::command_t::token_unstake, + dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon); if (ptx_vector.empty()) { er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; - er.message = "No outputs found, or daemon is not ready"; + er.message = "No transaction created"; return false; } - // ugly hack... used bitcoin_hash noy saved in sources - for (auto &ptx : ptx_vector) { - cryptonote::add_bitcoin_hash_to_extra(ptx.construction_data.extra, bitcoin_burn_transaction); - } - - std::string path = req.filename; - bool is_saved = m_wallet->save_tx(ptx_vector, path); - - if (!is_saved) { - er.code = WALLET_RPC_ERROR_CODE_COULD_NOT_SAVE_FILE; - er.message = "Could not save to file"; + // reject proposed transactions if there are more than one. see on_transfer_split below. + if (ptx_vector.size() != 1) { + er.code = WALLET_RPC_ERROR_CODE_TX_TOO_LARGE; + er.message = "Transaction would be too large. try /transfer_split."; return false; - } else { - res.filename = req.filename; } + + return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.token_amount, res.fee, res.multisig_txset, + req.do_not_relay, res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, + res.tx_metadata, er, true); } - catch (...) { - er.code = WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR; + catch (const std::exception &e) { + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR); + return false; } return true; } -bool wallet_rpc_server::on_sign_migration( - const tools::wallet_rpc::COMMAND_RPC_SIGN_MIGRATION::request &req, - tools::wallet_rpc::COMMAND_RPC_SIGN_MIGRATION::response &res, - epee::json_rpc::error &er) +bool wallet_rpc_server::on_make_demo_purchase(const wallet_rpc::COMMAND_RPC_DEMO_PURCHASE::request& req, wallet_rpc::COMMAND_RPC_DEMO_PURCHASE::response& res, epee::json_rpc::error& er) { - if (!m_wallet) return not_open(er); - - if (m_wallet->watch_only()) { - er.code = WALLET_RPC_ERROR_CODE_DENIED; - er.message = "Command unavailable in view only mode. Must be able to sign transactions."; - return false; - } + std::vector dsts; + std::vector extra; + LOG_PRINT_L3("on_transfer starts"); + if (!m_wallet) return not_open(er); if (m_wallet->restricted()) { er.code = WALLET_RPC_ERROR_CODE_DENIED; er.message = "Command unavailable in restricted mode."; return false; } - if (m_wallet->key_on_device()) { - er.code = WALLET_RPC_ERROR_CODE_DENIED; - er.message = "Command unavailable in restricted mode."; + // validate the transfer requested and populate dsts & extra + if (!validate_transfer_advanced(req.destinations, req.payment_id, dsts, extra, true, er, safex::command_t::simple_purchase)) { return false; } - if (m_wallet->multisig()) { - er.code = WALLET_RPC_ERROR_CODE_DENIED; - er.message = "This is a multisig wallet, it can only sign with sign_multisig"; + + if(simple_trade_ids.find(req.offer_id) == simple_trade_ids.end()){ + er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; + er.message = "There is no offer with given offer id!!!"; return false; + } else { + res.purchased_offer_id = req.offer_id; } - std::vector ptx; try { - bool success = m_wallet->sign_tx( - req.unsigned_filename, req.signed_filename, - ptx, [&](const tools::wallet::unsigned_tx_set &tx) { - return true; - }, false); + uint64_t mixin; + if (req.ring_size != 0) { + mixin = m_wallet->adjust_mixin(req.ring_size - 1); + } else { + mixin = m_wallet->adjust_mixin(req.mixin); - if (!success) { - er.code = WALLET_RPC_ERROR_CODE_COULD_NOT_SAVE_FILE; - er.message = "Failed to sign transaction"; + } + + uint32_t priority = m_wallet->adjust_priority(req.priority); + std::vector ptx_vector = m_wallet->create_transactions_advanced(safex::command_t::simple_purchase, + dsts, mixin, req.unlock_time, priority, extra, req.account_index, req.subaddr_indices, m_trusted_daemon); + + if (ptx_vector.empty()) { + er.code = WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE; + er.message = "No transaction created"; return false; } + + // reject proposed transactions if there are more than one. see on_transfer_split below. + if (ptx_vector.size() != 1) { + er.code = WALLET_RPC_ERROR_CODE_TX_TOO_LARGE; + er.message = "Transaction would be too large. try /transfer_split."; + return false; + } + + return fill_response(ptx_vector, req.get_tx_key, res.tx_key, res.token_amount, res.fee, res.multisig_txset, + req.do_not_relay, res.tx_hash, req.get_tx_hex, res.tx_blob, req.get_tx_metadata, + res.tx_metadata, er, true); } catch (const std::exception &e) { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = std::string("Failed to sign transaction: ") + e.what(); + handle_rpc_exception(std::current_exception(), er, WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR); return false; } - res.signed_filename = req.signed_filename; return true; } -bool wallet_rpc_server::on_submit_migration( - const tools::wallet_rpc::COMMAND_RPC_SUBMIT_MIGRATION::request &req, - tools::wallet_rpc::COMMAND_RPC_SUBMIT_MIGRATION::response &res, - epee::json_rpc::error &er) +bool wallet_rpc_server::on_available_interest(const wallet_rpc::COMMAND_RPC_GET_AVAILABLE_INTEREST::request& req, + wallet_rpc::COMMAND_RPC_GET_AVAILABLE_INTEREST::response& res, + epee::json_rpc::error& er) { - if (m_wallet->key_on_device()) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = "Command not supported by HW wallet"; - return false; - } - - try - { - std::vector pending_transactions; - bool is_loading_successful = m_wallet->load_tx(req.signed_filename, pending_transactions, - [&](const tools::wallet::signed_tx_set &tx) { - return true; - }); - if (!is_loading_successful) - { - er.code = WALLET_RPC_ERROR_CODE_COULD_NOT_LOAD_SIGNED_TX; - er.message = "Could not load signed transaction"; - return false; - } + std::vector> interest_per_output; + res.available_interest = m_wallet->get_current_interest(interest_per_output); - m_wallet->commit_tx(pending_transactions); - res.signed_filename = req.signed_filename; - } - catch (const std::exception& e) - { - er.code = WALLET_RPC_ERROR_CODE_UNKNOWN_ERROR; - er.message = std::string("Could not submit transaction: ") + e.what(); - return false; + for(auto& pair : interest_per_output) { + res.interest_per_output.push_back({pair.first, pair.second}); } return true; } + } int main(int argc, char** argv) { @@ -3422,3 +3462,5 @@ int main(int argc, char** argv) { } return 0; } + + diff --git a/src/wallet/wallet_rpc_server.h b/src/wallet/wallet_rpc_server.h index fd76a0883..dc905c252 100644 --- a/src/wallet/wallet_rpc_server.h +++ b/src/wallet/wallet_rpc_server.h @@ -94,7 +94,7 @@ namespace tools MAP_JON_RPC_WE("sweep_single", on_sweep_single, wallet_rpc::COMMAND_RPC_SWEEP_SINGLE) MAP_JON_RPC_WE("relay_tx", on_relay_tx, wallet_rpc::COMMAND_RPC_RELAY_TX) MAP_JON_RPC_WE("store", on_store, wallet_rpc::COMMAND_RPC_STORE) - MAP_JON_RPC_WE("get_payments", on_get_payments, wallet_rpc::COMMAND_RPC_GET_PAYMENTS) + MAP_JON_RPC_WE("get_payments", on_get_payments, wallet_rpc::COMMAND_RPC_GET_PAYMENTS) MAP_JON_RPC_WE("get_bulk_payments", on_get_bulk_payments, wallet_rpc::COMMAND_RPC_GET_BULK_PAYMENTS) MAP_JON_RPC_WE("incoming_transfers", on_incoming_transfers, wallet_rpc::COMMAND_RPC_INCOMING_TRANSFERS) MAP_JON_RPC_WE("query_key", on_query_key, wallet_rpc::COMMAND_RPC_QUERY_KEY) @@ -131,22 +131,27 @@ namespace tools MAP_JON_RPC_WE("get_languages", on_get_languages, wallet_rpc::COMMAND_RPC_GET_LANGUAGES) MAP_JON_RPC_WE("create_wallet", on_create_wallet, wallet_rpc::COMMAND_RPC_CREATE_WALLET) MAP_JON_RPC_WE("open_wallet", on_open_wallet, wallet_rpc::COMMAND_RPC_OPEN_WALLET) - MAP_JON_RPC_WE("is_multisig", on_is_multisig, wallet_rpc::COMMAND_RPC_IS_MULTISIG) - MAP_JON_RPC_WE("prepare_multisig", on_prepare_multisig, wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG) - MAP_JON_RPC_WE("make_multisig", on_make_multisig, wallet_rpc::COMMAND_RPC_MAKE_MULTISIG) - MAP_JON_RPC_WE("export_multisig_info", on_export_multisig, wallet_rpc::COMMAND_RPC_EXPORT_MULTISIG) - MAP_JON_RPC_WE("import_multisig_info", on_import_multisig, wallet_rpc::COMMAND_RPC_IMPORT_MULTISIG) - MAP_JON_RPC_WE("finalize_multisig", on_finalize_multisig, wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG) - MAP_JON_RPC_WE("sign_multisig", on_sign_multisig, wallet_rpc::COMMAND_RPC_SIGN_MULTISIG) - MAP_JON_RPC_WE("submit_multisig", on_submit_multisig, wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG) MAP_JON_RPC_WE("migrate_view_only", on_migrate_view_only, wallet_rpc::COMMAND_RPC_MIGRATE_VIEW_ONLY) MAP_JON_RPC_WE("sign_migration", on_sign_migration, wallet_rpc::COMMAND_RPC_SIGN_MIGRATION) MAP_JON_RPC_WE("submit_migration", on_submit_migration, wallet_rpc::COMMAND_RPC_SUBMIT_MIGRATION) + MAP_JON_RPC_WE("is_multisig", on_is_multisig, wallet_rpc::COMMAND_RPC_IS_MULTISIG) + + MAP_JON_RPC_WE("get_available_interest", on_available_interest, wallet_rpc::COMMAND_RPC_GET_AVAILABLE_INTEREST) + MAP_JON_RPC_WE("stake_token", on_stake_token, wallet_rpc::COMMAND_RPC_STAKE_TOKEN) + MAP_JON_RPC_WE("unstake_token", on_unstake_token, wallet_rpc::COMMAND_RPC_UNSTAKE_TOKEN) + MAP_JON_RPC_WE("donate_safex_fee", on_donate_safex_fee, wallet_rpc::COMMAND_RPC_DONATE_SAFEX_FEE) + MAP_JON_RPC_WE("make_demo_purchase", on_make_demo_purchase, wallet_rpc::COMMAND_RPC_DEMO_PURCHASE) END_JSON_RPC_MAP() END_URI_MAP2() //json_rpc + bool on_available_interest(const wallet_rpc::COMMAND_RPC_GET_AVAILABLE_INTEREST::request& req, wallet_rpc::COMMAND_RPC_GET_AVAILABLE_INTEREST::response& res, epee::json_rpc::error& er); + bool on_stake_token(const wallet_rpc::COMMAND_RPC_STAKE_TOKEN::request& req, wallet_rpc::COMMAND_RPC_STAKE_TOKEN::response& res, epee::json_rpc::error& er); + bool on_unstake_token(const wallet_rpc::COMMAND_RPC_UNSTAKE_TOKEN::request& req, wallet_rpc::COMMAND_RPC_UNSTAKE_TOKEN::response& res, epee::json_rpc::error& er); + bool on_donate_safex_fee(const wallet_rpc::COMMAND_RPC_DONATE_SAFEX_FEE::request& req, wallet_rpc::COMMAND_RPC_DONATE_SAFEX_FEE::response& res, epee::json_rpc::error& er); + bool on_make_demo_purchase(const wallet_rpc::COMMAND_RPC_DEMO_PURCHASE::request& req, wallet_rpc::COMMAND_RPC_DEMO_PURCHASE::response& res, epee::json_rpc::error& er); + bool on_refresh(const wallet_rpc::COMMAND_RPC_REFRESH::request& req, wallet_rpc::COMMAND_RPC_REFRESH::response& res, epee::json_rpc::error& er); bool on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE::request& req, wallet_rpc::COMMAND_RPC_GET_BALANCE::response& res, epee::json_rpc::error& er); bool on_getaddress(const wallet_rpc::COMMAND_RPC_GET_ADDRESS::request& req, wallet_rpc::COMMAND_RPC_GET_ADDRESS::response& res, epee::json_rpc::error& er); @@ -161,6 +166,7 @@ namespace tools bool on_set_account_tag_description(const wallet_rpc::COMMAND_RPC_SET_ACCOUNT_TAG_DESCRIPTION::request& req, wallet_rpc::COMMAND_RPC_SET_ACCOUNT_TAG_DESCRIPTION::response& res, epee::json_rpc::error& er); bool on_getheight(const wallet_rpc::COMMAND_RPC_GET_HEIGHT::request& req, wallet_rpc::COMMAND_RPC_GET_HEIGHT::response& res, epee::json_rpc::error& er); bool validate_transfer(const std::list& destinations, const std::string& payment_id, std::vector& dsts, std::vector& extra, bool at_least_one_destination, epee::json_rpc::error& er, bool is_token); + bool validate_transfer_advanced(const std::list &destinations, const std::string &payment_id, std::vector &dsts, std::vector &extra, bool at_least_one_destination, epee::json_rpc::error &er, safex::command_t cmd_type); bool on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res, epee::json_rpc::error& er); bool on_transfer_token(const wallet_rpc::COMMAND_RPC_TRANSFER_TOKEN::request &req, wallet_rpc::COMMAND_RPC_TRANSFER_TOKEN::response &res, epee::json_rpc::error &er); bool on_transfer_split(const wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::request& req, wallet_rpc::COMMAND_RPC_TRANSFER_SPLIT::response& res, epee::json_rpc::error& er); @@ -207,13 +213,6 @@ namespace tools bool on_create_wallet(const wallet_rpc::COMMAND_RPC_CREATE_WALLET::request& req, wallet_rpc::COMMAND_RPC_CREATE_WALLET::response& res, epee::json_rpc::error& er); bool on_open_wallet(const wallet_rpc::COMMAND_RPC_OPEN_WALLET::request& req, wallet_rpc::COMMAND_RPC_OPEN_WALLET::response& res, epee::json_rpc::error& er); bool 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); - bool on_prepare_multisig(const wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_PREPARE_MULTISIG::response& res, epee::json_rpc::error& er); - bool on_make_multisig(const wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_MAKE_MULTISIG::response& res, epee::json_rpc::error& er); - bool on_export_multisig(const wallet_rpc::COMMAND_RPC_EXPORT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_EXPORT_MULTISIG::response& res, epee::json_rpc::error& er); - bool on_import_multisig(const wallet_rpc::COMMAND_RPC_IMPORT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_IMPORT_MULTISIG::response& res, epee::json_rpc::error& er); - bool on_finalize_multisig(const wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_FINALIZE_MULTISIG::response& res, epee::json_rpc::error& er); - bool on_sign_multisig(const wallet_rpc::COMMAND_RPC_SIGN_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_SIGN_MULTISIG::response& res, epee::json_rpc::error& er); - bool on_submit_multisig(const wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG::request& req, wallet_rpc::COMMAND_RPC_SUBMIT_MULTISIG::response& res, epee::json_rpc::error& er); // migration rpc bool on_migrate_view_only(const wallet_rpc::COMMAND_RPC_MIGRATE_VIEW_ONLY::request& req, wallet_rpc::COMMAND_RPC_MIGRATE_VIEW_ONLY::response& res, epee::json_rpc::error& er); @@ -241,5 +240,7 @@ namespace tools std::atomic m_stop; bool m_trusted_daemon; const boost::program_options::variables_map *m_vm; + + std::map simple_trade_ids; }; } diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index 71893fe15..cf3555317 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -66,6 +66,8 @@ namespace wallet_rpc uint64_t unlocked_balance; uint64_t token_balance; uint64_t unlocked_token_balance; + uint64_t staked_tokens; + uint64_t unlocked_staked_tokens; std::string label; uint64_t num_unspent_outputs; uint64_t num_unspent_token_outputs; @@ -77,6 +79,8 @@ namespace wallet_rpc KV_SERIALIZE(unlocked_balance) KV_SERIALIZE(token_balance) KV_SERIALIZE(unlocked_token_balance) + KV_SERIALIZE(staked_tokens) + KV_SERIALIZE(unlocked_staked_tokens) KV_SERIALIZE(label) KV_SERIALIZE(num_unspent_outputs) KV_SERIALIZE(num_unspent_token_outputs) @@ -89,6 +93,8 @@ namespace wallet_rpc uint64_t unlocked_balance; uint64_t token_balance; uint64_t unlocked_token_balance; + uint64_t staked_tokens; + uint64_t unlocked_staked_tokens; bool multisig_import_needed; std::vector per_subaddress; @@ -97,6 +103,8 @@ namespace wallet_rpc KV_SERIALIZE(unlocked_balance) KV_SERIALIZE(token_balance) KV_SERIALIZE(unlocked_token_balance) + KV_SERIALIZE(staked_tokens) + KV_SERIALIZE(unlocked_staked_tokens) KV_SERIALIZE(multisig_import_needed) KV_SERIALIZE(per_subaddress) END_KV_SERIALIZE_MAP() @@ -2248,5 +2256,269 @@ struct COMMAND_RPC_REFRESH typedef epee::misc_utils::struct_init response; }; +// @todo Work in progress. + +struct COMMAND_RPC_STAKE_TOKEN +{ + struct request + { + std::list destinations; + uint32_t account_index; + std::set subaddr_indices; + uint32_t priority; + uint64_t mixin; + uint64_t ring_size; + uint64_t unlock_time; + std::string payment_id; + bool get_tx_key; + bool do_not_relay; + bool get_tx_hex; + bool get_tx_metadata; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(destinations) + KV_SERIALIZE(account_index) + KV_SERIALIZE(subaddr_indices) + KV_SERIALIZE(priority) + KV_SERIALIZE_OPT(mixin, (uint64_t)0) + KV_SERIALIZE_OPT(ring_size, (uint64_t)0) + KV_SERIALIZE(unlock_time) + KV_SERIALIZE(payment_id) + KV_SERIALIZE(get_tx_key) + KV_SERIALIZE_OPT(do_not_relay, false) + KV_SERIALIZE_OPT(get_tx_hex, false) + KV_SERIALIZE_OPT(get_tx_metadata, false) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string tx_hash; + std::string tx_key; + std::list amount_keys; + uint64_t token_amount; + uint64_t fee; + std::string tx_blob; + std::string tx_metadata; + std::string multisig_txset; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_hash) + KV_SERIALIZE(tx_key) + KV_SERIALIZE(amount_keys) + KV_SERIALIZE(token_amount) + KV_SERIALIZE(fee) + KV_SERIALIZE(tx_blob) + KV_SERIALIZE(tx_metadata) + KV_SERIALIZE(multisig_txset) + END_KV_SERIALIZE_MAP() + }; +}; + +struct COMMAND_RPC_UNSTAKE_TOKEN +{ + struct request + { + std::list destinations; + uint32_t account_index; + std::set subaddr_indices; + uint32_t priority; + uint64_t mixin; + uint64_t ring_size; + uint64_t unlock_time; + std::string payment_id; + bool get_tx_key; + bool do_not_relay; + bool get_tx_hex; + bool get_tx_metadata; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(destinations) + KV_SERIALIZE(account_index) + KV_SERIALIZE(subaddr_indices) + KV_SERIALIZE(priority) + KV_SERIALIZE_OPT(mixin, (uint64_t)0) + KV_SERIALIZE_OPT(ring_size, (uint64_t)0) + KV_SERIALIZE(unlock_time) + KV_SERIALIZE(payment_id) + KV_SERIALIZE(get_tx_key) + KV_SERIALIZE_OPT(do_not_relay, false) + KV_SERIALIZE_OPT(get_tx_hex, false) + KV_SERIALIZE_OPT(get_tx_metadata, false) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string tx_hash; + std::string tx_key; + std::list amount_keys; + uint64_t token_amount; + uint64_t fee; + std::string tx_blob; + std::string tx_metadata; + std::string multisig_txset; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_hash) + KV_SERIALIZE(tx_key) + KV_SERIALIZE(amount_keys) + KV_SERIALIZE(token_amount) + KV_SERIALIZE(fee) + KV_SERIALIZE(tx_blob) + KV_SERIALIZE(tx_metadata) + KV_SERIALIZE(multisig_txset) + END_KV_SERIALIZE_MAP() + }; +}; + +struct COMMAND_RPC_DONATE_SAFEX_FEE +{ + struct request + { + std::list destinations; + uint32_t account_index; + std::set subaddr_indices; + uint32_t priority; + uint64_t mixin; + uint64_t ring_size; + uint64_t unlock_time; + std::string payment_id; + bool get_tx_key; + bool do_not_relay; + bool get_tx_hex; + bool get_tx_metadata; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(destinations) + KV_SERIALIZE(account_index) + KV_SERIALIZE(subaddr_indices) + KV_SERIALIZE(priority) + KV_SERIALIZE_OPT(mixin, (uint64_t)0) + KV_SERIALIZE_OPT(ring_size, (uint64_t)0) + KV_SERIALIZE(unlock_time) + KV_SERIALIZE(payment_id) + KV_SERIALIZE(get_tx_key) + KV_SERIALIZE_OPT(do_not_relay, false) + KV_SERIALIZE_OPT(get_tx_hex, false) + KV_SERIALIZE_OPT(get_tx_metadata, false) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string tx_hash; + std::string tx_key; + std::list amount_keys; + uint64_t token_amount; + uint64_t fee; + std::string tx_blob; + std::string tx_metadata; + std::string multisig_txset; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_hash) + KV_SERIALIZE(tx_key) + KV_SERIALIZE(amount_keys) + KV_SERIALIZE(token_amount) + KV_SERIALIZE(fee) + KV_SERIALIZE(tx_blob) + KV_SERIALIZE(tx_metadata) + KV_SERIALIZE(multisig_txset) + END_KV_SERIALIZE_MAP() + }; +}; + +struct COMMAND_RPC_DEMO_PURCHASE +{ + struct request + { + std::list destinations; + uint32_t account_index; + std::string offer_id; + std::set subaddr_indices; + uint32_t priority; + uint64_t mixin; + uint64_t ring_size; + uint64_t unlock_time; + std::string payment_id; + bool get_tx_key; + bool do_not_relay; + bool get_tx_hex; + bool get_tx_metadata; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(destinations) + KV_SERIALIZE(account_index) + KV_SERIALIZE(offer_id) + KV_SERIALIZE(subaddr_indices) + KV_SERIALIZE(priority) + KV_SERIALIZE_OPT(mixin, (uint64_t)0) + KV_SERIALIZE_OPT(ring_size, (uint64_t)0) + KV_SERIALIZE(unlock_time) + KV_SERIALIZE(payment_id) + KV_SERIALIZE(get_tx_key) + KV_SERIALIZE_OPT(do_not_relay, false) + KV_SERIALIZE_OPT(get_tx_hex, false) + KV_SERIALIZE_OPT(get_tx_metadata, false) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string tx_hash; + std::string tx_key; + std::string purchased_offer_id; + std::list amount_keys; + uint64_t token_amount; + uint64_t fee; + std::string tx_blob; + std::string tx_metadata; + std::string multisig_txset; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(tx_hash) + KV_SERIALIZE(tx_key) + KV_SERIALIZE(purchased_offer_id) + KV_SERIALIZE(amount_keys) + KV_SERIALIZE(token_amount) + KV_SERIALIZE(fee) + KV_SERIALIZE(tx_blob) + KV_SERIALIZE(tx_metadata) + KV_SERIALIZE(multisig_txset) + END_KV_SERIALIZE_MAP() + }; +}; + +struct COMMAND_RPC_GET_AVAILABLE_INTEREST +{ + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct per_output { + uint64_t amount; + uint64_t interest; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount) + KV_SERIALIZE(interest) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + uint64_t available_interest; + std::vector interest_per_output; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(available_interest) + KV_SERIALIZE(interest_per_output) + END_KV_SERIALIZE_MAP() + }; +}; + } } diff --git a/src/wallet/wallet_rpc_server_error_codes.h b/src/wallet/wallet_rpc_server_error_codes.h index a7e83758c..65ee09c3a 100644 --- a/src/wallet/wallet_rpc_server_error_codes.h +++ b/src/wallet/wallet_rpc_server_error_codes.h @@ -48,7 +48,7 @@ #define WALLET_RPC_ERROR_CODE_ACCOUNT_INDEX_OUT_OF_BOUNDS -14 #define WALLET_RPC_ERROR_CODE_ADDRESS_INDEX_OUT_OF_BOUNDS -15 #define WALLET_RPC_ERROR_CODE_TX_NOT_POSSIBLE -16 -#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_MONEY -17 +#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_CASH -17 #define WALLET_RPC_ERROR_CODE_TX_TOO_LARGE -18 #define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_OUTS_TO_MIX -19 #define WALLET_RPC_ERROR_CODE_ZERO_DESTINATION -20 @@ -68,7 +68,7 @@ #define WALLET_RPC_ERROR_CODE_BAD_MULTISIG_TX_DATA -34 #define WALLET_RPC_ERROR_CODE_MULTISIG_SIGNATURE -35 #define WALLET_RPC_ERROR_CODE_MULTISIG_SUBMISSION -36 -#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_UNLOCKED_MONEY -37 +#define WALLET_RPC_ERROR_CODE_NOT_ENOUGH_UNLOCKED_CASH -37 #define WALLET_RPC_ERROR_CODE_NO_DAEMON_CONNECTION -38 #define WALLET_RPC_ERROR_CODE_COULD_NOT_SAVE_FILE -51 #define WALLET_RPC_ERROR_CODE_COULD_NOT_LOAD_SIGNED_TX -52 diff --git a/src/wallet/wallet_safex.cpp b/src/wallet/wallet_safex.cpp new file mode 100644 index 000000000..a75fab8dc --- /dev/null +++ b/src/wallet/wallet_safex.cpp @@ -0,0 +1,718 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "include_base_utils.h" + +using namespace epee; + +#include "cryptonote_config.h" +#include "wallet.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "rpc/core_rpc_server_commands_defs.h" +#include "misc_language.h" +#include "cryptonote_basic/cryptonote_basic_impl.h" +#include "common/boost_serialization_helper.h" +#include "common/command_line.h" +#include "common/threadpool.h" +#include "profile_tools.h" +#include "crypto/crypto.h" +#include "serialization/binary_utils.h" +#include "serialization/string.h" +#include "cryptonote_basic/blobdatatype.h" +#include "mnemonics/electrum-words.h" +#include "common/i18n.h" +#include "common/util.h" +#include "common/apply_permutation.h" +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" +#include "common/json_util.h" +#include "memwipe.h" +#include "common/base58.h" +#include "common/dns_utils.h" +#include "ringdb.h" + +extern "C" +{ +#include "crypto/keccak.h" +#include "crypto/crypto-ops.h" +} +using namespace std; +using namespace crypto; +using namespace cryptonote; + +namespace tools +{ + + uint64_t wallet::staked_token_balance(uint32_t index_major) const + { + uint64_t staked_token_amount = 0; + // if(m_light_wallet) + // return m_light_wallet_unlocked_token_balance; + for (const auto &i : staked_token_balance_per_subaddress(index_major)) + staked_token_amount += i.second; + return staked_token_amount; + } + + std::map wallet::staked_token_balance_per_subaddress(uint32_t index_major) const + { + std::map staked_token_amount_per_subaddr; + for (const auto &td: m_transfers) + { + if (td.m_subaddr_index.major == index_major && !td.m_spent && td.m_output_type == tx_out_type::out_staked_token) + { + auto found = staked_token_amount_per_subaddr.find(td.m_subaddr_index.minor); + if (found == staked_token_amount_per_subaddr.end()) + staked_token_amount_per_subaddr[td.m_subaddr_index.minor] = td.get_out_type() == tx_out_type::out_staked_token ? td.token_amount() : 0; + else + found->second += td.get_out_type() == tx_out_type::out_staked_token ? td.token_amount() : 0; + } + } + + return staked_token_amount_per_subaddr; + } + + uint64_t wallet::unlocked_staked_token_balance(uint32_t index_major) const + { + uint64_t staked_token_amount = 0; + // if(m_light_wallet) + // return m_light_wallet_unlocked_token_balance; + for (const auto &i : unlocked_staked_token_balance_per_subaddress(index_major)) + staked_token_amount += i.second; + return staked_token_amount; + } + + std::map wallet::unlocked_staked_token_balance_per_subaddress(uint32_t index_major) const + { + std::map staked_token_amount_per_subaddr; + for (const transfer_details &td: m_transfers) + { + if (td.m_output_type == cryptonote::tx_out_type::out_staked_token && td.m_subaddr_index.major == index_major && !td.m_spent && is_transfer_unlocked(td)) + { + auto found = staked_token_amount_per_subaddr.find(td.m_subaddr_index.minor); + if (found == staked_token_amount_per_subaddr.end()) + staked_token_amount_per_subaddr[td.m_subaddr_index.minor] = td.m_output_type == tx_out_type::out_staked_token ? td.token_amount() : 0; + else + found->second += td.m_output_type == tx_out_type::out_staked_token ? td.token_amount() : 0; + } + } + return staked_token_amount_per_subaddr; + } + + + uint64_t wallet::staked_token_balance_all() const + { + uint64_t r = 0; + for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major) + r += staked_token_balance(index_major); + return r; + } + + uint64_t wallet::unlocked_staked_token_balance_all() const + { + uint64_t r = 0; + for (uint32_t index_major = 0; index_major < get_num_subaddress_accounts(); ++index_major) + r += unlocked_staked_token_balance(index_major); + return r; + } + +//------------------------------------------------------------------------------------------------------------------ + + std::vector wallet::create_lock_transaction( + std::vector dsts, + const size_t fake_outs_count, + const uint64_t unlock_time, + uint32_t priority, + const std::vector &extra, + uint32_t subaddr_account, + std::set subaddr_indices, + bool trusted_daemon) + { + return std::vector{}; + } + +//----------------------------------------------------------------------------------------------------------------- + uint64_t wallet::get_current_interest(std::vector> &interest_per_output) + { + uint64_t my_interest = 0; + for (auto &transfer : m_transfers) + { + if (transfer.m_output_type != tx_out_type::out_staked_token || transfer.m_spent) + { + continue; + } + uint64_t interest = get_interest_for_transfer(transfer); + my_interest += interest; + + if (interest > 0) + { + interest_per_output.push_back({transfer.token_amount(), interest}); + } + } + + return my_interest; + } + //----------------------------------------------------------------------------------------------------------------- + std::map wallet::get_interest_map(const uint64_t start_interval, const uint64_t end_interval) + { + //TODO: GRKI Remove static at one point please... + static std::map interest_map; + + cryptonote::COMMAND_RPC_GET_INTEREST_MAP::request req = AUTO_VAL_INIT(req); + cryptonote::COMMAND_RPC_GET_INTEREST_MAP::response res = AUTO_VAL_INIT(res); + + req.begin_interval = start_interval; + req.end_interval = end_interval; + + if (req.begin_interval > req.end_interval) + return interest_map; + + if (interest_map.find(req.begin_interval) == interest_map.end() || interest_map.find(req.end_interval) == interest_map.end()) + { + + m_daemon_rpc_mutex.lock(); + bool r = net_utils::invoke_http_json("/get_interest_map", req, res, m_http_client, rpc_timeout); + m_daemon_rpc_mutex.unlock(); + + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_interest_map"); + THROW_WALLET_EXCEPTION_IF(res.status != "OK", error::no_connection_to_daemon, "Failed to get interest map"); + + for (auto &item : res.interest_per_interval) + { + interest_map.insert({item.interval, item.cash_per_token}); + } + + } + return interest_map; + + } + +//----------------------------------------------------------------------------------------------------------------- + uint64_t wallet::get_interest_for_transfer(const transfer_details &td) + { + if (td.m_spent) + { + LOG_PRINT_L2("Trying to get interest for spent transfer"); + return 0; + } + + if (td.m_output_type != tx_out_type::out_staked_token) + { + LOG_PRINT_L2("Trying to get interest for wrong transfer type"); + return 0; + } + + auto begin_interval = safex::calculate_interval_for_height(td.m_block_height, this->nettype()) + 1; //earning interest starts from next interval + auto end_interval = safex::calculate_interval_for_height(this->get_blockchain_current_height(), this->nettype()) - 1; //finishes in previous interval + auto interest_map = get_interest_map(begin_interval, end_interval); + + + uint64_t interest = 0; + for (uint64_t i = begin_interval; i <= end_interval; ++i) + { + LOG_PRINT_L2("Interest map for i=" << i << " is " << interest_map[i]); + interest += interest_map[i] * (td.token_amount() / SAFEX_TOKEN); + } + + return interest; + } + +//----------------------------------------------------------------------------------------------------------------- + std::vector wallet::create_unlock_transaction( + std::vector dsts, + const size_t fake_outs_count, + const uint64_t unlock_time, + uint32_t priority, + const std::vector &extra, + uint32_t subaddr_account, + std::set subaddr_indices, + bool trusted_daemon) + { + return std::vector{}; + } + +//----------------------------------------------------------------------------------------------------------------- + std::vector wallet::create_donation_transaction( + std::vector dsts, + const size_t fake_outs_count, + const uint64_t unlock_time, + uint32_t priority, + const std::vector &extra, + uint32_t subaddr_account, + std::set subaddr_indices, + bool trusted_daemon) + { + return std::vector{}; + } + + //----------------------------------------------------------------------------------------------------------------- + bool wallet::generate_safex_account(const std::string &username, const std::vector &account_data) + { + auto sfx_account = find_if(m_safex_accounts.begin(),m_safex_accounts.end(),[&username](const safex::safex_account& it){ + return it.username == username; + }); + + if(sfx_account != m_safex_accounts.end()) + return false; + + safex::safex_account_key_handler new_safex_account_keys; + new_safex_account_keys.generate(); + + safex::safex_account new_safex_account; + + new_safex_account.username = username; + new_safex_account.pkey = new_safex_account_keys.get_keys().m_public_key; + new_safex_account.account_data = account_data; + + m_safex_accounts_keys.push_back(new_safex_account_keys.get_keys()); + m_safex_accounts.push_back(new_safex_account); + + return true; + + } + //----------------------------------------------------------------------------------------------------------------- + bool wallet::remove_safex_account(const std::string &username) + { + + safex::safex_account new_safex_account; + + for (uint32_t i=0;i accdata) + { + + for (uint32_t i = 0; i < m_safex_accounts.size(); i++) + { + if (m_safex_accounts[i].username == username) + { + m_safex_accounts[i].account_data = accdata; + m_safex_accounts[i].activated = true; + } + } + + return true; + } + //----------------------------------------------------------------------------------------------------------------- + bool wallet::recover_safex_account(const std::string &username, const crypto::secret_key &secret_key) + { + safex::safex_account recover_safex_account = AUTO_VAL_INIT(recover_safex_account); + + safex::safex_account_key_handler recover_safex_account_keys; + recover_safex_account_keys.create_from_keys(secret_key); + + + recover_safex_account.username = username; + recover_safex_account.pkey = recover_safex_account_keys.get_keys().m_public_key; + //data will be updated during block parsing + + + safex::safex_account_keys sfx_keys; + if(!get_safex_account_keys(username,sfx_keys)) + m_safex_accounts_keys.push_back(recover_safex_account_keys.get_keys()); + if(!get_safex_account(username,recover_safex_account)) + m_safex_accounts.push_back(recover_safex_account); + + return true; + } +//----------------------------------------------------------------------------------------------------------------- + bool wallet::get_safex_account(const std::string &username, safex::safex_account &my_account) { + for (const safex::safex_account& acc: m_safex_accounts) { + if (username == acc.username) + { + my_account = acc; + return true; + } + } + + return false; + } +//----------------------------------------------------------------------------------------------------------------- + + std::vector wallet::get_safex_accounts() + { + return std::vector(m_safex_accounts.begin(), m_safex_accounts.end()); + } + //----------------------------------------------------------------------------------------------------------------- + uint8_t wallet::get_safex_account_status(const safex::safex_account& sfx_account) const { + if(!sfx_account.activated) + return 0; + else if (!is_safex_account_unlocked(sfx_account.username)) + return 1; + else + return 2; + + } + + bool wallet::is_create_account_token_fee(const transfer_details& td) const + { + auto output_token_fee = td.get_public_key(); + + return is_create_safex_account_token_fee(td.m_tx.vout, output_token_fee); + } +//----------------------------------------------------------------------------------------------------------------- + + bool wallet::is_safex_account_unlocked(const std::string& username) const + { + for(const transfer_details& td: m_transfers) + { + if(td.m_output_type != cryptonote::tx_out_type::out_safex_account) { + continue; + } + + for(auto tx_output: td.m_tx.vout) + if(tx_output.target.type() == typeid(txout_to_script) && get_tx_out_type(tx_output.target) == cryptonote::tx_out_type::out_safex_account){ + const txout_to_script &out = boost::get(tx_output.target); + safex::create_account_data sfx_account; + const cryptonote::blobdata accblob(std::begin(out.data), std::end(out.data)); + cryptonote::parse_and_validate_from_blob(accblob, sfx_account); + std::string sfx_username{sfx_account.username.begin(),sfx_account.username.end()}; + //If username is not the one, we get out of the loop + if(sfx_username != username) + break; + //If it is, we found it and we just check the height of the bc + return td.m_block_height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE <= m_local_bc_height; + } + } + return false; + } + //----------------------------------------------------------------------------------------------------------------- + bool wallet::get_safex_account_keys(const std::string &username, safex::safex_account_keys &acckeys) + { + + for (uint32_t i = 0; i < m_safex_accounts.size(); i++) + { + if (m_safex_accounts[i].username == username) + { + auto pkey = m_safex_accounts[i].pkey; + auto safex_keys = find_if(m_safex_accounts_keys.begin(),m_safex_accounts_keys.end(),[&pkey](const safex::safex_account_keys& it){ + return it.get_public_key() == pkey; + }); + if(safex_keys == m_safex_accounts_keys.end()) + return false; + acckeys = *safex_keys; + return true; + } + } + + return false; + } + + bool wallet::add_safex_offer(const safex::safex_offer& offer){ + auto exists = std::find_if(m_safex_offers.begin(), m_safex_offers.end(), [offer] (const safex::safex_offer& sfx_offer) { + return sfx_offer.offer_id == offer.offer_id; + }); + if(exists == m_safex_offers.end()) + m_safex_offers.push_back(offer); + + return true; + } + + bool wallet::update_safex_offer(const safex::safex_offer& offer){ + + for (uint32_t i = 0; i < m_safex_offers.size(); i++) + { + if (m_safex_offers[i].offer_id == offer.offer_id) + { + m_safex_offers[i]=offer; + return true; + } + } + + return true; + } + + bool wallet::update_safex_offer(const safex::create_purchase_data& purchase){ + + for (auto & m_safex_offer : m_safex_offers) + { + if (m_safex_offer.offer_id == purchase.offer_id) + { + m_safex_offer.quantity -= purchase.quantity; + return true; + } + } + + return true; + } + + bool wallet::safex_account_exists(const std::string &username) { + + cryptonote::COMMAND_RPC_SAFEX_ACCOUNT_INFO::request req = AUTO_VAL_INIT(req); + cryptonote::COMMAND_RPC_SAFEX_ACCOUNT_INFO::response res = AUTO_VAL_INIT(res); + + req.username = username; + + std::string fail_msg; + + m_daemon_rpc_mutex.lock(); + bool r = net_utils::invoke_http_json("/get_safex_account_info", req, res, m_http_client, rpc_timeout); + m_daemon_rpc_mutex.unlock(); + + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_safex_account_info"); + THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK && res.status != CORE_RPC_STATUS_SAFEX_ACCOUNT_DOESNT_EXIST, error::no_connection_to_daemon, "Failed to get safex offers"); + + return res.status != CORE_RPC_STATUS_SAFEX_ACCOUNT_DOESNT_EXIST; + } + + std::vector wallet::get_safex_offers() + { + cryptonote::COMMAND_RPC_GET_SAFEX_OFFERS::request req = AUTO_VAL_INIT(req); + cryptonote::COMMAND_RPC_GET_SAFEX_OFFERS::response res = AUTO_VAL_INIT(res); + + std::vector offers; + + m_daemon_rpc_mutex.lock(); + bool r = net_utils::invoke_http_json("/get_safex_offers", req, res, m_http_client, rpc_timeout); + m_daemon_rpc_mutex.unlock(); + + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_safex_offers"); + THROW_WALLET_EXCEPTION_IF(res.status != "OK", error::no_connection_to_daemon, "Failed to get safex offers"); + + for (auto &item : res.offers) { + if(item.height + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE > m_local_bc_height) + continue; + crypto::hash offer_hash{}; + epee::string_tools::hex_to_pod(item.offer_id, offer_hash); + crypto::hash price_peg_hash{}; + epee::string_tools::hex_to_pod(item.price_peg_id, price_peg_hash); + offers.emplace_back(item.title, item.quantity, item.price, item.description, offer_hash, item.seller, item.active,item.seller_address,item.price_peg_used,price_peg_hash,item.min_sfx_price); + } + + return offers; + } + + std::vector wallet::get_safex_price_pegs(const std::string ¤cy) + { + cryptonote::COMMAND_RPC_GET_SAFEX_PRICE_PEGS::request req = AUTO_VAL_INIT(req); + cryptonote::COMMAND_RPC_GET_SAFEX_PRICE_PEGS::response res = AUTO_VAL_INIT(res); + + std::vector price_pegs; + + req.currency = currency; + + m_daemon_rpc_mutex.lock(); + bool r = net_utils::invoke_http_json("/get_safex_price_pegs", req, res, m_http_client, rpc_timeout); + m_daemon_rpc_mutex.unlock(); + + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_safex_price_pegs"); + THROW_WALLET_EXCEPTION_IF(res.status != "OK", error::no_connection_to_daemon, "Failed to get safex price pegs"); + + for (auto &item : res.price_pegs) { + crypto::hash hash{}; + epee::string_tools::hex_to_pod(item.price_peg_id, hash); + price_pegs.emplace_back(item.title,item.creator,item.currency,item.description,hash,item.rate); + } + + return price_pegs; + } + + std::vector wallet::get_safex_ratings(const crypto::hash& offer_id) + { + cryptonote::COMMAND_RPC_GET_SAFEX_RATINGS::request req = AUTO_VAL_INIT(req); + cryptonote::COMMAND_RPC_GET_SAFEX_RATINGS::response res = AUTO_VAL_INIT(res); + + std::vector feedbacks; + + req.offer_id = offer_id; + + m_daemon_rpc_mutex.lock(); + bool r = net_utils::invoke_http_json("/get_safex_ratings", req, res, m_http_client, rpc_timeout); + m_daemon_rpc_mutex.unlock(); + + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "get_safex_ratings"); + THROW_WALLET_EXCEPTION_IF(res.status != CORE_RPC_STATUS_OK, error::no_connection_to_daemon, "Failed to get safex ratings"); + + for (auto &item : res.ratings) { + feedbacks.emplace_back(item.star_rating,item.comment,res.offer_id); + } + + return feedbacks; + } + + bool wallet::calculate_sfx_price(const safex::safex_offer& sfx_offer, uint64_t& sfx_price){ + + sfx_price = sfx_offer.min_sfx_price; + + std::vector sfx_price_pegs = get_safex_price_pegs(); + + if(sfx_offer.price_peg_used){ + crypto::hash price_peg_id = sfx_offer.price_peg_id; + auto it = std::find_if(sfx_price_pegs.begin(), sfx_price_pegs.end(), [price_peg_id](const safex::safex_price_peg &sfx_price_peg) { return price_peg_id == sfx_price_peg.price_peg_id; }); + + if(it == sfx_price_pegs.end()) + return false; + + std::string rate_str = print_money(it->rate); + double rate = stod(rate_str); + + std::string price_str = print_money(sfx_offer.price); + double price = stod(price_str); + + uint64_t pegged_price = (price*rate)*SAFEX_CASH_COIN; + + if(pegged_price > sfx_price) + sfx_price = pegged_price; + } + + return true; + } + + bool wallet::add_safex_feedback_token(const safex::create_feedback_token_data& feedback_token){ + + m_safex_feedback_tokens.push_back(feedback_token.offer_id); + + return true; + } + + bool wallet::remove_safex_feedback_token(const crypto::hash& offer_id){ + + for(auto it = m_safex_feedback_tokens.begin(); it!=m_safex_feedback_tokens.end();it++) + if(*it==offer_id) { + m_safex_feedback_tokens.erase(it); + return true; + } + + return true; + } + + bool wallet::add_safex_price_peg(const safex::safex_price_peg& price_peg){ + + m_safex_price_pegs.push_back(price_peg); + + return true; + } + + bool wallet::update_safex_price_peg(const crypto::hash &price_peg_id, const uint64_t& rate) { + + for (uint32_t i = 0; i < m_safex_price_pegs.size(); i++) + { + if (m_safex_price_pegs[i].price_peg_id == price_peg_id) + { + m_safex_price_pegs[i].rate=rate; + return true; + } + } + + return true; + } + + std::vector wallet::get_my_safex_offers() + { + return m_safex_offers; + } + + std::vector wallet::get_my_safex_price_pegs() + { + return m_safex_price_pegs; + } + + std::vector wallet::get_my_safex_feedbacks_to_give() + { + return m_safex_feedback_tokens; + } + + safex::safex_offer wallet::get_my_safex_offer(crypto::hash& offer_id) + { + for(auto it: m_safex_offers) + if(it.offer_id == offer_id) + return it; + return safex::safex_offer{}; + } + + void wallet::process_advanced_output(const cryptonote::txout_to_script &txout, const cryptonote::tx_out_type& output_type){ + if (txout.output_type == static_cast(tx_out_type::out_safex_account)) { + safex::create_account_data account; + const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string accusername(begin(account.username), end(account.username)); + update_safex_account_data(accusername, account.account_data); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_account_update)) { + safex::edit_account_data account; + const cryptonote::blobdata accblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(accblob, account); + std::string accusername(begin(account.username), end(account.username)); + update_safex_account_data(accusername, account.account_data); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer)){ + safex::create_offer_data offer; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, offer); + safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price,offer.description,offer.offer_id, + std::string{offer.seller.begin(),offer.seller.end()},offer.active,offer.seller_address,offer.price_peg_used,offer.price_peg_id,offer.min_sfx_price}; + add_safex_offer(sfx_offer); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_offer_update)){ + safex::edit_offer_data offer; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, offer); + safex::safex_offer sfx_offer{std::string{offer.title.begin(),offer.title.end()},offer.quantity,offer.price, + offer.description,offer.offer_id,std::string{offer.seller.begin(),offer.seller.end()}}; + if(offer.price_peg_used) + sfx_offer.set_price_peg(offer.price_peg_id,offer.price,offer.min_sfx_price); + sfx_offer.active = offer.active; + update_safex_offer(sfx_offer); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_purchase)){ + safex::create_purchase_data purchase_data; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, purchase_data); + safex::safex_offer my_offer = get_my_safex_offer(purchase_data.offer_id); + update_safex_offer(purchase_data); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback_token)){ + safex::create_feedback_token_data feedback_token; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, feedback_token); + add_safex_feedback_token(feedback_token); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_feedback)){ + safex::create_feedback_data feedback; + const cryptonote::blobdata offblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(offblob, feedback); + std::string comment{feedback.comment.begin(),feedback.comment.end()}; + remove_safex_feedback_token(feedback.offer_id); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg)){ + safex::create_price_peg_data price_peg; + const cryptonote::blobdata pricepeggblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(pricepeggblob, price_peg); + std::string creator{price_peg.creator.begin(),price_peg.creator.end()}; + std::string title{price_peg.title.begin(),price_peg.title.end()}; + std::string currency{price_peg.currency.begin(),price_peg.currency.end()}; + safex::safex_price_peg sfx_price_peg{title,creator,currency,price_peg.description,price_peg.price_peg_id,price_peg.rate}; + add_safex_price_peg(sfx_price_peg); + + } else if (txout.output_type == static_cast(tx_out_type::out_safex_price_peg_update)){ + safex::update_price_peg_data price_peg; + const cryptonote::blobdata pricepeggblob(std::begin(txout.data), std::end(txout.data)); + cryptonote::parse_and_validate_from_blob(pricepeggblob, price_peg); + update_safex_price_peg(price_peg.price_peg_id,price_peg.rate); + + } + + } + +} + diff --git a/src/wallet/wallet_safex_rpc_server.cpp b/src/wallet/wallet_safex_rpc_server.cpp new file mode 100644 index 000000000..3e0392e18 --- /dev/null +++ b/src/wallet/wallet_safex_rpc_server.cpp @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include "include_base_utils.h" +using namespace epee; + +#include "wallet_rpc_server.h" +#include "wallet/wallet_args.h" +#include "common/command_line.h" +#include "common/i18n.h" +#include "cryptonote_config.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_basic/account.h" +#include "wallet_rpc_server_commands_defs.h" +#include "misc_language.h" +#include "string_coding.h" +#include "string_tools.h" +#include "crypto/hash.h" +#include "mnemonics/electrum-words.h" +#include "rpc/rpc_args.h" +#include "rpc/core_rpc_server_commands_defs.h" + +#undef SAFEX_DEFAULT_LOG_CATEGORY +#define SAFEX_DEFAULT_LOG_CATEGORY "wallet.rpc" + + +namespace tools { +} diff --git a/tests/core_tests/CMakeLists.txt b/tests/core_tests/CMakeLists.txt index 8d100aa69..ae9397c22 100644 --- a/tests/core_tests/CMakeLists.txt +++ b/tests/core_tests/CMakeLists.txt @@ -37,15 +37,22 @@ set(core_tests_sources chaingen001.cpp chaingen_main.cpp token_transactions.cpp + token_stake.cpp + safex_account.cpp + safex_offer.cpp + safex_purchase.cpp double_spend.cpp + double_spend_token.cpp + double_advanced_tx.cpp integer_overflow.cpp - multisig.cpp ring_signature_1.cpp transaction_tests.cpp tx_validation.cpp v2_tests.cpp - rct.cpp - chain_migration.cpp) + chain_migration.cpp + network_fee.cpp + safex_price_peg.cpp + chain_split_safex.cpp) set(core_tests_headers block_reward.h @@ -56,15 +63,24 @@ set(core_tests_headers chaingen_tests_list.h double_spend.h double_spend.inl + double_spend_token.h + double_spend_token.inl + double_advanced_tx.h + double_advanced_tx.inl integer_overflow.h - multisig.h ring_signature_1.h transaction_tests.h tx_validation.h v2_tests.h - rct.h chain_migration.h - token_transactions.h) + token_transactions.h + token_stake.h + safex_account.h + safex_offer.h + safex_purchase.h + network_fee.h + safex_price_peg.h + chain_split_safex.h) add_executable(core_tests ${core_tests_sources} @@ -77,6 +93,7 @@ target_link_libraries(core_tests version epee device + ${GTEST_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} ${EXTRA_LIBRARIES}) set_property(TARGET core_tests diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp index 4e9501223..1d2d73b46 100644 --- a/tests/core_tests/block_validation.cpp +++ b/tests/core_tests/block_validation.cpp @@ -338,7 +338,6 @@ bool gen_block_miner_tx_has_2_in::generate(std::vector& events se.amount = blk_0.miner_tx.vout[0].amount; se.push_output(0, boost::get(blk_0.miner_tx.vout[0].target).key, se.amount); se.real_output = 0; - se.rct = false; se.real_out_tx_key = get_tx_pub_key_from_extra(blk_0.miner_tx); se.real_output_in_tx_index = 0; std::vector sources; @@ -381,7 +380,6 @@ bool gen_block_miner_tx_with_txin_to_key::generate(std::vector se.amount = blk_1.miner_tx.vout[0].amount; se.push_output(0, boost::get(blk_1.miner_tx.vout[0].target).key, se.amount); se.real_output = 0; - se.rct = false; se.real_out_tx_key = get_tx_pub_key_from_extra(blk_1.miner_tx); se.real_output_in_tx_index = 0; std::vector sources; @@ -509,7 +507,7 @@ bool gen_block_is_too_big::generate(std::vector& events) const // Creating a huge miner_tx, it will have a lot of outs MAKE_MINER_TX_MANUALLY(miner_tx, blk_0); static const size_t tx_out_count = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE_V1 / 2; - uint64_t amount = get_outs_money_amount(miner_tx); + uint64_t amount = get_outs_cash_amount(miner_tx); uint64_t portion = amount / tx_out_count; uint64_t remainder = amount % tx_out_count; txout_target_v target = miner_tx.vout[0].target; diff --git a/tests/core_tests/chain_migration.h b/tests/core_tests/chain_migration.h index 8e2bf8ae6..fddd260d4 100644 --- a/tests/core_tests/chain_migration.h +++ b/tests/core_tests/chain_migration.h @@ -41,8 +41,7 @@ #include "ring_signature_1.h" #include "tx_validation.h" #include "v2_tests.h" -#include "rct.h" -#include "multisig.h" +//#include "rct.h" /************************************************************************/ /* */ /************************************************************************/ diff --git a/tests/core_tests/chain_split_safex.cpp b/tests/core_tests/chain_split_safex.cpp new file mode 100644 index 000000000..6fc888447 --- /dev/null +++ b/tests/core_tests/chain_split_safex.cpp @@ -0,0 +1,2261 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#include "chaingen.h" +#include "chain_split_safex.h" + +using namespace std; + +using namespace epee; +using namespace cryptonote; + +bool gen_simple_chain_split_safex::expected_data_fields_intialized{false}; +const std::string gen_simple_chain_split_safex::data_alternative{"Edited account"}; + +uint64_t gen_simple_chain_split_safex::expected_network_fee; +uint64_t gen_simple_chain_split_safex::expected_alice_balance; +uint64_t gen_simple_chain_split_safex::expected_bob_balance; +uint64_t gen_simple_chain_split_safex::expected_alice_balance_before_purchase; +uint64_t gen_simple_chain_split_safex::expected_bob_balance_before_purchase; +uint64_t gen_simple_chain_split_safex::expected_alice_balance_after_unstake; + +safex::safex_offer gen_simple_chain_split_safex::expected_alice_safex_offer; +safex::safex_offer gen_simple_chain_split_safex::expected_alice_safex_offer_edited; +safex::safex_price_peg gen_simple_chain_split_safex::expected_alice_safex_price_peg; +safex::safex_price_peg gen_simple_chain_split_safex::expected_alice_safex_price_peg_edited; +safex::safex_purchase gen_simple_chain_split_safex::expected_safex_bob_purchase_from_alice; + +uint64_t gen_simple_chain_split_safex::expected_staked_tokens; +uint64_t gen_simple_chain_split_safex::expected_alice_token_balance; + +safex::safex_feedback gen_simple_chain_split_safex::expected_bob_feedback; +uint64_t gen_simple_chain_split_safex::expected_bob_balance_after_feedback; + +std::vector gen_simple_chain_split_safex::expected_sizes; + +gen_simple_chain_split_safex::gen_simple_chain_split_safex() +{ + REGISTER_CALLBACK("check_split_account_present_1", gen_simple_chain_split_safex::check_split_account_present_1); + REGISTER_CALLBACK("check_split_account_present_2", gen_simple_chain_split_safex::check_split_account_present_2); + REGISTER_CALLBACK("check_split_switched_account", gen_simple_chain_split_safex::check_split_switched_account); + REGISTER_CALLBACK("check_split_switched_back_account", gen_simple_chain_split_safex::check_split_switched_back_account); + REGISTER_CALLBACK("check_split_account_edit_1", gen_simple_chain_split_safex::check_split_account_edit_1); + REGISTER_CALLBACK("check_split_switched_account_edit", gen_simple_chain_split_safex::check_split_switched_account_edit); + REGISTER_CALLBACK("check_split_switched_back_account_edit", gen_simple_chain_split_safex::check_split_switched_back_account_edit); + REGISTER_CALLBACK("check_split_offer_present_1", gen_simple_chain_split_safex::check_split_offer_present_1); + REGISTER_CALLBACK("check_split_switched_offer", gen_simple_chain_split_safex::check_split_switched_offer); + REGISTER_CALLBACK("check_split_switched_back_offer", gen_simple_chain_split_safex::check_split_switched_back_offer); + REGISTER_CALLBACK("check_split_offer_edit_1", gen_simple_chain_split_safex::check_split_offer_edit_1); + REGISTER_CALLBACK("check_split_switched_offer_edit", gen_simple_chain_split_safex::check_split_switched_offer_edit); + REGISTER_CALLBACK("check_split_switched_back_offer_edit", gen_simple_chain_split_safex::check_split_switched_back_offer_edit); + REGISTER_CALLBACK("check_split_price_peg_present_1", gen_simple_chain_split_safex::check_split_price_peg_present_1); + REGISTER_CALLBACK("check_split_switched_price_peg", gen_simple_chain_split_safex::check_split_switched_price_peg); + REGISTER_CALLBACK("check_split_switched_back_price_peg", gen_simple_chain_split_safex::check_split_switched_back_price_peg); + REGISTER_CALLBACK("check_split_price_peg_edit_1", gen_simple_chain_split_safex::check_split_price_peg_edit_1); + REGISTER_CALLBACK("check_split_switched_price_peg_edit", gen_simple_chain_split_safex::check_split_switched_price_peg_edit); + REGISTER_CALLBACK("check_split_switched_back_price_peg_edit", gen_simple_chain_split_safex::check_split_switched_back_price_peg_edit); + REGISTER_CALLBACK("check_split_stake_token_1", gen_simple_chain_split_safex::check_split_stake_token_1); + REGISTER_CALLBACK("check_split_switched_stake_token", gen_simple_chain_split_safex::check_split_switched_stake_token); + REGISTER_CALLBACK("check_split_switched_back_stake_token", gen_simple_chain_split_safex::check_split_switched_back_stake_token); + REGISTER_CALLBACK("check_split_safex_purchase_1", gen_simple_chain_split_safex::check_split_safex_purchase_1); + REGISTER_CALLBACK("check_split_switched_safex_purchase", gen_simple_chain_split_safex::check_split_switched_safex_purchase); + REGISTER_CALLBACK("check_split_switched_back_safex_purchase", gen_simple_chain_split_safex::check_split_switched_back_safex_purchase); + REGISTER_CALLBACK("check_split_unstake_token_1", gen_simple_chain_split_safex::check_split_unstake_token_1); + REGISTER_CALLBACK("check_split_switched_unstake_token", gen_simple_chain_split_safex::check_split_switched_unstake_token); + REGISTER_CALLBACK("check_split_switched_back_unstake_token", gen_simple_chain_split_safex::check_split_switched_back_unstake_token); + REGISTER_CALLBACK("check_split_feedback_1", gen_simple_chain_split_safex::check_split_feedback_1); + REGISTER_CALLBACK("check_split_switched_feedback", gen_simple_chain_split_safex::check_split_switched_feedback); + REGISTER_CALLBACK("check_split_switched_back_feedback", gen_simple_chain_split_safex::check_split_switched_back_feedback); + + m_safex_account1_keys.generate(); + + alice_account.generate(); + + safex_account_alice.username = "alice01"; + safex_account_alice.pkey = m_safex_account1_keys.get_keys().m_public_key; + safex_account_alice.account_data = {'l','o','r','e','m',' ','i','p','s','u','m'}; + safex_offer_alice = safex::safex_offer("Black Sabbath T-shirt",100,MK_COINS(10),"Quality 100% cotton t-shirt with the heaviest band in the universe", + safex_account_alice.username,alice_account.get_keys().m_view_secret_key,alice_account.get_keys().m_account_address); + + safex_offer_alice_edited = safex_offer_alice; + + safex_offer_alice_edited.min_sfx_price = MK_COINS(20); + safex_offer_alice_edited.price = MK_COINS(20); + safex_offer_alice_edited.description = {'s','u','p','e','r'}; + safex_offer_alice_edited.quantity = 85; + + safex_price_peg_alice = safex::safex_price_peg{"Alice price peg",safex_account_alice.username,"USD","USD to SFX price peg",30}; + + safex_price_peg_alice_edited = safex_price_peg_alice; + + safex_price_peg_alice_edited.rate = 37; + + safex_bob_purchase_from_alice = safex::safex_purchase{2, safex_offer_alice_edited.price*2, safex_offer_alice_edited.offer_id, safex_offer_alice_edited.get_hash(), false}; + + safex_bob_feedback = safex::safex_feedback{3,"Perfect for my concert next week.",safex_offer_alice.offer_id}; + + if (!expected_data_fields_intialized) + { + + expected_alice_balance = 0; + expected_bob_balance = 0; + expected_network_fee = calculate_safex_network_fee(safex_bob_purchase_from_alice.price, FAKECHAIN, safex::command_t::simple_purchase); + + expected_alice_balance += MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE; + expected_alice_balance -= 7*TESTS_DEFAULT_FEE; + + expected_alice_balance_before_purchase = expected_alice_balance; + + expected_alice_balance += safex_bob_purchase_from_alice.price - expected_network_fee; + + expected_alice_balance_after_unstake = expected_alice_balance + expected_network_fee - TESTS_DEFAULT_FEE; + + expected_bob_balance += MK_TOKENS(20000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE; + + expected_bob_balance_before_purchase = expected_bob_balance; + + expected_bob_balance -= 1*TESTS_DEFAULT_FEE; + expected_bob_balance -= safex_bob_purchase_from_alice.price; + + expected_staked_tokens = MK_TOKENS(10000); + + expected_alice_token_balance = MK_TOKENS(10000); + + + expected_data_fields_intialized = true; + expected_alice_safex_offer = safex_offer_alice; + expected_alice_safex_offer_edited = safex_offer_alice_edited; + expected_alice_safex_price_peg = safex_price_peg_alice; + expected_alice_safex_price_peg_edited = safex_price_peg_alice_edited; + + expected_safex_bob_purchase_from_alice = safex_bob_purchase_from_alice; + + expected_bob_balance_after_feedback = expected_bob_balance - TESTS_DEFAULT_FEE; + expected_bob_feedback = safex_bob_feedback; + + } +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::generate(std::vector &events) const +{ + uint64_t ts_start = 1338224400; + cryptonote::account_base first_miner_account; + first_miner_account.generate(); + crypto::public_key miner_public_key = AUTO_VAL_INIT(miner_public_key); + crypto::secret_key_to_public_key(first_miner_account.get_keys().m_spend_secret_key, miner_public_key); + cryptonote::fakechain::set_core_tests_public_key(miner_public_key); + + MAKE_GENESIS_BLOCK(events, blk_0, first_miner_account, ts_start); // 0 + + events.push_back(alice_account); + MAKE_ACCOUNT(events, bob_account); // All events + 2 + events.push_back(first_miner_account); + MAKE_NEXT_BLOCK(events, blk_1, blk_0, first_miner_account); // 1 + MAKE_NEXT_BLOCK(events, blk_2, blk_1, first_miner_account); // 2 + MAKE_NEXT_BLOCK(events, blk_3, blk_2, first_miner_account); // 3 + REWIND_BLOCKS(events, blk_3r, blk_3, first_miner_account); // 63 + MAKE_TX_MIGRATION_LIST_START(events, txlist_0, first_miner_account, alice_account, MK_TOKENS(10000), blk_3, get_hash_from_string(bitcoin_tx_hashes_str[0])); // 64 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_4, blk_3r, first_miner_account, txlist_0); // 65 + MAKE_NEXT_BLOCK(events, blk_5, blk_4, first_miner_account); // 66 + MAKE_TX_MIGRATION_LIST_START(events, txlist_0r, first_miner_account, bob_account, MK_TOKENS(20000), blk_4, get_hash_from_string(bitcoin_tx_hashes_str[1])); // 67 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_6, blk_5, first_miner_account, txlist_0r); // 68 + MAKE_NEXT_BLOCK(events, blk_7, blk_6, first_miner_account); // 69 + MAKE_NEXT_BLOCK(events, blk_8, blk_7, first_miner_account); // 70 + MAKE_NEXT_BLOCK(events, blk_9, blk_8, first_miner_account); // 71 + MAKE_NEXT_BLOCK(events, blk_10, blk_9, first_miner_account); // 72 + MAKE_NEXT_BLOCK(events, blk_11, blk_10, first_miner_account); // 73 + MAKE_NEXT_BLOCK(events, blk_12, blk_11, first_miner_account); // 74 + MAKE_NEXT_BLOCK(events, blk_13, blk_12, first_miner_account); // 75 + MAKE_NEXT_BLOCK(events, blk_14, blk_13, first_miner_account); // 76 + + // Create safex account + + REWIND_BLOCKS(events, blk_14r, blk_14, first_miner_account); // 136 + MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(events, txlist_1, alice_account, safex_account_alice.username, safex_account_alice.pkey, safex_account_alice.account_data, m_safex_account1_keys.get_keys(), events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_14); // 137 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_15, blk_14r, first_miner_account, txlist_1); // 138 + MAKE_NEXT_BLOCK(events, blk_16, blk_15, first_miner_account); // 139 //height: 137 +// //split again and check back switching + MAKE_NEXT_BLOCK(events, blk_17, blk_8, first_miner_account); // 140 //70th block + MAKE_NEXT_BLOCK(events, blk_18, blk_17, first_miner_account); // 141 + REWIND_BLOCKS(events, blk_19, blk_18, first_miner_account); // 201 + MAKE_NEXT_BLOCK(events, blk_20, blk_19, first_miner_account); // 202 + MAKE_NEXT_BLOCK(events, blk_21, blk_20, first_miner_account); // 203 + DO_CALLBACK(events, "check_split_account_present_1"); // 204 + MAKE_NEXT_BLOCK(events, blk_22, blk_21, first_miner_account); // 205 + MAKE_NEXT_BLOCK(events, blk_23, blk_22, first_miner_account); // 206 + MAKE_NEXT_BLOCK(events, blk_24, blk_23, first_miner_account); // 207 + MAKE_NEXT_BLOCK(events, blk_25, blk_24, first_miner_account); // 208 + DO_CALLBACK(events, "check_split_account_present_2"); // 209 + MAKE_NEXT_BLOCK(events, blk_26, blk_25, first_miner_account); // 210 + DO_CALLBACK(events, "check_split_switched_account"); // 211 + MAKE_NEXT_BLOCK(events, blk_27, blk_16, first_miner_account); // 212 + MAKE_NEXT_BLOCK(events, blk_28, blk_27, first_miner_account); // 213 + DO_CALLBACK(events, "check_split_switched_back_account"); // 214 + + // Edit safex account + + REWIND_BLOCKS(events, blk_28r, blk_28, first_miner_account); // 273 + MAKE_TX_EDIT_SAFEX_ACCOUNT_LIST_START(events, txlist_2, alice_account, safex_account_alice.username, std::vector(data_alternative.begin(), data_alternative.end()), m_safex_account1_keys.get_keys(), blk_28); // 274 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_29, blk_28r, first_miner_account, txlist_2); // 275 + DO_CALLBACK(events, "check_split_account_edit_1"); // 276 + // //split again and check back switching + MAKE_NEXT_BLOCK(events, blk_30, blk_27, first_miner_account); // 277 + MAKE_NEXT_BLOCK(events, blk_31, blk_30, first_miner_account); // 278 + REWIND_BLOCKS(events, blk_31r, blk_31, first_miner_account); // 338 + MAKE_NEXT_BLOCK(events, blk_32, blk_31r, first_miner_account); // 339 + DO_CALLBACK(events, "check_split_switched_account_edit"); // 340 + MAKE_NEXT_BLOCK(events, blk_33, blk_29, first_miner_account); // 341 + MAKE_NEXT_BLOCK(events, blk_34, blk_33, first_miner_account); // 342 + DO_CALLBACK(events, "check_split_switched_back_account_edit"); // 343 + + // Create safex offer + + REWIND_BLOCKS(events, blk_34r, blk_34, first_miner_account); // 403 + MAKE_TX_CREATE_SAFEX_OFFER_LIST_START(events, txlist_3, alice_account, safex_account_alice.pkey, safex_offer_alice, m_safex_account1_keys.get_keys(), blk_34); // 404 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_35, blk_34r, first_miner_account, txlist_3); // 405 + DO_CALLBACK(events, "check_split_offer_present_1"); // 406 + // //split again and check back switching + MAKE_NEXT_BLOCK(events, blk_36, blk_33, first_miner_account); // 407 + MAKE_NEXT_BLOCK(events, blk_37, blk_36, first_miner_account); // 408 + REWIND_BLOCKS(events, blk_37r, blk_37, first_miner_account); // 468 + MAKE_NEXT_BLOCK(events, blk_38, blk_37r, first_miner_account); // 469 + DO_CALLBACK(events, "check_split_switched_offer"); // 470 + MAKE_NEXT_BLOCK(events, blk_39, blk_35, first_miner_account); // 471 + MAKE_NEXT_BLOCK(events, blk_40, blk_39, first_miner_account); // 472 + DO_CALLBACK(events, "check_split_switched_back_offer"); // 473 + + // Edit safex offer + + REWIND_BLOCKS(events, blk_40r, blk_40, first_miner_account); // 533 + MAKE_TX_EDIT_SAFEX_OFFER_LIST_START(events, txlist_4, alice_account, safex_account_alice.pkey, safex_offer_alice_edited, m_safex_account1_keys.get_keys(), blk_40); // 534 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_41, blk_40r, first_miner_account, txlist_4); // 535 + DO_CALLBACK(events, "check_split_offer_edit_1"); // 536 + // //split again and check back switching + MAKE_NEXT_BLOCK(events, blk_42, blk_39, first_miner_account); // 537 + MAKE_NEXT_BLOCK(events, blk_43, blk_42, first_miner_account); // 538 + REWIND_BLOCKS(events, blk_43r, blk_43, first_miner_account); // 598 + MAKE_NEXT_BLOCK(events, blk_44, blk_43r, first_miner_account); // 599 + DO_CALLBACK(events, "check_split_switched_offer_edit"); // 600 + MAKE_NEXT_BLOCK(events, blk_45, blk_41, first_miner_account); // 601 + MAKE_NEXT_BLOCK(events, blk_46, blk_45, first_miner_account); // 602 + DO_CALLBACK(events, "check_split_switched_back_offer_edit"); // 603 + + // Create safex price peg + + REWIND_BLOCKS(events, blk_46r, blk_46, first_miner_account); // 663 + MAKE_TX_CREATE_SAFEX_PRICE_PEG_LIST_START(events, txlist_5, alice_account, safex_account_alice.pkey, safex_price_peg_alice, m_safex_account1_keys.get_keys(), blk_46); // 664 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_47, blk_46r, first_miner_account, txlist_5); // 665 + DO_CALLBACK(events, "check_split_price_peg_present_1"); // 666 + // //split again and check back switching + MAKE_NEXT_BLOCK(events, blk_48, blk_45, first_miner_account); // 667 + MAKE_NEXT_BLOCK(events, blk_49, blk_48, first_miner_account); // 668 + REWIND_BLOCKS(events, blk_49r, blk_49, first_miner_account); // 728 + MAKE_NEXT_BLOCK(events, blk_50, blk_49r, first_miner_account); // 729 + DO_CALLBACK(events, "check_split_switched_price_peg"); // 730 + MAKE_NEXT_BLOCK(events, blk_51, blk_47, first_miner_account); // 731 + MAKE_NEXT_BLOCK(events, blk_52, blk_51, first_miner_account); // 732 + DO_CALLBACK(events, "check_split_switched_back_price_peg"); // 733 + + // Edit safex price peg + + REWIND_BLOCKS(events, blk_52r, blk_52, first_miner_account); // 793 + MAKE_TX_UPDATE_SAFEX_PRICE_PEG_LIST_START(events, txlist_6, alice_account, safex_account_alice.pkey, safex_price_peg_alice_edited, m_safex_account1_keys.get_keys(), blk_52); // 794 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_53, blk_52r, first_miner_account, txlist_6); // 795 + DO_CALLBACK(events, "check_split_price_peg_edit_1"); // 796 + // //split again and check back switching + MAKE_NEXT_BLOCK(events, blk_54, blk_51, first_miner_account); // 797 + MAKE_NEXT_BLOCK(events, blk_55, blk_54, first_miner_account); // 798 + REWIND_BLOCKS(events, blk_55r, blk_55, first_miner_account); // 858 + MAKE_NEXT_BLOCK(events, blk_56, blk_55r, first_miner_account); // 859 + DO_CALLBACK(events, "check_split_switched_price_peg_edit"); // 860 + MAKE_NEXT_BLOCK(events, blk_58, blk_53, first_miner_account); // 861 + MAKE_NEXT_BLOCK(events, blk_59, blk_58, first_miner_account); // 862 + DO_CALLBACK(events, "check_split_switched_back_price_peg_edit"); // 863 + + // Stake tokens + + REWIND_BLOCKS(events, blk_59r, blk_59, first_miner_account); // 923 + MAKE_TX_TOKEN_LOCK_LIST_START(events, txlist_7, alice_account, MK_TOKENS(10000), blk_59); // 924 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_60, blk_59r, first_miner_account, txlist_7); // 925 + DO_CALLBACK(events, "check_split_stake_token_1"); // 926 + // //split again and check back switching + MAKE_NEXT_BLOCK(events, blk_61, blk_58, first_miner_account); // 927 + MAKE_NEXT_BLOCK(events, blk_62, blk_61, first_miner_account); // 928 + REWIND_BLOCKS(events, blk_62r, blk_62, first_miner_account); // 988 + MAKE_NEXT_BLOCK(events, blk_63, blk_62r, first_miner_account); // 989 + DO_CALLBACK(events, "check_split_switched_stake_token"); // 990 + MAKE_NEXT_BLOCK(events, blk_64, blk_60, first_miner_account); // 991 + MAKE_NEXT_BLOCK(events, blk_65, blk_64, first_miner_account); // 992 + DO_CALLBACK(events, "check_split_switched_back_stake_token"); // 993 + + // Safex purchase + + REWIND_BLOCKS(events, blk_65r, blk_65, first_miner_account); // 1053 + MAKE_TX_CREATE_SAFEX_PURCHASE_LIST_START(events, txlist_8, bob_account, safex_bob_purchase_from_alice, safex_offer_alice_edited.seller_address, blk_65); // 1054 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_66, blk_65r, first_miner_account, txlist_8); // 1055 + DO_CALLBACK(events, "check_split_safex_purchase_1"); // 1056 + // //split again and check back switching + MAKE_NEXT_BLOCK(events, blk_67, blk_64, first_miner_account); // 1057 + MAKE_NEXT_BLOCK(events, blk_68, blk_67, first_miner_account); // 1058 + REWIND_BLOCKS(events, blk_68r, blk_68, first_miner_account); // 1118 + MAKE_NEXT_BLOCK(events, blk_69, blk_68r, first_miner_account); // 1119 + DO_CALLBACK(events, "check_split_switched_safex_purchase"); // 1120 + MAKE_NEXT_BLOCK(events, blk_70, blk_66, first_miner_account); // 1121 + MAKE_NEXT_BLOCK(events, blk_71, blk_70, first_miner_account); // 1122 + DO_CALLBACK(events, "check_split_switched_back_safex_purchase"); // 1123 + + // Unstake tokens + + MAKE_NEXT_BLOCK(events, blk_71b, blk_71, first_miner_account); + REWIND_BLOCKS(events, blk_71r, blk_71b, first_miner_account); // 1053 + MAKE_TX_TOKEN_UNLOCK_LIST_START(events, txlist_9, alice_account, MK_TOKENS(10000), blk_71b); // 1054 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_72, blk_71r, first_miner_account, txlist_9); // 1055 + DO_CALLBACK(events, "check_split_unstake_token_1"); // 1056 + // //split again and check back switching + MAKE_NEXT_BLOCK(events, blk_73, blk_70, first_miner_account); // 1057 + MAKE_NEXT_BLOCK(events, blk_74b, blk_73, first_miner_account); // 1058 + MAKE_NEXT_BLOCK(events, blk_74, blk_74b, first_miner_account); // 1057 + REWIND_BLOCKS(events, blk_74r, blk_74, first_miner_account); // 1118 + MAKE_NEXT_BLOCK(events, blk_75, blk_74r, first_miner_account); // 1119 + DO_CALLBACK(events, "check_split_switched_unstake_token"); // 1120 + MAKE_NEXT_BLOCK(events, blk_76, blk_72, first_miner_account); // 1121 + MAKE_NEXT_BLOCK(events, blk_77, blk_76, first_miner_account); // 1122 + DO_CALLBACK(events, "check_split_switched_back_unstake_token"); // 1123 + + // Feedback + + REWIND_BLOCKS(events, blk_77r, blk_77, first_miner_account); // 1053 + MAKE_TX_CREATE_SAFEX_FEEDBACK_LIST_START(events, txlist_10, bob_account, safex_bob_feedback, blk_77) // 1054 + MAKE_NEXT_BLOCK_TX_LIST(events, blk_78, blk_77r, first_miner_account, txlist_10); // 1055 + DO_CALLBACK(events, "check_split_feedback_1"); // 1056 + // //split again and check back switching + MAKE_NEXT_BLOCK(events, blk_79, blk_76, first_miner_account); // 1057 + MAKE_NEXT_BLOCK(events, blk_80, blk_79, first_miner_account); // 1058 + REWIND_BLOCKS(events, blk_80r, blk_80, first_miner_account); // 1118 + MAKE_NEXT_BLOCK(events, blk_81, blk_80r, first_miner_account); // 1119 + DO_CALLBACK(events, "check_split_switched_feedback"); // 1120 + MAKE_NEXT_BLOCK(events, blk_82, blk_78, first_miner_account); // 1121 + MAKE_NEXT_BLOCK(events, blk_83, blk_82, first_miner_account); // 1122 + DO_CALLBACK(events, "check_split_switched_back_feedback"); // 1123 + + return true; +} + +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_account_present_1(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_account_present_1"); + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == 137); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == 140); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[142]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 64); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_account_present_2(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_account_present_2"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == 137); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == 140); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[142]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 68); + + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + expected_sizes = sizes; + + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + + return true; +}//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_account(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_account"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == 138); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == 140); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[213]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 68); + + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + CHECK_TEST_CONDITION(safex_accounts.size() == 0); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_back_account(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_back_account"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 69); + + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(std::equal(safex_account_alice.account_data.begin(), safex_account_alice.account_data.end(), sfx_account.account_data.begin())); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + CHECK_TEST_CONDITION(std::equal(sizes.begin(),sizes.end(),expected_sizes.begin())); + + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_account_edit_1(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_account_edit_1"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + delta_blocks - 2); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + delta_blocks - 1); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total+63]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 69); + + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + expected_sizes = sizes; + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_account_edit(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_account_edit"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + delta_blocks - 1); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + delta_blocks - 1); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total+63+64]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 131); + + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(std::equal(safex_account_alice.account_data.begin(), safex_account_alice.account_data.end(), sfx_account.account_data.begin())); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_back_account_edit(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_back_account_edit"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + delta_blocks); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + delta_blocks + 1); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total+63+64+3]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 132); + + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + sizes.at(2)--; + + CHECK_TEST_CONDITION(std::equal(sizes.begin(),sizes.end(),expected_sizes.begin())); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_offer_present_1(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_offer_present_1"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 2*delta_blocks -2); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 2*delta_blocks); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total+delta_events+63]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 132); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer.description.begin(), expected_alice_safex_offer.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + expected_sizes = sizes; + + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_offer(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_offer"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 2*delta_blocks - 1); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 2*delta_blocks); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + delta_events + 63 + 64]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 194); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + CHECK_TEST_CONDITION(safex_offers.size() == 0); + + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_back_offer(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_back_offer"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 2*delta_blocks); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 2*delta_blocks + 2); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + delta_events + 63 + 64 + 3]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 195); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer.description.begin(), expected_alice_safex_offer.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + CHECK_TEST_CONDITION(std::equal(sizes.begin(),sizes.end(),expected_sizes.begin())); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_offer_edit_1(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_offer_edit_1"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 3*delta_blocks -2); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 3*delta_blocks+1); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total+2*delta_events+63]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 195); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + expected_sizes = sizes; + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_offer_edit(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_offer_edit"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 3*delta_blocks - 1); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 3*delta_blocks +1); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 2*delta_events + 63 + 64]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 257); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer.description.begin(), expected_alice_safex_offer.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_back_offer_edit(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_back_offer_edit"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 3*delta_blocks); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 3*delta_blocks + 3); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 2*delta_events + 63 + 64 + 3]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 258); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + CHECK_TEST_CONDITION(std::equal(sizes.begin(),sizes.end(),expected_sizes.begin())); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_price_peg_present_1(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_price_peg_present_1"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 4*delta_blocks - 2); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 4*delta_blocks + 2); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total+3*delta_events+63]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 258); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg.description.begin(), expected_alice_safex_price_peg.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + expected_sizes = sizes; + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_price_peg(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_price_peg"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 4*delta_blocks - 1); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 4*delta_blocks +2); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 3*delta_events + 63 + 64]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 320); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + CHECK_TEST_CONDITION(safex_price_pegs.size() == 0); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_back_price_peg(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_back_price_peg"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 4*delta_blocks); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 4*delta_blocks + 4); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 3*delta_events + 63 + 64 + 3]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 321); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg.description.begin(), expected_alice_safex_price_peg.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + sizes.at(2)--; + + CHECK_TEST_CONDITION(std::equal(sizes.begin(),sizes.end(),expected_sizes.begin())); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_price_peg_edit_1(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_price_peg_edit_1"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 5*delta_blocks - 2); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 5*delta_blocks + 3); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total+4*delta_events+63]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 321); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + expected_sizes = sizes; + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_price_peg_edit(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_price_peg_edit"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 5*delta_blocks - 1); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 5*delta_blocks +3); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 4*delta_events + 63 + 64]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 383); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg.description.begin(), expected_alice_safex_price_peg.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_back_price_peg_edit(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_back_price_peg_edit"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 5*delta_blocks); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 5*delta_blocks + 5); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 4*delta_events + 63 + 64 + 3]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 384); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + CHECK_TEST_CONDITION(std::equal(sizes.begin(),sizes.end(),expected_sizes.begin())); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_stake_token_1(cryptonote::core& c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_stake_token_1"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 6*delta_blocks - 2); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 6*delta_blocks + 4); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total+5*delta_events+63]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 384); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(expected_staked_tokens, staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(expected_alice_token_balance, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(0, get_token_balance(alice_account, blocks, mtx)); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + expected_sizes = sizes; + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_stake_token(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_stake_token"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 6*delta_blocks - 1); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 6*delta_blocks +4); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 5*delta_events + 63 + 64]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 446); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(0, staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(0, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_back_stake_token(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_back_stake_token"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 6*delta_blocks); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 6*delta_blocks + 6); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 5*delta_events + 63 + 64 + 3]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 447); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(expected_staked_tokens, staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(expected_alice_token_balance, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(0, get_token_balance(alice_account, blocks, mtx)); + //purchase + uint64_t network_fee_collected = c.get_collected_network_fee(0, c.get_current_blockchain_height()); + CHECK_EQ(network_fee_collected, 0); + + + uint64_t alice_balance = get_balance(alice_account, chain, mtx); + CHECK_EQ(alice_balance, expected_alice_balance_before_purchase); + + uint64_t bob_balance = get_balance(bob_account, chain, mtx); + CHECK_EQ(bob_balance, expected_bob_balance_before_purchase); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + CHECK_TEST_CONDITION(std::equal(sizes.begin(),sizes.end(),expected_sizes.begin())); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_safex_purchase_1(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_safex_purchase_1"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 7*delta_blocks - 2); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 7*delta_blocks + 5); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total+6*delta_events+63]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 447); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity-expected_safex_bob_purchase_from_alice.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(expected_staked_tokens, staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(expected_alice_token_balance, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(0, get_token_balance(alice_account, blocks, mtx)); + //purchase + uint64_t network_fee_collected = c.get_collected_network_fee(0, c.get_current_blockchain_height()); + CHECK_EQ(network_fee_collected, expected_network_fee); + + uint64_t network_fee_intervals = 0; + + for(uint64_t i=0;i<=c.get_current_blockchain_height()/10+1;i++) + network_fee_intervals += c.get_network_fee_for_interval(i); + + CHECK_EQ(network_fee_intervals, expected_network_fee); + + uint64_t alice_balance = get_balance(alice_account, chain, mtx); + CHECK_EQ(alice_balance, expected_alice_balance); + + uint64_t bob_balance = get_balance(bob_account, chain, mtx); + CHECK_EQ(bob_balance, expected_bob_balance); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + expected_sizes = sizes; + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_safex_purchase(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_safex_purchase"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 7*delta_blocks - 1); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 7*delta_blocks +5); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 6*delta_events + 63 + 64]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 509); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(expected_alice_token_balance, staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(expected_alice_token_balance, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(0, get_token_balance(alice_account, blocks, mtx)); + //purchase + uint64_t network_fee_collected = c.get_collected_network_fee(0, c.get_current_blockchain_height()); + CHECK_EQ(network_fee_collected, 0); + + + uint64_t alice_balance = get_balance(alice_account, chain, mtx); + CHECK_EQ(alice_balance, expected_alice_balance_before_purchase); + + uint64_t bob_balance = get_balance(bob_account, chain, mtx); + CHECK_EQ(bob_balance, expected_bob_balance_before_purchase); + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_back_safex_purchase(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_back_safex_purchase"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 7*delta_blocks); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 7*delta_blocks + 7); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 6*delta_events + 63 + 64 + 3]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 510); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity-expected_safex_bob_purchase_from_alice.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(expected_staked_tokens, staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(expected_alice_token_balance, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(0, get_token_balance(alice_account, blocks, mtx)); + //purchase + uint64_t network_fee_collected = c.get_collected_network_fee(0, c.get_current_blockchain_height()); + CHECK_EQ(network_fee_collected, expected_network_fee); + + uint64_t network_fee_intervals = 0; + + for(uint64_t i=0;i<=c.get_current_blockchain_height()/10+1;i++) + network_fee_intervals += c.get_network_fee_for_interval(i); + + CHECK_EQ(network_fee_intervals, expected_network_fee); + + uint64_t alice_balance = get_balance(alice_account, chain, mtx); + CHECK_EQ(alice_balance, expected_alice_balance); + + uint64_t bob_balance = get_balance(bob_account, chain, mtx); + CHECK_EQ(bob_balance, expected_bob_balance); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + CHECK_TEST_CONDITION(std::equal(sizes.begin(),sizes.end(),expected_sizes.begin())); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_unstake_token_1(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_unstake_token_1"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 8*delta_blocks - 1); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 8*delta_blocks + 7); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total+7*delta_events+64]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 510); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity-expected_safex_bob_purchase_from_alice.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(0, staked_tokens); + + uint64_t curr_staked_tokens = c.get_locked_tokens_for_interval(c.get_current_interval()); + CHECK_EQ(0, curr_staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(0, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + //purchase + uint64_t network_fee_collected = c.get_collected_network_fee(0, c.get_current_blockchain_height()); + CHECK_EQ(network_fee_collected, expected_network_fee); + + uint64_t network_fee_intervals = 0; + + for(uint64_t i=0;i<=c.get_current_blockchain_height()/10+1;i++) + network_fee_intervals += c.get_network_fee_for_interval(i); + + CHECK_EQ(network_fee_intervals, expected_network_fee); + + uint64_t alice_balance = get_balance(alice_account, chain, mtx); + CHECK_EQ(alice_balance, expected_alice_balance_after_unstake); + + uint64_t bob_balance = get_balance(bob_account, chain, mtx); + CHECK_EQ(bob_balance, expected_bob_balance); + //unstake token + + uint64_t network_fee_distributed = c.get_distributed_network_fee(0,c.get_current_blockchain_height()); + CHECK_EQ(network_fee_distributed, expected_network_fee); + + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + expected_sizes = sizes; + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_unstake_token(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_unstake_token"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 8*delta_blocks); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 8*delta_blocks + 7); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 7*delta_events + 64 + 64 + 1]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 510 + delta_blocks); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity-expected_safex_bob_purchase_from_alice.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(expected_alice_token_balance, staked_tokens); + + uint64_t curr_staked_tokens = c.get_locked_tokens_for_interval(c.get_current_interval()); + CHECK_EQ(expected_alice_token_balance, curr_staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(expected_alice_token_balance, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(0, get_token_balance(alice_account, blocks, mtx)); + //purchase + uint64_t network_fee_collected = c.get_collected_network_fee(0, c.get_current_blockchain_height()); + CHECK_EQ(network_fee_collected, expected_network_fee); + + uint64_t network_fee_intervals = 0; + + for(uint64_t i=0;i<=c.get_current_blockchain_height()/10+1;i++) + network_fee_intervals += c.get_network_fee_for_interval(i); + + CHECK_EQ(network_fee_intervals, expected_network_fee); + + uint64_t alice_balance = get_balance(alice_account, chain, mtx); + CHECK_EQ(alice_balance, expected_alice_balance); + + uint64_t bob_balance = get_balance(bob_account, chain, mtx); + CHECK_EQ(bob_balance, expected_bob_balance); + //unstake token + + uint64_t network_fee_distributed = c.get_distributed_network_fee(0,c.get_current_blockchain_height()); + CHECK_EQ(network_fee_distributed, 0); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_back_unstake_token(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_back_unstake_token"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 8*delta_blocks + 1); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 8*delta_blocks + 9); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 7*delta_events + 64 + 64 + 4]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 510 + delta_blocks + 1); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity-expected_safex_bob_purchase_from_alice.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(0, staked_tokens); + + uint64_t curr_staked_tokens = c.get_locked_tokens_for_interval(c.get_current_interval()); + CHECK_EQ(0, curr_staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(0, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + //purchase + uint64_t network_fee_collected = c.get_collected_network_fee(0, c.get_current_blockchain_height()); + CHECK_EQ(network_fee_collected, expected_network_fee); + + uint64_t network_fee_intervals = 0; + + for(uint64_t i=0;i<=c.get_current_blockchain_height()/10+1;i++) + network_fee_intervals += c.get_network_fee_for_interval(i); + + CHECK_EQ(network_fee_intervals, expected_network_fee); + + + uint64_t alice_balance = get_balance(alice_account, chain, mtx); + CHECK_EQ(alice_balance, expected_alice_balance_after_unstake); + + uint64_t bob_balance = get_balance(bob_account, chain, mtx); + CHECK_EQ(bob_balance, expected_bob_balance); + //unstake token + + uint64_t network_fee_distributed = c.get_distributed_network_fee(0,c.get_current_blockchain_height()); + CHECK_EQ(network_fee_distributed, expected_network_fee); + + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + CHECK_TEST_CONDITION(std::equal(sizes.begin(),sizes.end(),expected_sizes.begin())); + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_feedback_1(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_feedback_1"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 9*delta_blocks - 1); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 9*delta_blocks + 8); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total+8*delta_events+2 +63]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 510 + delta_blocks + 1); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity-expected_safex_bob_purchase_from_alice.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(0, staked_tokens); + + uint64_t curr_staked_tokens = c.get_locked_tokens_for_interval(c.get_current_interval()); + CHECK_EQ(0, curr_staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(0, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + //purchase + uint64_t network_fee_collected = c.get_collected_network_fee(0, c.get_current_blockchain_height()); + CHECK_EQ(network_fee_collected, expected_network_fee); + + uint64_t network_fee_intervals = 0; + + for(uint64_t i=0;i<=c.get_current_blockchain_height()/10+1;i++) + network_fee_intervals += c.get_network_fee_for_interval(i); + + CHECK_EQ(network_fee_intervals, expected_network_fee); + + uint64_t alice_balance = get_balance(alice_account, chain, mtx); + CHECK_EQ(alice_balance, expected_alice_balance_after_unstake); + + uint64_t bob_balance = get_balance(bob_account, chain, mtx); + CHECK_EQ(bob_balance, expected_bob_balance_after_feedback); + //unstake token + + uint64_t network_fee_distributed = c.get_distributed_network_fee(0,c.get_current_blockchain_height()); + CHECK_EQ(network_fee_distributed, expected_network_fee); + // feedback + std::vector sfx_feedbacks; + + CHECK_TEST_CONDITION(c.get_safex_feedbacks(sfx_feedbacks, expected_alice_safex_offer.offer_id)); + CHECK_TEST_CONDITION(sfx_feedbacks.size() == 1); + + CHECK_EQ(sfx_feedbacks[0].stars_given, expected_bob_feedback.stars_given); + CHECK_EQ(sfx_feedbacks[0].offer_id, expected_bob_feedback.offer_id); + CHECK_EQ(sfx_feedbacks[0].comment, expected_bob_feedback.comment); + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + expected_sizes = sizes; + + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_feedback(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_feedback"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 9*delta_blocks); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 9*delta_blocks + 8); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 8*delta_events + 2 + 63 + 64]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 510 + delta_blocks + delta_blocks); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity-expected_safex_bob_purchase_from_alice.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(0, staked_tokens); + + uint64_t curr_staked_tokens = c.get_locked_tokens_for_interval(c.get_current_interval()); + CHECK_EQ(0, curr_staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(0, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + //purchase + uint64_t network_fee_collected = c.get_collected_network_fee(0, c.get_current_blockchain_height()); + CHECK_EQ(network_fee_collected, expected_network_fee); + + uint64_t network_fee_intervals = 0; + + for(uint64_t i=0;i<=c.get_current_blockchain_height()/10+1;i++) + network_fee_intervals += c.get_network_fee_for_interval(i); + + CHECK_EQ(network_fee_intervals, expected_network_fee); + + uint64_t alice_balance = get_balance(alice_account, chain, mtx); + CHECK_EQ(alice_balance, expected_alice_balance_after_unstake); + + uint64_t bob_balance = get_balance(bob_account, chain, mtx); + CHECK_EQ(bob_balance, expected_bob_balance); + //unstake token + + uint64_t network_fee_distributed = c.get_distributed_network_fee(0,c.get_current_blockchain_height()); + CHECK_EQ(network_fee_distributed, expected_network_fee); + // feedback + std::vector sfx_feedbacks; + + CHECK_TEST_CONDITION(!c.get_safex_feedbacks(sfx_feedbacks, expected_alice_safex_offer.offer_id)); + return true; +} +//----------------------------------------------------------------------------------------------------- +bool gen_simple_chain_split_safex::check_split_switched_back_feedback(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_simple_chain_split_safex::check_split_switched_back_feedback"); + + //check height + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == chekpoint_blocks_total + 9*delta_blocks + 1); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == checkpoint_txs_total + 9*delta_blocks + 10); + CHECK_TEST_CONDITION(c.get_tail_id() == get_block_hash(boost::get(events[checkpoint_events_total + 8*delta_events + 2 + 63 + 64 + 3]))); + CHECK_TEST_CONDITION(c.get_alternative_blocks_count() == 510 + delta_blocks + delta_blocks + 1); + // safex account + std::vector> safex_accounts; + CHECK_TEST_CONDITION(c.get_safex_accounts(safex_accounts)); + + safex::safex_account sfx_account; + bool res = c.get_safex_account_info(safex_account_alice.username,sfx_account); + CHECK_TEST_CONDITION(res); + std::string sfx_account_data{sfx_account.account_data.begin(),sfx_account.account_data.end()}; + CHECK_EQ(sfx_account_data,data_alternative); + CHECK_TEST_CONDITION(safex_accounts.size() == 1); + // safex offer + std::vector safex_offers; + CHECK_TEST_CONDITION(c.get_safex_offers(safex_offers)); + + safex::safex_offer sfx_offer; + res = c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer_edited.offer_id, sfx_offer); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer_edited.price, sfx_offer.price); + CHECK_EQ(expected_alice_safex_offer_edited.min_sfx_price, sfx_offer.min_sfx_price); + CHECK_EQ(expected_alice_safex_offer_edited.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer_edited.quantity-expected_safex_bob_purchase_from_alice.quantity, sfx_offer.quantity); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_offer_edited.description.begin(), expected_alice_safex_offer_edited.description.end(), sfx_offer.description.begin())); + CHECK_EQ(expected_alice_safex_offer_edited.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer_edited.seller_address == sfx_offer.seller_address); + CHECK_TEST_CONDITION(safex_offers.size() == 1); + // safex price peg + std::vector safex_price_pegs; + CHECK_TEST_CONDITION(c.get_safex_price_pegs(safex_price_pegs)); + + safex::safex_price_peg sfx_price_peg; + res = c.get_blockchain_storage().get_safex_price_peg(expected_alice_safex_price_peg_edited.price_peg_id, sfx_price_peg); + CHECK_TEST_CONDITION(res); + CHECK_TEST_CONDITION(expected_alice_safex_price_peg_edited.title.compare(sfx_price_peg.title) == 0); + CHECK_EQ(expected_alice_safex_price_peg_edited.creator, sfx_price_peg.creator); + CHECK_EQ(expected_alice_safex_price_peg_edited.rate, sfx_price_peg.rate); + CHECK_EQ(expected_alice_safex_price_peg_edited.title, sfx_price_peg.title); + CHECK_EQ(expected_alice_safex_price_peg_edited.currency, sfx_price_peg.currency); + CHECK_TEST_CONDITION(std::equal(expected_alice_safex_price_peg_edited.description.begin(), expected_alice_safex_price_peg_edited.description.end(), sfx_price_peg.description.begin())); + CHECK_TEST_CONDITION(safex_price_pegs.size() == 1); + // stake token + uint64_t staked_tokens = c.get_staked_tokens(); + CHECK_EQ(0, staked_tokens); + + uint64_t curr_staked_tokens = c.get_locked_tokens_for_interval(c.get_current_interval()); + CHECK_EQ(0, curr_staked_tokens); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, c.get_current_blockchain_height(), block_list); + CHECK_TEST_CONDITION(r); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + CHECK_EQ(0, get_locked_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + //purchase + uint64_t network_fee_collected = c.get_collected_network_fee(0, c.get_current_blockchain_height()); + CHECK_EQ(network_fee_collected, expected_network_fee); + + uint64_t network_fee_intervals = 0; + + for(uint64_t i=0;i<=c.get_current_blockchain_height()/10+1;i++) + network_fee_intervals += c.get_network_fee_for_interval(i); + + CHECK_EQ(network_fee_intervals, expected_network_fee); + + + uint64_t alice_balance = get_balance(alice_account, chain, mtx); + CHECK_EQ(alice_balance, expected_alice_balance_after_unstake); + + uint64_t bob_balance = get_balance(bob_account, chain, mtx); + CHECK_EQ(bob_balance, expected_bob_balance_after_feedback); + //unstake token + + uint64_t network_fee_distributed = c.get_distributed_network_fee(0,c.get_current_blockchain_height()); + CHECK_EQ(network_fee_distributed, expected_network_fee); + // feedback + std::vector sfx_feedbacks; + + CHECK_TEST_CONDITION(c.get_safex_feedbacks(sfx_feedbacks, expected_alice_safex_offer.offer_id)); + CHECK_TEST_CONDITION(sfx_feedbacks.size() == 1); + + CHECK_EQ(sfx_feedbacks[0].stars_given, expected_bob_feedback.stars_given); + CHECK_EQ(sfx_feedbacks[0].offer_id, expected_bob_feedback.offer_id); + CHECK_EQ(sfx_feedbacks[0].comment, expected_bob_feedback.comment); + + std::vector sizes; + + CHECK_TEST_CONDITION(c.get_table_sizes(sizes)); + + CHECK_TEST_CONDITION(std::equal(sizes.begin(),sizes.end(),expected_sizes.begin())); + + return true; +} diff --git a/tests/core_tests/chain_split_safex.h b/tests/core_tests/chain_split_safex.h new file mode 100644 index 000000000..3ed6f892f --- /dev/null +++ b/tests/core_tests/chain_split_safex.h @@ -0,0 +1,126 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#pragma once +#include "chaingen.h" + +/************************************************************************/ +/* */ +/************************************************************************/ +class gen_simple_chain_split_safex : public test_chain_unit_base +{ +public: + gen_simple_chain_split_safex(); + bool generate(std::vector &events) const; + bool check_split_account_present_1(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_account_present_2(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_account(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_back_account(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_account_edit_1(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_account_edit(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_back_account_edit(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_offer_present_1(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_offer(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_back_offer(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_offer_edit_1(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_offer_edit(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_back_offer_edit(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_price_peg_present_1(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_price_peg(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_back_price_peg(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_price_peg_edit_1(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_price_peg_edit(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_back_price_peg_edit(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_stake_token_1(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_stake_token(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_back_stake_token(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_safex_purchase_1(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_safex_purchase(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_back_safex_purchase(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_unstake_token_1(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_unstake_token(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_back_unstake_token(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_feedback_1(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_feedback(cryptonote::core& c, size_t ev_index, const std::vector &events); + bool check_split_switched_back_feedback(cryptonote::core& c, size_t ev_index, const std::vector &events); + + static bool expected_data_fields_intialized; + static safex::safex_offer expected_alice_safex_offer; + static safex::safex_offer expected_alice_safex_offer_edited; + static safex::safex_price_peg expected_alice_safex_price_peg; + static safex::safex_price_peg expected_alice_safex_price_peg_edited; + static safex::safex_purchase expected_safex_bob_purchase_from_alice; + static safex::safex_feedback expected_bob_feedback; + + static uint64_t expected_staked_tokens; + static uint64_t expected_alice_token_balance; + + static uint64_t expected_network_fee; + static uint64_t expected_alice_balance; + static uint64_t expected_bob_balance; + static uint64_t expected_alice_balance_before_purchase; + static uint64_t expected_bob_balance_before_purchase; + static uint64_t expected_alice_balance_after_unstake; + static uint64_t expected_bob_balance_after_feedback; + + static std::vector expected_sizes; + + cryptonote::account_base alice_account; + cryptonote::account_base account; + + safex::safex_account_key_handler m_safex_account1_keys; + safex::safex_account safex_account_alice; + safex::safex_offer safex_offer_alice; + safex::safex_offer safex_offer_alice_edited; + safex::safex_price_peg safex_price_peg_alice; + safex::safex_price_peg safex_price_peg_alice_edited; + + safex::safex_purchase safex_bob_purchase_from_alice; + + safex::safex_feedback safex_bob_feedback; + + static const std::string data_alternative; + + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", + "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", + "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", + "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", + "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", + "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; + + const uint64_t chekpoint_blocks_total = 139; + const uint64_t checkpoint_txs_total = 142; + const uint64_t checkpoint_events_total = 216; + const uint64_t delta_blocks = 63; + const uint64_t delta_events = 130; + +private: +}; diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 8584ca809..f87215751 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -45,6 +45,9 @@ #include "chaingen.h" #include "device/device.hpp" + +#include "safex/command.h" + using namespace std; using namespace epee; @@ -181,7 +184,9 @@ bool test_generator::construct_block(cryptonote::block& blk, uint64_t height, co // Nonce search... blk.nonce = 0; - while (!miner::find_nonce_for_given_block(NULL, blk, get_test_difficulty(), height)) + while (!miner::find_nonce_for_given_block([](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash){ + return cryptonote::get_block_longhash(NULL, b, hash, height, threads); + }, blk, get_test_difficulty(), height)) blk.timestamp++; const uint8_t hf_version = 1; //hardcode hf version for tests @@ -270,15 +275,18 @@ struct output_index { size_t tx_no; // index of transaction in block size_t out_no; // index of out in transaction size_t idx; + size_t advanced_output_id{0}; bool spent; const cryptonote::block *p_blk; const cryptonote::transaction *p_tx; + cryptonote::tx_out_type out_type{cryptonote::tx_out_type::out_invalid}; output_index(const cryptonote::txout_target_v &_out, uint64_t _a, uint64_t _t_a, size_t _h, size_t tno, size_t ono, const cryptonote::block *_pb, const cryptonote::transaction *_pt) : out(_out), amount(_a), token_amount(_t_a), blk_height(_h), tx_no(tno), out_no(ono), idx(0), spent(false), p_blk(_pb), p_tx(_pt) { } output_index(const output_index &other) - : out(other.out), amount(other.amount), token_amount(other.token_amount), blk_height(other.blk_height), tx_no(other.tx_no), out_no(other.out_no), idx(other.idx), spent(other.spent), p_blk(other.p_blk), p_tx(other.p_tx) { } + : out(other.out), amount(other.amount), token_amount(other.token_amount), blk_height(other.blk_height), tx_no(other.tx_no), out_no(other.out_no), idx(other.idx), + spent(other.spent), p_blk(other.p_blk), p_tx(other.p_tx), advanced_output_id{other.advanced_output_id}, out_type{other.out_type} { } const std::string toString() const { std::stringstream ss; @@ -290,6 +298,7 @@ struct output_index { << " token_amount=" << token_amount << " idx=" << idx << " spent=" << spent + << " out_type=" << static_cast(out_type) << "}"; return ss.str(); @@ -332,8 +341,10 @@ namespace } bool init_output_indices(map_output_idx_t& outs, std::map >& outs_mine, const std::vector& blockchain, const map_hash2tx_t& mtx, - const cryptonote::account_base& from, cryptonote::tx_out_type out_type = cryptonote::tx_out_type::out_cash) { + const cryptonote::account_base& from, cryptonote::tx_out_type out_type = cryptonote::tx_out_type::out_cash, const crypto::public_key& safex_account_pkey = {}) { + int output_id_counter = 0; + int block_height = 0; BOOST_FOREACH (const block& blk, blockchain) { vector vtx; vtx.push_back(&blk.miner_tx); @@ -346,18 +357,23 @@ bool init_output_indices(map_output_idx_t& outs, std::mapsecond); } + //vtx.insert(vtx.end(), blk.); // TODO: add all other txes for (size_t i = 0; i < vtx.size(); i++) { - const transaction &tx = *vtx[i]; + const transaction &tx = *vtx[i]; for (size_t j = 0; j < tx.vout.size(); ++j) { + output_id_counter+=1; const tx_out &out = tx.vout[j]; const crypto::public_key &out_key = *boost::apply_visitor(cryptonote::destination_public_key_visitor(), out.target); - if (out_type == cryptonote::tx_out_type::out_token) + if ((out_type == cryptonote::tx_out_type::out_token) || (out_type == cryptonote::tx_out_type::out_staked_token) + || (out_type == cryptonote::tx_out_type::out_safex_account) || (out_type == cryptonote::tx_out_type::out_safex_account_update) + || (out_type == cryptonote::tx_out_type::out_safex_offer) || (out_type == cryptonote::tx_out_type::out_safex_offer_update) + || (out_type == cryptonote::tx_out_type::out_safex_price_peg) || (out_type == cryptonote::tx_out_type::out_safex_price_peg_update)) { if (out.target.type() == typeid(cryptonote::txout_token_to_key)) { @@ -371,9 +387,39 @@ bool init_output_indices(map_output_idx_t& outs, std::map(out.target); + if ((temp.output_type == static_cast(tx_out_type::out_staked_token)) + || (temp.output_type == static_cast(tx_out_type::out_safex_account)) + || (temp.output_type == static_cast(tx_out_type::out_safex_offer)) + || (temp.output_type == static_cast(tx_out_type::out_safex_price_peg)) + || (temp.output_type == static_cast(tx_out_type::out_safex_price_peg_update)) + || (temp.output_type == static_cast(tx_out_type::out_safex_purchase))) + { + //cast tx_out_type and use it as imaginary amount for advanced outputs + output_index oi(out.target, out.amount, out.token_amount, boost::get(*blk.miner_tx.vin.begin()).height, i, j, &blk, vtx[i]); + outs[static_cast(temp.output_type)].push_back(oi); + size_t tx_global_idx = outs[static_cast(temp.output_type)].size() - 1; + outs[static_cast(temp.output_type)][tx_global_idx].idx = tx_global_idx; + outs[static_cast(temp.output_type)][tx_global_idx].advanced_output_id = output_id_counter-1; + outs[static_cast(temp.output_type)][tx_global_idx].blk_height = block_height; + outs[static_cast(temp.output_type)][tx_global_idx].out_type = static_cast(temp.output_type); + + // Is out to me? + if (is_safex_out_to_acc(safex_account_pkey, out_key)) { + outs_mine[static_cast(temp.output_type)].push_back(tx_global_idx); + } + else if (is_out_to_acc(from.get_keys(), out_key, get_tx_pub_key_from_extra(tx), get_additional_tx_pub_keys_from_extra(tx), j)) + { + outs_mine[static_cast(temp.output_type)].push_back(tx_global_idx); + } + } + } } - else if (out_type == cryptonote::tx_out_type::out_cash) + else if ((out_type == cryptonote::tx_out_type::out_cash) || (out_type == cryptonote::tx_out_type::out_network_fee) + || (out_type == cryptonote::tx_out_type::out_safex_purchase)) { if (out.target.type() == typeid(cryptonote::txout_to_key)) { // out_to_key @@ -389,10 +435,28 @@ bool init_output_indices(map_output_idx_t& outs, std::map(out.target); + if(temp.output_type == static_cast(tx_out_type::out_safex_feedback_token)) + { + output_index oi(out.target, out.amount, out.token_amount, boost::get(*blk.miner_tx.vin.begin()).height, i, j, &blk, vtx[i]); + outs[static_cast(temp.output_type)].push_back(oi); + size_t tx_global_idx = outs[static_cast(temp.output_type)].size() - 1; + outs[static_cast(temp.output_type)][tx_global_idx].idx = tx_global_idx; + outs[static_cast(temp.output_type)][tx_global_idx].advanced_output_id = output_id_counter-1; + outs[static_cast(temp.output_type)][tx_global_idx].blk_height = block_height; + outs[static_cast(temp.output_type)][tx_global_idx].out_type = static_cast(temp.output_type); + if (is_out_to_acc(from.get_keys(), out_key, get_tx_pub_key_from_extra(tx), get_additional_tx_pub_keys_from_extra(tx), j)) + { + outs_mine[static_cast(temp.output_type)].push_back(tx_global_idx); + } + } + } } } + block_height++; } return true; @@ -411,6 +475,9 @@ bool init_spent_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, const crypto::public_key &out_key = *boost::apply_visitor(destination_public_key_visitor(), oi.out); std::unordered_map subaddresses; subaddresses[from.get_keys().m_account_address.m_spend_public_key] = {0,0}; + if(oi.out_type == cryptonote::tx_out_type::out_safex_account || oi.out_type == cryptonote::tx_out_type::out_safex_offer || + oi.out_type == cryptonote::tx_out_type::out_safex_price_peg) + continue; //key image check not relevant generate_key_image_helper(from.get_keys(), subaddresses, out_key, get_tx_pub_key_from_extra(*oi.p_tx), get_additional_tx_pub_keys_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, img, hw::get_device(("default"))); // lookup for this key image in the events vector @@ -434,6 +501,87 @@ bool init_spent_output_indices(map_output_idx_t& outs, map_output_t& outs_mine, return true; } +bool create_network_token_lock_interest_map(const std::vector &events, const block &blk_head, safex::map_interval_interest &interest_map) +{ + + std::vector blockchain; + map_hash2tx_t mtx; + if (!find_block_chain(events, blockchain, mtx, get_block_hash(blk_head))) + return false; + + int block_height_counter = 0; + int current_interval = 0; + uint64_t interval_collected_fee = 0; + uint64_t currently_locked_tokens = 0; + + BOOST_FOREACH (const block &blk, blockchain) + { + vector vtx; + vtx.push_back(&blk.miner_tx); + + BOOST_FOREACH(const crypto::hash &h, blk.tx_hashes) + { + const map_hash2tx_t::const_iterator cit = mtx.find(h); + if (mtx.end() == cit) + throw std::runtime_error("block contains an unknown tx hash"); + + vtx.push_back(cit->second); + } + + for (size_t i = 0; i < vtx.size(); i++) + { + const transaction &tx = *vtx[i]; + + for (size_t j = 0; j < tx.vin.size(); ++j) + { + const txin_v &txin = tx.vin[j]; + if (txin.type() == typeid(txin_to_script)) { + const txin_to_script &in = boost::get(txin); + if (in.command_type == safex::command_t::token_unstake) { + currently_locked_tokens -= in.token_amount; + } + } + + + + + + } + + for (size_t j = 0; j < tx.vout.size(); ++j) { + const tx_out &out = tx.vout[j]; + + if (out.target.type() == typeid(cryptonote::txout_to_script)) { + const txout_to_script &temp = boost::get(out.target); + if (temp.output_type == static_cast(tx_out_type::out_staked_token)) { + currently_locked_tokens += out.token_amount; + } else if (temp.output_type == static_cast(tx_out_type::out_network_fee)) { + interval_collected_fee += out.amount; + } + } + } + + + + } + block_height_counter++; + current_interval = safex::calculate_interval_for_height(block_height_counter, + cryptonote::network_type::FAKECHAIN); + + if (safex::is_interval_last_block(block_height_counter, cryptonote::network_type::FAKECHAIN)) { + uint64_t whole_token_amount = currently_locked_tokens/SAFEX_TOKEN; + uint64_t interest_per_token = interval_collected_fee>0? interval_collected_fee/whole_token_amount:0; + interest_map[current_interval] = interest_per_token; + if (interest_per_token>0) std::cout << "For interval "<& out_indices, size_t sender_out, size_t nmix, size_t& real_entry_idx, std::vector& output_entries) { if (out_indices.size() <= nmix) @@ -470,9 +618,57 @@ bool fill_output_entries(std::vector& out_indices, size_t sender_o return 0 == rest && sender_out_found; } +bool fill_output_entries_advanced(std::vector& out_indices, size_t sender_out, size_t nmix, size_t& real_entry_idx, std::vector& output_entries) +{ + if (out_indices.size() <= nmix) + return false; + + bool sender_out_found = false; + size_t rest = nmix; + for (size_t i = 0; i < out_indices.size() && (0 < rest || !sender_out_found); ++i) + { + const output_index& oi = out_indices[i]; + if (oi.spent) + continue; + + bool append = false; + if (i == sender_out) + { + append = true; + sender_out_found = true; + real_entry_idx = output_entries.size(); + } + else if (0 < rest) + { + --rest; + append = true; + } + + if (append) + { + if (oi.out_type == tx_out_type::out_safex_account) { + crypto::public_key key{}; + if (!safex::parse_safex_account_key(oi.out, key)) { + return false; + } + output_entries.push_back(tx_source_entry::output_entry(oi.idx, rct::ctkey({rct::pk2rct(key), rct::identity()}))); + + } + else + { + const crypto::public_key &key = *boost::apply_visitor(destination_public_key_visitor(), oi.out); + output_entries.push_back(tx_source_entry::output_entry(oi.idx, rct::ctkey({rct::pk2rct(key), rct::identity()}))); + } + } + } + + return 0 == rest && sender_out_found; +} + bool fill_tx_sources(std::vector& sources, const std::vector& events, const block& blk_head, const cryptonote::account_base& from, uint64_t value_amount, size_t nmix, - cryptonote::tx_out_type out_type = cryptonote::tx_out_type::out_cash) + cryptonote::tx_out_type out_type = cryptonote::tx_out_type::out_cash, + const crypto::public_key& safex_account_pkey = {}) { map_output_idx_t outs; map_output_t outs_mine; @@ -482,7 +678,7 @@ bool fill_tx_sources(std::vector& sources, const std::vector& sources, const std::vector 0 && out_type == cryptonote::tx_out_type::out_cash) || - (oi.amount > 0 && out_type == cryptonote::tx_out_type::out_token)) + const output_index &oi = outs[o.first][sender_out]; + if ((oi.spent) || (oi.token_amount > 0 && (out_type == cryptonote::tx_out_type::out_cash || out_type == cryptonote::tx_out_type::out_network_fee || out_type == cryptonote::tx_out_type::out_safex_purchase)) || + (oi.amount > 0 && (out_type == cryptonote::tx_out_type::out_token || out_type == cryptonote::tx_out_type::out_staked_token || out_type == cryptonote::tx_out_type::out_safex_account))) + continue; + + if ((out_type == cryptonote::tx_out_type::out_safex_account_update || out_type == cryptonote::tx_out_type::out_safex_offer || out_type == cryptonote::tx_out_type::out_safex_price_peg) + && oi.out_type != cryptonote::tx_out_type::out_safex_account) continue; + if (out_type == cryptonote::tx_out_type::out_safex_offer_update && oi.out_type != cryptonote::tx_out_type::out_safex_offer) + continue; + + if(out_type == cryptonote::tx_out_type::out_safex_feedback && oi.out_type != cryptonote::tx_out_type::out_safex_feedback_token) + continue; + + if(out_type == cryptonote::tx_out_type::out_safex_price_peg_update && oi.out_type != cryptonote::tx_out_type::out_safex_price_peg) + continue; + cryptonote::tx_source_entry ts = AUTO_VAL_INIT(ts); if (out_type == cryptonote::tx_out_type::out_cash) - ts.amount = oi.amount; + { + ts.amount = oi.amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_cash; + } else if (out_type == cryptonote::tx_out_type::out_token) { ts.token_amount = oi.token_amount; - ts.token_transaction = true; + ts.referenced_output_type = cryptonote::tx_out_type::out_token; } + else if (out_type == cryptonote::tx_out_type::out_staked_token) + { + ts.token_amount = oi.token_amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_token; + ts.command_type = safex::command_t::token_stake; + } + else if (out_type == cryptonote::tx_out_type::out_network_fee) + { + ts.amount = oi.amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_cash; + ts.command_type = safex::command_t::donate_network_fee; + } + else if (out_type == cryptonote::tx_out_type::out_safex_account) + { + ts.token_amount = oi.token_amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_token; + ts.command_type = safex::command_t::create_account; + } + else if (out_type == cryptonote::tx_out_type::out_safex_account_update) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_account; + ts.command_type = safex::command_t::edit_account; + } + else if (out_type == cryptonote::tx_out_type::out_safex_offer) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_account; + ts.command_type = safex::command_t::create_offer; + } + else if (out_type == cryptonote::tx_out_type::out_safex_offer_update) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_offer; + ts.command_type = safex::command_t::edit_offer; + } + else if (out_type == cryptonote::tx_out_type::out_safex_purchase) + { + ts.amount = oi.amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_cash; + ts.command_type = safex::command_t::simple_purchase; + } + else if (out_type == cryptonote::tx_out_type::out_safex_feedback) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_feedback_token; + ts.command_type = safex::command_t::create_feedback; + } + else if (out_type == cryptonote::tx_out_type::out_safex_price_peg) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_account; + ts.command_type = safex::command_t::create_price_peg; + } + else if (out_type == cryptonote::tx_out_type::out_safex_price_peg_update) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_price_peg; + ts.command_type = safex::command_t::update_price_peg; + } + else + { + throw std::runtime_error("unknown referenced output type"); + } + ts.real_output_in_tx_index = oi.out_no; ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // incoming tx public key size_t realOutput; - if (!fill_output_entries(outs[o.first], sender_out, nmix, realOutput, ts.outputs)) - continue; + + switch (out_type) { + case cryptonote::tx_out_type::out_safex_account_update: + case cryptonote::tx_out_type::out_safex_offer: + case cryptonote::tx_out_type::out_safex_offer_update: + case cryptonote::tx_out_type::out_safex_feedback: + case cryptonote::tx_out_type::out_safex_price_peg: + case cryptonote::tx_out_type::out_safex_price_peg_update: + { + if (!fill_output_entries_advanced(outs[static_cast(ts.referenced_output_type)], sender_out, nmix, realOutput, ts.outputs)) + continue; + sources_found = true; + } + break; + + case cryptonote::tx_out_type::out_cash: + case cryptonote::tx_out_type::out_token: + case cryptonote::tx_out_type::out_network_fee: + case cryptonote::tx_out_type::out_staked_token: + case cryptonote::tx_out_type::out_safex_account: + case cryptonote::tx_out_type::out_safex_purchase: + default: + { + if (!fill_output_entries(outs[o.first], sender_out, nmix, realOutput, ts.outputs)) + continue; + } + break; + } ts.real_output = realOutput; - ts.rct = false; sources.push_back(ts); - if (out_type == cryptonote::tx_out_type::out_cash) - { - sources_cash_amount += ts.amount; - sources_found = value_amount <= sources_cash_amount; - } - else if (out_type == cryptonote::tx_out_type::out_token) - { - sources_token_amount += ts.token_amount; - sources_found = value_amount <= sources_token_amount; - } - - + if ((out_type == cryptonote::tx_out_type::out_cash) || + (out_type == cryptonote::tx_out_type::out_network_fee) + || (out_type == cryptonote::tx_out_type::out_safex_purchase)) + { + sources_cash_amount += ts.amount; + sources_found = value_amount <= sources_cash_amount; + } + else if ((out_type == cryptonote::tx_out_type::out_token) + || (out_type == cryptonote::tx_out_type::out_staked_token) + || (out_type == cryptonote::tx_out_type::out_safex_account)) + { + sources_token_amount += ts.token_amount; + sources_found = value_amount <= sources_token_amount; + } + else if (out_type == cryptonote::tx_out_type::out_safex_feedback) + sources_found = true; } if (sources_found) @@ -542,6 +842,96 @@ bool fill_tx_sources(std::vector& sources, const std::vector 0) std::cout << "Interest in interval "< &sources, const std::vector &events, const block &blk_head, + const cryptonote::account_base &from, uint64_t value_amount, size_t nmix, cryptonote::tx_out_type out_type = cryptonote::tx_out_type::out_staked_token) +{ + map_output_idx_t outs; + map_output_t outs_mine; + + std::vector blockchain; + + map_hash2tx_t mtx; + if (!find_block_chain(events, blockchain, mtx, get_block_hash(blk_head))) return false; + + uint64_t current_height = blockchain.size(); + + if (!init_output_indices(outs, outs_mine, blockchain, mtx, from, out_type)) return false; + + if (!init_spent_output_indices(outs, outs_mine, blockchain, mtx, from)) return false; + + //insert fee calculation here + safex::map_interval_interest interest_map; + if (!create_network_token_lock_interest_map(events, blk_head, interest_map)) return false; + + // Iterate in reverse is more efficiency + uint64_t sources_locked_token_amount = 0; + bool sources_found = false; + BOOST_REVERSE_FOREACH(const map_output_t::value_type o, outs_mine) + { + for (size_t i = 0; i < o.second.size() && !sources_found; ++i) + { + size_t sender_out = o.second[i]; + const output_index &oi = outs[o.first][sender_out]; + if ((oi.spent) || (oi.token_amount > 0 && out_type == cryptonote::tx_out_type::out_cash) + || (oi.amount > 0 && (out_type == cryptonote::tx_out_type::out_token || out_type == cryptonote::tx_out_type::out_staked_token)) + || (oi.out.type() != typeid(txout_to_script))) + continue; + + + const cryptonote::txout_to_script &out = boost::get(oi.out); + + if (out.output_type != static_cast(cryptonote::tx_out_type::out_staked_token)) + continue; + + cryptonote::tx_source_entry ts = AUTO_VAL_INIT(ts); + ts.token_amount = oi.token_amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_staked_token; + ts.command_type = safex::command_t::token_unstake; + ts.real_output_in_tx_index = oi.out_no; + ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // incoming tx public key + size_t realOutput; + if (!fill_output_entries_advanced(outs[o.first], sender_out, nmix, realOutput, ts.outputs)) + continue; + ts.real_output = realOutput; + + sources_locked_token_amount = ts.token_amount; + sources_found = value_amount == sources_locked_token_amount; + + if (sources_found) + { + + ts.amount = calculate_token_holder_interest_for_output(oi.blk_height, current_height, interest_map, oi.token_amount); + sources.push_back(ts); + + } + + + } + + if (sources_found) + break; + } + + return sources_found; +} + + bool fill_migration_tx_sources(std::vector& sources, const std::vector& events, const block& blk_head, const cryptonote::account_base& from, uint64_t token_amount, uint64_t cash_airdrop_amount, const crypto::hash &bitcoin_transaction_hash) @@ -581,7 +971,6 @@ bool fill_migration_tx_sources(std::vector& sources, const std: continue; ts.real_output = realOutput; - ts.rct = false; sources.push_back(ts); @@ -601,9 +990,7 @@ bool fill_migration_tx_sources(std::vector& sources, const std: auto output = cryptonote::generate_migration_bitcoin_transaction_output(from.get_keys(), bitcoin_transaction_hash, token_amount); src.outputs.push_back(output); src.token_amount = token_amount; - src.rct = false; - src.token_transaction = true; - src.migration = true; + src.referenced_output_type = cryptonote::tx_out_type::out_bitcoin_migration; return sources_found; @@ -613,6 +1000,7 @@ bool fill_migration_tx_sources(std::vector& sources, const std: bool fill_tx_destination(tx_destination_entry &de, const cryptonote::account_base &to, uint64_t amount) { de.addr = to.get_keys().m_account_address; de.amount = amount; + de.output_type = cryptonote::tx_out_type::out_cash; return true; } @@ -620,6 +1008,7 @@ bool fill_token_tx_destination(tx_destination_entry &de, const cryptonote::accou de.addr = to.get_keys().m_account_address; de.token_amount = token_amount; de.token_transaction = true; + de.output_type = cryptonote::tx_out_type::out_token; return true; } @@ -727,50 +1116,556 @@ void fill_token_tx_sources_and_destinations(const std::vector& } } +tx_destination_entry create_tx_destination(const cryptonote::account_base &to, uint64_t amount) +{ + return tx_destination_entry{amount, to.get_keys().m_account_address, false, tx_out_type::out_cash}; +} -void fill_nonce(cryptonote::block& blk, const difficulty_type& diffic, uint64_t height) +tx_destination_entry create_token_tx_destination(const cryptonote::account_base &to, uint64_t token_amount) { - blk.nonce = 0; - while (!miner::find_nonce_for_given_block(NULL, blk, diffic, height)) - blk.timestamp++; + return tx_destination_entry{token_amount, to.get_keys().m_account_address, false, tx_out_type::out_token}; } -bool construct_miner_tx_manually(size_t height, uint64_t already_generated_coins, - const account_public_address& miner_address, transaction& tx, uint64_t fee, - keypair* p_txkey/* = 0*/) +tx_destination_entry create_locked_token_tx_destination(const cryptonote::account_base &to, uint64_t token_amount) { - keypair txkey; - txkey = keypair::generate(hw::get_device("default")); - add_tx_pub_key_to_extra(tx, txkey.pub); + return tx_destination_entry{token_amount, to.get_keys().m_account_address, false, tx_out_type::out_staked_token}; +} - if (0 != p_txkey) - *p_txkey = txkey; +tx_destination_entry create_network_fee_tx_destination(uint64_t cash_amount) +{ + account_public_address dummy = AUTO_VAL_INIT(dummy); + return tx_destination_entry{cash_amount, dummy, false, tx_out_type::out_network_fee}; +} - txin_gen in; - in.height = height; - tx.vin.push_back(in); +tx_destination_entry create_interest_destination(const cryptonote::account_base &to, uint64_t cash_amount) +{ + return tx_destination_entry{cash_amount, to.get_keys().m_account_address, false, tx_out_type::out_cash}; +} - // This will work, until size of constructed block is less then CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE - uint64_t block_reward; - if (!get_block_reward(0, 0, already_generated_coins, block_reward, 1, height)) +void fill_token_stake_tx_sources_and_destinations(const std::vector &events, const block &blk_head, + const cryptonote::account_base &from, const cryptonote::account_base &to, uint64_t token_amount, uint64_t fee, size_t nmix, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + //fill cache sources for fee + if (!fill_tx_sources(sources, events, blk_head, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + //token source + if (!fill_tx_sources(sources, events, blk_head, from, token_amount, nmix, cryptonote::tx_out_type::out_staked_token)) + throw std::runtime_error("couldn't fill token transaction sources for tokens to lock"); + + //locked token destination + tx_destination_entry de = create_locked_token_tx_destination(to, token_amount); + destinations.push_back(de); + + //destination token change + + uint64_t token_back = get_inputs_token_amount(sources) - token_amount; + if (0 < token_back) { - LOG_PRINT_L0("Block is too big"); - return false; + tx_destination_entry de_token_change = create_token_tx_destination(from, token_back); + destinations.push_back(de_token_change); } - block_reward += fee; - crypto::key_derivation derivation; - crypto::public_key out_eph_public_key; - crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation); - crypto::derive_public_key(derivation, 0, miner_address.m_spend_public_key, out_eph_public_key); + //sender change for fee - tx_out out; - out.amount = block_reward; - out.target = txout_to_key(out_eph_public_key); - tx.vout.push_back(out); + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } +} - tx.version = 1; - tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; + +void fill_token_unstake_tx_sources_and_destinations(const std::vector &events, const block &blk_head, const cryptonote::account_base &from, const cryptonote::account_base &to, + uint64_t token_amount, uint64_t fee, size_t nmix, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + //fill cache sources for fee + if (!fill_tx_sources(sources, events, blk_head, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + //locked token source + if (!fill_unstake_token_sources(sources, events, blk_head, from, token_amount, nmix)) + throw std::runtime_error("couldn't fill token transaction sources for tokens to unlock"); + + + //locked token destination, there is no token change, all tokens are unlocked + tx_destination_entry de_token = create_token_tx_destination(to, token_amount); + destinations.push_back(de_token); + + // Interest destination is added in construct_advanced_tx_with_tx_key, review if this is optimal + tx_destination_entry de_interest = AUTO_VAL_INIT(de_interest); + for (tx_source_entry &source: sources) { + if (source.command_type == safex::command_t::token_unstake && source.amount > 0) { + de_interest = create_interest_destination(to, source.amount); + } + } + + + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee - de_interest.amount; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } +} + +void fill_donation_tx_sources_and_destinations(const std::vector& events, const block& blk_head, + const cryptonote::account_base &from, uint64_t cash_amount, uint64_t fee, size_t nmix, + std::vector &sources, std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + //fill cache sources for fee + if (!fill_tx_sources(sources, events, blk_head, from, fee+cash_amount, nmix, cryptonote::tx_out_type::out_network_fee)) + throw std::runtime_error("couldn't fill transaction sources"); + + //fee donation, txout_to_script + tx_destination_entry de_donation_fee = create_network_fee_tx_destination(cash_amount); + destinations.push_back(de_donation_fee); + + //sender change for fee + + uint64_t cache_back = get_inputs_amount(sources) - fee - cash_amount; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } +} + +void fill_create_account_sources_and_destinations(const std::vector& events, const block& blk_head, + const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const std::string &username, const crypto::public_key &pkey, + const std::vector &account_data, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //token amount is amount of tokens we want to lock for a period for creating account + + //fill cache sources for fee + if (!fill_tx_sources(sources, events, blk_head, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + //safex account command source + if (!fill_tx_sources(sources, events, blk_head, from, token_amount, nmix, cryptonote::tx_out_type::out_safex_account)) + throw std::runtime_error("couldn't fill token transaction sources for create account"); + + //update source with new account data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::create_account) { + safex::create_account_data account{username, pkey, account_data}; + ts.command_safex_data = t_serializable_object_to_blob(account); + } + + } + + //destinations + + //locked token destination + tx_destination_entry de_token = create_token_tx_destination(to, token_amount); + destinations.push_back(de_token); + + //destination token change + uint64_t token_back = get_inputs_token_amount(sources) - token_amount; + if (0 < token_back) + { + tx_destination_entry de_token_change = create_token_tx_destination(from, token_back); + destinations.push_back(de_token_change); + } + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //account + tx_destination_entry de_account = create_safex_account_destination(from.get_keys().m_account_address, username, pkey, account_data); + destinations.push_back(de_account); +} + +void fill_edit_account_tx_sources_and_destinations(const std::vector& events, const block& blk_head, + const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const std::string &username, const std::vector &new_account_data, std::vector &sources, + std::vector &destinations, const crypto::public_key& safex_account_pkey = {}) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee + if (!fill_tx_sources(sources, events, blk_head, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + if (!fill_tx_sources(sources, events, blk_head, from, 0, nmix, cryptonote::tx_out_type::out_safex_account_update, safex_account_pkey)) + throw std::runtime_error("couldn't fill token transaction sources for edit account"); + + //update source with new account data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::edit_account) { + safex::edit_account_data editaccount{username, new_account_data}; + ts.command_safex_data = t_serializable_object_to_blob(editaccount); + } + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //new_account + tx_destination_entry de_account = edit_safex_account_destination(from.get_keys().m_account_address, username, new_account_data); + destinations.push_back(de_account); + +} + +void fill_create_offer_sources_and_destinations(const std::vector& events, const block& blk_head, + const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const safex::safex_offer &sfx_offer, std::vector &sources, + std::vector &destinations, const crypto::public_key& safex_account_pkey = {}){ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //token amount is amount of tokens we want to lock for a period for creating offer + + //fill cache sources for fee + if (!fill_tx_sources(sources, events, blk_head, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + //safex offer command source + if (!fill_tx_sources(sources, events, blk_head, from, token_amount, nmix, cryptonote::tx_out_type::out_safex_offer, safex_account_pkey)) + throw std::runtime_error("couldn't fill token transaction sources for create offer"); + + //update source with offer data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::create_offer) { + safex::create_offer_data offer{sfx_offer}; + ts.command_safex_data = t_serializable_object_to_blob(offer); + } + + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //offer + tx_destination_entry de_offer = create_safex_offer_destination(from.get_keys().m_account_address, sfx_offer); + destinations.push_back(de_offer); +} + +void fill_edit_offer_sources_and_destinations(const std::vector& events, const block& blk_head, + const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const safex::safex_offer &sfx_offer, std::vector &sources, + std::vector &destinations, const crypto::public_key& safex_account_pkey = {}){ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //token amount is amount of tokens we want to lock for a period for creating offer + + //fill cache sources for fee + if (!fill_tx_sources(sources, events, blk_head, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + //safex offer command source + if (!fill_tx_sources(sources, events, blk_head, from, token_amount, nmix, cryptonote::tx_out_type::out_safex_offer_update, safex_account_pkey)) + throw std::runtime_error("couldn't fill token transaction sources for edit offer"); + + //update source with offer data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::edit_offer) { + safex::edit_offer_data offer{sfx_offer}; + ts.command_safex_data = t_serializable_object_to_blob(offer); + } + + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //offer + tx_destination_entry de_offer = edit_safex_offer_destination(from.get_keys().m_account_address, sfx_offer); + destinations.push_back(de_offer); +} + +void fill_create_purchase_tx_sources_and_destinations(const std::vector& events, const block& blk_head, + const cryptonote::account_base &from, uint64_t cash_amount, uint64_t fee, + size_t nmix, const safex::safex_purchase &sfx_purchase, + const cryptonote::account_public_address seller_address, + std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee +// if (!fill_tx_sources(txmap, blocks, sources, from, sfx_purchase.price.price*5/100, nmix, cryptonote::tx_out_type::out_network_fee)) +// throw std::runtime_error("couldn't fill transaction sources"); + //fill cache sources for fee + if (!fill_tx_sources(sources, events, blk_head, from, 0, nmix, cryptonote::tx_out_type::out_safex_purchase)) + throw std::runtime_error("couldn't fill transaction sources for create purchase"); + + + + //update source with create purchase data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::simple_purchase) { + safex::create_purchase_data purchase_data{sfx_purchase}; + ts.command_safex_data = t_serializable_object_to_blob(purchase_data); + } + } + + //destinations + + //fee donation, txout_to_script + + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee - cash_amount; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //purchase + tx_destination_entry de_purchase = create_safex_purchase_destination(seller_address, sfx_purchase); + destinations.push_back(de_purchase); + + //feedback_token + safex::safex_feedback_token sfx_feedback_token; + sfx_feedback_token.offer_id = sfx_purchase.offer_id; + tx_destination_entry de_feedback_token = create_safex_feedback_token_destination(from.get_keys().m_account_address, sfx_feedback_token); + destinations.push_back(de_feedback_token); + + + tx_destination_entry de_donation_fee = AUTO_VAL_INIT(de_donation_fee); + de_donation_fee.addr = from.get_keys().m_account_address; + de_donation_fee.amount = calculate_safex_network_fee(sfx_purchase.price, FAKECHAIN, safex::command_t::simple_purchase); + de_donation_fee.script_output = true; + de_donation_fee.output_type = tx_out_type::out_network_fee; + destinations.push_back(de_donation_fee); + + cryptonote::tx_destination_entry item_purchase_fee = AUTO_VAL_INIT(item_purchase_fee); + item_purchase_fee.addr = seller_address; + item_purchase_fee.amount = sfx_purchase.price - de_donation_fee.amount; + item_purchase_fee.output_type = tx_out_type::out_cash; + destinations.push_back(item_purchase_fee); +} + +void fill_create_feedback_tx_sources_and_destinations(const std::vector& events, const block& blk_head, + const cryptonote::account_base &from, uint64_t cash_amount, uint64_t fee, + size_t nmix, const safex::safex_feedback &sfx_feedback, + std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee + if (!fill_tx_sources(sources, events, blk_head, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + //fill cache sources for feedback + if (!fill_tx_sources(sources, events, blk_head, from, 0, nmix, cryptonote::tx_out_type::out_safex_feedback)) + throw std::runtime_error("couldn't fill transaction sources for create feedback"); + + + + //update source with create feedback data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::create_feedback) { + safex::create_feedback_data feedback_data{sfx_feedback}; + ts.command_safex_data = t_serializable_object_to_blob(feedback_data); + } + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //feedback + tx_destination_entry de_feedback = create_safex_feedback_destination(from.get_keys().m_account_address, sfx_feedback); + destinations.push_back(de_feedback); +} + +void fill_create_price_peg_sources_and_destinations(const std::vector& events, const block& blk_head, + const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const safex::safex_price_peg &sfx_price_peg, std::vector &sources, + std::vector &destinations, const crypto::public_key& safex_account_pkey = {}){ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee + if (!fill_tx_sources(sources, events, blk_head, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + //safex price peg command source + if (!fill_tx_sources(sources, events, blk_head, from, token_amount, nmix, cryptonote::tx_out_type::out_safex_price_peg, safex_account_pkey)) + throw std::runtime_error("couldn't fill token transaction sources for create price peg"); + + //update source with price peg data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::create_price_peg) { + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + ts.command_safex_data = t_serializable_object_to_blob(price_peg_data); + } + + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //offer + tx_destination_entry de_price_peg = create_safex_price_peg_destination(from.get_keys().m_account_address, sfx_price_peg); + destinations.push_back(de_price_peg); +} + +void fill_update_price_peg_sources_and_destinations(const std::vector& events, const block& blk_head, + const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const safex::safex_price_peg &sfx_price_peg, std::vector &sources, + std::vector &destinations, const crypto::public_key& safex_account_pkey = {}){ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee + if (!fill_tx_sources(sources, events, blk_head, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + //safex price peg command source + if (!fill_tx_sources(sources, events, blk_head, from, token_amount, nmix, cryptonote::tx_out_type::out_safex_price_peg_update, safex_account_pkey)) + throw std::runtime_error("couldn't fill token transaction sources for update price peg"); + + //update source with price peg data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::update_price_peg) { + safex::update_price_peg_data price_peg_data{sfx_price_peg}; + ts.command_safex_data = t_serializable_object_to_blob(price_peg_data); + } + + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //offer + tx_destination_entry de_price_peg = update_safex_price_peg_destination(from.get_keys().m_account_address, sfx_price_peg); + destinations.push_back(de_price_peg); +} + +void fill_nonce(cryptonote::block& blk, const difficulty_type& diffic, uint64_t height) +{ + blk.nonce = 0; + while (!miner::find_nonce_for_given_block([](const cryptonote::block &b, uint64_t height, unsigned int threads, crypto::hash &hash){ + return cryptonote::get_block_longhash(NULL, b, hash, height, threads); + }, blk, diffic, height)) + blk.timestamp++; +} + +bool construct_miner_tx_manually(size_t height, uint64_t already_generated_coins, + const account_public_address& miner_address, transaction& tx, uint64_t fee, + keypair* p_txkey/* = 0*/) +{ + keypair txkey; + txkey = keypair::generate(hw::get_device("default")); + add_tx_pub_key_to_extra(tx, txkey.pub); + + if (0 != p_txkey) + *p_txkey = txkey; + + txin_gen in; + in.height = height; + tx.vin.push_back(in); + + // This will work, until size of constructed block is less then CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE + uint64_t block_reward; + if (!get_block_reward(0, 0, already_generated_coins, block_reward, 1, height)) + { + LOG_PRINT_L0("Block is too big"); + return false; + } + block_reward += fee; + + crypto::key_derivation derivation; + crypto::public_key out_eph_public_key; + crypto::generate_key_derivation(miner_address.m_view_public_key, txkey.sec, derivation); + crypto::derive_public_key(derivation, 0, miner_address.m_spend_public_key, out_eph_public_key); + + tx_out out; + out.amount = block_reward; + out.target = txout_to_key(out_eph_public_key); + tx.vout.push_back(out); + + tx.version = 1; + tx.unlock_time = height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; return true; } @@ -820,6 +1715,119 @@ transaction construct_tx_with_fee(std::vector& events, const b return tx; } +bool construct_token_stake_tx(const std::vector &events, cryptonote::transaction &tx, const block &blk_head, + const cryptonote::account_base &user_account, uint64_t token_amount, uint64_t fee, size_t nmix) +{ + std::vector sources; + std::vector destinations; + fill_token_stake_tx_sources_and_destinations(events, blk_head, user_account, user_account, token_amount, fee, nmix, sources, destinations); + + return construct_tx(user_account.get_keys(), sources, destinations, user_account.get_keys().m_account_address, std::vector(), tx, 0); +} + +bool construct_token_unstake_tx(const std::vector &events, cryptonote::transaction &tx, const block &blk_head, + const cryptonote::account_base &from, uint64_t token_amount, uint64_t fee, size_t nmix) +{ + std::vector sources; + std::vector destinations; + fill_token_unstake_tx_sources_and_destinations(events, blk_head, from, from, token_amount, fee, nmix, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0); +} + +bool construct_fee_donation_transaction(const std::vector& events, cryptonote::transaction &tx, const block& blk_head, + const cryptonote::account_base &from, uint64_t cash_amount, uint64_t fee, size_t nmix) +{ + std::vector sources; + std::vector destinations; + + fill_donation_tx_sources_and_destinations(events, blk_head, from, cash_amount, fee, nmix, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0); +} + +bool construct_create_account_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, + const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const std::string &username, const crypto::public_key &pkey, const std::vector &account_data, uint64_t unlock_time, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_create_account_sources_and_destinations(events, blk_head, from, SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE, fee, nmix, username, pkey, account_data, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx , unlock_time, sfx_acc_keys); +} + +bool construct_edit_account_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, + const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const std::string &username, const std::vector &new_account_data, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_edit_account_tx_sources_and_destinations(events, blk_head, from, 0, fee, nmix, username, new_account_data, sources, destinations, sfx_acc_keys.get_public_key()); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0, sfx_acc_keys); +} + +bool construct_create_offer_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_offer& sfx_offer, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_create_offer_sources_and_destinations(events, blk_head, from, 0, fee, nmix, sfx_offer, sources, destinations, sfx_acc_keys.get_public_key()); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0, sfx_acc_keys); +} + +bool construct_edit_offer_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_offer& sfx_offer, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_edit_offer_sources_and_destinations(events, blk_head, from, 0, fee, nmix, sfx_offer, sources, destinations, sfx_acc_keys.get_public_key()); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0, sfx_acc_keys); +} + +bool construct_create_purchase_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const safex::safex_purchase &sfx_purchase, const cryptonote::account_public_address seller_address){ + + std::vector sources; + std::vector destinations; + fill_create_purchase_tx_sources_and_destinations(events, blk_head, from, sfx_purchase.price, fee, nmix, sfx_purchase, seller_address, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0); +} + +bool construct_create_feedback_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const safex::safex_feedback &sfx_feedback){ + + std::vector sources; + std::vector destinations; + fill_create_feedback_tx_sources_and_destinations(events, blk_head, from, 0, fee, nmix, sfx_feedback, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0); +} + +bool construct_create_price_peg_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_price_peg& sfx_price_peg, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_create_price_peg_sources_and_destinations(events, blk_head, from, 0, fee, nmix, sfx_price_peg, sources, destinations, sfx_acc_keys.get_public_key()); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0, sfx_acc_keys); +} + +bool construct_update_price_peg_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_price_peg& sfx_price_peg, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_update_price_peg_sources_and_destinations(events, blk_head, from, 0, fee, nmix, sfx_price_peg, sources, destinations, sfx_acc_keys.get_public_key()); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0, sfx_acc_keys); +} + uint64_t get_balance(const cryptonote::account_base& addr, const std::vector& blockchain, const map_hash2tx_t& mtx) { uint64_t res = 0; std::map > outs; @@ -850,6 +1858,8 @@ uint64_t get_token_balance(const cryptonote::account_base& addr, const std::vect uint64_t res = 0; std::map > token_outs; std::map > token_outs_mine; + std::map > locked_token_outs; + std::map > locked_token_outs_mine; map_hash2tx_t confirmed_txs; get_confirmed_txs(blockchain, mtx, confirmed_txs); @@ -860,8 +1870,11 @@ uint64_t get_token_balance(const cryptonote::account_base& addr, const std::vect if (!init_spent_output_indices(token_outs, token_outs_mine, blockchain, confirmed_txs, addr)) return false; - BOOST_FOREACH (const map_output_t::value_type &o, token_outs_mine) { - for (size_t i = 0; i < o.second.size(); ++i) { + BOOST_FOREACH (const map_output_t::value_type &o, token_outs_mine) + { + if (o.first == static_cast(tx_out_type::out_staked_token)) continue; + for (size_t i = 0; i < o.second.size(); ++i) + { if (token_outs[o.first][o.second[i]].spent) continue; @@ -872,6 +1885,35 @@ uint64_t get_token_balance(const cryptonote::account_base& addr, const std::vect return res; } +uint64_t get_locked_token_balance(const cryptonote::account_base& addr, const std::vector& blockchain, const map_hash2tx_t& mtx) { + uint64_t res = 0; + std::map > locked_token_outs; + std::map > locked_token_outs_mine; + + map_hash2tx_t confirmed_txs; + get_confirmed_txs(blockchain, mtx, confirmed_txs); + + if (!init_output_indices(locked_token_outs, locked_token_outs_mine, blockchain, confirmed_txs, addr, cryptonote::tx_out_type::out_staked_token)) + return false; + + if (!init_spent_output_indices(locked_token_outs, locked_token_outs_mine, blockchain, confirmed_txs, addr)) + return false; + + BOOST_FOREACH (const map_output_t::value_type &o, locked_token_outs_mine) + { + if (o.first != static_cast(tx_out_type::out_staked_token)) continue; + for (size_t i = 0; i < o.second.size(); ++i) + { + if (locked_token_outs[o.first][o.second[i]].spent) + continue; + + res += locked_token_outs[o.first][o.second[i]].token_amount; + } + } + + return res; +} + void get_confirmed_txs(const std::vector& blockchain, const map_hash2tx_t& mtx, map_hash2tx_t& confirmed_txs) { std::unordered_set confirmed_hashes; @@ -940,3 +1982,17 @@ bool test_chain_unit_base::verify(const std::string& cb_name, cryptonote::core& } return cb_it->second(c, ev_index, events); } + + + +crypto::hash get_hash_from_string(const std::string hashstr) { + //parse bitcoin transaction hash + cryptonote::blobdata expected_bitcoin_hash_data; + if (!epee::string_tools::parse_hexstr_to_binbuff(std::string(hashstr), expected_bitcoin_hash_data) || expected_bitcoin_hash_data.size() != sizeof(crypto::hash)) + { + std::cerr << "failed to parse bitcoin transaction hash" << endl; + return boost::value_initialized(); + } + const crypto::hash bitcoin_transaction_hash = *reinterpret_cast(expected_bitcoin_hash_data.data()); + return bitcoin_transaction_hash; +} diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index afd1f808c..fd150e5b5 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -57,6 +57,9 @@ #define SAFEX_DEFAULT_LOG_CATEGORY "tests.core" +const size_t invalid_index_value = std::numeric_limits::max(); +const uint64_t FIRST_BLOCK_REWARD = (10000000 * SAFEX_CASH_COIN); + struct callback_entry { @@ -220,6 +223,10 @@ class test_generator inline cryptonote::difficulty_type get_test_difficulty() {return 1;} void fill_nonce(cryptonote::block& blk, const cryptonote::difficulty_type& diffic, uint64_t height); +cryptonote::tx_destination_entry create_tx_destination(const cryptonote::account_base &to, uint64_t amount); +cryptonote::tx_destination_entry create_token_tx_destination(const cryptonote::account_base &to, uint64_t token_amount); +cryptonote::tx_destination_entry create_locked_token_tx_destination(const cryptonote::account_base &to, uint64_t token_amount); + bool construct_miner_tx_manually(size_t height, uint64_t already_generated_coins, const cryptonote::account_public_address& miner_address, cryptonote::transaction& tx, uint64_t fee, cryptonote::keypair* p_txkey = 0); @@ -240,6 +247,40 @@ bool construct_token_tx_to_key(const std::vector& events, cryp const cryptonote::account_base& from, const cryptonote::account_base& to, uint64_t token_amount, uint64_t fee, size_t nmix); +bool construct_token_stake_tx(const std::vector &events, cryptonote::transaction &tx, const cryptonote::block &blk_head, + const cryptonote::account_base &user_account, uint64_t token_amount, uint64_t fee, size_t nmix); + +bool construct_token_unstake_tx(const std::vector &events, cryptonote::transaction &tx, const cryptonote::block &blk_head, + const cryptonote::account_base &from, uint64_t token_amount, uint64_t fee, size_t nmix); + +bool construct_fee_donation_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, + const cryptonote::account_base &from, uint64_t cash_amount, uint64_t fee, size_t nmix); + +bool construct_create_account_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const std::string &username, const crypto::public_key &pkey, const std::vector &account_data, uint64_t unlock_time, const safex::safex_account_keys &sfx_acc_keys); + +bool construct_edit_account_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, + const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const std::string &username, const std::vector &new_account_data, const safex::safex_account_keys &sfx_acc_keys); + +bool construct_create_offer_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_offer& sfx_offer, const safex::safex_account_keys &sfx_acc_keys); + +bool construct_edit_offer_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_offer& sfx_offer, const safex::safex_account_keys &sfx_acc_keys); + +bool construct_create_purchase_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const safex::safex_purchase &sfx_purchase, const cryptonote::account_public_address seller_address); + +bool construct_create_feedback_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const safex::safex_feedback &sfx_feedback); + +bool construct_create_price_peg_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_price_peg& sfx_price_peg, const safex::safex_account_keys &sfx_acc_keys); + +bool construct_update_price_peg_transaction(const std::vector& events, cryptonote::transaction &tx, const cryptonote::block& blk_head, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_price_peg& sfx_price_peg, const safex::safex_account_keys &sfx_acc_keys); + void get_confirmed_txs(const std::vector& blockchain, const map_hash2tx_t& mtx, map_hash2tx_t& confirmed_txs); bool find_block_chain(const std::vector& events, std::vector& blockchain, map_hash2tx_t& mtx, const crypto::hash& head); void fill_tx_sources_and_destinations(const std::vector& events, const cryptonote::block& blk_head, @@ -256,9 +297,15 @@ void fill_token_tx_sources_and_destinations(const std::vector& uint64_t token_amount, uint64_t fee, size_t nmix, std::vector& sources, std::vector& destinations); + +void fill_token_stake_tx_sources_and_destinations(const std::vector &events, const cryptonote::block &blk_head, + const cryptonote::account_base &from, const cryptonote::account_base &to, uint64_t token_amount, uint64_t fee, size_t nmix, std::vector &sources, + std::vector &destinations); + uint64_t get_balance(const cryptonote::account_base& addr, const std::vector& blockchain, const map_hash2tx_t& mtx); uint64_t get_token_balance(const cryptonote::account_base& addr, const std::vector& blockchain, const map_hash2tx_t& mtx); - +uint64_t get_locked_token_balance(const cryptonote::account_base& addr, const std::vector& blockchain, const map_hash2tx_t& mtx); +crypto::hash get_hash_from_string(const std::string hashstr); //-------------------------------------------------------------------------- template auto do_check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool tx_added, size_t event_index, const cryptonote::transaction& tx, t_test_class& validator, int) @@ -697,6 +744,11 @@ inline bool do_replay_file(const std::string& filename) +#define MAKE_MIGRATON_TX(VEC_EVENTS, TX_NAME, FROM, TO, AMOUNT, HEAD, BITCOIN_HASH) \ + cryptonote::transaction TX_NAME; \ + construct_migration_tx_to_key(VEC_EVENTS, t, HEAD, FROM, TO, AMOUNT, TESTS_DEFAULT_FEE, BITCOIN_HASH); \ + VEC_EVENTS.push_back(TX_NAME); + #define MAKE_MIGRATION_TX_LIST(VEC_EVENTS, SET_NAME, FROM, TO, AMOUNT, HEAD, BITCOIN_HASH) \ { \ cryptonote::transaction t; \ @@ -725,6 +777,168 @@ inline bool do_replay_file(const std::string& filename) miner_account.get_keys().m_account_address, TX, 0, KEY)) \ return false; + +#define MAKE_TOKEN_LOCK_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, TOKEN_AMOUNT, NMIX, HEAD) \ + { \ + cryptonote::transaction t; \ + construct_token_stake_tx(VEC_EVENTS, t, HEAD, FROM, TOKEN_AMOUNT, TESTS_DEFAULT_FEE, NMIX); \ + SET_NAME.push_back(t); \ + VEC_EVENTS.push_back(t); \ + } + +#define MAKE_TOKEN_LOCK_TX_LIST(VEC_EVENTS, SET_NAME, FROM, TOKEN_AMOUNT, HEAD) MAKE_TOKEN_LOCK_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, TOKEN_AMOUNT, 0, HEAD) + +#define MAKE_TX_TOKEN_LOCK_LIST_START(VEC_EVENTS, SET_NAME, FROM, TOKEN_AMOUNT, HEAD) \ + std::list SET_NAME; \ + MAKE_TOKEN_LOCK_TX_LIST(VEC_EVENTS, SET_NAME, FROM, TOKEN_AMOUNT, HEAD); + + +#define MAKE_TOKEN_UNLOCK_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, TOKEN_AMOUNT, NMIX, HEAD) \ + { \ + cryptonote::transaction t; \ + construct_token_unstake_tx(VEC_EVENTS, t, HEAD, FROM, TOKEN_AMOUNT, TESTS_DEFAULT_FEE, NMIX); \ + SET_NAME.push_back(t); \ + VEC_EVENTS.push_back(t); \ + } + +#define MAKE_TOKEN_UNLOCK_TX_LIST(VEC_EVENTS, SET_NAME, FROM, TOKEN_AMOUNT, HEAD) MAKE_TOKEN_UNLOCK_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, TOKEN_AMOUNT, 0, HEAD) + +#define MAKE_TX_TOKEN_UNLOCK_LIST_START(VEC_EVENTS, SET_NAME, FROM, TOKEN_AMOUNT, HEAD) \ + std::list SET_NAME; \ + MAKE_TOKEN_UNLOCK_TX_LIST(VEC_EVENTS, SET_NAME, FROM, TOKEN_AMOUNT, HEAD); + + + +#define MAKE_DONATE_FEE_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, CASH_AMOUNT, NMIX, HEAD) \ + { \ + cryptonote::transaction t; \ + construct_fee_donation_transaction(VEC_EVENTS, t, HEAD, FROM, CASH_AMOUNT, TESTS_DEFAULT_FEE, NMIX); \ + SET_NAME.push_back(t); \ + VEC_EVENTS.push_back(t); \ + } + +#define MAKE_DONATE_FEE_TX_LIST(VEC_EVENTS, SET_NAME, FROM, CASH_AMOUNT, HEAD) MAKE_DONATE_FEE_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, CASH_AMOUNT, 0, HEAD) + +#define MAKE_TX_DONATE_FEE_LIST_START(VEC_EVENTS, SET_NAME, FROM, CASH_AMOUNT, HEAD) \ + std::list SET_NAME; \ + MAKE_DONATE_FEE_TX_LIST(VEC_EVENTS, SET_NAME, FROM, CASH_AMOUNT, HEAD); + + + +#define MAKE_CREATE_SAFEX_ACCOUNT_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, USERNAME, PKEY, ACCOUNT_DATA, ACC_KEYS, UNLOCK_TIME, NMIX, HEAD) \ + { \ + cryptonote::transaction t; \ + construct_create_account_transaction(VEC_EVENTS, t, HEAD, FROM, TESTS_DEFAULT_FEE, NMIX, USERNAME, PKEY, ACCOUNT_DATA, UNLOCK_TIME, ACC_KEYS); \ + SET_NAME.push_back(t); \ + VEC_EVENTS.push_back(t); \ + } + +#define MAKE_CREATE_SAFEX_ACCOUNT_TX_LIST(VEC_EVENTS, SET_NAME, FROM, USERNAME, PKEY, ACCOUNT_DATA, ACC_KEYS, UNLOCK_TIME, HEAD) MAKE_CREATE_SAFEX_ACCOUNT_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, USERNAME, PKEY, ACCOUNT_DATA, ACC_KEYS, UNLOCK_TIME, 0, HEAD) + +#define MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(VEC_EVENTS, SET_NAME, FROM, USERNAME, PKEY, ACCOUNT_DATA, ACC_KEYS, UNLOCK_TIME, HEAD) \ + std::list SET_NAME; \ + MAKE_CREATE_SAFEX_ACCOUNT_TX_LIST(VEC_EVENTS, SET_NAME, FROM, USERNAME, PKEY, ACCOUNT_DATA, ACC_KEYS, UNLOCK_TIME, HEAD); + + +#define MAKE_EDIT_SAFEX_ACCOUNT_TX_LIST(VEC_EVENTS, SET_NAME, FROM, USERNAME, ACCOUNT_DATA, ACC_KEYS, HEAD) MAKE_EDIT_SAFEX_ACCOUNT_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, USERNAME, ACCOUNT_DATA, ACC_KEYS, 0, HEAD) + +#define MAKE_EDIT_SAFEX_ACCOUNT_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, USERNAME, ACCOUNT_DATA, ACC_KEYS, NMIX, HEAD) \ + { \ + cryptonote::transaction t; \ + construct_edit_account_transaction(VEC_EVENTS, t, HEAD, FROM, TESTS_DEFAULT_FEE, NMIX, USERNAME, ACCOUNT_DATA, ACC_KEYS); \ + SET_NAME.push_back(t); \ + VEC_EVENTS.push_back(t); \ + } + +#define MAKE_TX_EDIT_SAFEX_ACCOUNT_LIST_START(VEC_EVENTS, SET_NAME, FROM, USERNAME, ACCOUNT_DATA, ACC_KEYS, HEAD) \ + std::list SET_NAME; \ + MAKE_EDIT_SAFEX_ACCOUNT_TX_LIST(VEC_EVENTS, SET_NAME, FROM, USERNAME, ACCOUNT_DATA, ACC_KEYS, HEAD); + +#define MAKE_CREATE_SAFEX_OFFER_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_OFFER, ACC_KEYS, NMIX, HEAD) \ + { \ + cryptonote::transaction t; \ + construct_create_offer_transaction(VEC_EVENTS, t, HEAD, FROM, TESTS_DEFAULT_FEE, NMIX, PKEY, SFX_OFFER, ACC_KEYS); \ + SET_NAME.push_back(t); \ + VEC_EVENTS.push_back(t); \ + } + +#define MAKE_CREATE_SAFEX_OFFER_TX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_OFFER, ACC_KEYS, HEAD) MAKE_CREATE_SAFEX_OFFER_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_OFFER, ACC_KEYS, 0, HEAD) + +#define MAKE_TX_CREATE_SAFEX_OFFER_LIST_START(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_OFFER, ACC_KEYS, HEAD) \ + std::list SET_NAME; \ + MAKE_CREATE_SAFEX_OFFER_TX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_OFFER, ACC_KEYS, HEAD); + +#define MAKE_EDIT_SAFEX_OFFER_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_OFFER, ACC_KEYS, NMIX, HEAD) \ + { \ + cryptonote::transaction t; \ + construct_edit_offer_transaction(VEC_EVENTS, t, HEAD, FROM, TESTS_DEFAULT_FEE, NMIX, PKEY, SFX_OFFER, ACC_KEYS); \ + SET_NAME.push_back(t); \ + VEC_EVENTS.push_back(t); \ + } + +#define MAKE_EDIT_SAFEX_OFFER_TX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_OFFER, ACC_KEYS, HEAD) MAKE_EDIT_SAFEX_OFFER_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_OFFER, ACC_KEYS, 0, HEAD) + +#define MAKE_TX_EDIT_SAFEX_OFFER_LIST_START(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_OFFER, ACC_KEYS, HEAD) \ + std::list SET_NAME; \ + MAKE_EDIT_SAFEX_OFFER_TX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_OFFER, ACC_KEYS, HEAD); + +#define MAKE_CREATE_SAFEX_PURCHASE_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, SFX_PURCHASE, SELLER_ADDR, NMIX, HEAD) \ + { \ + cryptonote::transaction t; \ + construct_create_purchase_transaction(VEC_EVENTS, t, HEAD, FROM, TESTS_DEFAULT_FEE, NMIX, SFX_PURCHASE, SELLER_ADDR); \ + SET_NAME.push_back(t); \ + VEC_EVENTS.push_back(t); \ + } + +#define MAKE_CREATE_SAFEX_PURCHASE_TX_LIST(VEC_EVENTS, SET_NAME, FROM, SFX_PURCHASE, SELLER_ADDR, HEAD) MAKE_CREATE_SAFEX_PURCHASE_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, SFX_PURCHASE, SELLER_ADDR, 0, HEAD) + +#define MAKE_TX_CREATE_SAFEX_PURCHASE_LIST_START(VEC_EVENTS, SET_NAME, FROM, SFX_PURCHASE, SELLER_ADDR, HEAD) \ + std::list SET_NAME; \ + MAKE_CREATE_SAFEX_PURCHASE_TX_LIST(VEC_EVENTS, SET_NAME, FROM, SFX_PURCHASE, SELLER_ADDR, HEAD); + +#define MAKE_CREATE_SAFEX_FEEDBACK_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, SFX_FEEDBACK, NMIX, HEAD) \ + { \ + cryptonote::transaction t; \ + construct_create_feedback_transaction(VEC_EVENTS, t, HEAD, FROM, TESTS_DEFAULT_FEE, NMIX, SFX_FEEDBACK); \ + SET_NAME.push_back(t); \ + VEC_EVENTS.push_back(t); \ + } + +#define MAKE_CREATE_SAFEX_FEEDBACK_TX_LIST(VEC_EVENTS, SET_NAME, FROM, SFX_FEEDBACK, HEAD) MAKE_CREATE_SAFEX_FEEDBACK_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, SFX_FEEDBACK, 0, HEAD) + +#define MAKE_TX_CREATE_SAFEX_FEEDBACK_LIST_START(VEC_EVENTS, SET_NAME, FROM, SFX_FEEDBACK, HEAD) \ + std::list SET_NAME; \ + MAKE_CREATE_SAFEX_FEEDBACK_TX_LIST(VEC_EVENTS, SET_NAME, FROM, SFX_FEEDBACK, HEAD); + +#define MAKE_CREATE_SAFEX_PRICE_PEG_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_PRICE_PEG, ACC_KEYS, NMIX, HEAD) \ + { \ + cryptonote::transaction t; \ + construct_create_price_peg_transaction(VEC_EVENTS, t, HEAD, FROM, TESTS_DEFAULT_FEE, NMIX, PKEY, SFX_PRICE_PEG, ACC_KEYS); \ + SET_NAME.push_back(t); \ + VEC_EVENTS.push_back(t); \ + } + +#define MAKE_CREATE_SAFEX_PRICE_PEG_TX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_PRICE_PEG, ACC_KEYS, HEAD) MAKE_CREATE_SAFEX_PRICE_PEG_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_PRICE_PEG, ACC_KEYS, 0, HEAD) + +#define MAKE_TX_CREATE_SAFEX_PRICE_PEG_LIST_START(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_PRICE_PEG, ACC_KEYS, HEAD) \ + std::list SET_NAME; \ + MAKE_CREATE_SAFEX_PRICE_PEG_TX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_PRICE_PEG, ACC_KEYS, HEAD); + +#define MAKE_UPDATE_SAFEX_PRICE_PEG_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_PRICE_PEG, ACC_KEYS, NMIX, HEAD) \ + { \ + cryptonote::transaction t; \ + construct_update_price_peg_transaction(VEC_EVENTS, t, HEAD, FROM, TESTS_DEFAULT_FEE, NMIX, PKEY, SFX_PRICE_PEG, ACC_KEYS); \ + SET_NAME.push_back(t); \ + VEC_EVENTS.push_back(t); \ + } + +#define MAKE_UPDATE_SAFEX_PRICE_PEG_TX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_PRICE_PEG, ACC_KEYS, HEAD) MAKE_UPDATE_SAFEX_PRICE_PEG_TX_MIX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_PRICE_PEG, ACC_KEYS, 0, HEAD) + +#define MAKE_TX_UPDATE_SAFEX_PRICE_PEG_LIST_START(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_PRICE_PEG, ACC_KEYS, HEAD) \ + std::list SET_NAME; \ + MAKE_UPDATE_SAFEX_PRICE_PEG_TX_LIST(VEC_EVENTS, SET_NAME, FROM, PKEY, SFX_PRICE_PEG, ACC_KEYS, HEAD); + + #define MAKE_MINER_TX_MANUALLY(TX, BLK) MAKE_MINER_TX_AND_KEY_MANUALLY(TX, BLK, 0) #define SET_EVENT_VISITOR_SETT(VEC_EVENTS, SETT, VAL) VEC_EVENTS.push_back(event_visitor_settings(SETT, VAL)); diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 8e9bd8a49..ca6afb9f4 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -92,6 +92,7 @@ int main(int argc, char* argv[]) } else if (command_line::get_arg(vm, arg_generate_and_play_test_data)) { +#if 1 GENERATE_AND_PLAY(gen_simple_chain_001); GENERATE_AND_PLAY(gen_simple_chain_split_1); GENERATE_AND_PLAY(one_block); @@ -128,7 +129,8 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_block_miner_tx_has_out_to_alice); GENERATE_AND_PLAY(gen_block_has_invalid_tx); GENERATE_AND_PLAY(gen_block_is_too_big); - GENERATE_AND_PLAY(gen_block_invalid_binary_format); // Takes up to 3 hours, if CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW == 500, up to 30 minutes, if CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW == 10 + //GENERATE_AND_PLAY(gen_block_invalid_binary_format); // Takes up to 3 hours, if CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW == 500, up to 30 minutes, if CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW == 10 + // Transaction verification tests GENERATE_AND_PLAY(gen_tx_big_version); @@ -145,7 +147,9 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_tx_key_image_not_derive_from_tx_key); GENERATE_AND_PLAY(gen_tx_key_image_is_invalid); GENERATE_AND_PLAY(gen_tx_check_input_unlock_time); + GENERATE_AND_PLAY(gen_tx_txout_to_key_has_invalid_key); + GENERATE_AND_PLAY(gen_tx_output_with_zero_amount); GENERATE_AND_PLAY(gen_tx_output_is_not_txout_to_key); GENERATE_AND_PLAY(gen_tx_signatures_are_invalid); @@ -163,70 +167,84 @@ int main(int argc, char* argv[]) GENERATE_AND_PLAY(gen_double_spend_in_alt_chain_in_different_blocks); GENERATE_AND_PLAY(gen_double_spend_in_alt_chain_in_different_blocks); + // Token double spend + GENERATE_AND_PLAY(gen_double_spend_token_in_tx); + GENERATE_AND_PLAY(gen_double_spend_token_in_tx); + GENERATE_AND_PLAY(gen_double_spend_token_in_the_same_block); + GENERATE_AND_PLAY(gen_double_spend_token_in_the_same_block); + GENERATE_AND_PLAY(gen_double_spend_token_in_different_blocks); + GENERATE_AND_PLAY(gen_double_spend_token_in_different_blocks); + GENERATE_AND_PLAY(gen_double_spend_token_in_different_chains); + GENERATE_AND_PLAY(gen_double_spend_token_in_alt_chain_in_the_same_block); + GENERATE_AND_PLAY(gen_double_spend_token_in_alt_chain_in_the_same_block); + GENERATE_AND_PLAY(gen_double_spend_token_in_alt_chain_in_different_blocks); + GENERATE_AND_PLAY(gen_double_spend_token_in_alt_chain_in_different_blocks); + + // Advanced double spend + GENERATE_AND_PLAY(gen_double_advanced_tx_in_different_chains); + GENERATE_AND_PLAY(gen_double_purchase_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_double_purchase_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_edit_offer_purchase_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_edit_offer_purchase_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_purchase_edit_offer_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_purchase_edit_offer_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_purchase_update_price_peg_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_purchase_update_price_peg_tx_in_the_same_block); + + GENERATE_AND_PLAY(gen_uint_cash_overflow_1); GENERATE_AND_PLAY(gen_uint_cash_overflow_2); GENERATE_AND_PLAY(gen_uint_token_overflow_1); GENERATE_AND_PLAY(gen_block_reward); - GENERATE_AND_PLAY(gen_v2_tx_mixable_0_mixin); GENERATE_AND_PLAY(gen_v2_tx_mixable_low_mixin); + GENERATE_AND_PLAY(gen_v2_tx_dust); + + //todo ATANA check those tests if they are viable or remove them // GENERATE_AND_PLAY(gen_v2_tx_unmixable_only); // GENERATE_AND_PLAY(gen_v2_tx_unmixable_one); // GENERATE_AND_PLAY(gen_v2_tx_unmixable_two); - GENERATE_AND_PLAY(gen_v2_tx_dust); -#if (CURRENT_TRANSACTION_VERSION == 2) - GENERATE_AND_PLAY(gen_rct_tx_valid_from_pre_rct); - GENERATE_AND_PLAY(gen_rct_tx_valid_from_rct); - GENERATE_AND_PLAY(gen_rct_tx_valid_from_mixed); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_real_dest); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_real_mask); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_fake_dest); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_bad_fake_mask); - GENERATE_AND_PLAY(gen_rct_tx_rct_bad_real_dest); - GENERATE_AND_PLAY(gen_rct_tx_rct_bad_real_mask); - GENERATE_AND_PLAY(gen_rct_tx_rct_bad_fake_dest); - GENERATE_AND_PLAY(gen_rct_tx_rct_bad_fake_mask); - GENERATE_AND_PLAY(gen_rct_tx_rct_spend_with_zero_commit); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_zero_vin_amount); - GENERATE_AND_PLAY(gen_rct_tx_rct_non_zero_vin_amount); - GENERATE_AND_PLAY(gen_rct_tx_non_zero_vout_amount); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_duplicate_key_image); - GENERATE_AND_PLAY(gen_rct_tx_rct_duplicate_key_image); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_wrong_key_image); - GENERATE_AND_PLAY(gen_rct_tx_rct_wrong_key_image); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_wrong_fee); - GENERATE_AND_PLAY(gen_rct_tx_rct_wrong_fee); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_remove_vin); - GENERATE_AND_PLAY(gen_rct_tx_rct_remove_vin); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_add_vout); - GENERATE_AND_PLAY(gen_rct_tx_rct_add_vout); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_increase_vin_and_fee); - GENERATE_AND_PLAY(gen_rct_tx_pre_rct_altered_extra); - GENERATE_AND_PLAY(gen_rct_tx_rct_altered_extra); - - - GENERATE_AND_PLAY(gen_multisig_tx_valid_22_1_2); - GENERATE_AND_PLAY(gen_multisig_tx_valid_22_1_2_many_inputs); - GENERATE_AND_PLAY(gen_multisig_tx_valid_22_2_1); - GENERATE_AND_PLAY(gen_multisig_tx_valid_33_1_23); - GENERATE_AND_PLAY(gen_multisig_tx_valid_33_3_21); - GENERATE_AND_PLAY(gen_multisig_tx_valid_23_1_2); - GENERATE_AND_PLAY(gen_multisig_tx_valid_23_1_3); - GENERATE_AND_PLAY(gen_multisig_tx_valid_23_2_1); - GENERATE_AND_PLAY(gen_multisig_tx_valid_23_2_3); - GENERATE_AND_PLAY(gen_multisig_tx_valid_45_1_234); - GENERATE_AND_PLAY(gen_multisig_tx_valid_45_4_135_many_inputs); - GENERATE_AND_PLAY(gen_multisig_tx_valid_89_3_1245789); - GENERATE_AND_PLAY(gen_multisig_tx_invalid_23_1__no_threshold); - GENERATE_AND_PLAY(gen_multisig_tx_invalid_45_5_23_no_threshold); - GENERATE_AND_PLAY(gen_multisig_tx_invalid_22_1__no_threshold); - GENERATE_AND_PLAY(gen_multisig_tx_invalid_33_1__no_threshold); - GENERATE_AND_PLAY(gen_multisig_tx_invalid_33_1_2_no_threshold); - GENERATE_AND_PLAY(gen_multisig_tx_invalid_33_1_3_no_threshold); + /* safex advanced functionality related tests */ + GENERATE_AND_PLAY(gen_token_lock_001); + GENERATE_AND_PLAY(gen_network_fee_001); + + /* safex tx validation */ + GENERATE_AND_PLAY(gen_tx_not_enough_tokens_to_lock); + + /* accounts */ + GENERATE_AND_PLAY(gen_safex_account_001); + + GENERATE_AND_PLAY(gen_safex_offer_001); + + GENERATE_AND_PLAY(gen_safex_purchase_001); + + GENERATE_AND_PLAY(gen_safex_price_peg_001); + + GENERATE_AND_PLAY(gen_simple_chain_split_safex); + + //todo atana test unlock and interest invalid transacitons + +#else + + // Advanced double spend + GENERATE_AND_PLAY(gen_double_advanced_tx_in_different_chains); + GENERATE_AND_PLAY(gen_double_purchase_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_double_purchase_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_edit_offer_purchase_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_edit_offer_purchase_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_purchase_edit_offer_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_purchase_edit_offer_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_purchase_update_price_peg_tx_in_the_same_block); + GENERATE_AND_PLAY(gen_purchase_update_price_peg_tx_in_the_same_block); + + #endif + + + el::Level level = (failed_tests.empty() ? el::Level::Info : el::Level::Error); MLOG(level, "\nREPORT:"); MLOG(level, " Test run: " << tests_count); diff --git a/tests/core_tests/chaingen_tests_list.h b/tests/core_tests/chaingen_tests_list.h index f64ed4649..9f87d73c7 100644 --- a/tests/core_tests/chaingen_tests_list.h +++ b/tests/core_tests/chaingen_tests_list.h @@ -37,14 +37,21 @@ #include "chain_split_1.h" #include "chain_switch_1.h" #include "double_spend.h" +#include "double_spend_token.h" +#include "double_advanced_tx.h" #include "integer_overflow.h" #include "ring_signature_1.h" #include "tx_validation.h" #include "v2_tests.h" -#include "rct.h" -#include "multisig.h" #include "chain_migration.h" #include "token_transactions.h" +#include "token_stake.h" +#include "network_fee.h" +#include "safex_account.h" +#include "safex_offer.h" +#include "safex_purchase.h" +#include "safex_price_peg.h" +#include "chain_split_safex.h" /************************************************************************/ /* */ /************************************************************************/ diff --git a/tests/core_tests/double_advanced_tx.cpp b/tests/core_tests/double_advanced_tx.cpp new file mode 100644 index 000000000..5070e9124 --- /dev/null +++ b/tests/core_tests/double_advanced_tx.cpp @@ -0,0 +1,101 @@ +// Copyright (c) 2020, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#include "chaingen.h" +#include "double_advanced_tx.h" + +using namespace epee; +using namespace cryptonote; + + +//====================================================================================================================== + +gen_double_advanced_tx_in_different_chains::gen_double_advanced_tx_in_different_chains() +{ + REGISTER_CALLBACK_METHOD(gen_double_advanced_tx_in_different_chains, check_double_advanced_tx); +} + +bool gen_double_advanced_tx_in_different_chains::generate(std::vector& events) const +{ + INIT_DOUBLE_ADVANCED_TX_TEST(); + + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, true); + + + auto safex_alice_purchase_from_bob = safex::safex_purchase{1, safex_offer_alice.price, safex_offer_alice.offer_id, safex_offer_alice.get_hash(), false}; + + //create purchase + MAKE_TX_CREATE_SAFEX_PURCHASE_LIST_START(events, txlist_3, alice_account, safex_alice_purchase_from_bob, alice_account.get_keys().m_account_address, blk_1r); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txlist_3); + + // Alternative chain + + MAKE_TX_CREATE_SAFEX_PURCHASE_LIST_START(events, txlist_4, bob_account, safex_alice_purchase_from_bob, alice_account.get_keys().m_account_address, blk_1r); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_1r, miner_account, txlist_4); + + // Switch to alternative chain + MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_account); + CHECK_AND_NO_ASSERT_MES(expected_blockchain_height == get_block_height(blk_4) + 1, false, "expected_blockchain_height has invalid value"); + + DO_CALLBACK(events, "check_double_advanced_tx"); + + return true; +} + +bool gen_double_advanced_tx_in_different_chains::check_double_advanced_tx(cryptonote::core& c, size_t /*ev_index*/, const std::vector& events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_double_advanced_tx_in_different_chains::check_double_advanced_tx"); + + std::list block_list; + bool r = c.get_blocks(0, 18 + 5 * CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, block_list); + CHECK_TEST_CONDITION(r); + + std::vector blocks(block_list.begin(), block_list.end()); + CHECK_EQ(expected_blockchain_height, blocks.size()); + + CHECK_EQ(1, c.get_pool_transactions_count()); + CHECK_EQ(1, c.get_alternative_blocks_count()); + + cryptonote::account_base bob_account = boost::get(events[1]); + cryptonote::account_base alice_account = boost::get(events[2]); + + std::vector chain; + map_hash2tx_t mtx; + r = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(r); + + CHECK_EQ(expected_bob_balance, get_balance(bob_account, blocks, mtx)); + CHECK_EQ(expected_alice_balance, get_balance(alice_account, blocks, mtx)); + CHECK_EQ(expected_bob_token_balance, get_token_balance(bob_account, blocks, mtx)); + CHECK_EQ(expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + + return true; +} diff --git a/tests/core_tests/double_advanced_tx.h b/tests/core_tests/double_advanced_tx.h new file mode 100644 index 000000000..3949c0a1c --- /dev/null +++ b/tests/core_tests/double_advanced_tx.h @@ -0,0 +1,256 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#pragma once +#include "chaingen.h" + + +const std::string bitcoin_tx_hashes_str1[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; + + +template +class gen_double_advanced_tx_base : public test_chain_unit_base +{ +public: + static const uint64_t send_amount = FIRST_BLOCK_REWARD - TESTS_DEFAULT_FEE; + + gen_double_advanced_tx_base(); + + bool check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool tx_added, size_t event_idx, const cryptonote::transaction& tx); + bool check_block_verification_context(const cryptonote::block_verification_context& bvc, size_t event_idx, const cryptonote::block& block); + + bool mark_last_valid_block(cryptonote::core& c, size_t ev_index, const std::vector& events); + bool mark_invalid_tx(cryptonote::core& c, size_t ev_index, const std::vector& events); + bool mark_invalid_block(cryptonote::core& c, size_t ev_index, const std::vector& events); + bool check_double_advanced_tx(cryptonote::core& c, size_t ev_index, const std::vector& events); + +private: + cryptonote::block m_last_valid_block; + size_t m_invalid_tx_index; + size_t m_invalid_block_index; +}; + + +template +struct gen_double_purchase_tx_in_the_same_block : public gen_double_advanced_tx_base< gen_double_purchase_tx_in_the_same_block > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = !txs_keeped_by_block; + static const size_t expected_pool_txs_count = has_invalid_tx ? 1 : 2; + static const uint64_t expected_bob_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount - 2*TESTS_DEFAULT_FEE; + static const uint64_t expected_bob_token_balance = MK_TOKENS(10000); + static const uint64_t expected_alice_token_balance = MK_TOKENS(10000); + + bool generate(std::vector& events) const; +}; + +template +struct gen_edit_offer_purchase_tx_in_the_same_block : public gen_double_advanced_tx_base< gen_edit_offer_purchase_tx_in_the_same_block > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = !txs_keeped_by_block; + static const size_t expected_pool_txs_count = has_invalid_tx ? 1 : 2; + static const uint64_t expected_bob_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount - 2*TESTS_DEFAULT_FEE; + static const uint64_t expected_bob_token_balance = MK_TOKENS(10000); + static const uint64_t expected_alice_token_balance = MK_TOKENS(10000); + + bool generate(std::vector& events) const; +}; + +template +struct gen_purchase_edit_offer_tx_in_the_same_block : public gen_double_advanced_tx_base< gen_purchase_edit_offer_tx_in_the_same_block > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = false; + static const size_t expected_pool_txs_count = 2; + static const uint64_t expected_bob_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount - 2*TESTS_DEFAULT_FEE; + static const uint64_t expected_bob_token_balance = MK_TOKENS(10000); + static const uint64_t expected_alice_token_balance = MK_TOKENS(10000); + + bool generate(std::vector& events) const; +}; + +template +struct gen_purchase_update_price_peg_tx_in_the_same_block : public gen_double_advanced_tx_base< gen_purchase_update_price_peg_tx_in_the_same_block > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = false; + static const size_t expected_pool_txs_count = 2; + static const uint64_t expected_bob_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount - 3*TESTS_DEFAULT_FEE; + static const uint64_t expected_bob_token_balance = MK_TOKENS(10000); + static const uint64_t expected_alice_token_balance = MK_TOKENS(10000); + + bool generate(std::vector& events) const; +}; + +template +struct gen_double_advanced_tx_in_different_blocks : public gen_double_advanced_tx_base< gen_double_advanced_tx_in_different_blocks > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = !txs_keeped_by_block; + static const size_t expected_pool_txs_count = has_invalid_tx ? 0 : 1; + static const uint64_t expected_bob_balance = 0; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount - TESTS_DEFAULT_FEE; + static const uint64_t expected_bob_token_balance = MK_TOKENS(10000); + static const uint64_t expected_alice_token_balance = 0; + + bool generate(std::vector& events) const; +}; + + +template +struct gen_double_advanced_tx_in_alt_chain_in_the_same_block : public gen_double_advanced_tx_base< gen_double_advanced_tx_in_alt_chain_in_the_same_block > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = !txs_keeped_by_block; + static const size_t expected_pool_txs_count = has_invalid_tx ? 1 : 2; + static const uint64_t expected_bob_balance = 0; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount; + static const uint64_t expected_bob_token_balance = 0; + static const uint64_t expected_alice_token_balance = MK_TOKENS(10000); + + bool generate(std::vector& events) const; +}; + + +template +struct gen_double_advanced_tx_in_alt_chain_in_different_blocks : public gen_double_advanced_tx_base< gen_double_advanced_tx_in_alt_chain_in_different_blocks > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = !txs_keeped_by_block; + static const size_t expected_pool_txs_count = has_invalid_tx ? 1 : 2; + static const uint64_t expected_bob_balance = 0; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount; + static const uint64_t expected_bob_token_balance = 0; + static const uint64_t expected_alice_token_balance = MK_TOKENS(10000); + + bool generate(std::vector& events) const; +}; + + +class gen_double_advanced_tx_in_different_chains : public test_chain_unit_base +{ +public: + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const size_t expected_blockchain_height = 7 + 5 * CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW + 2; + static const uint64_t expected_bob_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - MK_COINS(10) - TESTS_DEFAULT_FEE; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount + (95*(MK_COINS(10)/100)) - 2*TESTS_DEFAULT_FEE; + static const uint64_t expected_bob_token_balance = MK_TOKENS(10000); + static const uint64_t expected_alice_token_balance = MK_TOKENS(10000); + + gen_double_advanced_tx_in_different_chains(); + + bool generate(std::vector& events) const; + + bool check_double_advanced_tx(cryptonote::core& c, size_t ev_index, const std::vector& events); +}; + + +#define INIT_DOUBLE_ADVANCED_TX_TEST() \ + uint64_t ts_start = 1514764801; \ + GENERATE_ACCOUNT(miner_account); \ + crypto::public_key miner_public_key = AUTO_VAL_INIT(miner_public_key); \ + crypto::secret_key_to_public_key(miner_account.get_keys().m_spend_secret_key, miner_public_key); \ + cryptonote::fakechain::set_core_tests_public_key(miner_public_key); \ + safex::safex_account safex_account_alice; \ + safex::safex_account_key_handler m_safex_account1_keys; \ + m_safex_account1_keys.generate(); \ + safex_account_alice.username = "alice01"; \ + safex_account_alice.pkey = m_safex_account1_keys.get_keys().m_public_key; \ + safex_account_alice.account_data = {'l','o','r','e','m',' ','i','p','s','u','m'}; \ + MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); \ + MAKE_ACCOUNT(events, bob_account); \ + MAKE_ACCOUNT(events, alice_account); \ + auto safex_offer_alice = safex::safex_offer("Black Sabbath T-shirt", 1, MK_COINS(10), "Quality 100% cotton t-shirt with the heaviest band in the universe", safex_account_alice.username,alice_account.get_keys().m_view_secret_key,alice_account.get_keys().m_account_address); \ + MAKE_NEXT_BLOCK(events, blk_1s, blk_0, miner_account); \ + MAKE_NEXT_BLOCK(events, blk_2z, blk_1s, miner_account); \ + REWIND_BLOCKS(events, blk_2r, blk_2z, miner_account); \ + MAKE_TX_MIGRATION_LIST_START(events, txlist_0, miner_account, alice_account, MK_TOKENS(10000), blk_2z, get_hash_from_string(bitcoin_tx_hashes_str1[0])); \ + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner_account, bob_account, MK_TOKENS(10000), blk_2z, get_hash_from_string(bitcoin_tx_hashes_str1[1])); \ + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3z, blk_2r, miner_account, txlist_0); \ + REWIND_BLOCKS(events, blk_4z, blk_3z, miner_account); \ + MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(events, txlist_1, alice_account, safex_account_alice.username, safex_account_alice.pkey, safex_account_alice.account_data, m_safex_account1_keys.get_keys(), events.size() + SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_4z); \ + MAKE_NEXT_BLOCK_TX_LIST(events, blk_5z, blk_4z, miner_account, txlist_1); \ + MAKE_TX(events, tx_fund, miner_account, alice_account, send_amount, blk_5z); \ + MAKE_NEXT_BLOCK_TX1(events, blk_6z, blk_5z, miner_account, tx_fund); \ + REWIND_BLOCKS(events, blk_1, blk_6z, miner_account); \ + MAKE_TX_CREATE_SAFEX_OFFER_LIST_START(events, txlist_2, alice_account, safex_account_alice.pkey, safex_offer_alice, m_safex_account1_keys.get_keys(), blk_1); \ + MAKE_NEXT_BLOCK_TX_LIST(events, blk_br, blk_1, miner_account, txlist_2); \ + REWIND_BLOCKS(events, blk_br2, blk_br, miner_account); \ + REWIND_BLOCKS(events, blk_1r, blk_br2, miner_account); + + + + +#define INIT_DOUBLE_ADVANCED_TX_WITH_PRICE_PEG_TEST() \ + uint64_t ts_start = 1514764801; \ + GENERATE_ACCOUNT(miner_account); \ + crypto::public_key miner_public_key = AUTO_VAL_INIT(miner_public_key); \ + crypto::secret_key_to_public_key(miner_account.get_keys().m_spend_secret_key, miner_public_key); \ + cryptonote::fakechain::set_core_tests_public_key(miner_public_key); \ + safex::safex_account safex_account_alice; \ + safex::safex_account_key_handler m_safex_account1_keys; \ + m_safex_account1_keys.generate(); \ + safex_account_alice.username = "alice01"; \ + safex_account_alice.pkey = m_safex_account1_keys.get_keys().m_public_key; \ + safex_account_alice.account_data = {'l','o','r','e','m',' ','i','p','s','u','m'}; \ + MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); \ + MAKE_ACCOUNT(events, bob_account); \ + MAKE_ACCOUNT(events, alice_account); \ + auto safex_offer_alice = safex::safex_offer("Black Sabbath T-shirt", 1, MK_COINS(10), "Quality 100% cotton t-shirt with the heaviest band in the universe", safex_account_alice.username,alice_account.get_keys().m_view_secret_key,alice_account.get_keys().m_account_address); \ + auto safex_price_peg_alice = safex::safex_price_peg("USDSFX", safex_account_alice.username, "USD", "Some desc", MK_COINS(10)); \ + safex_offer_alice.set_price_peg(safex_price_peg_alice.price_peg_id, MK_TOKENS(1)*1.5, MK_TOKENS(10)); \ + MAKE_NEXT_BLOCK(events, blk_1s, blk_0, miner_account); \ + MAKE_NEXT_BLOCK(events, blk_2z, blk_1s, miner_account); \ + REWIND_BLOCKS(events, blk_2r, blk_2z, miner_account); \ + MAKE_TX_MIGRATION_LIST_START(events, txlist_0, miner_account, alice_account, MK_TOKENS(10000), blk_2z, get_hash_from_string(bitcoin_tx_hashes_str1[0])); \ + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner_account, bob_account, MK_TOKENS(10000), blk_2z, get_hash_from_string(bitcoin_tx_hashes_str1[1])); \ + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3z, blk_2r, miner_account, txlist_0); \ + REWIND_BLOCKS(events, blk_4z, blk_3z, miner_account); \ + MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(events, txlist_1, alice_account, safex_account_alice.username, safex_account_alice.pkey, safex_account_alice.account_data, m_safex_account1_keys.get_keys(), events.size() + SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_4z); \ + MAKE_NEXT_BLOCK_TX_LIST(events, blk_5z, blk_4z, miner_account, txlist_1); \ + MAKE_TX(events, tx_fund, miner_account, alice_account, send_amount, blk_5z); \ + MAKE_NEXT_BLOCK_TX1(events, blk_6z, blk_5z, miner_account, tx_fund); \ + REWIND_BLOCKS(events, blk_1, blk_6z, miner_account); \ + MAKE_TX_CREATE_SAFEX_PRICE_PEG_LIST_START(events, txlist_pp, alice_account, safex_account_alice.pkey, safex_price_peg_alice, m_safex_account1_keys.get_keys(), blk_1); \ + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3g, blk_1, miner_account, txlist_pp); \ + REWIND_BLOCKS(events, blk_1g, blk_3g, miner_account); \ + MAKE_TX_CREATE_SAFEX_OFFER_LIST_START(events, txlist_2, alice_account, safex_account_alice.pkey, safex_offer_alice, m_safex_account1_keys.get_keys(), blk_1g); \ + MAKE_NEXT_BLOCK_TX_LIST(events, blk_br, blk_1g, miner_account, txlist_2); \ + REWIND_BLOCKS(events, blk_br2, blk_br, miner_account); \ + REWIND_BLOCKS(events, blk_1r, blk_br2, miner_account); + + +#include "double_advanced_tx.inl" diff --git a/tests/core_tests/double_advanced_tx.inl b/tests/core_tests/double_advanced_tx.inl new file mode 100644 index 000000000..9fea3e734 --- /dev/null +++ b/tests/core_tests/double_advanced_tx.inl @@ -0,0 +1,251 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#pragma once + +//====================================================================================================================== + +template +gen_double_advanced_tx_base::gen_double_advanced_tx_base() + : m_invalid_tx_index(invalid_index_value) + , m_invalid_block_index(invalid_index_value) +{ + REGISTER_CALLBACK_METHOD(gen_double_advanced_tx_base, mark_last_valid_block); + REGISTER_CALLBACK_METHOD(gen_double_advanced_tx_base, mark_invalid_tx); + REGISTER_CALLBACK_METHOD(gen_double_advanced_tx_base, mark_invalid_block); + REGISTER_CALLBACK_METHOD(gen_double_advanced_tx_base, check_double_advanced_tx); +} + +template +bool gen_double_advanced_tx_base::check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool tx_added, size_t event_idx, const cryptonote::transaction& /*tx*/) +{ + if (m_invalid_tx_index == event_idx) + return tvc.m_verifivation_failed; + else + return !tvc.m_verifivation_failed && tx_added; +} + +template +bool gen_double_advanced_tx_base::check_block_verification_context(const cryptonote::block_verification_context& bvc, size_t event_idx, const cryptonote::block& /*block*/) +{ + if (m_invalid_block_index == event_idx) + return bvc.m_verifivation_failed; + else + return !bvc.m_verifivation_failed; +} + +template +bool gen_double_advanced_tx_base::mark_last_valid_block(cryptonote::core& c, size_t /*ev_index*/, const std::vector& /*events*/) +{ + std::list block_list; + bool r = c.get_blocks(c.get_current_blockchain_height() - 1, 1, block_list); + CHECK_AND_ASSERT_MES(r, false, "core::get_blocks failed"); + m_last_valid_block = block_list.back(); + return true; +} + +template +bool gen_double_advanced_tx_base::mark_invalid_tx(cryptonote::core& /*c*/, size_t ev_index, const std::vector& /*events*/) +{ + m_invalid_tx_index = ev_index + 1; + return true; +} + +template +bool gen_double_advanced_tx_base::mark_invalid_block(cryptonote::core& /*c*/, size_t ev_index, const std::vector& /*events*/) +{ + m_invalid_block_index = ev_index + 1; + return true; +} + +template +bool gen_double_advanced_tx_base::check_double_advanced_tx(cryptonote::core& c, size_t /*ev_index*/, const std::vector& events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_double_advanced_tx_base::check_double_advanced_tx"); + + if (concrete_test::has_invalid_tx) + { + CHECK_NOT_EQ(invalid_index_value, m_invalid_tx_index); + } + CHECK_NOT_EQ(invalid_index_value, m_invalid_block_index); + + std::list block_list; + bool r = c.get_blocks(0, 18 + 7 * CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, block_list); + CHECK_TEST_CONDITION(r); + CHECK_TEST_CONDITION(m_last_valid_block == block_list.back()); + + CHECK_EQ(concrete_test::expected_pool_txs_count, c.get_pool_transactions_count()); + + cryptonote::account_base bob_account = boost::get(events[1]); + cryptonote::account_base alice_account = boost::get(events[2]); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + r = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(r); + CHECK_EQ(concrete_test::expected_bob_balance, get_balance(bob_account, blocks, mtx)); + CHECK_EQ(concrete_test::expected_alice_balance, get_balance(alice_account, blocks, mtx)); + CHECK_EQ(concrete_test::expected_bob_token_balance, get_token_balance(bob_account, blocks, mtx)); + CHECK_EQ(concrete_test::expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + + return true; +} + +//====================================================================================================================== + +template +bool gen_double_purchase_tx_in_the_same_block::generate(std::vector& events) const +{ + INIT_DOUBLE_ADVANCED_TX_TEST(); + + DO_CALLBACK(events, "mark_last_valid_block"); + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block); + + + auto safex_alice_purchase_from_bob = safex::safex_purchase{1, safex_offer_alice.price, safex_offer_alice.offer_id, safex_offer_alice.get_hash(), false}; + + //create purchase + MAKE_TX_CREATE_SAFEX_PURCHASE_LIST_START(events, txlist_3, alice_account, safex_alice_purchase_from_bob, alice_account.get_keys().m_account_address, blk_1r); + if (has_invalid_tx) + { + DO_CALLBACK(events, "mark_invalid_tx"); + } + //create purchase, but the item is out of stock + MAKE_CREATE_SAFEX_PURCHASE_TX_LIST(events, txlist_3, bob_account, safex_alice_purchase_from_bob, alice_account.get_keys().m_account_address, blk_1r); + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_13, blk_1r, miner_account, txlist_3); + + DO_CALLBACK(events, "check_double_advanced_tx"); + + return true; +} + +template +bool gen_edit_offer_purchase_tx_in_the_same_block::generate(std::vector& events) const +{ + INIT_DOUBLE_ADVANCED_TX_TEST(); + + DO_CALLBACK(events, "mark_last_valid_block"); + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block); + + + auto safex_alice_purchase_from_bob = safex::safex_purchase{1, safex_offer_alice.price, safex_offer_alice.offer_id, safex_offer_alice.get_hash(), false}; + +// safex_offer_alice.price += MK_COINS(10); +// safex_offer_alice.min_sfx_price += MK_COINS(10); + safex_offer_alice.description[0] = 'N'; + + + //edit offer + MAKE_TX_EDIT_SAFEX_OFFER_LIST_START(events, txlist_3, alice_account, safex_account_alice.pkey, safex_offer_alice, m_safex_account1_keys.get_keys(), blk_1r); + if (has_invalid_tx) + { + DO_CALLBACK(events, "mark_invalid_tx"); + } + //create purchase, but the item is out of stock + MAKE_CREATE_SAFEX_PURCHASE_TX_LIST(events, txlist_3, bob_account, safex_alice_purchase_from_bob, alice_account.get_keys().m_account_address, blk_1r); + + + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_13, blk_1r, miner_account, txlist_3); + + DO_CALLBACK(events, "check_double_advanced_tx"); + + return true; +} + +template +bool gen_purchase_edit_offer_tx_in_the_same_block::generate(std::vector& events) const +{ + INIT_DOUBLE_ADVANCED_TX_TEST(); + + DO_CALLBACK(events, "mark_last_valid_block"); + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, true); + + + auto safex_alice_purchase_from_bob = safex::safex_purchase{1, safex_offer_alice.price, safex_offer_alice.offer_id, safex_offer_alice.get_hash(), false}; + + safex_offer_alice.description[0] = 'N'; + + + //create purchase + MAKE_TX_CREATE_SAFEX_PURCHASE_LIST_START(events, txlist_3, bob_account, safex_alice_purchase_from_bob, alice_account.get_keys().m_account_address, blk_1r); + + //edit offer that is being purchased + MAKE_EDIT_SAFEX_OFFER_TX_LIST(events, txlist_3, alice_account, safex_account_alice.pkey, safex_offer_alice, m_safex_account1_keys.get_keys(), blk_1r); + + + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_13, blk_1r, miner_account, txlist_3); + + DO_CALLBACK(events, "check_double_advanced_tx"); + + return true; +} + + +template +bool gen_purchase_update_price_peg_tx_in_the_same_block::generate(std::vector& events) const +{ + INIT_DOUBLE_ADVANCED_TX_WITH_PRICE_PEG_TEST(); + + DO_CALLBACK(events, "mark_last_valid_block"); + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, true); + + std::string rate_str = cryptonote::print_money(safex_price_peg_alice.rate); + double rate = stod(rate_str); + + std::string price_str = cryptonote::print_money(safex_offer_alice.price); + double price = stod(price_str); + uint64_t pegged_price = (price*rate)*SAFEX_CASH_COIN; + + + auto safex_alice_purchase_from_bob = safex::safex_purchase{1, pegged_price, safex_offer_alice.offer_id, safex_offer_alice.get_hash(), false}; + + safex_price_peg_alice.rate *= 2; + + //update price peg that is used in offer that is purchased + MAKE_TX_UPDATE_SAFEX_PRICE_PEG_LIST_START(events, txlist_3, alice_account, safex_account_alice.pkey, safex_price_peg_alice, m_safex_account1_keys.get_keys(), blk_1r); + + //create purchase + MAKE_CREATE_SAFEX_PURCHASE_TX_LIST(events, txlist_3, bob_account, safex_alice_purchase_from_bob, alice_account.get_keys().m_account_address, blk_1r); + + + + + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_13, blk_1r, miner_account, txlist_3); + + DO_CALLBACK(events, "check_double_advanced_tx"); + + return true; +} diff --git a/tests/core_tests/double_spend.h b/tests/core_tests/double_spend.h index 25532f014..2a2b5003c 100644 --- a/tests/core_tests/double_spend.h +++ b/tests/core_tests/double_spend.h @@ -32,9 +32,6 @@ #pragma once #include "chaingen.h" -const size_t invalid_index_value = std::numeric_limits::max(); -const uint64_t FIRST_BLOCK_REWARD = (10000000 * SAFEX_CASH_COIN); - template class gen_double_spend_base : public test_chain_unit_base diff --git a/tests/core_tests/double_spend.inl b/tests/core_tests/double_spend.inl index 225a93b1b..964c88ad0 100644 --- a/tests/core_tests/double_spend.inl +++ b/tests/core_tests/double_spend.inl @@ -131,7 +131,6 @@ bool gen_double_spend_in_tx::generate(std::vector(tx_0.vout[0].target).key, se.amount); se.real_output = 0; - se.rct = false; se.real_out_tx_key = get_tx_pub_key_from_extra(tx_0); se.real_output_in_tx_index = 0; sources.push_back(se); diff --git a/tests/core_tests/double_spend_token.cpp b/tests/core_tests/double_spend_token.cpp new file mode 100644 index 000000000..924e2b05c --- /dev/null +++ b/tests/core_tests/double_spend_token.cpp @@ -0,0 +1,135 @@ +// Copyright (c) 2020, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#include "chaingen.h" +#include "double_spend_token.h" + +using namespace epee; +using namespace cryptonote; + + +//====================================================================================================================== + +gen_double_spend_token_in_different_chains::gen_double_spend_token_in_different_chains() +{ + REGISTER_CALLBACK_METHOD(gen_double_spend_token_in_different_chains, check_double_spend_token); +} + +bool gen_double_spend_token_in_different_chains::generate(std::vector& events) const +{ + INIT_DOUBLE_SPEND_TOKEN_TEST(); + + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, true); + MAKE_TOKEN_TX(events, tx_1, alice_account, bob_account, MK_TOKENS(10000), blk_1); + + + + + std::vector sources; + std::vector destinations; + + fill_tx_sources_and_destinations(events, blk_1r, alice_account, bob_account, send_amount - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, 0, sources, destinations); + + auto src_cash = sources[0]; + // Remove tx_1, it is being inserted back a little later + events.pop_back(); + + + + fill_token_tx_sources_and_destinations(events, blk_1r, alice_account, bob_account, MK_TOKENS(10000), TESTS_DEFAULT_FEE, 0, sources, destinations); + + for(auto &se: sources){ + if(se.amount > 0){ + se = src_cash; + break; + } + } + + for(auto &de: destinations){ + if(de.amount > 0){ + de.amount = send_amount - TESTS_DEFAULT_FEE; + break; + } + } + + + cryptonote::transaction tx_2; + if (!construct_tx(alice_account.get_keys(), sources, destinations, alice_account.get_keys().m_account_address, std::vector(), tx_2, 0)) + return false; + + + + + // Main chain + events.push_back(tx_1); + MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_account, tx_1); + + // Alternative chain + events.push_back(tx_2); + MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_1r, miner_account, tx_2); + // Switch to alternative chain + MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_account); + CHECK_AND_NO_ASSERT_MES(expected_blockchain_height == get_block_height(blk_4) + 1, false, "expected_blockchain_height has invalid value"); + + DO_CALLBACK(events, "check_double_spend_token"); + + return true; +} + +bool gen_double_spend_token_in_different_chains::check_double_spend_token(cryptonote::core& c, size_t /*ev_index*/, const std::vector& events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_double_spend_token_in_different_chains::check_double_spend_token"); + + std::list block_list; + bool r = c.get_blocks(0, 100 + 2 * CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, block_list); + CHECK_TEST_CONDITION(r); + + std::vector blocks(block_list.begin(), block_list.end()); + CHECK_EQ(expected_blockchain_height, blocks.size()); + + CHECK_EQ(1, c.get_pool_transactions_count()); + CHECK_EQ(1, c.get_alternative_blocks_count()); + + cryptonote::account_base bob_account = boost::get(events[1]); + cryptonote::account_base alice_account = boost::get(events[2]); + + std::vector chain; + map_hash2tx_t mtx; + r = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(r); + + CHECK_EQ(expected_bob_balance, get_balance(bob_account, blocks, mtx)); + CHECK_EQ(expected_alice_balance, get_balance(alice_account, blocks, mtx)); + CHECK_EQ(expected_bob_token_balance, get_token_balance(bob_account, blocks, mtx)); + CHECK_EQ(expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + + return true; +} diff --git a/tests/core_tests/double_spend_token.h b/tests/core_tests/double_spend_token.h new file mode 100644 index 000000000..69aeb8f6b --- /dev/null +++ b/tests/core_tests/double_spend_token.h @@ -0,0 +1,173 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#pragma once +#include "chaingen.h" + + +const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; + + +template +class gen_double_spend_token_base : public test_chain_unit_base +{ +public: + static const uint64_t send_amount = FIRST_BLOCK_REWARD - TESTS_DEFAULT_FEE; + + gen_double_spend_token_base(); + + bool check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool tx_added, size_t event_idx, const cryptonote::transaction& tx); + bool check_block_verification_context(const cryptonote::block_verification_context& bvc, size_t event_idx, const cryptonote::block& block); + + bool mark_last_valid_block(cryptonote::core& c, size_t ev_index, const std::vector& events); + bool mark_invalid_tx(cryptonote::core& c, size_t ev_index, const std::vector& events); + bool mark_invalid_block(cryptonote::core& c, size_t ev_index, const std::vector& events); + bool check_double_spend_token(cryptonote::core& c, size_t ev_index, const std::vector& events); + +private: + cryptonote::block m_last_valid_block; + size_t m_invalid_tx_index; + size_t m_invalid_block_index; +}; + + +template +struct gen_double_spend_token_in_tx : public gen_double_spend_token_base< gen_double_spend_token_in_tx > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = true; + static const size_t expected_pool_txs_count = 0; + static const uint64_t expected_bob_balance = 0; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount; + static const uint64_t expected_bob_token_balance = 0; + static const uint64_t expected_alice_token_balance = MK_TOKENS(10000); + + bool generate(std::vector& events) const; +}; + + +template +struct gen_double_spend_token_in_the_same_block : public gen_double_spend_token_base< gen_double_spend_token_in_the_same_block > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = !txs_keeped_by_block; + static const size_t expected_pool_txs_count = has_invalid_tx ? 1 : 2; + static const uint64_t expected_bob_balance = 0; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount; + static const uint64_t expected_bob_token_balance = 0; + static const uint64_t expected_alice_token_balance = MK_TOKENS(10000); + + bool generate(std::vector& events) const; +}; + + +template +struct gen_double_spend_token_in_different_blocks : public gen_double_spend_token_base< gen_double_spend_token_in_different_blocks > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = !txs_keeped_by_block; + static const size_t expected_pool_txs_count = has_invalid_tx ? 0 : 1; + static const uint64_t expected_bob_balance = 0; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount - TESTS_DEFAULT_FEE; + static const uint64_t expected_bob_token_balance = MK_TOKENS(10000); + static const uint64_t expected_alice_token_balance = 0; + + bool generate(std::vector& events) const; +}; + + +template +struct gen_double_spend_token_in_alt_chain_in_the_same_block : public gen_double_spend_token_base< gen_double_spend_token_in_alt_chain_in_the_same_block > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = !txs_keeped_by_block; + static const size_t expected_pool_txs_count = has_invalid_tx ? 1 : 2; + static const uint64_t expected_bob_balance = 0; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount; + static const uint64_t expected_bob_token_balance = 0; + static const uint64_t expected_alice_token_balance = MK_TOKENS(10000); + + bool generate(std::vector& events) const; +}; + + +template +struct gen_double_spend_token_in_alt_chain_in_different_blocks : public gen_double_spend_token_base< gen_double_spend_token_in_alt_chain_in_different_blocks > +{ + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const bool has_invalid_tx = !txs_keeped_by_block; + static const size_t expected_pool_txs_count = has_invalid_tx ? 1 : 2; + static const uint64_t expected_bob_balance = 0; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount; + static const uint64_t expected_bob_token_balance = 0; + static const uint64_t expected_alice_token_balance = MK_TOKENS(10000); + + bool generate(std::vector& events) const; +}; + + +class gen_double_spend_token_in_different_chains : public test_chain_unit_base +{ +public: + static const uint64_t send_amount = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE - TESTS_DEFAULT_FEE; + static const size_t expected_blockchain_height = 5 + 3 * CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; + static const uint64_t expected_bob_balance = 0; + static const uint64_t expected_alice_balance = MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE + send_amount - TESTS_DEFAULT_FEE; + static const uint64_t expected_bob_token_balance = MK_TOKENS(10000); + static const uint64_t expected_alice_token_balance = 0; + + gen_double_spend_token_in_different_chains(); + + bool generate(std::vector& events) const; + + bool check_double_spend_token(cryptonote::core& c, size_t ev_index, const std::vector& events); +}; + + +#define INIT_DOUBLE_SPEND_TOKEN_TEST() \ + uint64_t ts_start = 1514764801; \ + GENERATE_ACCOUNT(miner_account); \ + crypto::public_key miner_public_key = AUTO_VAL_INIT(miner_public_key); \ + crypto::secret_key_to_public_key(miner_account.get_keys().m_spend_secret_key, miner_public_key); \ + cryptonote::fakechain::set_core_tests_public_key(miner_public_key); \ + MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); \ + MAKE_ACCOUNT(events, bob_account); \ + MAKE_ACCOUNT(events, alice_account); \ + REWIND_BLOCKS(events, blk_00r, blk_0, miner_account); \ + MAKE_MIGRATION_TX(events, tx_migration, miner_account, alice_account, MK_TOKENS(10000), blk_0, get_hash_from_string(bitcoin_tx_hashes_str[0])); \ + MAKE_NEXT_BLOCK_TX1(events, blk_01, blk_00r, miner_account, tx_migration); \ + REWIND_BLOCKS(events, blk_0r, blk_01, miner_account); \ + MAKE_TX(events, tx_0, miner_account, alice_account, send_amount, blk_0r); \ + MAKE_NEXT_BLOCK_TX1(events, blk_1, blk_0r, miner_account, tx_0); \ + REWIND_BLOCKS(events, blk_1r, blk_1, miner_account); + + +#include "double_spend_token.inl" diff --git a/tests/core_tests/double_spend_token.inl b/tests/core_tests/double_spend_token.inl new file mode 100644 index 000000000..e9a43e01c --- /dev/null +++ b/tests/core_tests/double_spend_token.inl @@ -0,0 +1,418 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#pragma once + +//====================================================================================================================== + +template +gen_double_spend_token_base::gen_double_spend_token_base() + : m_invalid_tx_index(invalid_index_value) + , m_invalid_block_index(invalid_index_value) +{ + REGISTER_CALLBACK_METHOD(gen_double_spend_token_base, mark_last_valid_block); + REGISTER_CALLBACK_METHOD(gen_double_spend_token_base, mark_invalid_tx); + REGISTER_CALLBACK_METHOD(gen_double_spend_token_base, mark_invalid_block); + REGISTER_CALLBACK_METHOD(gen_double_spend_token_base, check_double_spend_token); +} + +template +bool gen_double_spend_token_base::check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool tx_added, size_t event_idx, const cryptonote::transaction& /*tx*/) +{ + if (m_invalid_tx_index == event_idx) + return tvc.m_verifivation_failed; + else + return !tvc.m_verifivation_failed && tx_added; +} + +template +bool gen_double_spend_token_base::check_block_verification_context(const cryptonote::block_verification_context& bvc, size_t event_idx, const cryptonote::block& /*block*/) +{ + if (m_invalid_block_index == event_idx) + return bvc.m_verifivation_failed; + else + return !bvc.m_verifivation_failed; +} + +template +bool gen_double_spend_token_base::mark_last_valid_block(cryptonote::core& c, size_t /*ev_index*/, const std::vector& /*events*/) +{ + std::list block_list; + bool r = c.get_blocks(c.get_current_blockchain_height() - 1, 1, block_list); + CHECK_AND_ASSERT_MES(r, false, "core::get_blocks failed"); + m_last_valid_block = block_list.back(); + return true; +} + +template +bool gen_double_spend_token_base::mark_invalid_tx(cryptonote::core& /*c*/, size_t ev_index, const std::vector& /*events*/) +{ + m_invalid_tx_index = ev_index + 1; + return true; +} + +template +bool gen_double_spend_token_base::mark_invalid_block(cryptonote::core& /*c*/, size_t ev_index, const std::vector& /*events*/) +{ + m_invalid_block_index = ev_index + 1; + return true; +} + +template +bool gen_double_spend_token_base::check_double_spend_token(cryptonote::core& c, size_t /*ev_index*/, const std::vector& events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_double_spend_token_base::check_double_spend_token"); + + if (concrete_test::has_invalid_tx) + { + CHECK_NOT_EQ(invalid_index_value, m_invalid_tx_index); + } + CHECK_NOT_EQ(invalid_index_value, m_invalid_block_index); + + std::list block_list; + bool r = c.get_blocks(0, 100 + 2 * CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, block_list); + CHECK_TEST_CONDITION(r); + CHECK_TEST_CONDITION(m_last_valid_block == block_list.back()); + + CHECK_EQ(concrete_test::expected_pool_txs_count, c.get_pool_transactions_count()); + + cryptonote::account_base bob_account = boost::get(events[1]); + cryptonote::account_base alice_account = boost::get(events[2]); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + r = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(r); + CHECK_EQ(concrete_test::expected_bob_balance, get_balance(bob_account, blocks, mtx)); + CHECK_EQ(concrete_test::expected_alice_balance, get_balance(alice_account, blocks, mtx)); + CHECK_EQ(concrete_test::expected_bob_token_balance, get_token_balance(bob_account, blocks, mtx)); + CHECK_EQ(concrete_test::expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + + return true; +} + +//====================================================================================================================== + +template +bool gen_double_spend_token_in_tx::generate(std::vector& events) const +{ + INIT_DOUBLE_SPEND_TOKEN_TEST(); + DO_CALLBACK(events, "mark_last_valid_block"); + + std::vector sources; + std::vector destinations; + + fill_token_tx_sources_and_destinations(events, blk_1r, alice_account, bob_account, MK_TOKENS(10000), TESTS_DEFAULT_FEE, 0, sources, destinations); + + for(auto se: sources){ + if(se.token_amount > 0){ + sources.push_back(se); + break; + } + } + + + cryptonote::transaction tx_1; + if (!construct_tx(alice_account.get_keys(), sources, destinations, alice_account.get_keys().m_account_address, std::vector(), tx_1, 0)) + return false; + + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block); + DO_CALLBACK(events, "mark_invalid_tx"); + events.push_back(tx_1); + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_account, tx_1); + DO_CALLBACK(events, "check_double_spend_token"); + + return true; +} + +template +bool gen_double_spend_token_in_the_same_block::generate(std::vector& events) const +{ + INIT_DOUBLE_SPEND_TOKEN_TEST(); + + DO_CALLBACK(events, "mark_last_valid_block"); + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block); + + MAKE_TOKEN_TX_LIST_START(events, txs_1, alice_account, bob_account, MK_TOKENS(10000), blk_1); + cryptonote::transaction tx_1 = txs_1.front(); + auto tx_1_idx = events.size() - 1; + + std::vector sources; + std::vector destinations; + + fill_tx_sources_and_destinations(events, blk_1r, alice_account, bob_account, send_amount - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, 0, sources, destinations); + + auto src_cash = sources[0]; + // Remove tx_1, it is being inserted back a little later + events.pop_back(); + + + + fill_token_tx_sources_and_destinations(events, blk_1r, alice_account, bob_account, MK_TOKENS(10000), TESTS_DEFAULT_FEE, 0, sources, destinations); + + for(auto &se: sources){ + if(se.amount > 0){ + se = src_cash; + break; + } + } + + for(auto &de: destinations){ + if(de.amount > 0){ + de.amount = send_amount - TESTS_DEFAULT_FEE; + break; + } + } + + + cryptonote::transaction tx_2; + if (!construct_tx(alice_account.get_keys(), sources, destinations, alice_account.get_keys().m_account_address, std::vector(), tx_2, 0)) + return false; + + events.push_back(tx_2); + txs_1.push_back(tx_2); + + if (has_invalid_tx) + { + DO_CALLBACK(events, "mark_invalid_tx"); + } + + events.push_back( tx_1); + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_2, blk_1r, miner_account, txs_1); + DO_CALLBACK(events, "check_double_spend_token"); + + return true; +} + +template +bool gen_double_spend_token_in_different_blocks::generate(std::vector& events) const +{ + INIT_DOUBLE_SPEND_TOKEN_TEST(); + + DO_CALLBACK(events, "mark_last_valid_block"); + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block); + + // Create two identical transactions, but don't push it to events list + MAKE_TOKEN_TX(events, tx_blk_2, alice_account, bob_account, MK_TOKENS(10000), blk_1); + + + + + + std::vector sources; + std::vector destinations; + + fill_tx_sources_and_destinations(events, blk_1r, alice_account, bob_account, send_amount - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, 0, sources, destinations); + + auto src_cash = sources[0]; + + events.pop_back(); + + fill_token_tx_sources_and_destinations(events, blk_1r, alice_account, bob_account, MK_TOKENS(10000), TESTS_DEFAULT_FEE, 0, sources, destinations); + + for(auto &se: sources){ + if(se.amount > 0){ + se = src_cash; + break; + } + } + + for(auto &de: destinations){ + if(de.amount > 0){ + de.amount = send_amount - TESTS_DEFAULT_FEE; + break; + } + } + + + cryptonote::transaction tx_blk_3; + if (!construct_tx(alice_account.get_keys(), sources, destinations, alice_account.get_keys().m_account_address, std::vector(), tx_blk_3, 0)) + return false; + + events.push_back(tx_blk_2); + MAKE_NEXT_BLOCK_TX1(events, blk_2, blk_1r, miner_account, tx_blk_2); + DO_CALLBACK(events, "mark_last_valid_block"); + + if (has_invalid_tx) + { + DO_CALLBACK(events, "mark_invalid_tx"); + } + events.push_back(tx_blk_3); + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_2, miner_account, tx_blk_3); + + DO_CALLBACK(events, "check_double_spend_token"); + + return true; +} + +template +bool gen_double_spend_token_in_alt_chain_in_the_same_block::generate(std::vector& events) const +{ + INIT_DOUBLE_SPEND_TOKEN_TEST(); + + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block); + + // Main chain + MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_account); + DO_CALLBACK(events, "mark_last_valid_block"); + + // Alt chain + MAKE_TOKEN_TX_LIST_START(events, txs_1, alice_account, bob_account, MK_TOKENS(10000), blk_1); + cryptonote::transaction tx_1 = txs_1.front(); + auto tx_1_idx = events.size() - 1; + + + + std::vector sources; + std::vector destinations; + + fill_tx_sources_and_destinations(events, blk_1r, alice_account, bob_account, send_amount - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, 0, sources, destinations); + + auto src_cash = sources[0]; + // Remove tx_1, it is being inserted back a little later + events.pop_back(); + + + + fill_token_tx_sources_and_destinations(events, blk_1r, alice_account, bob_account, MK_TOKENS(10000), TESTS_DEFAULT_FEE, 0, sources, destinations); + + for(auto &se: sources){ + if(se.amount > 0){ + se = src_cash; + break; + } + } + + for(auto &de: destinations){ + if(de.amount > 0){ + de.amount = send_amount - TESTS_DEFAULT_FEE; + break; + } + } + + + cryptonote::transaction tx_2; + if (!construct_tx(alice_account.get_keys(), sources, destinations, alice_account.get_keys().m_account_address, std::vector(), tx_2, 0)) + return false; + + + + events.push_back(tx_2); + txs_1.push_back(tx_2); + + + if (has_invalid_tx) + { + DO_CALLBACK(events, "mark_invalid_tx"); + } + + events.push_back( tx_1); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_1r, miner_account, txs_1); + + // Try to switch to alternative chain + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK(events, blk_4, blk_3, miner_account); + + DO_CALLBACK(events, "check_double_spend_token"); + + return true; +} + +template +bool gen_double_spend_token_in_alt_chain_in_different_blocks::generate(std::vector& events) const +{ + INIT_DOUBLE_SPEND_TOKEN_TEST(); + + SET_EVENT_VISITOR_SETT(events, event_visitor_settings::set_txs_keeped_by_block, txs_keeped_by_block); + + // Main chain + MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner_account); + DO_CALLBACK(events, "mark_last_valid_block"); + + // Alternative chain + MAKE_TOKEN_TX(events, tx_1, alice_account, bob_account, MK_TOKENS(10000), blk_1); + + + + + std::vector sources; + std::vector destinations; + + fill_tx_sources_and_destinations(events, blk_1r, alice_account, bob_account, send_amount - TESTS_DEFAULT_FEE, TESTS_DEFAULT_FEE, 0, sources, destinations); + + auto src_cash = sources[0]; + // Remove tx_1, it is being inserted back a little later + events.pop_back(); + + + + fill_token_tx_sources_and_destinations(events, blk_1r, alice_account, bob_account, MK_TOKENS(10000), TESTS_DEFAULT_FEE, 0, sources, destinations); + + for(auto &se: sources){ + if(se.amount > 0){ + se = src_cash; + break; + } + } + + for(auto &de: destinations){ + if(de.amount > 0){ + de.amount = send_amount - TESTS_DEFAULT_FEE; + break; + } + } + + + cryptonote::transaction tx_2; + if (!construct_tx(alice_account.get_keys(), sources, destinations, alice_account.get_keys().m_account_address, std::vector(), tx_2, 0)) + return false; + + + events.push_back(tx_1); + MAKE_NEXT_BLOCK_TX1(events, blk_3, blk_1r, miner_account, tx_1); + + // Try to switch to alternative chain + if (has_invalid_tx) + { + DO_CALLBACK(events, "mark_invalid_tx"); + } + events.push_back(tx_2); + DO_CALLBACK(events, "mark_invalid_block"); + MAKE_NEXT_BLOCK_TX1(events, blk_4, blk_3, miner_account, tx_2); + + DO_CALLBACK(events, "check_double_spend_token"); + + return true; +} diff --git a/tests/core_tests/integer_overflow.cpp b/tests/core_tests/integer_overflow.cpp index c729c9891..9be881e9c 100644 --- a/tests/core_tests/integer_overflow.cpp +++ b/tests/core_tests/integer_overflow.cpp @@ -39,7 +39,7 @@ namespace { void split_miner_tx_outs(transaction& miner_tx, uint64_t amount_1) { - uint64_t total_amount = get_outs_money_amount(miner_tx); + uint64_t total_amount = get_outs_cash_amount(miner_tx); uint64_t amount_2 = total_amount - amount_1; txout_target_v target = miner_tx.vout[0].target; @@ -62,7 +62,6 @@ namespace se.amount = tx.vout[out_idx].amount; se.push_output(0, boost::get(tx.vout[out_idx].target).key, se.amount); se.real_output = 0; - se.rct = false; se.real_out_tx_key = get_tx_pub_key_from_extra(tx); se.real_out_additional_tx_keys = get_additional_tx_pub_keys_from_extra(tx); se.real_output_in_tx_index = out_idx; @@ -74,13 +73,12 @@ namespace { cryptonote::tx_source_entry se; se.token_amount = tx.vout[out_idx].token_amount; - se.token_transaction = true; se.push_output(0, boost::get(tx.vout[out_idx].target).key, se.token_amount); se.real_output = 0; - se.rct = false; se.real_out_tx_key = get_tx_pub_key_from_extra(tx); se.real_out_additional_tx_keys = get_additional_tx_pub_keys_from_extra(tx); se.real_output_in_tx_index = out_idx; + se.referenced_output_type = cryptonote::tx_out_type::out_token; sources.push_back(se); } @@ -324,4 +322,4 @@ crypto::hash gen_uint_token_overflow_1::get_hash_from_string(const std::string h } const crypto::hash bitcoin_transaction_hash = *reinterpret_cast(expected_bitcoin_hash_data.data()); return bitcoin_transaction_hash; -} \ No newline at end of file +} diff --git a/tests/core_tests/multisig.cpp b/tests/core_tests/multisig.cpp deleted file mode 100644 index 2471a34f8..000000000 --- a/tests/core_tests/multisig.cpp +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright (c) 2018, The Safex 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 -// Parts of this file are originally copyright (c) 2017-2018 The Monero Project - -#include "ringct/rctSigs.h" -#include "cryptonote_basic/cryptonote_basic.h" -#include "multisig/multisig.h" -#include "common/apply_permutation.h" -#include "chaingen.h" -#include "multisig.h" -#include "device/device.hpp" -using namespace epee; -using namespace crypto; -using namespace cryptonote; - -//#define NO_MULTISIG - -//---------------------------------------------------------------------------------------------------------------------- -// Tests - -bool gen_multisig_tx_validation_base::generate_with(std::vector& events, - size_t inputs, size_t mixin, uint64_t amount_paid, bool valid, - size_t threshold, size_t total, size_t creator, std::vector signers, - const std::function &sources, std::vector &destinations)> &pre_tx, - const std::function &post_tx) const -{ - uint64_t ts_start = 1338224400; - bool r; - - CHECK_AND_ASSERT_MES(total >= 2, false, "Bad scheme"); - CHECK_AND_ASSERT_MES(threshold <= total, false, "Bad scheme"); - CHECK_AND_ASSERT_MES(threshold >= total - 1, false, "Unsupported scheme"); -#ifdef NO_MULTISIG - CHECK_AND_ASSERT_MES(total <= 5, false, "Unsupported scheme"); -#endif - CHECK_AND_ASSERT_MES(inputs >= 1 && inputs <= 8, false, "Inputs should between 1 and 8"); - - // given as 1 based for clarity - --creator; - for (size_t &signer: signers) - --signer; - - CHECK_AND_ASSERT_MES(creator < total, false, "invalid creator"); - for (size_t signer: signers) - CHECK_AND_ASSERT_MES(signer < total, false, "invalid signer"); - -#ifdef NO_MULTISIG - GENERATE_ACCOUNT(acc0); - GENERATE_ACCOUNT(acc1); - GENERATE_ACCOUNT(acc2); - GENERATE_ACCOUNT(acc3); - GENERATE_ACCOUNT(acc4); - account_base miner_account[5] = {acc0, acc1, acc2, acc3, acc4}; -#else - GENERATE_MULTISIG_ACCOUNT(miner_account, threshold, total); -#endif - - MAKE_GENESIS_BLOCK(events, blk_0, miner_account[creator], ts_start); - - // create 8 miner accounts, and have them mine the next 8 blocks - // they will have a coinbase with a single out that's pseudo rct - constexpr size_t n_coinbases = 8; - cryptonote::account_base miner_accounts[n_coinbases]; - const cryptonote::block *prev_block = &blk_0; - cryptonote::block blocks[n_coinbases]; - for (size_t n = 0; n < n_coinbases; ++n) { - // the first block goes to the multisig account - miner_accounts[n].generate(); - account_base &account = n < inputs ? miner_account[creator] : miner_accounts[n]; - CHECK_AND_ASSERT_MES(generator.construct_block_manually(blocks[n], *prev_block, account, - test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version | test_generator::bf_max_outs, - 4, 4, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), std::vector(), 0, 1, 4), - false, "Failed to generate block"); - events.push_back(blocks[n]); - prev_block = blocks + n; - LOG_PRINT_L0("Initial miner tx " << n << ": " << obj_to_json_str(blocks[n].miner_tx)); - LOG_PRINT_L0("in block: " << obj_to_json_str(blocks[n])); - } - - // rewind - cryptonote::block blk_r, blk_last; - { - blk_last = blocks[n_coinbases - 1]; - for (size_t i = 0; i < CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; ++i) - { - cryptonote::block blk; - CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_accounts[0], - test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version | test_generator::bf_max_outs, - 4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), std::vector(), 0, 1, 4), - false, "Failed to generate block"); - events.push_back(blk); - blk_last = blk; - } - blk_r = blk_last; - } - - cryptonote::keypair in_ephemeral; - crypto::public_key tx_pub_key[n_coinbases]; - crypto::public_key output_pub_key[n_coinbases]; - for (size_t n = 0; n < n_coinbases; ++n) - { - tx_pub_key[n] = get_tx_pub_key_from_extra(blocks[n].miner_tx); - MDEBUG("tx_pub_key: " << tx_pub_key); - output_pub_key[n] = boost::get(blocks[n].miner_tx.vout[0].target).key; - MDEBUG("output_pub_key: " << output_pub_key); - } - - std::unordered_map subaddresses; - subaddresses[miner_account[0].get_keys().m_account_address.m_spend_public_key] = {0,0}; - -#ifndef NO_MULTISIG - // create k/L/R/ki for that output we're going to spend - std::vector>> account_k(total); - std::vector>> account_L(total); - std::vector>> account_R(total); - std::vector>> account_ki(total); - std::vector additional_tx_keys; - for (size_t msidx = 0; msidx < total; ++msidx) - { - CHECK_AND_ASSERT_MES(miner_account[msidx].get_keys().m_account_address.m_spend_public_key == miner_account[0].get_keys().m_account_address.m_spend_public_key, - false, "Mismatched spend public keys"); - - size_t nlr = threshold < total ? threshold - 1 : 1; - account_k[msidx].resize(inputs); - account_L[msidx].resize(inputs); - account_R[msidx].resize(inputs); - account_ki[msidx].resize(inputs); - for (size_t tdidx = 0; tdidx < inputs; ++tdidx) - { - account_L[msidx][tdidx].resize(nlr); - account_R[msidx][tdidx].resize(nlr); - for (size_t n = 0; n < nlr; ++n) - { - account_k[msidx][tdidx].push_back(rct::rct2sk(rct::skGen())); - cryptonote::generate_multisig_LR(output_pub_key[tdidx], account_k[msidx][tdidx][n], account_L[msidx][tdidx][n], account_R[msidx][tdidx][n]); - } - size_t numki = miner_account[msidx].get_multisig_keys().size(); - account_ki[msidx][tdidx].resize(numki); - for (size_t kiidx = 0; kiidx < numki; ++kiidx) - { - r = cryptonote::generate_multisig_key_image(miner_account[msidx].get_keys(), kiidx, output_pub_key[tdidx], account_ki[msidx][tdidx][kiidx]); - CHECK_AND_ASSERT_MES(r, false, "Failed to generate multisig export key image"); - } - MDEBUG("Party " << msidx << ":"); - MDEBUG("spend: sec " << miner_account[msidx].get_keys().m_spend_secret_key << ", pub " << miner_account[msidx].get_keys().m_account_address.m_spend_public_key); - MDEBUG("view: sec " << miner_account[msidx].get_keys().m_view_secret_key << ", pub " << miner_account[msidx].get_keys().m_account_address.m_view_public_key); - for (const auto &k: miner_account[msidx].get_multisig_keys()) - MDEBUG("msk: " << k); - for (size_t n = 0; n < account_k[msidx][tdidx].size(); ++n) - { - MDEBUG("k: " << account_k[msidx][tdidx][n]); - MDEBUG("L: " << account_L[msidx][tdidx][n]); - MDEBUG("R: " << account_R[msidx][tdidx][n]); - } - for (const auto &ki: account_ki[msidx][tdidx]) - MDEBUG("ki: " << ki); - } - } -#endif - - // create kLRki - std::vector kLRkis; - std::unordered_set used_L; - for (size_t tdidx = 0; tdidx < inputs; ++tdidx) - { - kLRkis.push_back(rct::multisig_kLRki()); - rct::multisig_kLRki &kLRki = kLRkis.back(); -#ifdef NO_MULTISIG - kLRki = {rct::zero(), rct::zero(), rct::zero(), rct::zero()}; -#else - kLRki.k = rct::sk2rct(account_k[creator][tdidx][0]); - kLRki.L = rct::pk2rct(account_L[creator][tdidx][0]); - kLRki.R = rct::pk2rct(account_R[creator][tdidx][0]); - MDEBUG("Starting with k " << kLRki.k); - MDEBUG("Starting with L " << kLRki.L); - MDEBUG("Starting with R " << kLRki.R); - for (size_t msidx = 0; msidx < total; ++msidx) - { - if (msidx == creator) - continue; - if (std::find(signers.begin(), signers.end(), msidx) == signers.end()) - continue; - for (size_t lr = 0; lr < account_L[msidx][tdidx].size(); ++lr) - { - if (used_L.find(account_L[msidx][tdidx][lr]) == used_L.end()) - { - used_L.insert(account_L[msidx][tdidx][lr]); - MDEBUG("Adding L " << account_L[msidx][tdidx][lr] << " (for k " << account_k[msidx][tdidx][lr] << ")"); - MDEBUG("Adding R " << account_R[msidx][tdidx][lr]); - rct::addKeys((rct::key&)kLRki.L, kLRki.L, rct::pk2rct(account_L[msidx][tdidx][lr])); - rct::addKeys((rct::key&)kLRki.R, kLRki.R, rct::pk2rct(account_R[msidx][tdidx][lr])); - break; - } - } - } - std::vector pkis; - for (size_t msidx = 0; msidx < total; ++msidx) - for (size_t n = 0; n < account_ki[msidx][tdidx].size(); ++n) - pkis.push_back(account_ki[msidx][tdidx][n]); - r = cryptonote::generate_multisig_composite_key_image(miner_account[0].get_keys(), subaddresses, output_pub_key[tdidx], tx_pub_key[tdidx], additional_tx_keys, 0, pkis, (crypto::key_image&)kLRki.ki); - CHECK_AND_ASSERT_MES(r, false, "Failed to generate composite key image"); - MDEBUG("composite ki: " << kLRki.ki); - MDEBUG("L: " << kLRki.L); - MDEBUG("R: " << kLRki.R); - for (size_t n = 1; n < total; ++n) - { - rct::key ki; - r = cryptonote::generate_multisig_composite_key_image(miner_account[n].get_keys(), subaddresses, output_pub_key[tdidx], tx_pub_key[tdidx], additional_tx_keys, 0, pkis, (crypto::key_image&)ki); - CHECK_AND_ASSERT_MES(r, false, "Failed to generate composite key image"); - CHECK_AND_ASSERT_MES(kLRki.ki == ki, false, "Composite key images do not match"); - } - } -#endif - - // create a tx: we have 8 outputs, all from coinbase, so "fake" rct - use 2 - std::vector sources; - for (size_t n = 0; n < inputs; ++n) - { - sources.resize(sources.size() + 1); - tx_source_entry& src = sources.back(); - - src.real_output = n; - src.amount = blocks[n].miner_tx.vout[0].amount; - src.real_out_tx_key = tx_pub_key[n]; - src.real_output_in_tx_index = 0; - src.mask = rct::identity(); - src.rct = true; - src.multisig_kLRki = kLRkis[n]; - - for (size_t m = 0; m <= mixin; ++m) - { - rct::ctkey ctkey; - ctkey.dest = rct::pk2rct(boost::get(blocks[m].miner_tx.vout[0].target).key); - MDEBUG("using " << (m == n ? "real" : "fake") << " input " << ctkey.dest); - ctkey.mask = rct::commit(blocks[m].miner_tx.vout[0].amount, rct::identity()); // since those are coinbases, the masks are known - src.outputs.push_back(std::make_pair(m, ctkey)); - } - } - - //fill outputs entry - tx_destination_entry td; - td.addr = miner_account[creator].get_keys().m_account_address; - td.amount = amount_paid; - std::vector destinations; - destinations.push_back(td); - - if (pre_tx) - pre_tx(sources, destinations); - - transaction tx; - crypto::secret_key tx_key; -#ifdef NO_MULTISIG - rct::multisig_out *msoutp = NULL; -#else - rct::multisig_out msout; - rct::multisig_out *msoutp = &msout; -#endif - std::vector additional_tx_secret_keys; - auto sources_copy = sources; - bool use_rct = (CURRENT_TRANSACTION_VERSION == 2)?true:false; - r = construct_tx_and_get_tx_key(miner_account[creator].get_keys(), subaddresses, sources, destinations, boost::none, std::vector(), tx, 0, tx_key, additional_tx_secret_keys, use_rct, false, msoutp); - CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); - -#ifndef NO_MULTISIG - // work out the permutation done on sources - std::vector ins_order; - for (size_t n = 0; n < sources.size(); ++n) - { - for (size_t idx = 0; idx < sources_copy.size(); ++idx) - { - CHECK_AND_ASSERT_MES((size_t)sources_copy[idx].real_output < sources_copy[idx].outputs.size(), - false, "Invalid real_output"); - if (sources_copy[idx].outputs[sources_copy[idx].real_output].second.dest == sources[n].outputs[sources[n].real_output].second.dest) - ins_order.push_back(idx); - } - } - CHECK_AND_ASSERT_MES(ins_order.size() == sources.size(), false, "Failed to work out sources permutation"); -#endif - -#ifndef NO_MULTISIG - // sign - std::unordered_set used_keys; - const std::vector &msk0 = miner_account[creator].get_multisig_keys(); - for (const auto &sk: msk0) - used_keys.insert(sk); - for (size_t signer: signers) - { - rct::key skey = rct::zero(); - const std::vector &msk1 = miner_account[signer].get_multisig_keys(); - for (size_t n = 0; n < msk1.size(); ++n) - { - const crypto::secret_key &sk1 = msk1[n]; - if (used_keys.find(sk1) == used_keys.end()) - { - used_keys.insert(sk1); - sc_add(skey.bytes, skey.bytes, rct::sk2rct(sk1).bytes); - } - } - CHECK_AND_ASSERT_MES(!(skey == rct::zero()), false, "failed to find secret multisig key to sign transaction"); - std::vector indices; - for (const auto &src: sources_copy) - indices.push_back(src.real_output); - rct::keyV k; - for (size_t tdidx = 0; tdidx < inputs; ++tdidx) - { - k.push_back(rct::zero()); - for (size_t n = 0; n < account_k[signer][tdidx].size(); ++n) - { - crypto::public_key L; - rct::scalarmultBase((rct::key&)L, rct::sk2rct(account_k[signer][tdidx][n])); - if (used_L.find(L) != used_L.end()) - { - sc_add(k.back().bytes, k.back().bytes, rct::sk2rct(account_k[signer][tdidx][n]).bytes); - } - } - CHECK_AND_ASSERT_MES(!(k.back() == rct::zero()), false, "failed to find k to sign transaction"); - } - tools::apply_permutation(ins_order, indices); - tools::apply_permutation(ins_order, k); - - MDEBUG("signing with k size " << k.size()); - MDEBUG("signing with k " << k.back()); - MDEBUG("signing with sk " << skey); - for (const auto &sk: used_keys) - MDEBUG(" created with sk " << sk); - MDEBUG("signing with c size " << msout.c.size()); - MDEBUG("signing with c " << msout.c.back()); - r = rct::signMultisig(tx.rct_signatures, indices, k, msout, skey); - CHECK_AND_ASSERT_MES(r, false, "failed to sign transaction"); - } -#endif - - // verify this tx is really to the expected address - const crypto::public_key tx_pub_key2 = get_tx_pub_key_from_extra(tx, 0); - crypto::key_derivation derivation; - r = crypto::generate_key_derivation(tx_pub_key2, miner_account[creator].get_keys().m_view_secret_key, derivation); - CHECK_AND_ASSERT_MES(r, false, "Failed to generate derivation"); - uint64_t n_outs = 0, amount = 0; - std::vector additional_derivations; - for (size_t n = 0; n < tx.vout.size(); ++n) - { - CHECK_AND_ASSERT_MES(typeid(txout_to_key) == tx.vout[n].target.type(), false, "Unexpected tx out type"); - if (is_out_to_acc_precomp(subaddresses, boost::get(tx.vout[n].target).key, derivation, additional_derivations, n, hw::get_device(("default")))) - { - ++n_outs; - CHECK_AND_ASSERT_MES(tx.vout[n].amount == 0, false, "Destination amount is not zero"); - rct::key Ctmp; - crypto::secret_key scalar1; - crypto::derivation_to_scalar(derivation, n, scalar1); - rct::ecdhTuple ecdh_info = tx.rct_signatures.ecdhInfo[n]; - rct::ecdhDecode(ecdh_info, rct::sk2rct(scalar1)); - rct::key C = tx.rct_signatures.outPk[n].mask; - rct::addKeys2(Ctmp, ecdh_info.mask, ecdh_info.amount, rct::H); - CHECK_AND_ASSERT_MES(rct::equalKeys(C, Ctmp), false, "Failed to decode amount"); - amount += rct::h2d(ecdh_info.amount); - } - } - CHECK_AND_ASSERT_MES(n_outs == 1, false, "Not exactly 1 output was received"); - CHECK_AND_ASSERT_MES(amount == amount_paid, false, "Amount paid was not the expected amount"); - - if (post_tx) - post_tx(tx); - - if (!valid) - DO_CALLBACK(events, "mark_invalid_tx"); - events.push_back(tx); - LOG_PRINT_L0("Test tx: " << obj_to_json_str(tx)); - - return true; -} - -bool gen_multisig_tx_valid_22_1_2::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, true, 2, 2, 1, {2}, NULL, NULL); -} - -bool gen_multisig_tx_valid_22_1_2_many_inputs::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 4, mixin, amount_paid, true, 2, 2, 1, {2}, NULL, NULL); -} - -bool gen_multisig_tx_valid_22_2_1::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, true, 2, 2, 2, {1}, NULL, NULL); -} - -bool gen_multisig_tx_valid_33_1_23::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, true, 3, 3, 1, {2, 3}, NULL, NULL); -} - -bool gen_multisig_tx_valid_33_3_21::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, true, 3, 3, 3, {2, 1}, NULL, NULL); -} - -bool gen_multisig_tx_valid_23_1_2::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, true, 2, 3, 1, {2}, NULL, NULL); -} - -bool gen_multisig_tx_valid_23_1_3::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, true, 2, 3, 1, {3}, NULL, NULL); -} - -bool gen_multisig_tx_valid_23_2_1::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, true, 2, 3, 2, {1}, NULL, NULL); -} - -bool gen_multisig_tx_valid_23_2_3::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, true, 2, 3, 2, {3}, NULL, NULL); -} - -bool gen_multisig_tx_valid_45_1_234::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, true, 4, 5, 1, {2, 3, 4}, NULL, NULL); -} - -bool gen_multisig_tx_valid_45_4_135_many_inputs::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 4, mixin, amount_paid, true, 4, 5, 4, {1, 3, 5}, NULL, NULL); -} - -bool gen_multisig_tx_valid_89_3_1245789::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, true, 8, 9, 3, {1, 2, 4, 5, 7, 8, 9}, NULL, NULL); -} - -bool gen_multisig_tx_invalid_22_1__no_threshold::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, false, 2, 2, 1, {}, NULL, NULL); -} - -bool gen_multisig_tx_invalid_33_1__no_threshold::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, false, 3, 3, 1, {}, NULL, NULL); -} - -bool gen_multisig_tx_invalid_33_1_2_no_threshold::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, false, 3, 3, 1, {2}, NULL, NULL); -} - -bool gen_multisig_tx_invalid_33_1_3_no_threshold::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, false, 3, 3, 1, {3}, NULL, NULL); -} - -bool gen_multisig_tx_invalid_23_1__no_threshold::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, false, 2, 3, 1, {}, NULL, NULL); -} - -bool gen_multisig_tx_invalid_45_5_23_no_threshold::generate(std::vector& events) const -{ - const size_t mixin = 4; - const uint64_t amount_paid = 10000; - return generate_with(events, 2, mixin, amount_paid, false, 4, 5, 5, {2, 3}, NULL, NULL); -} diff --git a/tests/core_tests/multisig.h b/tests/core_tests/multisig.h deleted file mode 100644 index 62da5696b..000000000 --- a/tests/core_tests/multisig.h +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (c) 2018, The Safex 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 -// Parts of this file are originally copyright (c) 2017-2018 The Monero Project - -#pragma once -#include "chaingen.h" - -struct gen_multisig_tx_validation_base : public test_chain_unit_base -{ - gen_multisig_tx_validation_base() - : m_invalid_tx_index(0) - , m_invalid_block_index(0) - { - REGISTER_CALLBACK_METHOD(gen_multisig_tx_validation_base, mark_invalid_tx); - REGISTER_CALLBACK_METHOD(gen_multisig_tx_validation_base, mark_invalid_block); - } - - bool check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool tx_added, size_t event_idx, const cryptonote::transaction& /*tx*/) - { - if (m_invalid_tx_index == event_idx) - return tvc.m_verifivation_failed; - else - return !tvc.m_verifivation_failed && tx_added; - } - - bool check_block_verification_context(const cryptonote::block_verification_context& bvc, size_t event_idx, const cryptonote::block& /*block*/) - { - if (m_invalid_block_index == event_idx) - return bvc.m_verifivation_failed; - else - return !bvc.m_verifivation_failed; - } - - bool mark_invalid_block(cryptonote::core& /*c*/, size_t ev_index, const std::vector& /*events*/) - { - m_invalid_block_index = ev_index + 1; - return true; - } - - bool mark_invalid_tx(cryptonote::core& /*c*/, size_t ev_index, const std::vector& /*events*/) - { - m_invalid_tx_index = ev_index + 1; - return true; - } - - bool generate_with(std::vector& events, size_t inputs, size_t mixin, - uint64_t amount_paid, bool valid, - size_t threshold, size_t total, size_t creator, std::vector signers, - const std::function &sources, std::vector &destinations)> &pre_tx, - const std::function &post_tx) const; - -private: - size_t m_invalid_tx_index; - size_t m_invalid_block_index; -}; - -template<> -struct get_test_options { - const std::pair hard_forks[3] = {std::make_pair(1, 0), std::make_pair(4, 1), std::make_pair(0, 0)}; - const cryptonote::test_options test_options = { - hard_forks - }; -}; - -// valid -struct gen_multisig_tx_valid_22_1_2: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_valid_22_1_2_many_inputs: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_valid_22_2_1: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_valid_33_1_23: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_valid_33_3_21: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_valid_23_1_2: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_valid_23_1_3: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_valid_23_2_1: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_valid_23_2_3: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_valid_45_1_234: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_valid_45_4_135_many_inputs: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_valid_89_3_1245789: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -// invalid -struct gen_multisig_tx_invalid_22_1__no_threshold: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_invalid_33_1__no_threshold: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_invalid_33_1_2_no_threshold: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_invalid_33_1_3_no_threshold: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_invalid_23_1__no_threshold: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_multisig_tx_invalid_45_5_23_no_threshold: public gen_multisig_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; diff --git a/tests/core_tests/network_fee.cpp b/tests/core_tests/network_fee.cpp new file mode 100644 index 000000000..ac8be9dda --- /dev/null +++ b/tests/core_tests/network_fee.cpp @@ -0,0 +1,183 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#include +#include + +#include "include_base_utils.h" + +#include "console_handler.h" + +#include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/cryptonote_format_utils.h" + +#include "safex/safex_core.h" + +#include "chaingen.h" +#include "network_fee.h" + + + +using namespace std; + +using namespace epee; +using namespace cryptonote; + + +crypto::hash gen_network_fee_001::get_hash_from_string(const std::string hashstr) { + //parse bitcoin transaction hash + cryptonote::blobdata expected_bitcoin_hash_data; + if (!epee::string_tools::parse_hexstr_to_binbuff(std::string(hashstr), expected_bitcoin_hash_data) || expected_bitcoin_hash_data.size() != sizeof(crypto::hash)) + { + std::cerr << "failed to parse bitcoin transaction hash" << endl; + return boost::value_initialized(); + } + const crypto::hash bitcoin_transaction_hash = *reinterpret_cast(expected_bitcoin_hash_data.data()); + return bitcoin_transaction_hash; +} + +gen_network_fee_001::gen_network_fee_001() +{ + REGISTER_CALLBACK("verify_network_fee", gen_network_fee_001::verify_network_fee); +} + +bool gen_network_fee_001::generate(std::vector &events) +{ + uint64_t ts_start = 1530720632; + + GENERATE_ACCOUNT(miner); + crypto::public_key miner_public_key = AUTO_VAL_INIT(miner_public_key); + crypto::secret_key_to_public_key(miner.get_keys().m_spend_secret_key, miner_public_key); + cryptonote::fakechain::set_core_tests_public_key(miner_public_key); + + GENERATE_ACCOUNT(miner2); + + MAKE_GENESIS_BLOCK(events, blk_0, miner, ts_start); + + MAKE_ACCOUNT(events, alice); + MAKE_ACCOUNT(events, bob); + MAKE_ACCOUNT(events, daniel); + MAKE_ACCOUNT(events, jack); + + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner); + MAKE_NEXT_BLOCK(events, blk_1r, blk_1, miner); + MAKE_NEXT_BLOCK(events, blk_2, blk_1r, miner); + + REWIND_BLOCKS(events, blk_2r, blk_2, miner); + MAKE_TX_MIGRATION_LIST_START(events, txlist_0, miner, alice, MK_TOKENS(200000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[0])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, bob, MK_TOKENS(40000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[1])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, daniel, MK_TOKENS(10000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[2])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2r, miner, txlist_0); + REWIND_BLOCKS(events, blk_4, blk_3, miner); + + //lock some tokens + MAKE_TX_TOKEN_LOCK_LIST_START(events, txlist_1, alice, MK_TOKENS(80000), blk_4); + MAKE_TOKEN_LOCK_TX_LIST(events, txlist_1, bob, MK_TOKENS(20000), blk_4); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, alice, MK_TOKENS(15000), blk_4, get_hash_from_string(bitcoin_tx_hashes_str[3])); + MAKE_TOKEN_LOCK_TX_LIST(events, txlist_1, daniel, MK_TOKENS(10000), blk_4); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_5, blk_4, miner, txlist_1); + REWIND_BLOCKS(events, blk_6, blk_5, miner); + + MAKE_TX_TOKEN_LOCK_LIST_START(events, txlist_2, alice, MK_TOKENS(15000), blk_6); + MAKE_DONATE_FEE_TX_LIST(events, txlist_2, miner, MK_COINS(4), blk_6); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_7, blk_6, miner, txlist_2); + + MAKE_TX_DONATE_FEE_LIST_START(events, txlist_3, miner, MK_COINS(1000), blk_7); + MAKE_DONATE_FEE_TX_LIST(events, txlist_3, miner, 14000, blk_7); + MAKE_DONATE_FEE_TX_LIST(events, txlist_3, miner, 2800000, blk_7); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_8, blk_7, miner, txlist_3); + + REWIND_BLOCKS(events, blk_9, blk_8, miner); + MAKE_TX_DONATE_FEE_LIST_START(events, txlist_4, miner, MK_COINS(500), blk_8); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_10, blk_9, miner, txlist_4); + REWIND_BLOCKS(events, blk_11, blk_10, miner); + REWIND_BLOCKS(events, blk_12, blk_11, miner); + + + MAKE_TX_TOKEN_UNLOCK_LIST_START(events, txlist_5, alice, MK_TOKENS(15000), blk_12); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_13, blk_12, miner, txlist_5); + + + MAKE_TX_TOKEN_UNLOCK_LIST_START(events, txlist_6, bob, MK_TOKENS(20000), blk_12); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_14, blk_13, miner, txlist_6); + + DO_CALLBACK(events, "verify_network_fee"); + + return true; +} + +bool gen_network_fee_001::verify_network_fee(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("token_lock_001::verify_network_fee"); + std::cout << "current_blockchain_height:" << c.get_current_blockchain_height() << " get_blockchain_total_transactions:" << c.get_blockchain_total_transactions() << std::endl; + + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == gen_network_fee_001::expected_blockchain_height); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == gen_network_fee_001::expected_blockchain_total_transactions); + + std::list block_list; + bool r = c.get_blocks((uint64_t) 0, gen_network_fee_001::expected_blockchain_height, block_list); + CHECK_TEST_CONDITION(r); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + cryptonote::account_base daniel_account = boost::get(events[3]); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + //cout << "check_token_lock_balance: cash alice = " << get_balance(alice_account, blocks, mtx) << endl; + cout << "final alice token balance= " << print_money(get_token_balance(alice_account, blocks, mtx)) << " locked token balance= " << print_money(get_locked_token_balance(alice_account, blocks, mtx)) << endl; + cout << "final bob token balance= " << print_money(get_token_balance(bob_account, blocks, mtx)) << " locked token balance= " << print_money(get_locked_token_balance(bob_account, blocks, mtx)) << endl; + cout << "final daniel token balance= " << print_money(get_token_balance(daniel_account, blocks, mtx)) << " locked token balance= " << print_money(get_locked_token_balance(daniel_account, blocks, mtx)) << endl; + + int64_t locked_tokens = c.get_staked_tokens(0, gen_network_fee_001::expected_blockchain_height); + cout << "total core locked tokens: " << print_money(locked_tokens) << endl; + + int64_t network_fee_collected = c.get_collected_network_fee(0, gen_network_fee_001::expected_blockchain_height); + cout << "total network fee collected: " << print_money(network_fee_collected) << endl; + + int64_t network_fee_distributed = c.get_distributed_network_fee(0, gen_network_fee_001::expected_blockchain_height); + cout << "total network fee distributed: " << print_money(network_fee_distributed) << endl; + + + CHECK_EQ(gen_network_fee_001::expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(gen_network_fee_001::expected_bob_token_balance, get_token_balance(bob_account, blocks, mtx)); + CHECK_EQ(gen_network_fee_001::expected_daniel_token_balance, get_token_balance(daniel_account, blocks, mtx)); + CHECK_EQ(gen_network_fee_001::expected_locked_tokens, c.get_staked_tokens(0, gen_network_fee_001::expected_blockchain_height)); +// + + //todo implement condition check + + return true; +} diff --git a/tests/core_tests/network_fee.h b/tests/core_tests/network_fee.h new file mode 100644 index 000000000..f0e472dcf --- /dev/null +++ b/tests/core_tests/network_fee.h @@ -0,0 +1,69 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#pragma once + +#include "chaingen.h" +#include "block_reward.h" +#include "block_validation.h" +#include "chain_split_1.h" +#include "chain_switch_1.h" +#include "double_spend.h" +#include "integer_overflow.h" +#include "ring_signature_1.h" +#include "tx_validation.h" +#include "v2_tests.h" + +/************************************************************************/ +/* */ +/************************************************************************/ +class gen_network_fee_001: public test_chain_unit_base +{ +public: + gen_network_fee_001(); + + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; + + bool generate(std::vector &events); + bool verify_network_fee(cryptonote::core &c, size_t ev_index, const std::vector &events); + crypto::hash get_hash_from_string(const std::string hashstr); + + static const size_t expected_blockchain_total_transactions = 385; + static const size_t expected_blockchain_height = 371; + + static const uint64_t expected_alice_token_balance = 120000 * SAFEX_TOKEN; + static const uint64_t expected_bob_token_balance = 40000 * SAFEX_TOKEN; + static const uint64_t expected_daniel_token_balance = 0 * SAFEX_TOKEN; + + static const uint64_t expected_locked_tokens = 90000 * SAFEX_TOKEN; + +}; + diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp deleted file mode 100644 index f0bc679c9..000000000 --- a/tests/core_tests/rct.cpp +++ /dev/null @@ -1,509 +0,0 @@ -// Copyright (c) 2018, The Safex 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 -// Parts of this file are originally copyright (c) 2014-2018 The Monero Project - -#include "ringct/rctSigs.h" -#include "chaingen.h" -#include "rct.h" -#include "device/device.hpp" - -using namespace epee; -using namespace crypto; -using namespace cryptonote; - -//---------------------------------------------------------------------------------------------------------------------- -// Tests - -bool gen_rct_tx_validation_base::generate_with(std::vector& events, - const int *out_idx, int mixin, uint64_t amount_paid, bool valid, - const std::function &sources, std::vector &destinations)> &pre_tx, - const std::function &post_tx) const -{ - uint64_t ts_start = 1338224400; - - GENERATE_ACCOUNT(miner_account); - MAKE_GENESIS_BLOCK(events, blk_0, miner_account, ts_start); - - // create 4 miner accounts, and have them mine the next 4 blocks - cryptonote::account_base miner_accounts[4]; - const cryptonote::block *prev_block = &blk_0; - cryptonote::block blocks[4]; - for (size_t n = 0; n < 4; ++n) { - miner_accounts[n].generate(); - CHECK_AND_ASSERT_MES(generator.construct_block_manually(blocks[n], *prev_block, miner_accounts[n], - test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, - 2, 2, prev_block->timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), std::vector(), 0, 0, 2), - false, "Failed to generate block"); - events.push_back(blocks[n]); - prev_block = blocks + n; - LOG_PRINT_L0("Initial miner tx " << n << ": " << obj_to_json_str(blocks[n].miner_tx)); - } - - // rewind - cryptonote::block blk_r, blk_last; - { - blk_last = blocks[3]; - for (size_t i = 0; i < CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; ++i) - { - cryptonote::block blk; - CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account, - test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version, - 2, 2, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), std::vector(), 0, 0, 2), - false, "Failed to generate block"); - events.push_back(blk); - blk_last = blk; - } - blk_r = blk_last; - } - - // create 4 txes from these miners in another block, to generate some rct outputs - transaction rct_txes[4]; - rct::key rct_tx_masks[16]; - cryptonote::block blk_txes[4]; - for (size_t n = 0; n < 4; ++n) - { - std::vector starting_rct_tx_hashes; - std::vector sources; - - sources.resize(1); - tx_source_entry& src = sources.back(); - - const size_t index_in_tx = 5; - src.amount = 30000000000000; - for (int m = 0; m < 4; ++m) { - src.push_output(m, boost::get(blocks[m].miner_tx.vout[index_in_tx].target).key, src.amount); - } - src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[n].miner_tx); - src.real_output = n; - src.real_output_in_tx_index = index_in_tx; - src.mask = rct::identity(); - src.rct = false; - - //fill outputs entry - tx_destination_entry td; - td.addr = miner_accounts[n].get_keys().m_account_address; - td.amount = 7390000000000; - std::vector destinations; - destinations.push_back(td); - destinations.push_back(td); - destinations.push_back(td); - destinations.push_back(td); // 30 -> 7.39 * 4 - - crypto::secret_key tx_key; - std::vector additional_tx_keys; - std::unordered_map 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(), rct_txes[n], 0, 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])); - - for (size_t o = 0; o < 4; ++o) - { - crypto::key_derivation derivation; - bool r = crypto::generate_key_derivation(destinations[o].addr.m_view_public_key, tx_key, derivation); - CHECK_AND_ASSERT_MES(r, false, "Failed to generate key derivation"); - crypto::secret_key amount_key; - crypto::derivation_to_scalar(derivation, o, amount_key); - if (rct_txes[n].rct_signatures.type == rct::RCTTypeSimple || rct_txes[n].rct_signatures.type == rct::RCTTypeSimpleBulletproof) - rct::decodeRctSimple(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4], hw::get_device("default")); - else - rct::decodeRct(rct_txes[n].rct_signatures, rct::sk2rct(amount_key), o, rct_tx_masks[o+n*4], hw::get_device("default")); - } - - CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk_txes[n], blk_last, miner_account, - test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_tx_hashes | test_generator::bf_hf_version | test_generator::bf_max_outs, - 4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), starting_rct_tx_hashes, 0, 6, 4), - false, "Failed to generate block"); - events.push_back(blk_txes[n]); - blk_last = blk_txes[n]; - } - - // rewind - { - for (size_t i = 0; i < CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW; ++i) - { - cryptonote::block blk; - CHECK_AND_ASSERT_MES(generator.construct_block_manually(blk, blk_last, miner_account, - test_generator::bf_major_ver | test_generator::bf_minor_ver | test_generator::bf_timestamp | test_generator::bf_hf_version | test_generator::bf_max_outs, - 4, 4, blk_last.timestamp + DIFFICULTY_BLOCKS_ESTIMATE_TIMESPAN * 2, // v2 has blocks twice as long - crypto::hash(), 0, transaction(), std::vector(), 0, 6, 4), - false, "Failed to generate block"); - events.push_back(blk); - blk_last = blk; - } - blk_r = blk_last; - } - - // create a tx from the requested ouputs - std::vector sources; - size_t global_rct_idx = 6; // skip first coinbase (6 outputs) - size_t rct_idx = 0; - size_t pre_rct_idx = 0; - for (size_t out_idx_idx = 0; out_idx[out_idx_idx] >= 0; ++out_idx_idx) { - sources.resize(sources.size()+1); - tx_source_entry& src = sources.back(); - - src.real_output = 0; - if (out_idx[out_idx_idx]) { - // rct - src.amount = 7390000000000; - src.real_out_tx_key = get_tx_pub_key_from_extra(rct_txes[rct_idx/4]); - src.real_output_in_tx_index = rct_idx&3; - src.mask = rct_tx_masks[rct_idx]; - src.rct = true; - for (int m = 0; m <= mixin; ++m) { - rct::ctkey ctkey; - ctkey.dest = rct::pk2rct(boost::get(rct_txes[rct_idx/4].vout[rct_idx&3].target).key); - ctkey.mask = rct_txes[rct_idx/4].rct_signatures.outPk[rct_idx&3].mask; - src.outputs.push_back(std::make_pair(global_rct_idx, ctkey)); - ++rct_idx; - ++global_rct_idx; - if (global_rct_idx % 10 == 0) - global_rct_idx += 6; // skip the coinbase - } - } - else - { - // pre rct - src.amount = 5000000000000; - src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[pre_rct_idx].miner_tx); - src.real_output_in_tx_index = 4; - src.mask = rct::identity(); - src.rct = false; - for (int m = 0; m <= mixin; ++m) { - src.push_output(m, boost::get(blocks[pre_rct_idx].miner_tx.vout[4].target).key, src.amount); - ++pre_rct_idx; - } - } - } - - //fill outputs entry - tx_destination_entry td; - td.addr = miner_account.get_keys().m_account_address; - td.amount = amount_paid; - std::vector destinations; - destinations.push_back(td); - - if (pre_tx) - pre_tx(sources, destinations); - - transaction tx; - crypto::secret_key tx_key; - std::vector additional_tx_keys; - std::unordered_map 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(), tx, 0, tx_key, additional_tx_keys, true); - CHECK_AND_ASSERT_MES(r, false, "failed to construct transaction"); - - if (post_tx) - post_tx(tx); - - if (!valid) - DO_CALLBACK(events, "mark_invalid_tx"); - events.push_back(tx); - LOG_PRINT_L0("Test tx: " << obj_to_json_str(tx)); - - return true; -} - -bool gen_rct_tx_valid_from_pre_rct::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, true, NULL, NULL); -} - -bool gen_rct_tx_valid_from_rct::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, true, NULL, NULL); -} - -bool gen_rct_tx_valid_from_mixed::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, 0, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, true, NULL, NULL); -} - -bool gen_rct_tx_pre_rct_bad_real_dest::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - bool tx_creation_succeeded = false; - // in the case, the tx will fail to create, due to mismatched sk/pk - bool ret = generate_with(events, out_idx, mixin, amount_paid, false, - [](std::vector &sources, std::vector &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[0].second.dest);}, - [&tx_creation_succeeded](const transaction &tx){tx_creation_succeeded=true;}); - return !ret && !tx_creation_succeeded; -} - -bool gen_rct_tx_pre_rct_bad_real_mask::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - [](std::vector &sources, std::vector &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(99999);}, - NULL); -} - -bool gen_rct_tx_pre_rct_bad_fake_dest::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - [](std::vector &sources, std::vector &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[1].second.dest);}, - NULL); -} - -bool gen_rct_tx_pre_rct_bad_fake_mask::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - [](std::vector &sources, std::vector &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommit(99999);}, - NULL); -} - -bool gen_rct_tx_rct_bad_real_dest::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - bool tx_creation_succeeded = false; - // in the case, the tx will fail to create, due to mismatched sk/pk - bool ret = generate_with(events, out_idx, mixin, amount_paid, false, - [](std::vector &sources, std::vector &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[0].second.dest);}, - [&tx_creation_succeeded](const transaction &tx){tx_creation_succeeded=true;}); - return !ret && !tx_creation_succeeded; -} - -bool gen_rct_tx_rct_bad_real_mask::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - [](std::vector &sources, std::vector &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(99999);}, - NULL); -} - -bool gen_rct_tx_rct_bad_fake_dest::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - [](std::vector &sources, std::vector &destinations) {rct::key sk; rct::skpkGen(sk, sources[0].outputs[1].second.dest);}, - NULL); -} - -bool gen_rct_tx_rct_bad_fake_mask::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - [](std::vector &sources, std::vector &destinations) {sources[0].outputs[1].second.mask = rct::zeroCommit(99999);}, - NULL); -} - -bool gen_rct_tx_rct_spend_with_zero_commit::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - [](std::vector &sources, std::vector &destinations) {sources[0].outputs[0].second.mask = rct::zeroCommit(sources[0].amount); sources[0].mask = rct::identity();}, - [](transaction &tx){boost::get(tx.vin[0]).amount = 0;}); -} - -bool gen_rct_tx_pre_rct_zero_vin_amount::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {boost::get(tx.vin[0]).amount = 0;}); -} - -bool gen_rct_tx_rct_non_zero_vin_amount::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {boost::get(tx.vin[0]).amount = 5000000000000;}); // one that we know exists -} - -bool gen_rct_tx_non_zero_vout_amount::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {tx.vout[0].amount = 5000000000000;}); // one that we know exists -} - -bool gen_rct_tx_pre_rct_duplicate_key_image::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [&events](transaction &tx) {boost::get(tx.vin[0]).k_image = boost::get(boost::get(events[67]).vin[0]).k_image;}); -} - -bool gen_rct_tx_rct_duplicate_key_image::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [&events](transaction &tx) {boost::get(tx.vin[0]).k_image = boost::get(boost::get(events[67]).vin[0]).k_image;}); -} - -bool gen_rct_tx_pre_rct_wrong_key_image::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - // some random key image from the monero blockchain, so we get something that is a valid key image - static const uint8_t k_image[33] = "\x49\x3b\x56\x16\x54\x76\xa8\x75\xb7\xf4\xa8\x51\xf5\x55\xd3\x44\xe7\x3e\xea\x73\xee\xc1\x06\x7c\x7d\xb6\x57\x28\x46\x85\xe1\x07"; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {memcpy(&boost::get(tx.vin[0]).k_image, k_image, 32);}); -} - -bool gen_rct_tx_rct_wrong_key_image::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - // some random key image from the monero blockchain, so we get something that is a valid key image - static const uint8_t k_image[33] = "\x49\x3b\x56\x16\x54\x76\xa8\x75\xb7\xf4\xa8\x51\xf5\x55\xd3\x44\xe7\x3e\xea\x73\xee\xc1\x06\x7c\x7d\xb6\x57\x28\x46\x85\xe1\x07"; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {memcpy(&boost::get(tx.vin[0]).k_image, k_image, 32);}); -} - -bool gen_rct_tx_pre_rct_wrong_fee::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {tx.rct_signatures.txnFee++;}); -} - -bool gen_rct_tx_rct_wrong_fee::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {tx.rct_signatures.txnFee++;}); -} - -bool gen_rct_tx_pre_rct_increase_vin_and_fee::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {boost::get(tx.vin[0]).amount++;tx.rct_signatures.txnFee++;}); -} - -bool gen_rct_tx_pre_rct_remove_vin::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {tx.vin.pop_back();}); -} - -bool gen_rct_tx_rct_remove_vin::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {tx.vin.pop_back();}); -} - -bool gen_rct_tx_pre_rct_add_vout::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {tx.vout.push_back(tx.vout.back());}); -} - -bool gen_rct_tx_rct_add_vout::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [](transaction &tx) {tx.vout.push_back(tx.vout.back());}); -} - -bool gen_rct_tx_pre_rct_altered_extra::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {0, -1}; - const uint64_t amount_paid = 10000; - bool failed = false; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [&failed](transaction &tx) {std::string extra_nonce; crypto::hash pid = crypto::null_hash; set_payment_id_to_tx_extra_nonce(extra_nonce, pid); if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) failed = true; }) && !failed; -} - -bool gen_rct_tx_rct_altered_extra::generate(std::vector& events) const -{ - const int mixin = 2; - const int out_idx[] = {1, -1}; - const uint64_t amount_paid = 10000; - bool failed = false; - return generate_with(events, out_idx, mixin, amount_paid, false, - NULL, [&failed](transaction &tx) {std::string extra_nonce; crypto::hash pid = crypto::null_hash; set_payment_id_to_tx_extra_nonce(extra_nonce, pid); if (!add_extra_nonce_to_tx_extra(tx.extra, extra_nonce)) failed = true; }) && !failed; -} - diff --git a/tests/core_tests/rct.h b/tests/core_tests/rct.h deleted file mode 100644 index d6c9d511b..000000000 --- a/tests/core_tests/rct.h +++ /dev/null @@ -1,265 +0,0 @@ -// Copyright (c) 2018, The Safex 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 -// Parts of this file are originally copyright (c) 2014-2018 The Monero Project - -#pragma once -#include "chaingen.h" - -struct gen_rct_tx_validation_base : public test_chain_unit_base -{ - gen_rct_tx_validation_base() - : m_invalid_tx_index(0) - , m_invalid_block_index(0) - { - REGISTER_CALLBACK_METHOD(gen_rct_tx_validation_base, mark_invalid_tx); - REGISTER_CALLBACK_METHOD(gen_rct_tx_validation_base, mark_invalid_block); - } - - bool check_tx_verification_context(const cryptonote::tx_verification_context& tvc, bool tx_added, size_t event_idx, const cryptonote::transaction& /*tx*/) - { - if (m_invalid_tx_index == event_idx) - return tvc.m_verifivation_failed; - else - return !tvc.m_verifivation_failed && tx_added; - } - - bool check_block_verification_context(const cryptonote::block_verification_context& bvc, size_t event_idx, const cryptonote::block& /*block*/) - { - if (m_invalid_block_index == event_idx) - return bvc.m_verifivation_failed; - else - return !bvc.m_verifivation_failed; - } - - bool mark_invalid_block(cryptonote::core& /*c*/, size_t ev_index, const std::vector& /*events*/) - { - m_invalid_block_index = ev_index + 1; - return true; - } - - bool mark_invalid_tx(cryptonote::core& /*c*/, size_t ev_index, const std::vector& /*events*/) - { - m_invalid_tx_index = ev_index + 1; - return true; - } - - bool generate_with(std::vector& events, const int *out_idx, int mixin, - uint64_t amount_paid, bool valid, - const std::function &sources, std::vector &destinations)> &pre_tx, - const std::function &post_tx) const; - -private: - size_t m_invalid_tx_index; - size_t m_invalid_block_index; -}; - -template<> -struct get_test_options { - const std::pair hard_forks[4] = {std::make_pair(1, 0), std::make_pair(2, 1), std::make_pair(4, 65), std::make_pair(0, 0)}; - const cryptonote::test_options test_options = { - hard_forks - }; -}; - -// valid -struct gen_rct_tx_valid_from_pre_rct : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_valid_from_rct : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_valid_from_mixed : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -// altered commitment/dest -struct gen_rct_tx_pre_rct_bad_real_dest : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_pre_rct_bad_real_mask : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_pre_rct_bad_fake_dest : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_pre_rct_bad_fake_mask : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_bad_real_dest : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_bad_real_mask : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_bad_fake_dest : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_bad_fake_mask : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_spend_with_zero_commit : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -// altered amounts -struct gen_rct_tx_pre_rct_zero_vin_amount : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_non_zero_vin_amount : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_non_zero_vout_amount : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -// key image -struct gen_rct_tx_pre_rct_duplicate_key_image : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_duplicate_key_image : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_pre_rct_wrong_key_image : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_wrong_key_image : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -// fee -struct gen_rct_tx_pre_rct_wrong_fee : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_wrong_fee : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_pre_rct_increase_vin_and_fee : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -// modify vin/vout -struct gen_rct_tx_pre_rct_remove_vin : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_remove_vin : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_pre_rct_add_vout : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_add_vout : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -// extra -struct gen_rct_tx_pre_rct_altered_extra : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - -struct gen_rct_tx_rct_altered_extra : public gen_rct_tx_validation_base -{ - bool generate(std::vector& events) const; -}; -template<> struct get_test_options: public get_test_options {}; - diff --git a/tests/core_tests/safex_account.cpp b/tests/core_tests/safex_account.cpp new file mode 100644 index 000000000..5b55be88d --- /dev/null +++ b/tests/core_tests/safex_account.cpp @@ -0,0 +1,224 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#include +#include + +#include "include_base_utils.h" + +#include "console_handler.h" + +#include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/cryptonote_format_utils.h" + +#include "safex/safex_core.h" + +#include "chaingen.h" +#include "safex_account.h" + + + +using namespace std; + +using namespace epee; +using namespace cryptonote; + + +const std::string gen_safex_account_001::data2_alternative{"Bob's alternative data"}; +const std::string gen_safex_account_001::data2_alternative_2{"Bob's second alternative data"}; +const std::string gen_safex_account_001::data3_alternative{"Daniels's alternative data 2 ----------------------------------------------------- some other data here -----------------------------------------------" +" and more data here ----------------------------------------------------------------------------------*****************--------------------------------"}; + +bool gen_safex_account_001::expected_data_fields_intialized{false}; +crypto::public_key gen_safex_account_001::expected_alice_account_key{}; +crypto::public_key gen_safex_account_001::expected_bob_account_key{}; +crypto::public_key gen_safex_account_001::expected_daniel_account_key{}; + +std::vector gen_safex_account_001::expected_alice_account_data; +std::vector gen_safex_account_001::expected_bob_account_data; +std::vector gen_safex_account_001::expected_daniel_account_data; + + +gen_safex_account_001::gen_safex_account_001() +{ + + + + m_safex_account1_keys.generate(); + m_safex_account2_keys.generate(); + m_safex_account3_keys.generate(); + m_safex_account4_keys.generate(); + + safex_account_alice.username = "alice01"; + safex_account_alice.pkey = m_safex_account1_keys.get_keys().m_public_key; + safex_account_alice.account_data = {'l','o','r','e','m',' ','i','p','s','u','m'}; + + + safex_account_bob.username = "bob02"; + safex_account_bob.pkey = m_safex_account2_keys.get_keys().m_public_key; + std::string data2 = "Bob's data"; + safex_account_bob.account_data = std::vector(data2.begin(), data2.end()); + + + safex_account_daniel.username = "daniel03"; + safex_account_daniel.pkey = m_safex_account3_keys.get_keys().m_public_key; + std::string data3 = "This is some data for test"; + safex_account_daniel.account_data = std::vector(data3.begin(), data3.end()); + + + safex_account_edward.username = "edward04"; + safex_account_edward.pkey = m_safex_account4_keys.get_keys().m_public_key; + std::string data4 = "Тхис ис соме Едвардс дата фор тест"; + safex_account_edward.account_data = std::vector(data4.begin(), data4.end()); + + if (!expected_data_fields_intialized) + { + expected_alice_account_key = safex_account_alice.pkey; + expected_bob_account_key = safex_account_bob.pkey; + expected_daniel_account_key = safex_account_daniel.pkey; + expected_data_fields_intialized = true; + expected_alice_account_data = std::vector(std::begin(safex_account_alice.account_data), std::end(safex_account_alice.account_data)); + expected_bob_account_data = std::vector(std::begin(data2_alternative_2), std::end(data2_alternative_2)); + expected_daniel_account_data = std::vector(std::begin(data3_alternative), std::end(data3_alternative)); + } + + REGISTER_CALLBACK("verify_safex_account", gen_safex_account_001::verify_safex_account); +} + +bool gen_safex_account_001::generate(std::vector &events) +{ + uint64_t ts_start = 1530720632; + + GENERATE_ACCOUNT(miner); + crypto::public_key miner_public_key = AUTO_VAL_INIT(miner_public_key); + crypto::secret_key_to_public_key(miner.get_keys().m_spend_secret_key, miner_public_key); + cryptonote::fakechain::set_core_tests_public_key(miner_public_key); + + GENERATE_ACCOUNT(miner2); + + MAKE_GENESIS_BLOCK(events, blk_0, miner, ts_start); + + MAKE_ACCOUNT(events, alice); + MAKE_ACCOUNT(events, bob); + MAKE_ACCOUNT(events, daniel); + MAKE_ACCOUNT(events, edward); + + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner); + MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner); + + REWIND_BLOCKS(events, blk_2r, blk_2, miner); + MAKE_TX_MIGRATION_LIST_START(events, txlist_0, miner, alice, MK_TOKENS(10000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[0])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, bob, MK_TOKENS(10000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[1])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, daniel, MK_TOKENS(25000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[2])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2r, miner, txlist_0); + REWIND_BLOCKS(events, blk_4, blk_3, miner); + + //create alice and bob accounts + MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(events, txlist_2, alice, safex_account_alice.username, safex_account_alice.pkey, safex_account_alice.account_data, m_safex_account1_keys.get_keys(), events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_4); + MAKE_CREATE_SAFEX_ACCOUNT_TX_LIST(events, txlist_2, bob, safex_account_bob.username, safex_account_bob.pkey, safex_account_bob.account_data, m_safex_account2_keys.get_keys(),events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_4); + MAKE_MIGRATION_TX_LIST(events, txlist_2, miner, edward, MK_TOKENS(8000), blk_4, get_hash_from_string(bitcoin_tx_hashes_str[3])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_5, blk_4, miner, txlist_2); + REWIND_BLOCKS(events, blk_6, blk_5, miner); + + MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(events, txlist_3, daniel, safex_account_daniel.username, safex_account_daniel.pkey, safex_account_daniel.account_data, m_safex_account3_keys.get_keys(), events.size() + SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_6); + MAKE_EDIT_SAFEX_ACCOUNT_TX_LIST(events, txlist_3, bob, safex_account_bob.username, std::vector(data2_alternative.begin(), data2_alternative.end()), m_safex_account2_keys.get_keys(), blk_6); + MAKE_MIGRATION_TX_LIST(events, txlist_3, miner, bob, MK_TOKENS(20000), blk_6, get_hash_from_string(bitcoin_tx_hashes_str[4])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_7, blk_6, miner, txlist_3); + REWIND_BLOCKS(events, blk_8, blk_7, miner); + + MAKE_TX_EDIT_SAFEX_ACCOUNT_LIST_START(events, txlist_4, daniel, safex_account_daniel.username, std::vector(data3_alternative.begin(), data3_alternative.end()), m_safex_account3_keys.get_keys(), blk_8); + MAKE_EDIT_SAFEX_ACCOUNT_TX_LIST(events, txlist_4, bob, safex_account_bob.username, std::vector(data2_alternative_2.begin(), data2_alternative_2.end()), m_safex_account2_keys.get_keys(), blk_8); + MAKE_CREATE_SAFEX_ACCOUNT_TX_LIST(events, txlist_4, edward, safex_account_edward.username, safex_account_edward.pkey, safex_account_edward.account_data, m_safex_account4_keys.get_keys(), events.size() + SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_8); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_9, blk_8, miner, txlist_4); + REWIND_BLOCKS(events, blk_10, blk_9, miner); + + + DO_CALLBACK(events, "verify_safex_account"); + + return true; +} + +bool gen_safex_account_001::verify_safex_account(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("safex_account_001::verify_safex_account"); + std::cout << "current_blockchain_height:" << c.get_current_blockchain_height() << " get_blockchain_total_transactions:" << c.get_blockchain_total_transactions() << std::endl; + + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == gen_safex_account_001::expected_blockchain_height); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == gen_safex_account_001::expected_blockchain_total_transactions); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, gen_safex_account_001::expected_blockchain_height, block_list); + CHECK_TEST_CONDITION(r); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + cryptonote::account_base daniel_account = boost::get(events[3]); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + crypto::public_key pkey{}; + const safex::account_username username01{safex_account_alice.username}; + c.get_blockchain_storage().get_safex_account_public_key(username01, pkey); + CHECK_EQ(memcmp((void *)&pkey, (void *)&expected_alice_account_key, sizeof(pkey)), 0); + + crypto::public_key pkey2{}; + const safex::account_username username02{safex_account_bob.username}; + c.get_blockchain_storage().get_safex_account_public_key(username02, pkey2); + CHECK_EQ(memcmp((void *)&pkey2, (void *)&expected_bob_account_key, sizeof(pkey2)), 0); + + crypto::public_key pkey3{}; + const safex::account_username username03{safex_account_daniel.username}; + c.get_blockchain_storage().get_safex_account_public_key(username03, pkey3); + CHECK_EQ(memcmp((void *)&pkey3, (void *)&expected_daniel_account_key, sizeof(pkey3)), 0); + + std::vector> accounts; + c.get_safex_accounts(accounts); + + std::cout << "All accounts in blockchain" << std::endl; + for(auto account: accounts) + std::cout << "Username: " << account.first << std::endl<<"\tDescription: "< accdata01; + c.get_blockchain_storage().get_safex_account_data(username01, accdata01); + CHECK_TEST_CONDITION(std::equal(expected_alice_account_data.begin(), expected_alice_account_data.end(), accdata01.begin())); + + + std::vector accdata02; + c.get_blockchain_storage().get_safex_account_data(username02, accdata02); + CHECK_TEST_CONDITION(std::equal(expected_bob_account_data.begin(), expected_bob_account_data.end(), accdata02.begin())); + + + return true; +} diff --git a/tests/core_tests/safex_account.h b/tests/core_tests/safex_account.h new file mode 100644 index 000000000..cf02b37b9 --- /dev/null +++ b/tests/core_tests/safex_account.h @@ -0,0 +1,86 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#pragma once + +#include "chaingen.h" +#include "block_reward.h" +#include "block_validation.h" +#include "chain_split_1.h" +#include "chain_switch_1.h" +#include "double_spend.h" +#include "integer_overflow.h" +#include "ring_signature_1.h" +#include "tx_validation.h" +#include "v2_tests.h" + +/************************************************************************/ +/* */ +/************************************************************************/ +class gen_safex_account_001: public test_chain_unit_base +{ +public: + gen_safex_account_001(); + + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; + + bool generate(std::vector &events); + bool verify_safex_account(cryptonote::core& c, size_t ev_index, const std::vector &events); + + safex::safex_account_key_handler m_safex_account1_keys; + safex::safex_account_key_handler m_safex_account2_keys; + safex::safex_account_key_handler m_safex_account3_keys; + safex::safex_account_key_handler m_safex_account4_keys; + + safex::safex_account safex_account_alice; + safex::safex_account safex_account_bob; + safex::safex_account safex_account_daniel; + safex::safex_account safex_account_edward; + + static const std::string data2_alternative; + static const std::string data2_alternative_2; + static const std::string data3_alternative; + + + static const size_t expected_blockchain_total_transactions = 319; + static const size_t expected_blockchain_height = 307; + + static bool expected_data_fields_intialized; + static crypto::public_key expected_alice_account_key; + static crypto::public_key expected_bob_account_key; + static crypto::public_key expected_daniel_account_key; + + static std::vector expected_alice_account_data; + static std::vector expected_bob_account_data; + static std::vector expected_daniel_account_data; + +}; + diff --git a/tests/core_tests/safex_offer.cpp b/tests/core_tests/safex_offer.cpp new file mode 100644 index 000000000..20b859186 --- /dev/null +++ b/tests/core_tests/safex_offer.cpp @@ -0,0 +1,315 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#include +#include +#include + +#include "include_base_utils.h" + +#include "console_handler.h" + +#include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/cryptonote_format_utils.h" + +#include "safex/safex_core.h" + +#include "chaingen.h" +#include "safex_offer.h" + + + +using namespace std; + +using namespace epee; +using namespace cryptonote; + + +const std::string gen_safex_offer_001::data2_alternative{"Bob's alternative data"}; +const std::string gen_safex_offer_001::data2_alternative_2{"Bob's second alternative data"}; +const std::string gen_safex_offer_001::data3_alternative{"Daniels's alternative data 2 ----------------------------------------------------- some other data here -----------------------------------------------" +" and more data here ----------------------------------------------------------------------------------*****************--------------------------------"}; + +bool gen_safex_offer_001::expected_data_fields_intialized{false}; +crypto::public_key gen_safex_offer_001::expected_alice_account_key{}; +crypto::public_key gen_safex_offer_001::expected_bob_account_key{}; +crypto::public_key gen_safex_offer_001::expected_daniel_account_key{}; + +std::vector gen_safex_offer_001::expected_alice_account_data; +std::vector gen_safex_offer_001::expected_bob_account_data; +std::vector gen_safex_offer_001::expected_daniel_account_data; + +safex::safex_offer gen_safex_offer_001::expected_alice_safex_offer; +safex::safex_offer gen_safex_offer_001::expected_bob_safex_offer; + +gen_safex_offer_001::gen_safex_offer_001() +{ + + + + m_safex_account1_keys.generate(); + m_safex_account2_keys.generate(); + m_safex_account3_keys.generate(); + m_safex_account4_keys.generate(); + + safex_account_alice.username = "alice01"; + safex_account_alice.pkey = m_safex_account1_keys.get_keys().m_public_key; + safex_account_alice.account_data = {'l','o','r','e','m',' ','i','p','s','u','m'}; + + + safex_account_bob.username = "bob02"; + safex_account_bob.pkey = m_safex_account2_keys.get_keys().m_public_key; + std::string data2 = "Bob's data"; + safex_account_bob.account_data = std::vector(data2.begin(), data2.end()); + + + safex_account_daniel.username = "daniel03"; + safex_account_daniel.pkey = m_safex_account3_keys.get_keys().m_public_key; + std::string data3 = "This is some data for test"; + safex_account_daniel.account_data = std::vector(data3.begin(), data3.end()); + + + safex_account_edward.username = "edward04"; + safex_account_edward.pkey = m_safex_account4_keys.get_keys().m_public_key; + std::string data4 = "Тхис ис соме Едвардс дата фор тест"; + safex_account_edward.account_data = std::vector(data4.begin(), data4.end()); + + alice.generate(); + bob.generate(); + + safex_offer_alice = safex::safex_offer("Black Sabbath T-shirt",100,MK_COINS(10),"Quality 100% cotton t-shirt with the heaviest band in the universe", + safex_account_alice.username,alice.get_keys().m_view_secret_key,alice.get_keys().m_account_address); + safex_offer_bob = safex::safex_offer("Metallica T-shirt",1000,MK_COINS(10),"Quality 100% cotton t-shirt with the loudest band in the universe", + safex_account_bob.username,bob.get_keys().m_view_secret_key,bob.get_keys().m_account_address); + + safex_price_peg_bob = safex::safex_price_peg("TestPricePeg",safex_account_bob.username,"USD","Best price my man",3.5*COIN); + + safex_offer_bob.set_price_peg(safex_price_peg_bob.price_peg_id,800,MK_COINS(1000)); + + if (!expected_data_fields_intialized) + { + expected_alice_account_key = safex_account_alice.pkey; + expected_bob_account_key = safex_account_bob.pkey; + expected_daniel_account_key = safex_account_daniel.pkey; + expected_data_fields_intialized = true; + expected_alice_account_data = std::vector(std::begin(safex_account_alice.account_data), std::end(safex_account_alice.account_data)); + expected_bob_account_data = std::vector(std::begin(data2_alternative_2), std::end(data2_alternative_2)); + expected_daniel_account_data = std::vector(std::begin(data3_alternative), std::end(data3_alternative)); + + + expected_alice_safex_offer = safex_offer_alice; + expected_bob_safex_offer = safex_offer_bob; + + std::string new_str_desc{"Now in white!!!"}; + expected_alice_safex_offer.description = {new_str_desc.begin(),new_str_desc.end()};; + } + + REGISTER_CALLBACK("verify_safex_offer", gen_safex_offer_001::verify_safex_offer); +} + +bool gen_safex_offer_001::generate(std::vector &events) +{ + uint64_t ts_start = 1530720632; + + GENERATE_ACCOUNT(miner); + crypto::public_key miner_public_key = AUTO_VAL_INIT(miner_public_key); + crypto::secret_key_to_public_key(miner.get_keys().m_spend_secret_key, miner_public_key); + cryptonote::fakechain::set_core_tests_public_key(miner_public_key); + + GENERATE_ACCOUNT(miner2); + + MAKE_GENESIS_BLOCK(events, blk_0, miner, ts_start); + + MAKE_ACCOUNT(events, alice); + MAKE_ACCOUNT(events, bob); + MAKE_ACCOUNT(events, daniel); + MAKE_ACCOUNT(events, edward); + + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner); + MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner); + + REWIND_BLOCKS(events, blk_2r, blk_2, miner); + MAKE_TX_MIGRATION_LIST_START(events, txlist_0, miner, alice, MK_TOKENS(10000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[0])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, bob, MK_TOKENS(10000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[1])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, daniel, MK_TOKENS(25000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[2])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2r, miner, txlist_0); + REWIND_BLOCKS(events, blk_4, blk_3, miner); + + //create alice and bob accounts + MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(events, txlist_2, alice, safex_account_alice.username, safex_account_alice.pkey, safex_account_alice.account_data, m_safex_account1_keys.get_keys(), events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_4); + MAKE_CREATE_SAFEX_ACCOUNT_TX_LIST(events, txlist_2, bob, safex_account_bob.username, safex_account_bob.pkey, safex_account_bob.account_data, m_safex_account2_keys.get_keys(), events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_4); + MAKE_MIGRATION_TX_LIST(events, txlist_2, miner, edward, MK_TOKENS(8000), blk_4, get_hash_from_string(bitcoin_tx_hashes_str[3])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_5, blk_4, miner, txlist_2); + REWIND_BLOCKS(events, blk_6, blk_5, miner); + + MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(events, txlist_3, daniel, safex_account_daniel.username, safex_account_daniel.pkey, safex_account_daniel.account_data, m_safex_account3_keys.get_keys(), events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_6); + MAKE_CREATE_SAFEX_PRICE_PEG_TX_LIST(events, txlist_3, bob, safex_account_bob.pkey, safex_price_peg_bob, m_safex_account2_keys.get_keys(), blk_6); + MAKE_MIGRATION_TX_LIST(events, txlist_3, miner, bob, MK_TOKENS(20000), blk_6, get_hash_from_string(bitcoin_tx_hashes_str[4])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_7, blk_6, miner, txlist_3); + REWIND_BLOCKS(events, blk_8, blk_7, miner); + + MAKE_TX_EDIT_SAFEX_ACCOUNT_LIST_START(events, txlist_4, daniel, safex_account_daniel.username, std::vector(data3_alternative.begin(), data3_alternative.end()), m_safex_account3_keys.get_keys(), blk_8); + MAKE_EDIT_SAFEX_ACCOUNT_TX_LIST(events, txlist_4, bob, safex_account_bob.username, std::vector(data2_alternative_2.begin(), data2_alternative_2.end()), m_safex_account2_keys.get_keys(), blk_8); + MAKE_CREATE_SAFEX_ACCOUNT_TX_LIST(events, txlist_4, edward, safex_account_edward.username, safex_account_edward.pkey, safex_account_edward.account_data, m_safex_account4_keys.get_keys(), events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_8); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_9, blk_8, miner, txlist_4); + REWIND_BLOCKS(events, blk_10, blk_9, miner); + + //create test offer + MAKE_TX_CREATE_SAFEX_OFFER_LIST_START(events, txlist_5, alice, safex_account_alice.pkey, safex_offer_alice, m_safex_account1_keys.get_keys(), blk_10); + MAKE_CREATE_SAFEX_OFFER_TX_LIST(events, txlist_5, bob, safex_account_bob.pkey, safex_offer_bob, m_safex_account2_keys.get_keys(), blk_10); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_11, blk_10, miner, txlist_5); + REWIND_BLOCKS(events, blk_12, blk_11, miner); + + + + safex_offer_alice.description = expected_alice_safex_offer.description; + + MAKE_TX_EDIT_SAFEX_OFFER_LIST_START(events, txlist_6, alice, safex_account_alice.pkey, safex_offer_alice, m_safex_account1_keys.get_keys(), blk_12); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_13, blk_12, miner, txlist_6); + REWIND_BLOCKS(events, blk_14, blk_13, miner); + + DO_CALLBACK(events, "verify_safex_offer"); + + return true; +} + +bool gen_safex_offer_001::verify_safex_offer(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_safex_offer_001::verify_safex_offer"); + std::cout << "current_blockchain_height:" << c.get_current_blockchain_height() << " get_blockchain_total_transactions:" << c.get_blockchain_total_transactions() << std::endl; + + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == gen_safex_offer_001::expected_blockchain_height); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == gen_safex_offer_001::expected_blockchain_total_transactions); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, gen_safex_offer_001::expected_blockchain_height, block_list); + CHECK_TEST_CONDITION(r); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + cryptonote::account_base daniel_account = boost::get(events[3]); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + //Check safex account + crypto::public_key pkey{}; + const safex::account_username username01{safex_account_alice.username}; + c.get_blockchain_storage().get_safex_account_public_key(username01, pkey); + CHECK_EQ(memcmp((void *)&pkey, (void *)&expected_alice_account_key, sizeof(pkey)), 0); + + crypto::public_key pkey2{}; + const safex::account_username username02{safex_account_bob.username}; + c.get_blockchain_storage().get_safex_account_public_key(username02, pkey2); + CHECK_EQ(memcmp((void *)&pkey2, (void *)&expected_bob_account_key, sizeof(pkey2)), 0); + + crypto::public_key pkey3{}; + const safex::account_username username03{safex_account_daniel.username}; + c.get_blockchain_storage().get_safex_account_public_key(username03, pkey3); + CHECK_EQ(memcmp((void *)&pkey3, (void *)&expected_daniel_account_key, sizeof(pkey3)), 0); + + + std::vector accdata01; + c.get_blockchain_storage().get_safex_account_data(username01, accdata01); + CHECK_TEST_CONDITION(std::equal(expected_alice_account_data.begin(), expected_alice_account_data.end(), accdata01.begin())); + + + std::vector accdata02; + c.get_blockchain_storage().get_safex_account_data(username02, accdata02); + CHECK_TEST_CONDITION(std::equal(expected_bob_account_data.begin(), expected_bob_account_data.end(), accdata02.begin())); + + //Check alice safex offer + std::string offer_seller; + c.get_blockchain_storage().get_safex_offer_seller(expected_alice_safex_offer.offer_id,offer_seller); + CHECK_TEST_CONDITION(expected_alice_safex_offer.seller.compare(offer_seller) == 0); + + uint64_t offer_price; + c.get_blockchain_storage().get_safex_offer_price(expected_alice_safex_offer.offer_id,offer_price); + CHECK_EQ(expected_alice_safex_offer.price, offer_price); + + uint64_t offer_quantity; + c.get_blockchain_storage().get_safex_offer_quantity(expected_alice_safex_offer.offer_id,offer_quantity); + CHECK_EQ(expected_alice_safex_offer.quantity, offer_quantity); + + bool offer_active; + c.get_blockchain_storage().get_safex_offer_active_status(expected_alice_safex_offer.offer_id,offer_active); + CHECK_EQ(expected_alice_safex_offer.active, offer_active); + + safex::safex_offer sfx_offer; + c.get_blockchain_storage().get_safex_offer(expected_alice_safex_offer.offer_id,sfx_offer); + CHECK_TEST_CONDITION(expected_alice_safex_offer.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_alice_safex_offer.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_alice_safex_offer.seller_address == sfx_offer.seller_address); + + CHECK_EQ(expected_alice_safex_offer.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_alice_safex_offer.price_peg_id, sfx_offer.price_peg_id); + CHECK_EQ(expected_alice_safex_offer.min_sfx_price, sfx_offer.min_sfx_price); + + CHECK_TEST_CONDITION(std::equal(sfx_offer.description.begin(), sfx_offer.description.end(), expected_alice_safex_offer.description.begin())); + + //Check bob safex offer + c.get_blockchain_storage().get_safex_offer_seller(expected_bob_safex_offer.offer_id,offer_seller); + CHECK_TEST_CONDITION(expected_bob_safex_offer.seller.compare(offer_seller) == 0); + + c.get_blockchain_storage().get_safex_offer_price(expected_bob_safex_offer.offer_id,offer_price); + CHECK_EQ(expected_bob_safex_offer.price, offer_price); + + c.get_blockchain_storage().get_safex_offer_quantity(expected_bob_safex_offer.offer_id,offer_quantity); + CHECK_EQ(expected_bob_safex_offer.quantity, offer_quantity); + + c.get_blockchain_storage().get_safex_offer_active_status(expected_bob_safex_offer.offer_id,offer_active); + CHECK_EQ(expected_bob_safex_offer.active, offer_active); + + c.get_blockchain_storage().get_safex_offer(expected_bob_safex_offer.offer_id,sfx_offer); + CHECK_TEST_CONDITION(expected_bob_safex_offer.title.compare(sfx_offer.title) == 0); + CHECK_EQ(expected_bob_safex_offer.seller_private_view_key, sfx_offer.seller_private_view_key); + CHECK_TEST_CONDITION(expected_bob_safex_offer.seller_address == sfx_offer.seller_address); + + CHECK_EQ(expected_bob_safex_offer.price_peg_used, sfx_offer.price_peg_used); + CHECK_EQ(expected_bob_safex_offer.price_peg_id, sfx_offer.price_peg_id); + CHECK_EQ(expected_bob_safex_offer.min_sfx_price, sfx_offer.min_sfx_price); + + CHECK_TEST_CONDITION(std::equal(sfx_offer.description.begin(), sfx_offer.description.end(), expected_bob_safex_offer.description.begin())); + + + //Print offers + std::vector offers; + bool result = c.get_safex_offers(offers); + CHECK_TEST_CONDITION(result); + + std::cout << boost::format("%30s %20s %20s %30s %100s %20s") % "Offer title" % "Price" % "Quantity" % "Seller" % "Description" % "Offer ID"< &events); + bool verify_safex_offer(cryptonote::core& c, size_t ev_index, const std::vector &events); + + safex::safex_account_key_handler m_safex_account1_keys; + safex::safex_account_key_handler m_safex_account2_keys; + safex::safex_account_key_handler m_safex_account3_keys; + safex::safex_account_key_handler m_safex_account4_keys; + + safex::safex_account safex_account_alice; + safex::safex_account safex_account_bob; + safex::safex_account safex_account_daniel; + safex::safex_account safex_account_edward; + + safex::safex_offer safex_offer_alice; + safex::safex_offer safex_offer_bob; + + safex::safex_price_peg safex_price_peg_bob; + + cryptonote::account_base alice; + cryptonote::account_base bob; + + static const std::string data2_alternative; + static const std::string data2_alternative_2; + static const std::string data3_alternative; + + + static const size_t expected_blockchain_total_transactions = 444; + static const size_t expected_blockchain_height = 429; + + static bool expected_data_fields_intialized; + static crypto::public_key expected_alice_account_key; + static crypto::public_key expected_bob_account_key; + static crypto::public_key expected_daniel_account_key; + + + static std::vector expected_alice_account_data; + static std::vector expected_bob_account_data; + static std::vector expected_daniel_account_data; + + static safex::safex_offer expected_alice_safex_offer; + static safex::safex_offer expected_bob_safex_offer; + + +}; + diff --git a/tests/core_tests/safex_price_peg.cpp b/tests/core_tests/safex_price_peg.cpp new file mode 100644 index 000000000..242b0110d --- /dev/null +++ b/tests/core_tests/safex_price_peg.cpp @@ -0,0 +1,269 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#include +#include +#include + +#include "include_base_utils.h" + +#include "console_handler.h" + +#include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/cryptonote_format_utils.h" + +#include "safex/safex_core.h" + +#include "chaingen.h" +#include "safex_price_peg.h" + + + +using namespace std; + +using namespace epee; +using namespace cryptonote; + + +const std::string gen_safex_price_peg_001::data2_alternative{"Bob's alternative data"}; +const std::string gen_safex_price_peg_001::data2_alternative_2{"Bob's second alternative data"}; +const std::string gen_safex_price_peg_001::data3_alternative{"Daniels's alternative data 2 ----------------------------------------------------- some other data here -----------------------------------------------" +" and more data here ----------------------------------------------------------------------------------*****************--------------------------------"}; + +bool gen_safex_price_peg_001::expected_data_fields_intialized{false}; +crypto::public_key gen_safex_price_peg_001::expected_alice_account_key{}; +crypto::public_key gen_safex_price_peg_001::expected_bob_account_key{}; +crypto::public_key gen_safex_price_peg_001::expected_daniel_account_key{}; + +std::vector gen_safex_price_peg_001::expected_alice_account_data; +std::vector gen_safex_price_peg_001::expected_bob_account_data; +std::vector gen_safex_price_peg_001::expected_daniel_account_data; + +crypto::hash gen_safex_price_peg_001::expected_alice_price_peg_id; +std::string gen_safex_price_peg_001::expected_alice_price_peg_title; +std::string gen_safex_price_peg_001::expected_alice_price_peg_currency; +std::vector gen_safex_price_peg_001::expected_alice_price_peg_description; +uint64_t gen_safex_price_peg_001::expected_alice_price_peg_new_rate; +uint64_t gen_safex_price_peg_001::exptected_alice_price_peg_rate; + +gen_safex_price_peg_001::gen_safex_price_peg_001() +{ + + + + m_safex_account1_keys.generate(); + m_safex_account2_keys.generate(); + m_safex_account3_keys.generate(); + m_safex_account4_keys.generate(); + + safex_account_alice.username = "alice01"; + safex_account_alice.pkey = m_safex_account1_keys.get_keys().m_public_key; + safex_account_alice.account_data = {'l','o','r','e','m',' ','i','p','s','u','m'}; + + + safex_account_bob.username = "bob02"; + safex_account_bob.pkey = m_safex_account2_keys.get_keys().m_public_key; + std::string data2 = "Bob's data"; + safex_account_bob.account_data = std::vector(data2.begin(), data2.end()); + + + safex_account_daniel.username = "daniel03"; + safex_account_daniel.pkey = m_safex_account3_keys.get_keys().m_public_key; + std::string data3 = "This is some data for test"; + safex_account_daniel.account_data = std::vector(data3.begin(), data3.end()); + + + safex_account_edward.username = "edward04"; + safex_account_edward.pkey = m_safex_account4_keys.get_keys().m_public_key; + std::string data4 = "Тхис ис соме Едвардс дата фор тест"; + safex_account_edward.account_data = std::vector(data4.begin(), data4.end()); + + alice.generate(); + bob.generate(); + + safex_price_peg_alice = safex::safex_price_peg{"Alice price peg",safex_account_alice.username,"USD","USD to SFX price peg",30}; + + if (!expected_data_fields_intialized) + { + expected_alice_account_key = safex_account_alice.pkey; + expected_bob_account_key = safex_account_bob.pkey; + expected_daniel_account_key = safex_account_daniel.pkey; + expected_data_fields_intialized = true; + expected_alice_account_data = std::vector(std::begin(safex_account_alice.account_data), std::end(safex_account_alice.account_data)); + expected_bob_account_data = std::vector(std::begin(data2_alternative_2), std::end(data2_alternative_2)); + expected_daniel_account_data = std::vector(std::begin(data3_alternative), std::end(data3_alternative)); + + expected_alice_price_peg_new_rate = 4; + + expected_alice_price_peg_id = safex_price_peg_alice.price_peg_id; + expected_alice_price_peg_title = safex_price_peg_alice.title; + expected_alice_price_peg_currency = safex_price_peg_alice.currency; + expected_alice_price_peg_description = safex_price_peg_alice.description; + exptected_alice_price_peg_rate = safex_price_peg_alice.rate; + + } + + REGISTER_CALLBACK("verify_safex_price_peg", gen_safex_price_peg_001::verify_safex_price_peg); +} + +bool gen_safex_price_peg_001::generate(std::vector &events) +{ + uint64_t ts_start = 1530720632; + + GENERATE_ACCOUNT(miner); + crypto::public_key miner_public_key = AUTO_VAL_INIT(miner_public_key); + crypto::secret_key_to_public_key(miner.get_keys().m_spend_secret_key, miner_public_key); + cryptonote::fakechain::set_core_tests_public_key(miner_public_key); + + GENERATE_ACCOUNT(miner2); + + MAKE_GENESIS_BLOCK(events, blk_0, miner, ts_start); + + MAKE_ACCOUNT(events, alice); + MAKE_ACCOUNT(events, bob); + MAKE_ACCOUNT(events, daniel); + MAKE_ACCOUNT(events, edward); + + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner); + MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner); + + REWIND_BLOCKS(events, blk_2r, blk_2, miner); + MAKE_TX_MIGRATION_LIST_START(events, txlist_0, miner, alice, MK_TOKENS(10000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[0])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, bob, MK_TOKENS(10000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[1])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, daniel, MK_TOKENS(25000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[2])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2r, miner, txlist_0); + REWIND_BLOCKS(events, blk_4, blk_3, miner); + + //create alice and bob accounts + MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(events, txlist_2, alice, safex_account_alice.username, safex_account_alice.pkey, safex_account_alice.account_data, m_safex_account1_keys.get_keys(), events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_4); + MAKE_CREATE_SAFEX_ACCOUNT_TX_LIST(events, txlist_2, bob, safex_account_bob.username, safex_account_bob.pkey, safex_account_bob.account_data, m_safex_account2_keys.get_keys(), events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_4); + MAKE_MIGRATION_TX_LIST(events, txlist_2, miner, edward, MK_TOKENS(8000), blk_4, get_hash_from_string(bitcoin_tx_hashes_str[3])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_5, blk_4, miner, txlist_2); + REWIND_BLOCKS(events, blk_6, blk_5, miner); + + MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(events, txlist_3, daniel, safex_account_daniel.username, safex_account_daniel.pkey, safex_account_daniel.account_data, m_safex_account3_keys.get_keys(), events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_6); + MAKE_EDIT_SAFEX_ACCOUNT_TX_LIST(events, txlist_3, bob, safex_account_bob.username, std::vector(data2_alternative.begin(), data2_alternative.end()), m_safex_account2_keys.get_keys(), blk_6); + MAKE_MIGRATION_TX_LIST(events, txlist_3, miner, bob, MK_TOKENS(20000), blk_6, get_hash_from_string(bitcoin_tx_hashes_str[4])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_7, blk_6, miner, txlist_3); + REWIND_BLOCKS(events, blk_8, blk_7, miner); + + MAKE_TX_EDIT_SAFEX_ACCOUNT_LIST_START(events, txlist_4, daniel, safex_account_daniel.username, std::vector(data3_alternative.begin(), data3_alternative.end()), m_safex_account3_keys.get_keys(), blk_8); + MAKE_EDIT_SAFEX_ACCOUNT_TX_LIST(events, txlist_4, bob, safex_account_bob.username, std::vector(data2_alternative_2.begin(), data2_alternative_2.end()), m_safex_account2_keys.get_keys(), blk_8); + MAKE_CREATE_SAFEX_ACCOUNT_TX_LIST(events, txlist_4, edward, safex_account_edward.username, safex_account_edward.pkey, safex_account_edward.account_data, m_safex_account4_keys.get_keys(), events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_8); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_9, blk_8, miner, txlist_4); + REWIND_BLOCKS(events, blk_10, blk_9, miner); + + MAKE_TX_CREATE_SAFEX_PRICE_PEG_LIST_START(events, txlist_5, alice, safex_account_alice.pkey, safex_price_peg_alice, m_safex_account1_keys.get_keys(), blk_10); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_11, blk_10, miner, txlist_5); + REWIND_BLOCKS(events, blk_12, blk_11, miner); + + safex_price_peg_alice.rate = expected_alice_price_peg_new_rate; + + MAKE_TX_UPDATE_SAFEX_PRICE_PEG_LIST_START(events, txlist_6, alice, safex_account_alice.pkey, safex_price_peg_alice, m_safex_account1_keys.get_keys(), blk_12); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_13, blk_12, miner, txlist_6); + REWIND_BLOCKS(events, blk_14, blk_13, miner); + + DO_CALLBACK(events, "verify_safex_price_peg"); + + return true; +} + +bool gen_safex_price_peg_001::verify_safex_price_peg(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_safex_price_peg_001::verify_safex_price_peg"); + std::cout << "current_blockchain_height:" << c.get_current_blockchain_height() << " get_blockchain_total_transactions:" << c.get_blockchain_total_transactions() << std::endl; + + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == gen_safex_price_peg_001::expected_blockchain_height); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == gen_safex_price_peg_001::expected_blockchain_total_transactions); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, gen_safex_price_peg_001::expected_blockchain_height, block_list); + CHECK_TEST_CONDITION(r); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + cryptonote::account_base daniel_account = boost::get(events[3]); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + crypto::public_key pkey{}; + const safex::account_username username01{safex_account_alice.username}; + c.get_blockchain_storage().get_safex_account_public_key(username01, pkey); + CHECK_EQ(memcmp((void *)&pkey, (void *)&expected_alice_account_key, sizeof(pkey)), 0); + + crypto::public_key pkey2{}; + const safex::account_username username02{safex_account_bob.username}; + c.get_blockchain_storage().get_safex_account_public_key(username02, pkey2); + CHECK_EQ(memcmp((void *)&pkey2, (void *)&expected_bob_account_key, sizeof(pkey2)), 0); + + crypto::public_key pkey3{}; + const safex::account_username username03{safex_account_daniel.username}; + c.get_blockchain_storage().get_safex_account_public_key(username03, pkey3); + CHECK_EQ(memcmp((void *)&pkey3, (void *)&expected_daniel_account_key, sizeof(pkey3)), 0); + + + std::vector accdata01; + c.get_blockchain_storage().get_safex_account_data(username01, accdata01); + CHECK_TEST_CONDITION(std::equal(expected_alice_account_data.begin(), expected_alice_account_data.end(), accdata01.begin())); + + + std::vector accdata02; + c.get_blockchain_storage().get_safex_account_data(username02, accdata02); + CHECK_TEST_CONDITION(std::equal(expected_bob_account_data.begin(), expected_bob_account_data.end(), accdata02.begin())); + + safex::safex_price_peg sfx_price_peg; + + bool result = c.get_safex_price_peg(expected_alice_price_peg_id,sfx_price_peg); + CHECK_TEST_CONDITION(result); + + CHECK_TEST_CONDITION(std::equal(expected_alice_price_peg_description.begin(), expected_alice_price_peg_description.end(), sfx_price_peg.description.begin())); + CHECK_EQ(expected_alice_price_peg_id, sfx_price_peg.price_peg_id); + CHECK_EQ(expected_alice_price_peg_currency, sfx_price_peg.currency); + CHECK_EQ(expected_alice_price_peg_title, sfx_price_peg.title); + CHECK_EQ(expected_alice_price_peg_new_rate, sfx_price_peg.rate); + + + + std::vector price_pegs; + result = c.get_safex_price_pegs(price_pegs); + CHECK_TEST_CONDITION(result); + + std::cout << boost::format("%30s %10s %10s %30s %60s %20s") % "Price peg title" % "Currency" % "Rate" % "Creator" % "Description" % "Price peg ID"< &events); + bool verify_safex_price_peg(cryptonote::core& c, size_t ev_index, const std::vector &events); + + safex::safex_account_key_handler m_safex_account1_keys; + safex::safex_account_key_handler m_safex_account2_keys; + safex::safex_account_key_handler m_safex_account3_keys; + safex::safex_account_key_handler m_safex_account4_keys; + + safex::safex_account safex_account_alice; + safex::safex_account safex_account_bob; + safex::safex_account safex_account_daniel; + safex::safex_account safex_account_edward; + + safex::safex_price_peg safex_price_peg_alice; + + cryptonote::account_base alice; + cryptonote::account_base bob; + + static const std::string data2_alternative; + static const std::string data2_alternative_2; + static const std::string data3_alternative; + + + static const size_t expected_blockchain_total_transactions = 443; + static const size_t expected_blockchain_height = 429; + + static bool expected_data_fields_intialized; + static crypto::public_key expected_alice_account_key; + static crypto::public_key expected_bob_account_key; + static crypto::public_key expected_daniel_account_key; + + + static std::vector expected_alice_account_data; + static std::vector expected_bob_account_data; + static std::vector expected_daniel_account_data; + + static crypto::hash expected_alice_price_peg_id; + static std::string expected_alice_price_peg_title; + static std::string expected_alice_price_peg_currency; + static std::vector expected_alice_price_peg_description; + static uint64_t expected_alice_price_peg_new_rate; + static uint64_t exptected_alice_price_peg_rate; + +}; + diff --git a/tests/core_tests/safex_purchase.cpp b/tests/core_tests/safex_purchase.cpp new file mode 100644 index 000000000..60cce8156 --- /dev/null +++ b/tests/core_tests/safex_purchase.cpp @@ -0,0 +1,274 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#include +#include + +#include "include_base_utils.h" + +#include "console_handler.h" + +#include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/cryptonote_format_utils.h" + +#include "safex/safex_core.h" + +#include "chaingen.h" +#include "safex_purchase.h" + + + +using namespace std; + +using namespace epee; +using namespace cryptonote; + + +const std::string gen_safex_purchase_001::data2_alternative{"Bob's alternative data"}; +const std::string gen_safex_purchase_001::data2_alternative_2{"Bob's second alternative data"}; +const std::string gen_safex_purchase_001::data3_alternative{"Daniels's alternative data 2 ----------------------------------------------------- some other data here -----------------------------------------------" +" and more data here ----------------------------------------------------------------------------------*****************--------------------------------"}; + +bool gen_safex_purchase_001::expected_data_fields_intialized{false}; + +uint64_t gen_safex_purchase_001::expected_network_fee; +uint64_t gen_safex_purchase_001::expected_alice_balance; +uint64_t gen_safex_purchase_001::expected_bob_balance; + +uint64_t gen_safex_purchase_001::expected_bob_offer_quantity; +crypto::hash gen_safex_purchase_001::expected_purchased_offer_id; + +uint64_t gen_safex_purchase_001::expected_alice_feedback_star_rating; + +gen_safex_purchase_001::gen_safex_purchase_001() +{ + + m_safex_account1_keys.generate(); + m_safex_account2_keys.generate(); + m_safex_account3_keys.generate(); + m_safex_account4_keys.generate(); + + safex_account_alice.username = "alice01"; + safex_account_alice.pkey = m_safex_account1_keys.get_keys().m_public_key; + safex_account_alice.account_data = {'l','o','r','e','m',' ','i','p','s','u','m'}; + + + safex_account_bob.username = "bob02"; + safex_account_bob.pkey = m_safex_account2_keys.get_keys().m_public_key; + std::string data2 = "Bob's data"; + safex_account_bob.account_data = std::vector(data2.begin(), data2.end()); + + + safex_account_daniel.username = "daniel03"; + safex_account_daniel.pkey = m_safex_account3_keys.get_keys().m_public_key; + std::string data3 = "This is some data for test"; + safex_account_daniel.account_data = std::vector(data3.begin(), data3.end()); + + + safex_account_edward.username = "edward04"; + safex_account_edward.pkey = m_safex_account4_keys.get_keys().m_public_key; + std::string data4 = "Тхис ис соме Едвардс дата фор тест"; + safex_account_edward.account_data = std::vector(data4.begin(), data4.end()); + + alice.generate(); + bob.generate(); + + safex_offer_alice = safex::safex_offer("Black Sabbath T-shirt",100,MK_COINS(10),"Quality 100% cotton t-shirt with the heaviest band in the universe", + safex_account_alice.username,alice.get_keys().m_view_secret_key,alice.get_keys().m_account_address); + safex_offer_bob = safex::safex_offer("Metallica T-shirt",1000,MK_COINS(10),"Quality 100% cotton t-shirt with the loudest band in the universe", + safex_account_bob.username,bob.get_keys().m_view_secret_key,bob.get_keys().m_account_address); + + + + + + safex_price_peg_bob = safex::safex_price_peg("TestPricePeg",safex_account_bob.username,"USD","Best price my man",0.005018*COIN); + safex_offer_bob.set_price_peg(safex_price_peg_bob.price_peg_id,MK_COINS(800),MK_COINS(3)); + + std::string rate_str = print_money(safex_price_peg_bob.rate); + double rate = stod(rate_str); + + std::string price_str = print_money(safex_offer_bob.price); + double price = stod(price_str); + + uint64_t pegged_price = (price*rate)*SAFEX_CASH_COIN; + + safex_alice_purchase_from_bob = safex::safex_purchase{1, pegged_price, safex_offer_bob.offer_id, safex_offer_bob.get_hash(), false}; + + + safex_alice_feedback = safex::safex_feedback{3,"Perfect for my concert next week.",safex_offer_bob.offer_id}; + + + if (!expected_data_fields_intialized) + { + expected_data_fields_intialized = true; + + expected_alice_balance = 0; + expected_bob_balance = 0; + expected_network_fee = 0; + + expected_bob_offer_quantity = safex_offer_bob.quantity-safex_alice_purchase_from_bob.quantity; + expected_purchased_offer_id = safex_alice_purchase_from_bob.offer_id; + + + expected_network_fee += calculate_safex_network_fee(pegged_price, FAKECHAIN, safex::command_t::simple_purchase); + + expected_alice_balance += MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE; + expected_alice_balance -= 2*TESTS_DEFAULT_FEE; + expected_alice_balance += MK_COINS(30); + expected_alice_balance -= pegged_price; + expected_alice_balance -= TESTS_DEFAULT_FEE; + + expected_bob_balance += MK_TOKENS(10000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE; + expected_bob_balance += MK_TOKENS(20000)*AIRDROP_TOKEN_TO_CASH_REWARD_RATE; + expected_bob_balance -= 4*TESTS_DEFAULT_FEE; + expected_bob_balance += pegged_price-expected_network_fee; + + + expected_alice_feedback_star_rating = safex_alice_feedback.stars_given*COIN; + expected_alice_balance -= TESTS_DEFAULT_FEE; + + } + + REGISTER_CALLBACK("verify_safex_purchase", gen_safex_purchase_001::verify_safex_purchase); +} + +bool gen_safex_purchase_001::generate(std::vector &events) +{ + uint64_t ts_start = 1530720632; + + GENERATE_ACCOUNT(miner); + crypto::public_key miner_public_key = AUTO_VAL_INIT(miner_public_key); + crypto::secret_key_to_public_key(miner.get_keys().m_spend_secret_key, miner_public_key); + cryptonote::fakechain::set_core_tests_public_key(miner_public_key); + + GENERATE_ACCOUNT(miner2); + + MAKE_GENESIS_BLOCK(events, blk_0, miner, ts_start); + + events.push_back(alice); + events.push_back(bob); + MAKE_ACCOUNT(events, daniel); + MAKE_ACCOUNT(events, edward); + + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner); + MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner); + + REWIND_BLOCKS(events, blk_2r, blk_2, miner); + MAKE_TX_MIGRATION_LIST_START(events, txlist_0, miner, alice, MK_TOKENS(10000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[0])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, bob, MK_TOKENS(10000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[1])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, daniel, MK_TOKENS(25000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[2])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2r, miner, txlist_0); + REWIND_BLOCKS(events, blk_4, blk_3, miner); + + //create alice and bob accounts + MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(events, txlist_2, alice, safex_account_alice.username, safex_account_alice.pkey, safex_account_alice.account_data, m_safex_account1_keys.get_keys(),events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_4); + MAKE_CREATE_SAFEX_ACCOUNT_TX_LIST(events, txlist_2, bob, safex_account_bob.username, safex_account_bob.pkey, safex_account_bob.account_data, m_safex_account2_keys.get_keys(),events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_4); + MAKE_MIGRATION_TX_LIST(events, txlist_2, miner, edward, MK_TOKENS(8000), blk_4, get_hash_from_string(bitcoin_tx_hashes_str[3])); + MAKE_TX_LIST(events, txlist_2, miner, alice, MK_COINS(30), blk_4); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_5, blk_4, miner, txlist_2); + REWIND_BLOCKS(events, blk_6, blk_5, miner); + + MAKE_TX_CREATE_SAFEX_ACCOUNT_LIST_START(events, txlist_3, daniel, safex_account_daniel.username, safex_account_daniel.pkey, safex_account_daniel.account_data, m_safex_account3_keys.get_keys(),events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_6); + MAKE_EDIT_SAFEX_ACCOUNT_TX_LIST(events, txlist_3, bob, safex_account_bob.username, std::vector(data2_alternative.begin(), data2_alternative.end()), m_safex_account2_keys.get_keys(), blk_6); + MAKE_MIGRATION_TX_LIST(events, txlist_3, miner, bob, MK_TOKENS(20000), blk_6, get_hash_from_string(bitcoin_tx_hashes_str[4])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_7, blk_6, miner, txlist_3); + REWIND_BLOCKS(events, blk_8, blk_7, miner); + + MAKE_TX_EDIT_SAFEX_ACCOUNT_LIST_START(events, txlist_4, daniel, safex_account_daniel.username, std::vector(data3_alternative.begin(), data3_alternative.end()), m_safex_account3_keys.get_keys(), blk_8); + MAKE_CREATE_SAFEX_PRICE_PEG_TX_LIST(events, txlist_4, bob, safex_account_bob.pkey, safex_price_peg_bob, m_safex_account2_keys.get_keys(), blk_8); + MAKE_CREATE_SAFEX_ACCOUNT_TX_LIST(events, txlist_4, edward, safex_account_edward.username, safex_account_edward.pkey, safex_account_edward.account_data, m_safex_account4_keys.get_keys(), events.size()+SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_PERIOD_FAKECHAIN, blk_8); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_9, blk_8, miner, txlist_4); + REWIND_BLOCKS(events, blk_10, blk_9, miner); + + //create test offer + MAKE_TX_CREATE_SAFEX_OFFER_LIST_START(events, txlist_5, alice, safex_account_alice.pkey, safex_offer_alice, m_safex_account1_keys.get_keys(), blk_10); + MAKE_CREATE_SAFEX_OFFER_TX_LIST(events, txlist_5, bob, safex_account_bob.pkey, safex_offer_bob, m_safex_account2_keys.get_keys(), blk_10); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_11, blk_10, miner, txlist_5); + REWIND_BLOCKS(events, blk_12, blk_11, miner); + + //create purchase + MAKE_TX_CREATE_SAFEX_PURCHASE_LIST_START(events, txlist_6, alice, safex_alice_purchase_from_bob, bob.get_keys().m_account_address, blk_12); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_13, blk_12, miner, txlist_6); + REWIND_BLOCKS(events, blk_14, blk_13, miner); + + //create feedbackl + MAKE_TX_CREATE_SAFEX_FEEDBACK_LIST_START(events, txlist_7, alice, safex_alice_feedback, blk_14); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_15, blk_14, miner, txlist_7); + REWIND_BLOCKS(events, blk_16, blk_15, miner); + + DO_CALLBACK(events, "verify_safex_purchase"); + + return true; +} + +bool gen_safex_purchase_001::verify_safex_purchase(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("gen_safex_purchase_001::verify_safex_purchase"); + std::cout << "current_blockchain_height:" << c.get_current_blockchain_height() << " get_blockchain_total_transactions:" << c.get_blockchain_total_transactions() << std::endl; + + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == gen_safex_purchase_001::expected_blockchain_height); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == gen_safex_purchase_001::expected_blockchain_total_transactions); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, gen_safex_purchase_001::expected_blockchain_height, block_list); + CHECK_TEST_CONDITION(r); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + cryptonote::account_base daniel_account = boost::get(events[3]); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + uint64_t network_fee_collected = c.get_collected_network_fee(0, gen_safex_purchase_001::expected_blockchain_height); + CHECK_EQ(network_fee_collected, expected_network_fee); + + + uint64_t alice_balance = get_balance(alice_account, chain, mtx); + CHECK_EQ(alice_balance, expected_alice_balance); + + uint64_t bob_balance = get_balance(bob_account, chain, mtx); + CHECK_EQ(bob_balance, expected_bob_balance); + + uint64_t offer_quantity; + c.get_blockchain_storage().get_safex_offer_quantity(expected_purchased_offer_id,offer_quantity); + CHECK_EQ(expected_bob_offer_quantity, offer_quantity); + + uint64_t offer_rating; + c.get_blockchain_storage().get_safex_offer_rating(expected_purchased_offer_id,offer_rating); + CHECK_EQ(expected_alice_feedback_star_rating, offer_rating); + + return true; +} diff --git a/tests/core_tests/safex_purchase.h b/tests/core_tests/safex_purchase.h new file mode 100644 index 000000000..a59adf7bd --- /dev/null +++ b/tests/core_tests/safex_purchase.h @@ -0,0 +1,102 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#pragma once + +#include "safex/safex_feedback.h" +#include "safex/safex_purchase.h" +#include "chaingen.h" +#include "block_reward.h" +#include "block_validation.h" +#include "chain_split_1.h" +#include "chain_switch_1.h" +#include "double_spend.h" +#include "integer_overflow.h" +#include "ring_signature_1.h" +#include "tx_validation.h" +#include "v2_tests.h" + +/************************************************************************/ +/* */ +/************************************************************************/ +class gen_safex_purchase_001: public test_chain_unit_base +{ +public: + gen_safex_purchase_001(); + + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", + "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", + "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; + + bool generate(std::vector &events); + bool verify_safex_purchase(cryptonote::core& c, size_t ev_index, const std::vector &events); + + safex::safex_account_key_handler m_safex_account1_keys; + safex::safex_account_key_handler m_safex_account2_keys; + safex::safex_account_key_handler m_safex_account3_keys; + safex::safex_account_key_handler m_safex_account4_keys; + + safex::safex_account safex_account_alice; + safex::safex_account safex_account_bob; + safex::safex_account safex_account_daniel; + safex::safex_account safex_account_edward; + + cryptonote::account_base alice; + cryptonote::account_base bob; + + safex::safex_offer safex_offer_alice; + safex::safex_offer safex_offer_bob; + + safex::safex_price_peg safex_price_peg_bob; + + safex::safex_purchase safex_alice_purchase_from_bob; + + safex::safex_feedback safex_alice_feedback; + + static const std::string data2_alternative; + static const std::string data2_alternative_2; + static const std::string data3_alternative; + + + static const size_t expected_blockchain_total_transactions = 507; + static const size_t expected_blockchain_height = 490; + + static bool expected_data_fields_intialized; + + static uint64_t expected_network_fee; + static uint64_t expected_alice_balance; + static uint64_t expected_bob_balance; + static uint64_t expected_bob_offer_quantity; + static crypto::hash expected_purchased_offer_id; + static uint64_t expected_alice_feedback_star_rating; + +}; + diff --git a/tests/core_tests/token_stake.cpp b/tests/core_tests/token_stake.cpp new file mode 100644 index 000000000..1017b8f2d --- /dev/null +++ b/tests/core_tests/token_stake.cpp @@ -0,0 +1,170 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#include +#include + +#include "include_base_utils.h" + +#include "console_handler.h" + +#include "cryptonote_basic/cryptonote_basic.h" +#include "cryptonote_basic/cryptonote_format_utils.h" + +#include "safex/safex_core.h" + +#include "chaingen.h" +#include "token_stake.h" + + + +using namespace std; + +using namespace epee; +using namespace cryptonote; + + +// class token_lock_001; + +crypto::hash gen_token_lock_001::get_hash_from_string(const std::string hashstr) { + //parse bitcoin transaction hash + cryptonote::blobdata expected_bitcoin_hash_data; + if (!epee::string_tools::parse_hexstr_to_binbuff(std::string(hashstr), expected_bitcoin_hash_data) || expected_bitcoin_hash_data.size() != sizeof(crypto::hash)) + { + std::cerr << "failed to parse bitcoin transaction hash" << endl; + return boost::value_initialized(); + } + const crypto::hash bitcoin_transaction_hash = *reinterpret_cast(expected_bitcoin_hash_data.data()); + return bitcoin_transaction_hash; +} + +gen_token_lock_001::gen_token_lock_001() +{ + REGISTER_CALLBACK("verify_token_lock", gen_token_lock_001::verify_token_lock); +} + +bool gen_token_lock_001::generate(std::vector &events) +{ + uint64_t ts_start = 1530720632; + + GENERATE_ACCOUNT(miner); + crypto::public_key miner_public_key = AUTO_VAL_INIT(miner_public_key); + crypto::secret_key_to_public_key(miner.get_keys().m_spend_secret_key, miner_public_key); + cryptonote::fakechain::set_core_tests_public_key(miner_public_key); + + GENERATE_ACCOUNT(miner2); + + MAKE_GENESIS_BLOCK(events, blk_0, miner, ts_start); + + MAKE_ACCOUNT(events, alice); + MAKE_ACCOUNT(events, bob); + MAKE_ACCOUNT(events, daniel); + MAKE_ACCOUNT(events, jack); + + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner); + MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner); + + REWIND_BLOCKS(events, blk_2r, blk_2, miner); + MAKE_TX_MIGRATION_LIST_START(events, txlist_0, miner, alice, MK_TOKENS(200000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[0])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, bob, MK_TOKENS(20000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[1])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, daniel, MK_TOKENS(10000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[2])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2r, miner, txlist_0); + REWIND_BLOCKS(events, blk_4, blk_3, miner); + + //lock some tokens + MAKE_TX_TOKEN_LOCK_LIST_START(events, txlist_1, alice, MK_TOKENS(80000), blk_4); + MAKE_TOKEN_LOCK_TX_LIST(events, txlist_1, bob, MK_TOKENS(20000), blk_4); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_5, blk_4, miner, txlist_1); + REWIND_BLOCKS(events, blk_6, blk_5, miner); + + MAKE_TX_TOKEN_LOCK_LIST_START(events, txlist_2, alice, MK_TOKENS(15000), blk_6); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_6r, blk_6, miner, txlist_2); + + REWIND_BLOCKS(events, blk_7, blk_6r, miner); + + MAKE_TX_TOKEN_UNLOCK_LIST_START(events, txlist_3, alice, MK_TOKENS(80000), blk_7); + MAKE_TOKEN_LOCK_TX_LIST(events, txlist_3, daniel, MK_TOKENS(10000), blk_7); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_7r, blk_7, miner, txlist_3); + + REWIND_BLOCKS(events, blk_8, blk_7r, miner); + + MAKE_TX_TOKEN_LOCK_LIST_START(events, txlist_4, alice, MK_TOKENS(25000), blk_8); + MAKE_TOKEN_UNLOCK_TX_LIST(events, txlist_4, bob, MK_TOKENS(20000), blk_8); + MAKE_TOKEN_UNLOCK_TX_LIST(events, txlist_4, daniel, MK_TOKENS(10000), blk_8); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_9, blk_8, miner, txlist_4); + + DO_CALLBACK(events, "verify_token_lock"); + + return true; +} + +bool gen_token_lock_001::verify_token_lock(cryptonote::core &c, size_t ev_index, const std::vector &events) +{ + DEFINE_TESTS_ERROR_CONTEXT("token_lock_001::verify_network_fee"); + std::cout << "current_blockchain_height:" << c.get_current_blockchain_height() << " get_blockchain_total_transactions:" << c.get_blockchain_total_transactions() << std::endl; + + CHECK_TEST_CONDITION(c.get_current_blockchain_height() == gen_token_lock_001::expected_blockchain_height); + CHECK_TEST_CONDITION(c.get_blockchain_total_transactions() == gen_token_lock_001::expected_blockchain_total_transactions); + + std::list block_list; + bool r = c.get_blocks((uint64_t)0, gen_token_lock_001::expected_blockchain_height, block_list); + CHECK_TEST_CONDITION(r); + + cryptonote::account_base alice_account = boost::get(events[1]); + cryptonote::account_base bob_account = boost::get(events[2]); + cryptonote::account_base daniel_account = boost::get(events[3]); + + std::vector chain; + map_hash2tx_t mtx; + std::vector blocks(block_list.begin(), block_list.end()); + bool re = find_block_chain(events, chain, mtx, get_block_hash(blocks.back())); + CHECK_TEST_CONDITION(re); + + //cout << "check_token_lock_balance: cash alice = " << get_balance(alice_account, blocks, mtx) << endl; + cout << "final alice token balance= " << print_money(get_token_balance(alice_account, blocks, mtx)) << " locked token balance= " << print_money(get_locked_token_balance(alice_account, blocks, mtx)) << endl; + cout << "final bob token balance= " << print_money(get_token_balance(bob_account, blocks, mtx)) << " locked token balance= " << print_money(get_locked_token_balance(bob_account, blocks, mtx)) << endl; + cout << "final daniel token balance= " << print_money(get_token_balance(daniel_account, blocks, mtx)) << " locked token balance= " << print_money(get_locked_token_balance(daniel_account, blocks, mtx)) << endl; + + int64_t locked_tokens = c.get_staked_tokens(0, gen_token_lock_001::expected_blockchain_height); + uint64_t locked_tokens2 = c.get_staked_tokens(); + cout << "total core locked tokens: " << print_money(locked_tokens) << " currently locked tokens" << print_money(locked_tokens2) << endl; + CHECK_EQ(static_cast(locked_tokens), locked_tokens2); + + CHECK_EQ(gen_token_lock_001::expected_alice_token_balance, get_token_balance(alice_account, blocks, mtx)); + CHECK_EQ(gen_token_lock_001::expected_bob_token_balance, get_token_balance(bob_account, blocks, mtx)); + CHECK_EQ(gen_token_lock_001::expected_daniel_token_balance, get_token_balance(daniel_account, blocks, mtx)); + CHECK_EQ(gen_token_lock_001::expected_staked_tokens, c.get_staked_tokens(0, gen_token_lock_001::expected_blockchain_height)); + + + //todo implement condition check + + return true; +} diff --git a/tests/core_tests/token_stake.h b/tests/core_tests/token_stake.h new file mode 100644 index 000000000..279219377 --- /dev/null +++ b/tests/core_tests/token_stake.h @@ -0,0 +1,68 @@ +// Copyright (c) 2018, The Safex 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 +// Parts of this file are originally copyright (c) 2014-2018 The Monero Project + +#pragma once + +#include "chaingen.h" +#include "block_reward.h" +#include "block_validation.h" +#include "chain_split_1.h" +#include "chain_switch_1.h" +#include "double_spend.h" +#include "integer_overflow.h" +#include "ring_signature_1.h" +#include "tx_validation.h" +#include "v2_tests.h" + +/************************************************************************/ +/* */ +/************************************************************************/ +class gen_token_lock_001: public test_chain_unit_base +{ +public: + gen_token_lock_001(); + + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; + + bool generate(std::vector &events); + bool verify_token_lock(cryptonote::core& c, size_t ev_index, const std::vector &events); + crypto::hash get_hash_from_string(const std::string hashstr); + + static const size_t expected_blockchain_total_transactions = 319; + static const size_t expected_blockchain_height = 308; + + static const uint64_t expected_alice_token_balance = 160000 * SAFEX_TOKEN; + static const uint64_t expected_bob_token_balance = 20000 * SAFEX_TOKEN; + static const uint64_t expected_daniel_token_balance = 10000 * SAFEX_TOKEN; + + static const uint64_t expected_staked_tokens = 40000 * SAFEX_TOKEN; +}; + diff --git a/tests/core_tests/token_transactions.h b/tests/core_tests/token_transactions.h index 3598d1e83..aa578a8cc 100644 --- a/tests/core_tests/token_transactions.h +++ b/tests/core_tests/token_transactions.h @@ -41,8 +41,7 @@ #include "ring_signature_1.h" #include "tx_validation.h" #include "v2_tests.h" -#include "rct.h" -#include "multisig.h" +//#include "rct.h" /************************************************************************/ /* */ /************************************************************************/ diff --git a/tests/core_tests/transaction_tests.cpp b/tests/core_tests/transaction_tests.cpp index e037229fd..e81c45678 100644 --- a/tests/core_tests/transaction_tests.cpp +++ b/tests/core_tests/transaction_tests.cpp @@ -98,7 +98,6 @@ bool test_transaction_generation_and_ring_signature() src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(tx_mine_2); src.real_output = 1; - src.rct = false; src.real_output_in_tx_index = 0; } //fill outputs entry diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index 25ac9cc40..d9ac83d6c 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -37,6 +37,7 @@ using namespace epee; using namespace crypto; using namespace cryptonote; + namespace { struct tx_builder @@ -100,6 +101,46 @@ namespace } } + void step3_fill_advanced_outputs(const std::vector& destinations) + { + size_t output_index = 0; + BOOST_FOREACH(const tx_destination_entry& dst_entr, destinations) + { + crypto::key_derivation derivation; + crypto::public_key out_eph_public_key; + crypto::generate_key_derivation(dst_entr.addr.m_view_public_key, m_tx_key.sec, derivation); + crypto::derive_public_key(derivation, output_index, dst_entr.addr.m_spend_public_key, out_eph_public_key); + + tx_out out; + out.token_amount = dst_entr.token_amount; + out.amount = dst_entr.amount; + + if (dst_entr.output_type == tx_out_type::out_staked_token) { + txout_to_script ts; + ts.key = out_eph_public_key; + ts.output_type = static_cast(tx_out_type::out_staked_token); + out.target = ts; + + } else if (dst_entr.output_type == tx_out_type::out_token) { + txout_token_to_key tk; + tk.key = out_eph_public_key; + out.target = tk; + } else { + txout_to_key tk; + tk.key = out_eph_public_key; + out.target = tk; + } + + + + + + + m_tx.vout.push_back(out); + output_index++; + } + } + void step4_calc_hash() { get_transaction_prefix_hash(m_tx, m_tx_prefix_hash); @@ -195,7 +236,7 @@ bool gen_tx_big_version::generate(std::vector& events) const fill_tx_sources_and_destinations(events, blk_0, miner_account, miner_account, MK_COINS(1), TESTS_DEFAULT_FEE, 0, sources, destinations); tx_builder builder; - builder.step1_init(1 + 1, 0); + builder.step1_init(MAX_SUPPORTED_TX_VERSION + 1, 0); builder.step2_fill_inputs(miner_account.get_keys(), sources); builder.step3_fill_outputs(destinations); builder.step4_calc_hash(); @@ -787,3 +828,41 @@ bool gen_tx_signatures_are_invalid::generate(std::vector& even return true; } + + + +bool gen_tx_not_enough_tokens_to_lock::generate(std::vector& events) const +{ + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; + + uint64_t ts_start = 1530720632; + + GENERATE_ACCOUNT(miner); + crypto::public_key miner_public_key = AUTO_VAL_INIT(miner_public_key); + crypto::secret_key_to_public_key(miner.get_keys().m_spend_secret_key, miner_public_key); + cryptonote::fakechain::set_core_tests_public_key(miner_public_key); + + GENERATE_ACCOUNT(miner2); + + MAKE_GENESIS_BLOCK(events, blk_0, miner, ts_start); + + MAKE_ACCOUNT(events, alice); + MAKE_ACCOUNT(events, bob); + MAKE_ACCOUNT(events, daniel); + + MAKE_NEXT_BLOCK(events, blk_1, blk_0, miner); + MAKE_NEXT_BLOCK(events, blk_2, blk_1, miner); + + REWIND_BLOCKS(events, blk_2r, blk_2, miner); + MAKE_TX_MIGRATION_LIST_START(events, txlist_0, miner, alice, MK_TOKENS(200000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[0])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, bob, MK_TOKENS(20000), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[1])); + MAKE_MIGRATION_TX_LIST(events, txlist_0, miner, daniel, MK_TOKENS(100), blk_2, get_hash_from_string(bitcoin_tx_hashes_str[2])); + MAKE_NEXT_BLOCK_TX_LIST(events, blk_3, blk_2r, miner, txlist_0); + REWIND_BLOCKS(events, blk_4, blk_3, miner); + + //lock some tokens + DO_CALLBACK(events, "mark_invalid_tx"); + MAKE_TX_TOKEN_LOCK_LIST_START(events, txlist_1, alice, MK_TOKENS(1000), blk_4); + + return true; +} diff --git a/tests/core_tests/tx_validation.h b/tests/core_tests/tx_validation.h index 88ff6a582..468ad69a7 100644 --- a/tests/core_tests/tx_validation.h +++ b/tests/core_tests/tx_validation.h @@ -164,3 +164,8 @@ struct gen_tx_signatures_are_invalid : public get_tx_validation_base { bool generate(std::vector& events) const; }; + +struct gen_tx_not_enough_tokens_to_lock : public get_tx_validation_base +{ + bool generate(std::vector& events) const; +}; diff --git a/tests/core_tests/v2_tests.cpp b/tests/core_tests/v2_tests.cpp index 943a4e624..32dbb81ca 100644 --- a/tests/core_tests/v2_tests.cpp +++ b/tests/core_tests/v2_tests.cpp @@ -97,7 +97,6 @@ bool gen_v2_tx_validation_base::generate_with(std::vector& eve } src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(blocks[0].miner_tx); src.real_output = 0; - src.rct = false; src.real_output_in_tx_index = out_idx[out_idx_idx]; } diff --git a/tests/performance_tests/check_tx_signature.h b/tests/performance_tests/check_tx_signature.h index 82c056503..f85d5ab4a 100644 --- a/tests/performance_tests/check_tx_signature.h +++ b/tests/performance_tests/check_tx_signature.h @@ -69,7 +69,7 @@ class test_check_tx_signature : private multi_tx_test_base std::vector additional_tx_keys; std::unordered_map subaddresses; subaddresses[this->m_miners[this->real_source_idx].get_keys().m_account_address.m_spend_public_key] = {0,0}; - 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(), m_tx, 0, tx_key, additional_tx_keys, rct)) + 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(), m_tx, 0, tx_key, additional_tx_keys)) return false; get_transaction_prefix_hash(m_tx, m_tx_prefix_hash); diff --git a/tests/performance_tests/construct_tx.h b/tests/performance_tests/construct_tx.h index d32209e68..c7b4dba49 100644 --- a/tests/performance_tests/construct_tx.h +++ b/tests/performance_tests/construct_tx.h @@ -74,7 +74,7 @@ class test_construct_tx : private multi_tx_test_base std::vector additional_tx_keys; std::unordered_map subaddresses; subaddresses[this->m_miners[this->real_source_idx].get_keys().m_account_address.m_spend_public_key] = {0,0}; - 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(), m_tx, 0, tx_key, additional_tx_keys, rct); + 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(), m_tx, 0, tx_key, additional_tx_keys); } private: diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index 994af259e..9983b6cae 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -141,9 +141,9 @@ int main(int argc, char** argv) TEST_PERFORMANCE2(filter, test_check_tx_signature, 10, false); TEST_PERFORMANCE2(filter, test_check_tx_signature, 100, false); - TEST_PERFORMANCE2(filter, test_check_tx_signature, 2, true); - TEST_PERFORMANCE2(filter, test_check_tx_signature, 10, true); - TEST_PERFORMANCE2(filter, test_check_tx_signature, 100, true); + TEST_PERFORMANCE2(filter, test_check_tx_signature, 2, false); + TEST_PERFORMANCE2(filter, test_check_tx_signature, 10, false); + TEST_PERFORMANCE2(filter, test_check_tx_signature, 100, false); TEST_PERFORMANCE0(filter, test_is_out_to_acc); TEST_PERFORMANCE0(filter, test_is_out_to_acc_precomp); diff --git a/tests/performance_tests/multi_tx_test_base.h b/tests/performance_tests/multi_tx_test_base.h index f501ac499..2efd1d0c8 100644 --- a/tests/performance_tests/multi_tx_test_base.h +++ b/tests/performance_tests/multi_tx_test_base.h @@ -73,8 +73,6 @@ class multi_tx_test_base source_entry.real_output_in_tx_index = 0; source_entry.outputs.swap(output_entries); source_entry.real_output = real_source_idx; - source_entry.mask = rct::identity(); - source_entry.rct = false; m_sources.push_back(source_entry); diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index 0422d3eb2..043a8ad5d 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -55,7 +55,6 @@ set(unit_tests_sources memwipe.cpp mnemonics.cpp mul_div.cpp - multisig.cpp parse_amount.cpp serialization.cpp sha256.cpp @@ -70,11 +69,21 @@ set(unit_tests_sources varint.cpp ringct.cpp output_selection.cpp - vercmp.cpp) + vercmp.cpp + safex_blockchain_db.cpp + # Safex db tests + safex_db/safex_test_common.cpp + safex_db/safex_stake_unstake.cpp + safex_db/safex_account.cpp + safex_db/safex_offer.cpp + safex_db/simple_purchase.cpp + safex_db/safex_price_peg.cpp + ) set(unit_tests_headers - unit_tests_utils.h) + unit_tests_utils.h + safex_test_common.h) add_executable(unit_tests ${unit_tests_sources} @@ -85,6 +94,7 @@ target_link_libraries(unit_tests cryptonote_protocol cryptonote_core blockchain_db + safex_core rpc wallet p2p diff --git a/tests/unit_tests/blockchain_db.cpp b/tests/unit_tests/blockchain_db.cpp index 4683a0da0..8836b272e 100644 --- a/tests/unit_tests/blockchain_db.cpp +++ b/tests/unit_tests/blockchain_db.cpp @@ -147,7 +147,6 @@ class BlockchainDBTest : public testing::Test src.push_output(0, boost::get(m_blocks[i - 1].miner_tx.vout[0].target).key, src.amount); src.real_out_tx_key = cryptonote::get_tx_pub_key_from_extra(m_blocks[i - 1].miner_tx); src.real_output = 0; - src.rct = false; src.real_output_in_tx_index = 0; } //fill outputs entry diff --git a/tests/unit_tests/epee_utils.cpp b/tests/unit_tests/epee_utils.cpp index fe911d6a0..8336f0ace 100644 --- a/tests/unit_tests/epee_utils.cpp +++ b/tests/unit_tests/epee_utils.cpp @@ -29,6 +29,7 @@ // Parts of this file are originally copyright (c) 2014-2018 The Monero Project #include +#include #include #include #include @@ -134,7 +135,7 @@ namespace EXPECT_FALSE( lhs >= rhs ); \ EXPECT_TRUE( rhs >= lhs ) - #ifdef BOOST_LITTLE_ENDIAN + #if BOOST_ENDIAN_LITTLE_BYTE #define CHECK_LESS_ENDIAN(lhs, rhs) CHECK_LESS( rhs , lhs ) #else #define CHECK_LESS_ENDIAN(lhs, rhs) CHECK_LESS( lhs , rhs ) diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index 8beae60a0..26797d242 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -35,6 +35,7 @@ #include "blockchain_db/blockchain_db.h" #include "cryptonote_basic/cryptonote_format_utils.h" #include "cryptonote_basic/hardfork.h" +#include "safex_test_common.h" using namespace cryptonote; @@ -42,117 +43,6 @@ using namespace cryptonote; #define SECONDS_PER_YEAR 31557600 -class TestDB: public BlockchainDB { -public: - TestDB() {}; - virtual void open(const std::string& filename, const int db_flags = 0) { } - virtual void close() {} - virtual void sync() {} - virtual void safesyncmode(const bool onoff) {} - virtual void reset() {} - virtual std::vector get_filenames() const { return std::vector(); } - virtual std::string get_db_name() const { return std::string(); } - virtual bool lock() { return true; } - virtual void unlock() { } - virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) { return true; } - virtual void batch_stop() {} - virtual void set_batch_transactions(bool) {} - virtual void block_txn_start(bool readonly=false) {} - virtual void block_txn_stop() {} - virtual void block_txn_abort() {} - virtual void drop_hard_fork_info() {} - virtual bool block_exists(const crypto::hash& h, uint64_t *height) const { return false; } - virtual blobdata get_block_blob_from_height(const uint64_t& height) const { return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); } - virtual blobdata get_block_blob(const crypto::hash& h) const { return blobdata(); } - virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const { return false; } - virtual uint64_t get_block_height(const crypto::hash& h) const { return 0; } - virtual block_header get_block_header(const crypto::hash& h) const { return block_header(); } - virtual uint64_t get_block_timestamp(const uint64_t& height) const { return 0; } - virtual uint64_t get_top_block_timestamp() const { return 0; } - virtual size_t get_block_size(const uint64_t& height) const { return 128; } - virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const { return 10; } - virtual difficulty_type get_block_difficulty(const uint64_t& height) const { return 0; } - virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const { return 10000000000; } - virtual uint64_t get_block_already_migrated_tokens(const uint64_t& height) const { return 10000000000; } - virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const { return crypto::hash(); } - virtual std::vector get_blocks_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector(); } - virtual std::vector get_hashes_range(const uint64_t& h1, const uint64_t& h2) const { return std::vector(); } - virtual crypto::hash top_block_hash() const { return crypto::hash(); } - virtual block get_top_block() const { return block(); } - virtual uint64_t height() const { return blocks.size(); } - virtual bool tx_exists(const crypto::hash& h) const { return false; } - virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const { return false; } - virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const { return 0; } - virtual transaction get_tx(const crypto::hash& h) const { return transaction(); } - virtual bool get_tx(const crypto::hash& h, transaction &tx) const { return false; } - virtual uint64_t get_tx_count() const { return 0; } - virtual std::vector get_tx_list(const std::vector& hlist) const { return std::vector(); } - virtual uint64_t get_tx_block_height(const crypto::hash& h) const { return 0; } - virtual uint64_t get_num_outputs(const uint64_t& amount, const tx_out_type output_type) const { return 1; } - virtual uint64_t get_indexing_base() const { return 0; } - virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) { return output_data_t(); } - virtual output_data_t get_output_key(const uint64_t& global_index) const { return output_data_t(); } - virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const { return tx_out_index(); } - virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const { return tx_out_index(); } - virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices, const tx_out_type output_type) const {} - virtual void get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs, const tx_out_type output_type, bool allow_partial = false) {} - virtual bool can_thread_bulk_indices() const { return false; } - virtual std::vector get_tx_output_indices(const crypto::hash& h) const { return std::vector(); } - virtual std::vector get_tx_amount_output_indices(const uint64_t tx_index) const { return std::vector(); } - virtual bool has_key_image(const crypto::key_image& img) const { return false; } - virtual void remove_block() { blocks.pop_back(); } - virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) {return 0;} - virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) {} - virtual uint64_t add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) {return 0;} - virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector& amount_output_indices) {} - virtual void add_spent_key(const crypto::key_image& k_image) {} - virtual void remove_spent_key(const crypto::key_image& k_image) {} - - virtual bool for_all_key_images(std::function) const { return true; } - virtual bool for_blocks_range(const uint64_t&, const uint64_t&, std::function) const { return true; } - virtual bool for_all_transactions(std::function) const { return true; } - virtual bool for_all_outputs(std::function f, const tx_out_type output_type) const { return true; } - virtual bool for_all_outputs(uint64_t amount, const std::function &f, const tx_out_type output_type) const { return true; } - virtual bool is_read_only() const { return false; } - virtual std::map> get_output_histogram(const std::vector &amounts, bool unlocked, uint64_t recent_cutoff, const tx_out_type output_type) const { return std::map>(); } - - virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t& details) {} - virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& details) {} - virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const { return 0; } - virtual bool txpool_has_tx(const crypto::hash &txid) const { return false; } - virtual void remove_txpool_tx(const crypto::hash& txid) {} - virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const { return false; } - virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const { return false; } - virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const { return ""; } - virtual bool for_all_txpool_txes(std::function, bool include_blob = false, bool include_unrelayed_txes = false) const { return false; } - - virtual void add_block( const block& blk - , const size_t& block_size - , const difficulty_type& cumulative_difficulty - , const uint64_t& coins_generated - , const uint64_t& tokens_migrated - , const crypto::hash& blk_hash - ) { - blocks.push_back(blk); - } - virtual block get_block_from_height(const uint64_t& height) const { - return blocks.at(height); - } - virtual void set_hard_fork_version(uint64_t height, uint8_t version) { - if (versions.size() <= height) - versions.resize(height+1); - versions[height] = version; - } - virtual uint8_t get_hard_fork_version(uint64_t height) const { - return versions.at(height); - } - virtual void check_hard_fork_info() {} - -private: - std::vector blocks; - std::deque versions; -}; - static cryptonote::block mkblock(uint8_t version, uint8_t vote) { cryptonote::block b; diff --git a/tests/unit_tests/multisig.cpp b/tests/unit_tests/multisig.cpp deleted file mode 100644 index 3efdd4822..000000000 --- a/tests/unit_tests/multisig.cpp +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright (c) 2018, The Safex 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) 2017-2018 The Monero Project - -#include "gtest/gtest.h" - -#include - -#include "wallet/wallet.h" - -static const struct -{ - const char *address; - const char *spendkey; -} test_addresses[] = -{ - { - "9uvjbU54ZJb8j7Dcq1h3F1DnBRkxXdYUX4pbJ7mE3ghM8uF3fKzqRKRNAKYZXcNLqMg7MxjVVD2wKC2PALUwEveGSC3YSWD", - "2dd6e34a234c3e8b5d29a371789e4601e96dee4ea6f7ef79224d1a2d91164c01" - }, - { - "9ywDBAyDbb6QKFiZxDJ4hHZqZEQXXCR5EaYNcndUpqPDeE7rEgs6neQdZnhcDrWbURYK8xUjhuG2mVjJdmknrZbcG7NnbaB", - "fac47aecc948ce9d3531aa042abb18235b1df632087c55a361b632ffdd6ede0c" - }, - { - "9t6Hn946u3eah5cuncH1hB5hGzsTUoevtf4SY7MHN5NgJZh2SFWsyVt3vUhuHyRKyrCQvr71Lfc1AevG3BXE11PQFoXDtD8", - "bbd3175ef9fd9f5eefdc43035f882f74ad14c4cf1799d8b6f9001bc197175d02" - } -}; - -static void make_wallet(unsigned int idx, tools::wallet &wallet) -{ - ASSERT_TRUE(idx < sizeof(test_addresses) / sizeof(test_addresses[0])); - - crypto::secret_key spendkey; - epee::string_tools::hex_to_pod(test_addresses[idx].spendkey, spendkey); - - try - { - wallet.init(""); - wallet.set_subaddress_lookahead(1, 1); - wallet.generate("", "", spendkey, true, false); - ASSERT_TRUE(test_addresses[idx].address == wallet.get_account().get_public_address_str(cryptonote::TESTNET)); - } - catch (const std::exception &e) - { - MFATAL("Error creating test wallet: " << e.what()); - ASSERT_TRUE(0); - } -} - -static void make_M_2_wallet(tools::wallet &wallet0, tools::wallet &wallet1, unsigned int M) -{ - ASSERT_TRUE(M <= 2); - - make_wallet(0, wallet0); - make_wallet(1, wallet1); - - std::vector sk0(1), sk1(1); - std::vector pk0(1), pk1(1); - - std::string mi0 = wallet0.get_multisig_info(); - std::string mi1 = wallet1.get_multisig_info(); - - ASSERT_TRUE(tools::wallet::verify_multisig_info(mi1, sk0[0], pk0[0])); - ASSERT_TRUE(tools::wallet::verify_multisig_info(mi0, sk1[0], pk1[0])); - - ASSERT_FALSE(wallet0.multisig() || wallet1.multisig()); - wallet0.make_multisig("", sk0, pk0, M); - wallet1.make_multisig("", sk1, pk1, M); - - ASSERT_TRUE(wallet0.get_account().get_public_address_str(cryptonote::TESTNET) == wallet1.get_account().get_public_address_str(cryptonote::TESTNET)); - - bool ready; - uint32_t threshold, total; - ASSERT_TRUE(wallet0.multisig(&ready, &threshold, &total)); - ASSERT_TRUE(ready); - ASSERT_TRUE(threshold == M); - ASSERT_TRUE(total == 2); - ASSERT_TRUE(wallet1.multisig(&ready, &threshold, &total)); - ASSERT_TRUE(ready); - ASSERT_TRUE(threshold == M); - ASSERT_TRUE(total == 2); -} - -static void make_M_3_wallet(tools::wallet &wallet0, tools::wallet &wallet1, tools::wallet &wallet2, unsigned int M) -{ - ASSERT_TRUE(M <= 3); - - make_wallet(0, wallet0); - make_wallet(1, wallet1); - make_wallet(2, wallet2); - - std::vector sk0(2), sk1(2), sk2(2); - std::vector pk0(2), pk1(2), pk2(2); - - std::string mi0 = wallet0.get_multisig_info(); - std::string mi1 = wallet1.get_multisig_info(); - std::string mi2 = wallet2.get_multisig_info(); - - ASSERT_TRUE(tools::wallet::verify_multisig_info(mi1, sk0[0], pk0[0])); - ASSERT_TRUE(tools::wallet::verify_multisig_info(mi2, sk0[1], pk0[1])); - ASSERT_TRUE(tools::wallet::verify_multisig_info(mi0, sk1[0], pk1[0])); - ASSERT_TRUE(tools::wallet::verify_multisig_info(mi2, sk1[1], pk1[1])); - ASSERT_TRUE(tools::wallet::verify_multisig_info(mi0, sk2[0], pk2[0])); - ASSERT_TRUE(tools::wallet::verify_multisig_info(mi1, sk2[1], pk2[1])); - - ASSERT_FALSE(wallet0.multisig() || wallet1.multisig() || wallet2.multisig()); - std::string mxi0 = wallet0.make_multisig("", sk0, pk0, M); - std::string mxi1 = wallet1.make_multisig("", sk1, pk1, M); - std::string mxi2 = wallet2.make_multisig("", sk2, pk2, M); - - const size_t nset = !mxi0.empty() + !mxi1.empty() + !mxi2.empty(); - ASSERT_TRUE((M < 3 && nset == 3) || (M == 3 && nset == 0)); - - if (nset > 0) - { - std::unordered_set pkeys; - std::vector signers(3, crypto::null_pkey); - ASSERT_TRUE(tools::wallet::verify_extra_multisig_info(mxi0, pkeys, signers[0])); - ASSERT_TRUE(tools::wallet::verify_extra_multisig_info(mxi1, pkeys, signers[1])); - ASSERT_TRUE(tools::wallet::verify_extra_multisig_info(mxi2, pkeys, signers[2])); - ASSERT_TRUE(pkeys.size() == 3); - ASSERT_TRUE(wallet0.finalize_multisig("", pkeys, signers)); - ASSERT_TRUE(wallet1.finalize_multisig("", pkeys, signers)); - ASSERT_TRUE(wallet2.finalize_multisig("", pkeys, signers)); - } - - ASSERT_TRUE(wallet0.get_account().get_public_address_str(cryptonote::TESTNET) == wallet1.get_account().get_public_address_str(cryptonote::TESTNET)); - ASSERT_TRUE(wallet0.get_account().get_public_address_str(cryptonote::TESTNET) == wallet2.get_account().get_public_address_str(cryptonote::TESTNET)); - - bool ready; - uint32_t threshold, total; - ASSERT_TRUE(wallet0.multisig(&ready, &threshold, &total)); - ASSERT_TRUE(ready); - ASSERT_TRUE(threshold == M); - ASSERT_TRUE(total == 3); - ASSERT_TRUE(wallet1.multisig(&ready, &threshold, &total)); - ASSERT_TRUE(ready); - ASSERT_TRUE(threshold == M); - ASSERT_TRUE(total == 3); - ASSERT_TRUE(wallet2.multisig(&ready, &threshold, &total)); - ASSERT_TRUE(ready); - ASSERT_TRUE(threshold == M); - ASSERT_TRUE(total == 3); -} - -#if (CURRENT_TRANSACTION_VERSION >= 2) - -TEST(multisig, make_2_2) -{ - tools::wallet wallet0, wallet1; - make_M_2_wallet(wallet0, wallet1, 2); -} - -TEST(multisig, make_3_3) -{ - tools::wallet wallet0, wallet1, wallet; - make_M_3_wallet(wallet0, wallet1, wallet, 3); -} - -TEST(multisig, make_2_3) -{ - tools::wallet wallet0, wallet1, wallet; - make_M_3_wallet(wallet0, wallet1, wallet, 2); -} - -#endif diff --git a/tests/unit_tests/safex_blockchain_db.cpp b/tests/unit_tests/safex_blockchain_db.cpp new file mode 100644 index 000000000..650422fba --- /dev/null +++ b/tests/unit_tests/safex_blockchain_db.cpp @@ -0,0 +1,497 @@ +// Copyright (c) 2018, The Safex 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) 2014-2018 The Monero Project + +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" + +#include "string_tools.h" +#include "blockchain_db/blockchain_db.h" +#include "blockchain_db/lmdb/db_lmdb.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_tx_utils.h" +#include "safex_test_common.h" + +using namespace cryptonote; +using epee::string_tools::pod_to_hex; + +#define ASSERT_HASH_EQ(a, b) ASSERT_EQ(pod_to_hex(a), pod_to_hex(b)) + +namespace +{ // anonymous namespace + + const int NUMBER_OF_BLOCKS = 53; + const uint64_t default_miner_fee = ((uint64_t) 500000000); + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", + "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", + "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; + + + template + class SafexBlockchainDBTest : public testing::Test + { + protected: + SafexBlockchainDBTest() : m_db(new T(false, cryptonote::network_type::FAKECHAIN)), m_hardfork(*m_db, 1, 0) + { + m_test_sizes = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_coins = std::vector(NUMBER_OF_BLOCKS, 60); + m_test_coins[0] = 2000 * SAFEX_CASH_COIN; //genesis tx airdrop + m_test_tokens = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_tokens[0] = 1000 * SAFEX_TOKEN; + m_test_tokens[1] = 100 * SAFEX_TOKEN; + m_test_diffs = std::vector(NUMBER_OF_BLOCKS, 200); + m_test_diffs[0] = 1; + m_test_diffs[1] = 100; + m_test_diffs[2] = 180; + + //m_txs = std::vector>(1, std::vector()); + + m_miner_acc.generate(); + m_users_acc[0].generate(); + m_users_acc[1].generate(); + + for (int i = 0; i < NUMBER_OF_BLOCKS; i++) + { + block blk; + std::list tx_list; // fill tx list with transactions for that block + crypto::hash prev_hash = boost::value_initialized();/* null hash*/ + + if (i > 0) prev_hash = cryptonote::get_block_hash(m_blocks[i - 1]); + + if (i == 0) + { + //skip, genesis block + } + else if (i == 1) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_migration_tx_to_key(m_txmap, m_blocks, tx, m_miner_acc, m_users_acc[0], m_test_tokens[0], default_miner_fee, get_hash_from_string(bitcoin_tx_hashes_str[0])); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 2) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_tx_to_key(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[1], 200 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_tx_to_key(m_txmap, m_blocks, tx2, m_miner_acc, m_users_acc[1], 10 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx2)] = tx2; + } + else if (i == 3) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_tx_to_key(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[1], 100 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 10) + { + //create token stake transaction, user 0 locks 100 safex token + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_stake_transaction(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[0], 100 * SAFEX_TOKEN, default_miner_fee, 0); +// std::cout << "tx 10 hash: " << epee::string_tools::pod_to_hex(get_transaction_hash(tx)) << std::endl; + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 11) + { + //create other token stake transaction + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_stake_transaction(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[0], 400 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_token_stake_transaction(m_txmap, m_blocks, tx2, m_users_acc[1], m_users_acc[1], 100 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx2)] = tx2; + + } + else if (i == 13) + { + //add network fee + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_fee_donation_transaction(m_txmap, m_blocks, tx, m_miner_acc, 2 * SAFEX_CASH_COIN, default_miner_fee, 0); + std::cout << "tx 13 hash: " << epee::string_tools::pod_to_hex(get_transaction_hash(tx)) << std::endl; + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 15) + { + //add more network fee + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_fee_donation_transaction(m_txmap, m_blocks, tx, m_miner_acc, 12.5 * SAFEX_CASH_COIN, default_miner_fee, 0); + std::cout << "tx 15 hash: " << epee::string_tools::pod_to_hex(get_transaction_hash(tx)) << std::endl; + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 47) + { + //token unlock transaction + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); + construct_token_unstake_transaction(m_txmap, m_blocks, tx, m_users_acc[1], m_users_acc[1], 100 * SAFEX_TOKEN, default_miner_fee, 0); //unlock 100 + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 49) + { + //token stake transaction + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); + construct_token_stake_transaction(m_txmap, m_blocks, tx, m_users_acc[1], m_users_acc[1], 200 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 51) + { + //token unlock transaction + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); + construct_token_unstake_transaction(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[0], 400 * SAFEX_TOKEN, default_miner_fee, 0); //unlock 400 + m_txmap[get_transaction_hash(tx)] = tx; + } + + + construct_block(blk, i, prev_hash, m_miner_acc, 0, m_test_sizes[i], tx_list); + + m_txs.push_back(std::vector{tx_list.begin(), tx_list.end()}); + m_blocks.push_back(blk); + } + + } + + + ~SafexBlockchainDBTest() + { + delete m_db; + remove_files(m_filenames, m_prefix); + } + + BlockchainDB *m_db; + HardFork m_hardfork; + std::string m_prefix; + std::vector m_blocks; + //std::unordered_map + map_hash2tx_t m_txmap; //vector of all transactions + std::vector > m_txs; + std::vector m_filenames; + + cryptonote::account_base m_miner_acc; + cryptonote::account_base m_users_acc[2]; + + std::vector m_test_sizes; + std::vector m_test_coins; + std::vector m_test_tokens; + std::vector m_test_diffs; + + + void init_hard_fork() + { + m_hardfork.init(); + m_db->set_hard_fork(&m_hardfork); + } + + void get_filenames() + { + m_filenames = m_db->get_filenames(); + for (auto &f : m_filenames) + { + std::cerr << "File created by test: " << f << std::endl; + } + } + + void set_prefix(const std::string &prefix) + { + m_prefix = prefix; + } + }; + + using testing::Types; + + typedef Types implementations; + + TYPED_TEST_CASE(SafexBlockchainDBTest, implementations); + +#if 1 + TYPED_TEST(SafexBlockchainDBTest, OpenAndClose) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + + // make sure open when already open DOES throw + ASSERT_THROW(this->m_db->open(dirPath), DB_OPEN_FAILURE); + + ASSERT_NO_THROW(this->m_db->close()); + } + + TYPED_TEST(SafexBlockchainDBTest, AddBlock) + { + + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + // adding a block with no parent in the blockchain should throw. + // note: this shouldn't be possible, but is a good (and cheap) failsafe. + // + // TODO: need at least one more block to make this reasonable, as the + // BlockchainDB implementation should not check for parent if + // no blocks have been added yet (because genesis has no parent). + //ASSERT_THROW(this->m_db->add_block(this->m_blocks[1], m_test_sizes[1], t_diffs[1], t_coins[1], this->m_txs[1]), BLOCK_PARENT_DNE); + +// for (int i = 0; i < NUMBER_OF_BLOCKS; i++) +// ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + + for (int i = 0; i < NUMBER_OF_BLOCKS; i++) + { + try + { + this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i]); + } + catch (std::exception &e) + { + std::cout << "Error: " << e.what() << std::endl; + } + } + + + block b; + ASSERT_TRUE(this->m_db->block_exists(get_block_hash(this->m_blocks[0]))); + ASSERT_NO_THROW(b = this->m_db->get_block(get_block_hash(this->m_blocks[0]))); + + ASSERT_TRUE(compare_blocks(this->m_blocks[0], b)); + + ASSERT_NO_THROW(b = this->m_db->get_block_from_height(0)); + + ASSERT_TRUE(compare_blocks(this->m_blocks[0], b)); + + // assert that we can't add the same block twice + ASSERT_THROW(this->m_db->add_block(this->m_blocks[0], this->m_test_sizes[0], this->m_test_diffs[0], this->m_test_coins[0], this->m_test_tokens[0], this->m_txs[0]), TX_EXISTS); + + for (auto &h : this->m_blocks[NUMBER_OF_BLOCKS - 1].tx_hashes) + { + transaction tx; + ASSERT_TRUE(this->m_db->tx_exists(h)); + ASSERT_NO_THROW(tx = this->m_db->get_tx(h)); + ASSERT_HASH_EQ(h, get_transaction_hash(tx)); + } + } + + TYPED_TEST(SafexBlockchainDBTest, RetrieveBlockData) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS - 1; i++) + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + + ASSERT_EQ(this->m_test_sizes[0], this->m_db->get_block_size(0)); + ASSERT_EQ(this->m_test_diffs[0], this->m_db->get_block_cumulative_difficulty(0)); + ASSERT_EQ(this->m_test_diffs[0], this->m_db->get_block_difficulty(0)); + ASSERT_EQ(this->m_test_coins[0], this->m_db->get_block_already_generated_coins(0)); + + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[NUMBER_OF_BLOCKS - 1], this->m_test_sizes[NUMBER_OF_BLOCKS - 1], this->m_test_diffs[NUMBER_OF_BLOCKS - 1], this->m_test_coins[NUMBER_OF_BLOCKS - 1], this->m_test_tokens[NUMBER_OF_BLOCKS - 1], + this->m_txs[NUMBER_OF_BLOCKS - 1])); + ASSERT_EQ(this->m_test_diffs[1] - this->m_test_diffs[0], this->m_db->get_block_difficulty(1)); + + ASSERT_HASH_EQ(get_block_hash(this->m_blocks[0]), this->m_db->get_block_hash_from_height(0)); + + std::vector blks; + ASSERT_NO_THROW(blks = this->m_db->get_blocks_range(0, NUMBER_OF_BLOCKS - 1)); + ASSERT_EQ(NUMBER_OF_BLOCKS, blks.size()); + + ASSERT_HASH_EQ(get_block_hash(this->m_blocks[0]), get_block_hash(blks[0])); + ASSERT_HASH_EQ(get_block_hash(this->m_blocks[1]), get_block_hash(blks[1])); + ASSERT_HASH_EQ(get_block_hash(this->m_blocks[10]), get_block_hash(blks[10])); + ASSERT_HASH_EQ(get_block_hash(this->m_blocks[NUMBER_OF_BLOCKS - 1]), get_block_hash(blks[NUMBER_OF_BLOCKS - 1])); + + std::vector hashes; + ASSERT_NO_THROW(hashes = this->m_db->get_hashes_range(0, NUMBER_OF_BLOCKS - 1)); + ASSERT_EQ(NUMBER_OF_BLOCKS, hashes.size()); + + ASSERT_HASH_EQ(get_block_hash(this->m_blocks[0]), hashes[0]); + ASSERT_HASH_EQ(get_block_hash(this->m_blocks[1]), hashes[1]); + ASSERT_HASH_EQ(get_block_hash(this->m_blocks[10]), hashes[10]); + ASSERT_HASH_EQ(get_block_hash(this->m_blocks[NUMBER_OF_BLOCKS - 1]), hashes[NUMBER_OF_BLOCKS - 1]); + } + +#endif + + TYPED_TEST(SafexBlockchainDBTest, RetrieveTokenLockData) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS - 1; i++) + { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + uint64_t number_of_locked_tokens = this->m_db->get_current_staked_token_sum(); + ASSERT_EQ(number_of_locked_tokens, 300 * SAFEX_TOKEN); //100+400+100-100+200-400 + + std::vector data = this->m_db->get_token_stake_expiry_outputs(SAFEX_DEFAULT_TOKEN_STAKE_EXPIRY_PERIOD + 11); + ASSERT_EQ(data.size(), 2); + + data = this->m_db->get_token_stake_expiry_outputs(SAFEX_DEFAULT_TOKEN_STAKE_EXPIRY_PERIOD + 15); + ASSERT_EQ(data.size(), 0); + + data = this->m_db->get_token_stake_expiry_outputs(SAFEX_DEFAULT_TOKEN_STAKE_EXPIRY_PERIOD + 49); + ASSERT_EQ(data.size(), 1); + + uint64_t test_output_id = data[0]; //first tx in 11 block + + + uint64_t token_lock_output_num = this->m_db->get_num_outputs(tx_out_type::out_staked_token); + ASSERT_EQ(token_lock_output_num, 4); + + + + output_advanced_data_t outd = this->m_db->get_output_advanced_data(tx_out_type::out_staked_token, test_output_id); + bool match = false; + crypto::hash matching_tx_hash; + + //find pkey key in transaction output of block 49 + for (transaction& tx: this->m_txs[49]) + { + for (tx_out out: tx.vout) + { + crypto::public_key check = *boost::apply_visitor(cryptonote::destination_public_key_visitor(), out.target); //get public key of first output of first tx in 11 block + if (memcmp(outd.pubkey.data, check.data, sizeof(outd.pubkey.data)) == 0) { + match = true; + matching_tx_hash = tx.hash; + } + } + } + ASSERT_EQ(match, true); + + tx_out_index index1 = this->m_db->get_output_tx_and_index_from_global(outd.output_id); + ASSERT_EQ(matching_tx_hash, index1.first); + + + ASSERT_THROW(this->m_db->get_output_advanced_data(tx_out_type::out_staked_token, 5913), DB_ERROR); + ASSERT_THROW(this->m_db->get_output_advanced_data(tx_out_type::out_cash, test_output_id), DB_ERROR); + + + uint64_t tx_index; + if (!this->m_db->tx_exists(matching_tx_hash, tx_index)) + { + ASSERT_TRUE(false); + } + + std::vector output_indexs; + + // get amount or output id for outputs, currently referred to in parts as "output global indices", but they are actually specific to amounts for cash and token outputs + output_indexs = this->m_db->get_tx_amount_output_indices(tx_index); + if (output_indexs.empty()) + { + ASSERT_TRUE(false); + } + + + this->m_db->for_all_advanced_outputs([](const crypto::hash &tx_hash, uint64_t height, uint64_t output_id, const txout_to_script& txout){ + std::cout << "Height: " << height << " txid: " << output_id << " txout type: "<< static_cast(txout.output_type) << std::endl; + return true; + }, cryptonote::tx_out_type::out_staked_token); + + ASSERT_NO_THROW(this->m_db->close()); + + } + +#if 1 + + TYPED_TEST(SafexBlockchainDBTest, RetrieveCollectedFee) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS - 1; i++) + { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + uint64_t number_of_locked_tokens = this->m_db->get_current_staked_token_sum(); + ASSERT_EQ(number_of_locked_tokens, 300 * SAFEX_TOKEN); //100+400+100-100+200-400 + + uint64_t fee_sum = this->m_db->get_network_fee_sum_for_interval(2); + std::cout << "Fee sum:" << fee_sum << std::endl; + ASSERT_EQ(fee_sum, 14.5 * SAFEX_CASH_COIN); // 2 + 12.5 + + + + ASSERT_NO_THROW(this->m_db->close()); + + } + +#endif + + +} // anonymous namespace diff --git a/tests/unit_tests/safex_db/safex_account.cpp b/tests/unit_tests/safex_db/safex_account.cpp new file mode 100644 index 000000000..6c30a64df --- /dev/null +++ b/tests/unit_tests/safex_db/safex_account.cpp @@ -0,0 +1,934 @@ +// Copyright (c) 2018, The Safex 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) 2014-2018 The Monero Project + +#include +#include +#include +#include + +#include "gtest/gtest.h" + +#include "string_tools.h" +#include "blockchain_db/blockchain_db.h" +#include "blockchain_db/lmdb/db_lmdb.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "safex/safex_account.h" +#include "../safex_test_common.h" + + +using namespace cryptonote; +using epee::string_tools::pod_to_hex; + +#define ASSERT_HASH_EQ(a, b) ASSERT_EQ(pod_to_hex(a), pod_to_hex(b)) + +namespace +{ // anonymous namespace + + const int NUMBER_OF_BLOCKS = 20; + const int NUMBER_OF_BLOCKS1 = 10; + const int NUMBER_OF_BLOCKS2 = 20; + const uint64_t default_miner_fee = ((uint64_t) 500000000); + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", + "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182"}; + + class SafexCreateAccountCommand : public ::testing::Test + { + public: + SafexCreateAccountCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + class SafexEditAccountCommand : public ::testing::Test + { + public: + SafexEditAccountCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + template + class SafexAccountTest : public testing::Test + { + protected: + SafexAccountTest() : m_db(new T(false, cryptonote::network_type::FAKECHAIN)), m_hardfork(*m_db, 1, 0) + { + m_test_sizes = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_coins = std::vector(NUMBER_OF_BLOCKS, 60); + m_test_coins[0] = 2000 * SAFEX_CASH_COIN; //genesis tx airdrop + m_test_tokens = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_tokens[0] = 4000 * SAFEX_TOKEN; + m_test_diffs = std::vector(NUMBER_OF_BLOCKS, 200); + m_test_diffs[0] = 1; + m_test_diffs[1] = 100; + m_test_diffs[2] = 180; + + m_miner_acc.generate(); + m_users_acc[0].generate(); + m_users_acc[1].generate(); + + m_safex_account1_keys.generate(); + m_safex_account2_keys.generate(); + m_safex_account3_keys.generate(); + + m_safex_account1.username = "user1"; + m_safex_account1.pkey = m_safex_account1_keys.get_keys().m_public_key; + m_safex_account1.account_data = {'s','m','o','r'}; + m_safex_account2.username = "user2"; + m_safex_account2.pkey = m_safex_account2_keys.get_keys().m_public_key; + m_safex_account3.username = "user3"; + m_safex_account3.pkey = m_safex_account3_keys.get_keys().m_public_key; + std::string data3 = "This is some data for test"; + m_safex_account3.account_data = std::vector(data3.begin(), data3.end()); + + std::cout << "Alice public key: " << epee::string_tools::pod_to_hex(m_safex_account1_keys.get_keys().m_public_key) << std::endl; + std::cout << "Alice private key: " << epee::string_tools::pod_to_hex(m_safex_account1_keys.get_keys().m_secret_key) << std::endl; + + const std::string data1_new_str = "Another data tesst for edit"; + data1_new = std::vector(data1_new_str.begin(), data1_new_str.end()); + + + + for (int i = 0; i < NUMBER_OF_BLOCKS; i++) + { + block blk; + std::list tx_list; // fill tx list with transactions for that block + crypto::hash prev_hash = boost::value_initialized();/* null hash*/ + + if (i > 0) prev_hash = cryptonote::get_block_hash(m_blocks[i - 1]); + + if (i == 0) + { + //skip, genesis block + } + else if (i == 1) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_migration_tx_to_key(m_txmap, m_blocks, tx, m_miner_acc, m_users_acc[0], m_test_tokens[0], default_miner_fee, get_hash_from_string(bitcoin_tx_hashes_str[0])); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 2) + { + //distribute tokens and coins to accounts as starter + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_tx_to_key(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[1], 1000 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_tx_to_key(m_txmap, m_blocks, tx2, m_miner_acc, m_users_acc[0], 100 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx2)] = tx2; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx3 = tx_list.back(); \ + construct_tx_to_key(m_txmap, m_blocks, tx3, m_miner_acc, m_users_acc[1], 200 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx3)] = tx3; + } + else if (i == 5) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_account_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.username, m_safex_account1.pkey, m_safex_account1.account_data, m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_create_account_transaction(m_txmap, m_blocks, tx2, m_users_acc[1], default_miner_fee, 0, m_safex_account2.username, m_safex_account2.pkey, m_safex_account2.account_data, m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx2)] = tx2; + } + else if (i == 7) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_account_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account3.username, m_safex_account3.pkey, m_safex_account3.account_data, m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 14) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_edit_account_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.username, data1_new, m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + } + + + construct_block(blk, i, prev_hash, m_miner_acc, 0, m_test_sizes[i], tx_list); + + m_txs.push_back(std::vector{tx_list.begin(), tx_list.end()}); + m_blocks.push_back(blk); + } + } + + + ~SafexAccountTest() + { + delete m_db; + remove_files(m_filenames, m_prefix); + } + + BlockchainDB *m_db; + HardFork m_hardfork; + std::string m_prefix; + std::vector m_blocks; + //std::unordered_map + map_hash2tx_t m_txmap; //vector of all transactions + std::vector > m_txs; + std::vector m_filenames; + + cryptonote::account_base m_miner_acc; + cryptonote::account_base m_users_acc[2]; + + std::vector m_test_sizes; + std::vector m_test_coins; + std::vector m_test_tokens; + std::vector m_test_diffs; + + safex::safex_account_key_handler m_safex_account1_keys{}; + safex::safex_account_key_handler m_safex_account2_keys{}; + safex::safex_account_key_handler m_safex_account3_keys{}; + safex::safex_account m_safex_account1; + safex::safex_account m_safex_account2; + safex::safex_account m_safex_account3; + + std::vector data1_new; + + + void init_hard_fork() + { + m_hardfork.init(); + m_db->set_hard_fork(&m_hardfork); + } + + void get_filenames() + { + m_filenames = m_db->get_filenames(); + for (auto &f : m_filenames) + { + std::cerr << "File created by test: " << f << std::endl; + } + } + + + void set_prefix(const std::string &prefix) + { + m_prefix = prefix; + } + }; + + using testing::Types; + + typedef Types implementations; + + TYPED_TEST_CASE(SafexAccountTest, implementations); + + +#if 1 + TYPED_TEST(SafexAccountTest, AccountSignature) + { + safex::safex_account_key_handler account1; + safex::safex_account_key_handler account2; + account1.generate(); + account2.generate(); + + const blobdata test_data01 = std::string("Some test data that should be signed"); + const blobdata test_data02 = std::string("Some test data that should be signed2"); + const blobdata test_data03 = std::string("Some test data that should be signed, here is also some addition 123241"); + + //calculate hash of signature + crypto::hash message_hash01 = get_blob_hash(test_data01); + crypto::hash message_hash02 = get_blob_hash(test_data02); + crypto::hash message_hash03 = get_blob_hash(test_data03); + + crypto::signature message_sig01{}; + crypto::signature message_sig02{}; + + crypto::generate_signature(message_hash01, account1.get_keys().m_public_key, account1.get_keys().m_secret_key, message_sig01); + crypto::generate_signature(message_hash02, account2.get_keys().m_public_key, account2.get_keys().m_secret_key, message_sig02); + + + ASSERT_EQ(crypto::check_signature(message_hash01, account1.get_keys().m_public_key, message_sig01), true); + ASSERT_EQ(crypto::check_signature(message_hash01, account1.get_keys().m_public_key, message_sig02), false); + ASSERT_EQ(crypto::check_signature(message_hash02, account1.get_keys().m_public_key, message_sig02), false); + ASSERT_EQ(crypto::check_signature(message_hash02, account2.get_keys().m_public_key, message_sig02), true); + ASSERT_EQ(crypto::check_signature(message_hash01, account2.get_keys().m_public_key, message_sig02), false); + + //check create from keys + crypto::secret_key skey; + crypto::public_key pkey; + crypto::signature message_sig03{}; + char skeydata[32]{6, -13, -3, 101, 39, 96, -33, 20, -25, -59, -42, 91, 108, -120, 39, -120, -93, 21, -7, 87, 6, -115, 60, 75, 29, 125, -87, -26, 16, -18, 37, 14}; + memcpy(skey.data, skeydata, 32); + safex::safex_account_key_handler account3{}; + account3.create_from_keys(skey); + crypto::generate_signature(message_hash03, account3.get_keys().m_public_key, account3.get_keys().m_secret_key, message_sig03); + crypto::hash message_hash04 = message_hash03; + message_hash04.data[12] = 0x35; + + char pkeydata[32]{30, 55, 2, -52, 116, 83, -100, 86, -70, 87, 28, 44, 120, -16, 18, 100, -100, -68, 67, -74, -94, -52, -91, -29, 123, 22, 79, 64, 69, -15, 92, 15}; + memcpy(pkey.data, pkeydata, 32); + + ASSERT_EQ(crypto::check_signature(message_hash03, pkey, message_sig03), true); + ASSERT_EQ(crypto::check_signature(message_hash04, pkey, message_sig03), false); + ASSERT_EQ(crypto::check_signature(message_hash03, pkey, message_sig02), false); + + } + + TEST_F(SafexCreateAccountCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_account), safex::command_exception); + + } + + TEST_F(SafexEditAccountCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::edit_account), safex::command_exception); + + } + + TEST_F(SafexCreateAccountCommand, HandlesUnknownProtocolVersion) + { + + std::string username = "test01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + try + { + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, username, safex_keys.get_keys().get_public_key(), description}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexEditAccountCommand, HandlesUnknownProtocolVersion) + { + + std::string username = "test01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + try + { + safex::edit_account command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, username, description}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexCreateAccountCommand, HandlesCommandParsing) + { + + std::string username = "test01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::create_account) << "Safex create account command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_account); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_username(), dynamic_cast(command2.get())->get_username()) << "Original and deserialized command must have same username"; + ASSERT_EQ(command1.get_account_key(), dynamic_cast(command2.get())->get_account_key()) << "Original and deserialized command must have same account key"; + ASSERT_EQ(command1.get_account_data(), dynamic_cast(command2.get())->get_account_data()) << "Original and deserialized command must have same description"; + + } + + TEST_F(SafexEditAccountCommand, HandlesCommandParsing) + { + + std::string username = "test01"; + std::string description = "Some newtest data inserted"; + + safex::edit_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, description}; + + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::edit_account) << "Safex edit account command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::edit_account); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_username(), dynamic_cast(command2.get())->get_username()) << "Original and deserialized command must have same username"; + ASSERT_EQ(command1.get_new_account_data(), dynamic_cast(command2.get())->get_new_account_data()) << "Original and deserialized command must have same description"; + + } + + TEST_F(SafexCreateAccountCommand, CreateAccountExecute) + { + + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = "test_0-1"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + + } + catch (safex::command_exception &exception) + { + FAIL() << exception.what(); + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + } + + TEST_F(SafexCreateAccountCommand, CreateAccountExceptions) + { + + // No tokens in the input + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 0; + std::string username = "test01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_account_no_tokens); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with token amount zero"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Invalid username + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = "Test01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_invalid_account_name); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with invalid account name"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Invalid username + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = "test/01"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_invalid_account_name); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with invalid account name"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Username too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = "012345678901234567890123456789azb"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_account_data_too_big); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with username too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Account data too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = "test0"; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = ""; + for(int i=0; i < SAFEX_ACCOUNT_DATA_MAX_SIZE + 1; i++) + description += "x"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_account_data_too_big); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with username too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + } + + TYPED_TEST(SafexAccountTest, CreateAccountCommand) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1 - 1; i++) + { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + crypto::public_key pkey{}; + const safex::account_username username01{this->m_safex_account1.username}; + this->m_db->get_account_key(username01, pkey); + ASSERT_EQ(memcmp((void *)&pkey, (void *)&this->m_safex_account1.pkey, sizeof(pkey)), 0); + + + memset((void *)&pkey, 0, sizeof(pkey)); + const safex::account_username username02{this->m_safex_account2.username}; + this->m_db->get_account_key(username02, pkey); + ASSERT_EQ(memcmp((void *)&pkey, (void *)&this->m_safex_account2.pkey, sizeof(pkey)), 0); + + memset((void *)&pkey, 0, sizeof(pkey)); + const safex::account_username username03{this->m_safex_account3.username}; + this->m_db->get_account_key(username03, pkey); + ASSERT_EQ(memcmp((void *)&pkey, (void *)&this->m_safex_account3.pkey, sizeof(pkey)), 0); + + std::vector accdata01; + this->m_db->get_account_data(username01, accdata01); + ASSERT_TRUE(std::equal(this->m_safex_account1.account_data.begin(), this->m_safex_account1.account_data.end(), accdata01.begin())); + + std::vector accdata03; + this->m_db->get_account_data(username03, accdata03); + ASSERT_TRUE(std::equal(this->m_safex_account3.account_data.begin(), this->m_safex_account3.account_data.end(), accdata03.begin())); + + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexAccountTest, EditAccount) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS2 - 1; i++) + { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + crypto::public_key pkey{}; + const safex::account_username username01{this->m_safex_account1.username}; + this->m_db->get_account_key(username01, pkey); + ASSERT_EQ(memcmp((void *)&pkey, (void *)&this->m_safex_account1.pkey, sizeof(pkey)), 0); + + + std::vector accdata01; + this->m_db->get_account_data(username01, accdata01); + ASSERT_TRUE(std::equal(accdata01.begin(), accdata01.end(), this->data1_new.begin())); + + memset((void *)&pkey, 0, sizeof(pkey)); + const safex::account_username username03{this->m_safex_account3.username}; + this->m_db->get_account_key(username03, pkey); + ASSERT_EQ(memcmp((void *)&pkey, (void *)&this->m_safex_account3.pkey, sizeof(pkey)), 0); + + std::vector accdata03; + this->m_db->get_account_data(username03, accdata03); + ASSERT_TRUE(std::equal(this->m_safex_account3.account_data.begin(), this->m_safex_account3.account_data.end(), accdata03.begin())); + + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexAccountTest, CreateSafexAccountExceptions) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS2 - 1; i++) + { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex account exists + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_account; + txinput.token_amount = 100*SAFEX_TOKEN; + std::string username = this->m_safex_account1.username; + safex::safex_account_key_handler safex_keys{}; + safex_keys.generate(); + std::string description = "Some test data inserted"; + safex::create_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, safex_keys.get_keys().get_public_key(), description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_account); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_already_exists); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account already exists"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexAccountTest, EditSafexAccountExecute) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS2 - 1; i++) + { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_account; + txinput.token_amount = 100*SAFEX_TOKEN; + txinput.key_offsets.push_back(0); + std::string username = this->m_safex_account1.username; + std::string description = "Some test data inserted"; + safex::edit_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_account); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + + } + catch (safex::command_exception &exception) + { + FAIL() << exception.what(); + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexAccountTest, EditSafexAccountExceptions) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS2 - 1; i++) + { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex username not existant + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_account; + txinput.token_amount = 100*SAFEX_TOKEN; + txinput.key_offsets.push_back(0); + std::string username = "not_here"; + std::string description = "Some test data inserted"; + safex::edit_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_account); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account already exists"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex account data too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_account; + txinput.token_amount = 100*SAFEX_TOKEN; + txinput.key_offsets.push_back(0); + std::string username = this->m_safex_account1.username; + std::string description = ""; + for(int i=0; i < SAFEX_ACCOUNT_DATA_MAX_SIZE + 1; i++) + description += "x"; + safex::edit_account command1{SAFEX_COMMAND_PROTOCOL_VERSION, username, description}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_account); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account already exists"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } +#endif + +} // anonymous namespace diff --git a/tests/unit_tests/safex_db/safex_offer.cpp b/tests/unit_tests/safex_db/safex_offer.cpp new file mode 100644 index 000000000..6881ec979 --- /dev/null +++ b/tests/unit_tests/safex_db/safex_offer.cpp @@ -0,0 +1,1224 @@ +// Copyright (c) 2018, The Safex 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) 2014-2018 The Monero Project + +#include +#include +#include +#include + +#include "gtest/gtest.h" + +#include "string_tools.h" +#include "blockchain_db/blockchain_db.h" +#include "blockchain_db/lmdb/db_lmdb.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "safex/safex_account.h" +#include "safex/safex_offer.h" +#include "../safex_test_common.h" + + +using namespace cryptonote; +using epee::string_tools::pod_to_hex; + +#define ASSERT_HASH_EQ(a, b) ASSERT_EQ(pod_to_hex(a), pod_to_hex(b)) + +namespace +{ // anonymous namespace + + const int NUMBER_OF_BLOCKS = 30; + const int NUMBER_OF_BLOCKS1 = 15; + const int NUMBER_OF_BLOCKS2 = 20; + const int NUMBER_OF_BLOCKS3 = 30; + const uint64_t default_miner_fee = ((uint64_t) 500000000); + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", + "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182"}; + + + class SafexCreateOfferCommand : public ::testing::Test + { + public: + SafexCreateOfferCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + class SafexEditOfferCommand : public ::testing::Test + { + public: + SafexEditOfferCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + template + class SafexOfferTest : public testing::Test + { + protected: + SafexOfferTest() : m_db(new T(false, cryptonote::network_type::FAKECHAIN)), m_hardfork(*m_db, 1, 0) + { + m_test_sizes = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_coins = std::vector(NUMBER_OF_BLOCKS, 60); + m_test_coins[0] = 2000 * SAFEX_CASH_COIN; //genesis tx airdrop + m_test_tokens = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_tokens[0] = 4000 * SAFEX_TOKEN; + m_test_diffs = std::vector(NUMBER_OF_BLOCKS, 200); + m_test_diffs[0] = 1; + m_test_diffs[1] = 100; + m_test_diffs[2] = 180; + + m_miner_acc.generate(); + m_users_acc[0].generate(); + m_users_acc[1].generate(); + + m_safex_account1_keys.generate(); + m_safex_account2_keys.generate(); + + + + m_safex_account1.username = "user1"; + m_safex_account1.pkey = m_safex_account1_keys.get_keys().m_public_key; + m_safex_account1.account_data = {'s','m','o','r'}; + m_safex_account2.username = "user2"; + m_safex_account2.pkey = m_safex_account2_keys.get_keys().m_public_key; + + std::cout << "Alice public key: " << epee::string_tools::pod_to_hex(m_safex_account1_keys.get_keys().m_public_key) << std::endl; + std::cout << "Alice private key: " << epee::string_tools::pod_to_hex(m_safex_account1_keys.get_keys().m_secret_key) << std::endl; + + const std::string data1_new_str = "Another data tesst for edit"; + data1_new = std::vector(data1_new_str.begin(), data1_new_str.end()); + + + m_safex_offer[0] = safex::safex_offer("Apple",10,100*COIN,"This is an apple", m_safex_account1.username,m_users_acc[0].get_keys().m_view_secret_key,m_users_acc[0].get_keys().m_account_address); + m_safex_offer[1] = safex::safex_offer("Barbie",30,500*COIN,"This is a Barbie", m_safex_account2.username,m_users_acc[1].get_keys().m_view_secret_key,m_users_acc[1].get_keys().m_account_address); + m_safex_offer[2] = safex::safex_offer("Car",1,1000*COIN,"This is a car", m_safex_account1.username,m_users_acc[0].get_keys().m_view_secret_key,m_users_acc[0].get_keys().m_account_address); + + m_safex_price_peg = safex::safex_price_peg("USD price peg",m_safex_account1.username, "USD", "xcalibra USD price peg", 30); + + m_safex_offer[2].set_price_peg(m_safex_price_peg.price_peg_id,100,1000*COIN); + + std::string new_str_desc{"Now without worms!!"}; + std::vector new_desc{new_str_desc.begin(),new_str_desc.end()}; + m_edited_safex_offer = m_safex_offer[0]; + m_edited_safex_offer.description = new_desc; + + + for (int i = 0; i < NUMBER_OF_BLOCKS; i++) + { + block blk; + std::list tx_list; // fill tx list with transactions for that block + crypto::hash prev_hash = boost::value_initialized();/* null hash*/ + + if (i > 0) prev_hash = cryptonote::get_block_hash(m_blocks[i - 1]); + + if (i == 0) + { + //skip, genesis block + } + else if (i == 1) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_migration_tx_to_key(m_txmap, m_blocks, tx, m_miner_acc, m_users_acc[0], m_test_tokens[0], default_miner_fee, get_hash_from_string(bitcoin_tx_hashes_str[0])); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 2) + { + //distribute tokens and coins to accounts as starter + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_tx_to_key(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[1], 1000 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_tx_to_key(m_txmap, m_blocks, tx2, m_miner_acc, m_users_acc[0], 100 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx2)] = tx2; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx3 = tx_list.back(); \ + construct_tx_to_key(m_txmap, m_blocks, tx3, m_miner_acc, m_users_acc[1], 200 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx3)] = tx3; + } + else if (i == 5) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_account_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.username, m_safex_account1.pkey, m_safex_account1.account_data, m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_create_account_transaction(m_txmap, m_blocks, tx2, m_users_acc[1], default_miner_fee, 0, m_safex_account2.username, m_safex_account2.pkey, m_safex_account2.account_data, m_safex_account2_keys.get_keys()); + m_txmap[get_transaction_hash(tx2)] = tx2; + } + else if (i == 6) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_price_peg_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.pkey, m_safex_price_peg, m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 7) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_offer_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.pkey, m_safex_offer[0], m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_create_offer_transaction(m_txmap, m_blocks, tx2, m_users_acc[1], default_miner_fee, 0, m_safex_account2.pkey, m_safex_offer[1], m_safex_account2_keys.get_keys()); + m_txmap[get_transaction_hash(tx2)] = tx2; + } + else if (i == 12) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_offer_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.pkey, m_safex_offer[2], m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 14) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_edit_account_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.username, data1_new, m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 16) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_edit_offer_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.pkey, m_edited_safex_offer, m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + } + + construct_block(blk, i, prev_hash, m_miner_acc, 0, m_test_sizes[i], tx_list); + + m_txs.push_back(std::vector{tx_list.begin(), tx_list.end()}); + m_blocks.push_back(blk); + } + } + + + ~SafexOfferTest() + { + delete m_db; + remove_files(m_filenames, m_prefix); + } + + BlockchainDB *m_db; + HardFork m_hardfork; + std::string m_prefix; + std::vector m_blocks; + //std::unordered_map + map_hash2tx_t m_txmap; //vector of all transactions + std::vector > m_txs; + std::vector m_filenames; + + cryptonote::account_base m_miner_acc; + cryptonote::account_base m_users_acc[2]; + + std::vector m_test_sizes; + std::vector m_test_coins; + std::vector m_test_tokens; + std::vector m_test_diffs; + + safex::safex_account_key_handler m_safex_account1_keys{}; + safex::safex_account_key_handler m_safex_account2_keys{}; + safex::safex_account m_safex_account1; + safex::safex_account m_safex_account2; + + safex::safex_offer m_safex_offer[3]; + + safex::safex_offer m_edited_safex_offer; + + safex::safex_price_peg m_safex_price_peg; + + + std::vector data1_new; + + + void init_hard_fork() + { + m_hardfork.init(); + m_db->set_hard_fork(&m_hardfork); + } + + void get_filenames() + { + m_filenames = m_db->get_filenames(); + for (auto &f : m_filenames) + { + std::cerr << "File created by test: " << f << std::endl; + } + } + + + void set_prefix(const std::string &prefix) + { + m_prefix = prefix; + } + }; + + using testing::Types; + + typedef Types implementations; + + TYPED_TEST_CASE(SafexOfferTest, implementations); + +#if 1 + + TEST_F(SafexCreateOfferCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_offer), safex::command_exception); + + } + + TEST_F(SafexEditOfferCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::edit_offer), safex::command_exception); + + } + + TEST_F(SafexCreateOfferCommand, HandlesUnknownProtocolVersion) + { + + safex::create_offer_data offer_data{}; + try + { + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, offer_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexEditOfferCommand, HandlesUnknownProtocolVersion) + { + + safex::edit_offer_data offer_data{}; + try + { + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, offer_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexCreateOfferCommand, HandlesCommandParsing) + { + + cryptonote::account_base acc_base; + acc_base.generate(); + + safex::safex_account_key_handler m_safex_account_keys; + m_safex_account_keys.generate(); + + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + "username",acc_base.get_keys().m_view_secret_key, + acc_base.get_keys().m_account_address); + + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::create_offer) << "Safex create offer command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_offer); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_offerid(), dynamic_cast(command2.get())->get_offerid()) << "Original and deserialized command must have same offer ID"; + ASSERT_EQ(command1.get_price_peg_id(), dynamic_cast(command2.get())->get_price_peg_id()) << "Original and deserialized command must have same price peg ID"; + ASSERT_EQ(command1.get_seller(), dynamic_cast(command2.get())->get_seller()) << "Original and deserialized command must have same seller"; + ASSERT_EQ(command1.get_title(), dynamic_cast(command2.get())->get_title()) << "Original and deserialized command must have same title"; + ASSERT_EQ(command1.get_price(), dynamic_cast(command2.get())->get_price()) << "Original and deserialized command must have same price"; + ASSERT_EQ(command1.get_min_sfx_price(), dynamic_cast(command2.get())->get_min_sfx_price()) << "Original and deserialized command must have same minimal Safex price"; + ASSERT_EQ(command1.get_quantity(), dynamic_cast(command2.get())->get_quantity()) << "Original and deserialized command must have same quantity"; + ASSERT_EQ(command1.get_active(), dynamic_cast(command2.get())->get_active()) << "Original and deserialized command must have same active status"; + ASSERT_EQ(command1.get_price_peg_used(), dynamic_cast(command2.get())->get_price_peg_used()) << "Original and deserialized command must have same price peg used field"; + ASSERT_EQ(command1.get_description(), dynamic_cast(command2.get())->get_description()) << "Original and deserialized command must have same description"; + ASSERT_EQ(command1.get_seller_address(), dynamic_cast(command2.get())->get_seller_address()) << "Original and deserialized command must have same seller address"; + ASSERT_EQ(command1.get_seller_private_view_key(), dynamic_cast(command2.get())->get_seller_private_view_key()) << "Original and deserialized command must have same sellers private key"; + + } + + TEST_F(SafexEditOfferCommand, HandlesCommandParsing) + { + + cryptonote::account_base acc_base; + acc_base.generate(); + + safex::safex_account_key_handler m_safex_account_keys; + m_safex_account_keys.generate(); + + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + "username",acc_base.get_keys().m_view_secret_key, + acc_base.get_keys().m_account_address); + + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::edit_offer) << "Safex edit offer command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::edit_offer); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_offerid(), dynamic_cast(command2.get())->get_offerid()) << "Original and deserialized command must have same offer ID"; + ASSERT_EQ(command1.get_price_peg_id(), dynamic_cast(command2.get())->get_price_peg_id()) << "Original and deserialized command must have same price peg ID"; + ASSERT_EQ(command1.get_seller(), dynamic_cast(command2.get())->get_seller()) << "Original and deserialized command must have same seller"; + ASSERT_EQ(command1.get_title(), dynamic_cast(command2.get())->get_title()) << "Original and deserialized command must have same title"; + ASSERT_EQ(command1.get_price(), dynamic_cast(command2.get())->get_price()) << "Original and deserialized command must have same price"; + ASSERT_EQ(command1.get_min_sfx_price(), dynamic_cast(command2.get())->get_min_sfx_price()) << "Original and deserialized command must have same minimal Safex price"; + ASSERT_EQ(command1.get_quantity(), dynamic_cast(command2.get())->get_quantity()) << "Original and deserialized command must have same quantity"; + ASSERT_EQ(command1.get_active(), dynamic_cast(command2.get())->get_active()) << "Original and deserialized command must have same active status"; + ASSERT_EQ(command1.get_price_peg_used(), dynamic_cast(command2.get())->get_price_peg_used()) << "Original and deserialized command must have same price peg used field"; + ASSERT_EQ(command1.get_description(), dynamic_cast(command2.get())->get_description()) << "Original and deserialized command must have same description"; + } + + TYPED_TEST(SafexOfferTest, CreateOfferCommand) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + bool result; + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + //Checking created offers + for (auto safex_offer: this->m_safex_offer) { + + safex::safex_offer saved_offer; + result = this->m_db->get_offer(safex_offer.offer_id,saved_offer); + ASSERT_TRUE(result); + ASSERT_TRUE(std::equal(safex_offer.description.begin(), safex_offer.description.end(), + saved_offer.description.begin())); + ASSERT_EQ(safex_offer.title,saved_offer.title); + ASSERT_EQ(safex_offer.seller_private_view_key, saved_offer.seller_private_view_key); + ASSERT_EQ(safex_offer.seller_address, saved_offer.seller_address); + + ASSERT_EQ(safex_offer.price_peg_used, saved_offer.price_peg_used); + ASSERT_EQ(safex_offer.price_peg_id, saved_offer.price_peg_id); + ASSERT_EQ(safex_offer.min_sfx_price, saved_offer.min_sfx_price); + + std::string username; + result = this->m_db->get_offer_seller(safex_offer.offer_id, username); + ASSERT_TRUE(result); + ASSERT_EQ(username.compare(safex_offer.seller), 0); + + uint64_t price; + result = this->m_db->get_offer_price(safex_offer.offer_id, price); + ASSERT_TRUE(result); + ASSERT_EQ(price, safex_offer.price); + + uint64_t quantity; + result = this->m_db->get_offer_quantity(safex_offer.offer_id, quantity); + ASSERT_TRUE(result); + ASSERT_EQ(safex_offer.quantity, quantity); + + bool active; + result = this->m_db->get_offer_active_status(safex_offer.offer_id, active); + ASSERT_TRUE(result); + ASSERT_EQ(safex_offer.active, active); + + } + + for (int i = NUMBER_OF_BLOCKS1; i < NUMBER_OF_BLOCKS2; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + //Checking edited offer + safex::safex_offer saved_offer; + result = this->m_db->get_offer(this->m_edited_safex_offer.offer_id,saved_offer); + ASSERT_TRUE(result); + ASSERT_TRUE(std::equal(this->m_edited_safex_offer.description.begin(), this->m_edited_safex_offer.description.end(), + saved_offer.description.begin())); + ASSERT_EQ(this->m_edited_safex_offer.title,saved_offer.title); + ASSERT_EQ(this->m_edited_safex_offer.seller_private_view_key, saved_offer.seller_private_view_key); + ASSERT_EQ(this->m_edited_safex_offer.seller_address, saved_offer.seller_address); + + ASSERT_EQ(this->m_edited_safex_offer.price_peg_used, saved_offer.price_peg_used); + ASSERT_EQ(this->m_edited_safex_offer.price_peg_id, saved_offer.price_peg_id); + ASSERT_EQ(this->m_edited_safex_offer.min_sfx_price, saved_offer.min_sfx_price); + + std::string username; + result = this->m_db->get_offer_seller(this->m_edited_safex_offer.offer_id, username); + ASSERT_TRUE(result); + ASSERT_EQ(username.compare(this->m_edited_safex_offer.seller), 0); + + uint64_t price; + result = this->m_db->get_offer_price(this->m_edited_safex_offer.offer_id, price); + ASSERT_TRUE(result); + ASSERT_EQ(price, this->m_edited_safex_offer.price); + + uint64_t quantity; + result = this->m_db->get_offer_quantity(this->m_edited_safex_offer.offer_id, quantity); + ASSERT_TRUE(result); + ASSERT_EQ(this->m_edited_safex_offer.quantity, quantity); + + bool active; + result = this->m_db->get_offer_active_status(this->m_edited_safex_offer.offer_id, active); + ASSERT_TRUE(result); + ASSERT_EQ(this->m_edited_safex_offer.active, active); + + for (int i = NUMBER_OF_BLOCKS2; i < NUMBER_OF_BLOCKS3; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexOfferTest, CreateOfferExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex account doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + "usernamenothere",this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price too small + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.min_sfx_price = SAFEX_OFFER_MINIMUM_PRICE - 1; + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_too_small); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer min price too small"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.min_sfx_price = MONEY_SUPPLY + 1; + sfx_offer.price = sfx_offer.min_sfx_price; + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer min price too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price mismatch + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.min_sfx_price = sfx_offer.price + 1; + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_mismatch); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price mismatch"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer title too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.title = ""; + for(int i = 0; i<=SAFEX_OFFER_NAME_MAX_SIZE+1; i++) + sfx_offer.title+='x'; + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer title too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer description too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.description.clear(); + for(int i = 0; i<=SAFEX_OFFER_DATA_MAX_SIZE+1; i++) + sfx_offer.description.push_back('x'); + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer description too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price peg doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + this->m_safex_account1.username,this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + sfx_offer.set_price_peg(sfx_offer.offer_id,100,100*COIN); + + safex::create_offer_data offer_data{sfx_offer}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_peg_not_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer already exists + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_offer; + txinput.key_offsets.push_back(0); + + safex::create_offer_data offer_data{this->m_safex_offer[0]}; + + safex::create_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_already_exists); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexOfferTest, EditOfferExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex account doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = safex::safex_offer("Apple",10,100*COIN,"This is an apple", + "usernamenothere",this->m_users_acc[0].get_keys().m_view_secret_key, + this->m_users_acc[0].get_keys().m_account_address); + + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price too small + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = this->m_safex_offer[0]; + + sfx_offer.min_sfx_price = SAFEX_OFFER_MINIMUM_PRICE - 1; + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_too_small); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer min price too small"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = this->m_safex_offer[0]; + + sfx_offer.min_sfx_price = MONEY_SUPPLY + 1; + sfx_offer.price = sfx_offer.min_sfx_price; + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer min price too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price mismatch + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = this->m_safex_offer[0]; + + sfx_offer.min_sfx_price = sfx_offer.price + 1; + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_mismatch); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price mismatch"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer title too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = this->m_safex_offer[0]; + + sfx_offer.title = ""; + for(int i = 0; i<=SAFEX_OFFER_NAME_MAX_SIZE+1; i++) + sfx_offer.title+='x'; + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer title too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer description too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = this->m_safex_offer[0]; + + sfx_offer.description.clear(); + for(int i = 0; i<=SAFEX_OFFER_DATA_MAX_SIZE+1; i++) + sfx_offer.description.push_back('x'); + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer description too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer price peg doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + txinput.key_offsets.push_back(0); + safex::safex_offer sfx_offer = this->m_safex_offer[0]; + + sfx_offer.set_price_peg(sfx_offer.offer_id,100,100*COIN); + + safex::edit_offer_data offer_data{sfx_offer}; + + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_price_peg_not_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::edit_offer; + txinput.key_offsets.push_back(0); + + safex::edit_offer_data offer_data{this->m_safex_offer[0]}; + offer_data.offer_id.data[0] +=1; + safex::edit_offer command1{SAFEX_COMMAND_PROTOCOL_VERSION , offer_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::edit_offer); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer price peg doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + + ASSERT_NO_THROW(this->m_db->close()); + + } +#endif + +} // anonymous namespace diff --git a/tests/unit_tests/safex_db/safex_price_peg.cpp b/tests/unit_tests/safex_db/safex_price_peg.cpp new file mode 100644 index 000000000..197a9ba92 --- /dev/null +++ b/tests/unit_tests/safex_db/safex_price_peg.cpp @@ -0,0 +1,867 @@ +// Copyright (c) 2018, The Safex 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) 2014-2018 The Monero Project + +#include +#include +#include +#include + +#include "gtest/gtest.h" + +#include "string_tools.h" +#include "blockchain_db/blockchain_db.h" +#include "blockchain_db/lmdb/db_lmdb.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "safex/safex_account.h" +#include "safex/safex_price_peg.h" +#include "../safex_test_common.h" + + +using namespace cryptonote; +using epee::string_tools::pod_to_hex; + +#define ASSERT_HASH_EQ(a, b) ASSERT_EQ(pod_to_hex(a), pod_to_hex(b)) + +namespace +{ // anonymous namespace + + const int NUMBER_OF_BLOCKS = 30; + const int NUMBER_OF_BLOCKS1 = 15; + const int NUMBER_OF_BLOCKS2 = 20; + const int NUMBER_OF_BLOCKS3 = 30; + const uint64_t default_miner_fee = ((uint64_t) 500000000); + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", + "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182"}; + + class SafexCreatePricePegCommand : public ::testing::Test + { + public: + SafexCreatePricePegCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + class SafexUpdatePricePegCommand : public ::testing::Test + { + public: + SafexUpdatePricePegCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + template + class SafexPricePegTest : public testing::Test + { + protected: + SafexPricePegTest() : m_db(new T(false, cryptonote::network_type::FAKECHAIN)), m_hardfork(*m_db, 1, 0) + { + m_test_sizes = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_coins = std::vector(NUMBER_OF_BLOCKS, 60); + m_test_coins[0] = 2000 * SAFEX_CASH_COIN; //genesis tx airdrop + m_test_tokens = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_tokens[0] = 4000 * SAFEX_TOKEN; + m_test_diffs = std::vector(NUMBER_OF_BLOCKS, 200); + m_test_diffs[0] = 1; + m_test_diffs[1] = 100; + m_test_diffs[2] = 180; + + m_miner_acc.generate(); + m_users_acc[0].generate(); + m_users_acc[1].generate(); + + m_safex_account1_keys.generate(); + m_safex_account2_keys.generate(); + + + + m_safex_account1.username = "user1"; + m_safex_account1.pkey = m_safex_account1_keys.get_keys().m_public_key; + m_safex_account1.account_data = {'s','m','o','r'}; + m_safex_account2.username = "user2"; + m_safex_account2.pkey = m_safex_account2_keys.get_keys().m_public_key; + + std::cout << "Alice public key: " << epee::string_tools::pod_to_hex(m_safex_account1_keys.get_keys().m_public_key) << std::endl; + std::cout << "Alice private key: " << epee::string_tools::pod_to_hex(m_safex_account1_keys.get_keys().m_secret_key) << std::endl; + + const std::string data1_new_str = "Another data tesst for edit"; + data1_new = std::vector(data1_new_str.begin(), data1_new_str.end()); + + m_safex_price_pegs.emplace_back("USD price peg",m_safex_account1.username, "USD", "xcalibra USD price peg", 30); + m_safex_price_pegs.emplace_back("RSD price peg",m_safex_account2.username, "RSD", "xcalibra RSD price peg", 100); + + m_edited_safex_price_peg = m_safex_price_pegs[1]; + + m_edited_safex_price_peg.rate = 40; + + for (int i = 0; i < NUMBER_OF_BLOCKS; i++) + { + block blk; + std::list tx_list; // fill tx list with transactions for that block + crypto::hash prev_hash = boost::value_initialized();/* null hash*/ + + if (i > 0) prev_hash = cryptonote::get_block_hash(m_blocks[i - 1]); + + if (i == 0) + { + //skip, genesis block + } + else if (i == 1) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_migration_tx_to_key(m_txmap, m_blocks, tx, m_miner_acc, m_users_acc[0], m_test_tokens[0], default_miner_fee, get_hash_from_string(bitcoin_tx_hashes_str[0])); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 2) + { + //distribute tokens and coins to accounts as starter + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_tx_to_key(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[1], 1000 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_tx_to_key(m_txmap, m_blocks, tx2, m_miner_acc, m_users_acc[0], 100 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx2)] = tx2; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx3 = tx_list.back(); \ + construct_tx_to_key(m_txmap, m_blocks, tx3, m_miner_acc, m_users_acc[1], 200 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx3)] = tx3; + } + else if (i == 5) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_account_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.username, m_safex_account1.pkey, m_safex_account1.account_data, m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_create_account_transaction(m_txmap, m_blocks, tx2, m_users_acc[1], default_miner_fee, 0, m_safex_account2.username, m_safex_account2.pkey, m_safex_account2.account_data, m_safex_account2_keys.get_keys()); + m_txmap[get_transaction_hash(tx2)] = tx2; + } + else if (i == 7) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_price_peg_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.pkey, m_safex_price_pegs[0], m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 8) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_price_peg_transaction(m_txmap, m_blocks, tx, m_users_acc[1], default_miner_fee, 0, m_safex_account2.pkey, m_safex_price_pegs[1], m_safex_account2_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 15) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_update_price_peg_transaction(m_txmap, m_blocks, tx, m_users_acc[1], default_miner_fee, 0, m_safex_account2.pkey, m_edited_safex_price_peg, m_safex_account2_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + } + + construct_block(blk, i, prev_hash, m_miner_acc, 0, m_test_sizes[i], tx_list); + + m_txs.push_back(std::vector{tx_list.begin(), tx_list.end()}); + m_blocks.push_back(blk); + } + } + + + ~SafexPricePegTest() + { + delete m_db; + remove_files(m_filenames, m_prefix); + } + + BlockchainDB *m_db; + HardFork m_hardfork; + std::string m_prefix; + std::vector m_blocks; + //std::unordered_map + map_hash2tx_t m_txmap; //vector of all transactions + std::vector > m_txs; + std::vector m_filenames; + + cryptonote::account_base m_miner_acc; + cryptonote::account_base m_users_acc[2]; + + std::vector m_test_sizes; + std::vector m_test_coins; + std::vector m_test_tokens; + std::vector m_test_diffs; + + safex::safex_account_key_handler m_safex_account1_keys{}; + safex::safex_account_key_handler m_safex_account2_keys{}; + safex::safex_account m_safex_account1; + safex::safex_account m_safex_account2; + + std::vector m_safex_price_pegs; + safex::safex_price_peg m_edited_safex_price_peg; + + std::vector data1_new; + + + void init_hard_fork() + { + m_hardfork.init(); + m_db->set_hard_fork(&m_hardfork); + } + + void get_filenames() + { + m_filenames = m_db->get_filenames(); + for (auto &f : m_filenames) + { + std::cerr << "File created by test: " << f << std::endl; + } + } + + + void set_prefix(const std::string &prefix) + { + m_prefix = prefix; + } + }; + + using testing::Types; + + typedef Types implementations; + + TYPED_TEST_CASE(SafexPricePegTest, implementations); + +#if 1 + + TEST_F(SafexCreatePricePegCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_price_peg), safex::command_exception); + + } + + TEST_F(SafexUpdatePricePegCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::update_price_peg), safex::command_exception); + + } + + TEST_F(SafexCreatePricePegCommand, HandlesUnknownProtocolVersion) + { + + safex::create_price_peg_data price_peg_data{}; + try + { + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, price_peg_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexUpdatePricePegCommand, HandlesUnknownProtocolVersion) + { + + safex::update_price_peg_data price_peg_data{}; + try + { + safex::update_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, price_peg_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexCreatePricePegCommand, HandlesCommandParsing) + { + + cryptonote::account_base acc_base; + acc_base.generate(); + + safex::safex_account_key_handler m_safex_account_keys; + m_safex_account_keys.generate(); + + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", "username","USD","Some description", 1828); + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::create_price_peg) << "Safex create price peg command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_price_peg); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_price_peg_id(), dynamic_cast(command2.get())->get_price_peg_id()) << "Original and deserialized command must have same price peg ID"; + ASSERT_EQ(command1.get_creator(), dynamic_cast(command2.get())->get_creator()) << "Original and deserialized command must have same creator"; + ASSERT_EQ(command1.get_title(), dynamic_cast(command2.get())->get_title()) << "Original and deserialized command must have same title"; + ASSERT_EQ(command1.get_description(), dynamic_cast(command2.get())->get_description()) << "Original and deserialized command must have same description"; + ASSERT_EQ(command1.get_currency(), dynamic_cast(command2.get())->get_currency()) << "Original and deserialized command must have same currency"; + ASSERT_EQ(command1.get_rate(), dynamic_cast(command2.get())->get_rate()) << "Original and deserialized command must have same rate"; + + } + + TEST_F(SafexUpdatePricePegCommand, HandlesCommandParsing) + { + + cryptonote::account_base acc_base; + acc_base.generate(); + + safex::safex_account_key_handler m_safex_account_keys; + m_safex_account_keys.generate(); + + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", "username","USD","Some description", 1828); + + safex::update_price_peg_data price_peg_data{sfx_price_peg}; + + safex::update_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::update_price_peg) << "Safex create price peg command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::update_price_peg); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_price_peg_id(), dynamic_cast(command2.get())->get_price_peg_id()) << "Original and deserialized command must have same price peg ID"; + ASSERT_EQ(command1.get_rate(), dynamic_cast(command2.get())->get_rate()) << "Original and deserialized command must have same rate"; + + } + + TYPED_TEST(SafexPricePegTest, CreatePricePegCommand) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + bool result; + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + //Checking created price pegs + for (auto safex_price_peg: this->m_safex_price_pegs) { + + std::vector saved_price_pegs; + result = this->m_db->get_safex_price_pegs(saved_price_pegs,safex_price_peg.currency); + ASSERT_TRUE(result); + + safex::safex_price_peg saved_price_peg = saved_price_pegs[0]; + + ASSERT_TRUE(std::equal(safex_price_peg.description.begin(), safex_price_peg.description.end(), + saved_price_peg.description.begin())); + ASSERT_EQ(safex_price_peg.title,saved_price_peg.title); + ASSERT_EQ(safex_price_peg.currency,saved_price_peg.currency); + ASSERT_EQ(safex_price_peg.creator,saved_price_peg.creator); + ASSERT_EQ(safex_price_peg.rate,saved_price_peg.rate); + ASSERT_EQ(safex_price_peg.price_peg_id,saved_price_peg.price_peg_id); + + } + + for (int i = NUMBER_OF_BLOCKS1; i < NUMBER_OF_BLOCKS2; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + //Checking edited price peg + + safex::safex_price_peg saved_price_peg; + result = this->m_db->get_safex_price_peg(this->m_edited_safex_price_peg.price_peg_id,saved_price_peg); + ASSERT_TRUE(result); + + ASSERT_TRUE(std::equal(this->m_edited_safex_price_peg.description.begin(), this->m_edited_safex_price_peg.description.end(), + saved_price_peg.description.begin())); + ASSERT_EQ(this->m_edited_safex_price_peg.title,saved_price_peg.title); + ASSERT_EQ(this->m_edited_safex_price_peg.currency,saved_price_peg.currency); + ASSERT_EQ(this->m_edited_safex_price_peg.creator,saved_price_peg.creator); + ASSERT_EQ(this->m_edited_safex_price_peg.rate,saved_price_peg.rate); + ASSERT_EQ(this->m_edited_safex_price_peg.price_peg_id,saved_price_peg.price_peg_id); + + + + for (int i = NUMBER_OF_BLOCKS2; i < NUMBER_OF_BLOCKS3; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexPricePegTest, CreatePricePegExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex account doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + txinput.key_offsets.push_back(0); + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", "username","USD","Some description", 1828); + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_account_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex account doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg ID already exists + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + txinput.key_offsets.push_back(0); + + safex::create_price_peg_data price_peg_data{this->m_safex_price_pegs[0]}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_already_exists); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg ID already in the DB"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg name too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + txinput.key_offsets.push_back(0); + + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"USD","Some description", 1828); + + sfx_price_peg.title = ""; + for (int i=0; i < SAFEX_PRICE_PEG_NAME_MAX_SIZE + 2 ; i++) { + sfx_price_peg.title += "x"; + } + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg title too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg curreny name too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + txinput.key_offsets.push_back(0); + + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"USD","Some description", 1828); + + sfx_price_peg.currency = ""; + for (int i=0; i < SAFEX_PRICE_PEG_CURRENCY_MAX_SIZE + 2 ; i++) { + sfx_price_peg.currency += "x"; + } + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg currency name too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg description too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + txinput.key_offsets.push_back(0); + + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"USD","Some description", 1828); + + sfx_price_peg.description.clear(); + for (int i=0; i < SAFEX_PRICE_PEG_DATA_MAX_SIZE + 2 ; i++) { + sfx_price_peg.description.push_back('x'); + } + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg currency description too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg curreny name invalid + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + txinput.key_offsets.push_back(0); + + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"US-D","Some description", 1828); + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_bad_currency_format); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg currency name invalid"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg rate zero + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_price_peg; + txinput.key_offsets.push_back(0); + + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"USD","Some description", 1828); + + sfx_price_peg.rate = 0; + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_rate_zero); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg rate is zero"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexPricePegTest, UpdatePricePegExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex price peg doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::update_price_peg; + txinput.key_offsets.push_back(0); + + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", "username","USD","Some description", 1828); + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::update_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_not_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg already exists"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex price peg rate zero + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::update_price_peg; + txinput.key_offsets.push_back(0); + + safex::safex_price_peg sfx_price_peg = safex::safex_price_peg("Apple", this->m_safex_account1.username,"USD","Some description", 1828); + + sfx_price_peg.rate = 0; + + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + + safex::create_price_peg command1{SAFEX_COMMAND_PROTOCOL_VERSION , price_peg_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::update_price_peg); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_price_peg_rate_zero); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex price peg rate zero"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + +#endif + +} // anonymous namespace diff --git a/tests/unit_tests/safex_db/safex_stake_unstake.cpp b/tests/unit_tests/safex_db/safex_stake_unstake.cpp new file mode 100644 index 000000000..19fbb86e8 --- /dev/null +++ b/tests/unit_tests/safex_db/safex_stake_unstake.cpp @@ -0,0 +1,896 @@ +// Copyright (c) 2018, The Safex 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) 2014-2018 The Monero Project + +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" + +#include "string_tools.h" +#include "blockchain_db/blockchain_db.h" +#include "blockchain_db/lmdb/db_lmdb.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_tx_utils.h" +#include "../safex_test_common.h" + +using namespace cryptonote; +using epee::string_tools::pod_to_hex; + +#define ASSERT_HASH_EQ(a, b) ASSERT_EQ(pod_to_hex(a), pod_to_hex(b)) + +namespace +{ // anonymous namespace + + const int NUMBER_OF_BLOCKS = 543; + const uint64_t default_miner_fee = ((uint64_t) 500000000); + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", + "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182", + "80220aec436a2298bae6b35c920017d36646cda874a0516e121e658a888d2b55", "361074a34cf1723c7f797f2764b4c34a8e1584475c28503867778ca90bebbc0a"}; + + class SafexStakeCommand : public ::testing::Test + { + public: + SafexStakeCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + class SafexUnstakeCommand : public ::testing::Test + { + public: + SafexUnstakeCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + template + class SafexBlockchainFeeTest : public testing::Test + { + protected: + SafexBlockchainFeeTest() : m_db(new T(false, cryptonote::network_type::FAKECHAIN)), m_hardfork(*m_db, 1, 0) + { + m_test_sizes = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_coins = std::vector(NUMBER_OF_BLOCKS, 60); + m_test_coins[0] = 2000 * SAFEX_CASH_COIN; //genesis tx airdrop + m_test_tokens = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_tokens[0] = 1000 * SAFEX_TOKEN; + m_test_tokens[1] = 100 * SAFEX_TOKEN; + m_test_diffs = std::vector(NUMBER_OF_BLOCKS, 200); + m_test_diffs[0] = 1; + m_test_diffs[1] = 100; + m_test_diffs[2] = 180; + + //m_txs = std::vector>(1, std::vector()); + + m_miner_acc.generate(); + m_users_acc[0].generate(); + m_users_acc[1].generate(); + + for (int i = 0; i < NUMBER_OF_BLOCKS; i++) + { + block blk; + std::list tx_list; // fill tx list with transactions for that block + crypto::hash prev_hash = boost::value_initialized();/* null hash*/ + + if (i > 0) prev_hash = cryptonote::get_block_hash(m_blocks[i - 1]); + + if (i == 0) + { + //skip, genesis block + } + else if (i == 1) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_migration_tx_to_key(m_txmap, m_blocks, tx, m_miner_acc, m_users_acc[0], m_test_tokens[0], default_miner_fee, get_hash_from_string(bitcoin_tx_hashes_str[0])); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 2) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_tx_to_key(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[1], 200 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_tx_to_key(m_txmap, m_blocks, tx2, m_miner_acc, m_users_acc[1], 10 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx2)] = tx2; + } + else if (i == 3) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_tx_to_key(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[1], 100 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 10) + { + //create token stake transaction, user 0 locks 100 safex token + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_stake_transaction(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[0], 100 * SAFEX_TOKEN, default_miner_fee, 0); +// std::cout << "tx 10 hash: " << epee::string_tools::pod_to_hex(get_transaction_hash(tx)) << std::endl; + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 11) + { + //create other token stake transaction + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_stake_transaction(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[0], 400 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_token_stake_transaction(m_txmap, m_blocks, tx2, m_users_acc[1], m_users_acc[1], 100 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx2)] = tx2; + + } + else if (i == 13) + { + //add network fee + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_fee_donation_transaction(m_txmap, m_blocks, tx, m_miner_acc, 2 * SAFEX_CASH_COIN, default_miner_fee, 0); + std::cout << "tx 13 hash: " << epee::string_tools::pod_to_hex(get_transaction_hash(tx)) << std::endl; + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 15) + { + //add more network fee + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_fee_donation_transaction(m_txmap, m_blocks, tx, m_miner_acc, 12.5 * SAFEX_CASH_COIN, default_miner_fee, 0); + std::cout << "tx 15 hash: " << epee::string_tools::pod_to_hex(get_transaction_hash(tx)) << std::endl; + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 19) + { + //token stake transaction + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); + construct_token_stake_transaction(m_txmap, m_blocks, tx, m_users_acc[1], m_users_acc[1], 200 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 157) + { + //add network fee + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_fee_donation_transaction(m_txmap, m_blocks, tx, m_miner_acc, 1 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 243) + { + //add network fee + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_fee_donation_transaction(m_txmap, m_blocks, tx, m_miner_acc, 1 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_fee_donation_transaction(m_txmap, m_blocks, tx2, m_miner_acc, 60404980, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx2)] = tx2; + } + else if (i == 517) + { + //token unstake transaction + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); + construct_token_unstake_transaction(m_txmap, m_blocks, tx, m_users_acc[1], m_users_acc[1], 100 * SAFEX_TOKEN, default_miner_fee, 0); //unstake 100 + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 520) + { + //token unstake transaction + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); + construct_token_unstake_transaction(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[0], 400 * SAFEX_TOKEN, default_miner_fee, 0); //unstake 400 + m_txmap[get_transaction_hash(tx)] = tx; + } + + + construct_block(blk, i, prev_hash, m_miner_acc, 0, m_test_sizes[i], tx_list); + + m_txs.push_back(std::vector{tx_list.begin(), tx_list.end()}); + m_blocks.push_back(blk); + } + + } + + + ~SafexBlockchainFeeTest() + { + delete m_db; + remove_files(m_filenames, m_prefix); + } + + BlockchainDB *m_db; + HardFork m_hardfork; + std::string m_prefix; + std::vector m_blocks; + //std::unordered_map + map_hash2tx_t m_txmap; //vector of all transactions + std::vector > m_txs; + std::vector m_filenames; + + cryptonote::account_base m_miner_acc; + cryptonote::account_base m_users_acc[2]; + + std::vector m_test_sizes; + std::vector m_test_coins; + std::vector m_test_tokens; + std::vector m_test_diffs; + + + void init_hard_fork() + { + m_hardfork.init(); + m_db->set_hard_fork(&m_hardfork); + } + + void get_filenames() + { + m_filenames = m_db->get_filenames(); + for (auto &f : m_filenames) + { + std::cerr << "File created by test: " << f << std::endl; + } + } + + void set_prefix(const std::string &prefix) + { + m_prefix = prefix; + } + }; + + using testing::Types; + + typedef Types implementations; + + TYPED_TEST_CASE(SafexBlockchainFeeTest, implementations); + +#if 1 + + TEST_F(SafexStakeCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::token_stake), safex::command_exception); + + } + + TEST_F(SafexUnstakeCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::token_unstake), safex::command_exception); + + } + + TEST_F(SafexStakeCommand, HandlesUnknownProtocolVersion) + { + + try + { + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, 2000}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexUnstakeCommand, HandlesUnknownProtocolVersion) + { + + try + { + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, 1}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexStakeCommand, HandlesCommandParsing) + { + + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 2000}; + + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::token_stake) << "Token stake command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::token_stake); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_staked_token_amount(), dynamic_cast(command2.get())->get_staked_token_amount()) << "Original and deserialized command must have same staked amount"; + + } + + TEST_F(SafexUnstakeCommand, HandlesCommandParsing) + { + + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 1}; + + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::token_unstake) << "Token stake command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::token_unstake); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_staked_token_output_index(), dynamic_cast(command2.get())->get_staked_token_output_index()) << "Original and deserialized command must have same staked index"; + + } + + + + TEST_F(SafexStakeCommand, TokenStakeExecute) + { + + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::token_stake; + txinput.token_amount = 10000*SAFEX_TOKEN; + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 10000*SAFEX_TOKEN}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + + std::cout << "Token amount: " << static_cast(result.get())->token_amount << " status:" << static_cast(result->status) + << " block number:" << static_cast(result.get())->block_number << std::endl; + } + catch (safex::command_exception &exception) + { + FAIL() << exception.what(); + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + } + + TEST_F(SafexStakeCommand, TokenStakeExceptions) + { + + // Token amount not whole + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 8000; + txinput.command_type = safex::command_t::token_stake; + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 8000}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_stake_token_not_whole_amount); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with token amount not whole"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + + // Token amount not matching + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 19000*SAFEX_TOKEN; + txinput.command_type = safex::command_t::token_stake; + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, 11000*SAFEX_TOKEN}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); + + safex::execution_status status = command2->validate(this->m_db, txinput); + ASSERT_EQ(status, safex::execution_status::error_stake_token_amount_not_matching); + + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + FAIL() << "Should throw exception with input amount differs from token stake command amount"; + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + + } + + + TEST_F(SafexStakeCommand, TokenStakeExecuteWrongType) + { + + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 10000*SAFEX_TOKEN; //stake 10k tokens + txinput.command_type = safex::command_t::token_stake; + txinput.key_offsets.push_back(23); + uint64_t staked_token_output_index = 23; + safex::token_stake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ("Could not create command, wrong command type", std::string(exception.what()).c_str()); + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexUnstakeCommand, TokenUnstakeExecuteWrongType) + { + + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 10000; //unstake 10k tokens + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(23); + uint64_t staked_token_output_index = 23; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_stake); + std::unique_ptr result{command2->execute(this->m_db, txinput)}; + + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ("Could not create command, wrong command type", std::string(exception.what()).c_str()); + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TYPED_TEST(SafexBlockchainFeeTest, RetrieveCollectedFee) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS - 1; i++) + { + try + { + this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i]); + } + catch (std::exception &e) + { + std::cout << "Error: " << e.what() << std::endl; + } + + if (i == 517) { + //here, we have unstaked 100, check current db status + uint64_t number_of_staked_tokens51 = this->m_db->get_staked_token_sum_for_interval(51); + uint64_t number_of_staked_tokens52 = this->m_db->get_staked_token_sum_for_interval(52); + uint64_t number_of_staked_tokens52_cur = this->m_db->get_current_staked_token_sum(); + + ASSERT_EQ(number_of_staked_tokens51, 800 * SAFEX_TOKEN); + ASSERT_EQ(number_of_staked_tokens52, 700 * SAFEX_TOKEN); + ASSERT_EQ(number_of_staked_tokens52_cur, 700 * SAFEX_TOKEN); + } else if (i == 520) { + //here, we have unstaked 400, check current db status + uint64_t number_of_staked_tokens51 = this->m_db->get_staked_token_sum_for_interval(51); + uint64_t number_of_staked_tokens52 = this->m_db->get_staked_token_sum_for_interval(52); + uint64_t number_of_staked_tokens52_cur = this->m_db->get_current_staked_token_sum(); + + ASSERT_EQ(number_of_staked_tokens51, 800 * SAFEX_TOKEN); + ASSERT_EQ(number_of_staked_tokens52, 300 * SAFEX_TOKEN); + ASSERT_EQ(number_of_staked_tokens52_cur, 300 * SAFEX_TOKEN); + } else if (i == 521) { + //new period 53 started, check current db status + uint64_t number_of_staked_tokens51 = this->m_db->get_staked_token_sum_for_interval(51); + uint64_t number_of_staked_tokens52 = this->m_db->get_staked_token_sum_for_interval(52); + uint64_t number_of_staked_tokens53 = this->m_db->get_staked_token_sum_for_interval(53); + uint64_t number_of_staked_tokens54 = this->m_db->get_staked_token_sum_for_interval(54); + uint64_t number_of_staked_tokens53_cur = this->m_db->get_current_staked_token_sum(); + + ASSERT_EQ(number_of_staked_tokens51, 800 * SAFEX_TOKEN); + ASSERT_EQ(number_of_staked_tokens52, 300 * SAFEX_TOKEN); + ASSERT_EQ(number_of_staked_tokens53, 300 * SAFEX_TOKEN); + ASSERT_EQ(number_of_staked_tokens53_cur, 300 * SAFEX_TOKEN); + } + + } + + uint64_t number_of_staked_tokens2 = this->m_db->get_staked_token_sum_for_interval(2); // in first interval we have staked 100, they receive interest in interval 2 + ASSERT_EQ(number_of_staked_tokens2, 100 * SAFEX_TOKEN); + + uint64_t number_of_staked_tokens3 = this->m_db->get_staked_token_sum_for_interval(3); // in first interval we have staked another 700, in totall 800, they receive interest in interval 3 + ASSERT_EQ(number_of_staked_tokens3, 800 * SAFEX_TOKEN); + + uint64_t number_of_staked_tokens10 = this->m_db->get_staked_token_sum_for_interval(10); + ASSERT_EQ(number_of_staked_tokens10, 800 * SAFEX_TOKEN); + + uint64_t number_of_staked_tokens51 = this->m_db->get_staked_token_sum_for_interval(51); + ASSERT_EQ(number_of_staked_tokens51, 800 * SAFEX_TOKEN); + + uint64_t number_of_staked_tokens52 = this->m_db->get_staked_token_sum_for_interval(52); + ASSERT_EQ(number_of_staked_tokens52, 300 * SAFEX_TOKEN); + + uint64_t number_of_staked_tokens55 = this->m_db->get_staked_token_sum_for_interval(55); + ASSERT_EQ(number_of_staked_tokens55, 300 * SAFEX_TOKEN); + + uint64_t number_of_staked_tokens_endsum = this->m_db->get_current_staked_token_sum(); + ASSERT_EQ(number_of_staked_tokens_endsum, 300 * SAFEX_TOKEN); //100+400+100+200-400-100 + + + + + uint64_t fee_sum = this->m_db->get_network_fee_sum_for_interval(0); +// ASSERT_EQ(fee_sum, 14.5 * SAFEX_CASH_COIN); // 2 + 12.5 + std::cout << "Cash collected fee:" << print_money(fee_sum) << std::endl; + + + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexBlockchainFeeTest, TokenUnstakeExecute) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS - 1; i++) + { + try + { + this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i]); + } + catch (std::exception &e) + { + std::cout << "Error: " << e.what() << std::endl; + } + } + + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 400 * SAFEX_TOKEN; //unstake 120k tokens + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(1); + uint64_t staked_token_output_index = 1; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; + safex::token_unstake_result* result = static_cast(rslt.get()); + + std::cout << "Token amount: " << result->token_amount << " valid:" << result->valid << " block number:" << result->block_number << " interest: " << result->interest << std::endl; + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SafexBlockchainFeeTest, TokenUnstakeExceptions) + { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + uint64_t minimum_stake_block_height = 10 + safex::get_safex_minumum_token_lock_period(this->m_db->get_net_type()); + + for (int i = 0; i < minimum_stake_block_height; i++) + { + try + { + this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i]); + } + catch (std::exception &e) + { + std::cout << "Error: " << e.what() << std::endl; + } + } + + // Not enough time passed + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 400 * SAFEX_TOKEN; //unstake 400 tokens + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(1); + uint64_t staked_token_output_index = 0; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_unstake_token_minimum_period); + + std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with matching output not found"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + + try + { + this->m_db->add_block(this->m_blocks[minimum_stake_block_height], this->m_test_sizes[minimum_stake_block_height], + this->m_test_diffs[minimum_stake_block_height], this->m_test_coins[minimum_stake_block_height], + this->m_test_tokens[minimum_stake_block_height], this->m_txs[minimum_stake_block_height]); + } + catch (std::exception &e) + { + std::cout << "Error: " << e.what() << std::endl; + } + + + // Token amount offset more than one + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 400 * SAFEX_TOKEN; //unstake 400 tokens + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(1); + txinput.key_offsets.push_back(12); + uint64_t staked_token_output_index = 1; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_unstake_token_offset_not_one); + + std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with offsets size more than 1"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Interest too big + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 400 * SAFEX_TOKEN; //unstake 400 tokens + txinput.amount = 5000 * SAFEX_CASH_COIN; + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(1); + uint64_t staked_token_output_index = 0; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_unstake_token_network_fee_not_matching); + + std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with interest too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Output not found + try + { + + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.token_amount = 100 * SAFEX_TOKEN; //unstake 400 tokens + txinput.command_type = safex::command_t::token_unstake; + txinput.key_offsets.push_back(1); + uint64_t staked_token_output_index = 0; + safex::token_unstake command1{SAFEX_COMMAND_PROTOCOL_VERSION, staked_token_output_index}; + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::token_unstake); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_unstake_token_output_not_found); + + std::unique_ptr rslt{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with matching output not found"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + +#endif + + +} // anonymous namespace diff --git a/tests/unit_tests/safex_db/safex_test_common.cpp b/tests/unit_tests/safex_db/safex_test_common.cpp new file mode 100644 index 000000000..4e3951f45 --- /dev/null +++ b/tests/unit_tests/safex_db/safex_test_common.cpp @@ -0,0 +1,1476 @@ +// +// Created by amarko on 19.4.19.. +// + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" + +#include "string_tools.h" +#include "blockchain_db/blockchain_db.h" +#include "blockchain_db/lmdb/db_lmdb.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_tx_utils.h" +#include "safex/safex_offer.h" +#include "safex/safex_purchase.h" + +#include "../safex_test_common.h" + +using namespace cryptonote; +using epee::string_tools::pod_to_hex; + +#define ASSERT_HASH_EQ(a, b) ASSERT_EQ(pod_to_hex(a), pod_to_hex(b)) + +// if the return type (blobdata for now) of block_to_blob ever changes +// from std::string, this might break. +bool compare_blocks(const block &a, const block &b) +{ + auto hash_a = pod_to_hex(get_block_hash(a)); + auto hash_b = pod_to_hex(get_block_hash(b)); + + return hash_a == hash_b; +} + + + +/* +void print_block(const block& blk, const std::string& prefix = "") +{ + std::cerr << prefix << ": " << std::endl + << "\thash - " << pod_to_hex(get_block_hash(blk)) << std::endl + << "\tparent - " << pod_to_hex(blk.prev_id) << std::endl + << "\ttimestamp - " << blk.timestamp << std::endl + ; +} + +// if the return type (blobdata for now) of tx_to_blob ever changes +// from std::string, this might break. +bool compare_txs(const transaction& a, const transaction& b) +{ + auto ab = tx_to_blob(a); + auto bb = tx_to_blob(b); + + return ab == bb; +} +*/ + +//----------------------------------------------------------------------------------------------------- +bool find_nonce_for_given_block(block &bl, const difficulty_type &diffic, uint64_t height) +{ + for (; bl.nonce != std::numeric_limits::max(); bl.nonce++) + { + crypto::hash h; + get_block_longhash(NULL, bl, h, height, 0); + + if (check_hash(h, diffic)) + { + bl.invalidate_hashes(); + return true; + } + } + bl.invalidate_hashes(); + return false; +} + + +tx_destination_entry create_tx_destination(const cryptonote::account_base &to, uint64_t amount) +{ + return tx_destination_entry{amount, to.get_keys().m_account_address, false, tx_out_type::out_cash}; +} + +tx_destination_entry create_token_tx_destination(const cryptonote::account_base &to, uint64_t token_amount) +{ + return tx_destination_entry{token_amount, to.get_keys().m_account_address, false, tx_out_type::out_token}; +} + +tx_destination_entry create_network_fee_tx_destination(uint64_t cash_amount) +{ + account_public_address dummy = AUTO_VAL_INIT(dummy); + return tx_destination_entry{cash_amount, dummy, false, tx_out_type::out_network_fee}; +} + +tx_destination_entry create_locked_token_tx_destination(const cryptonote::account_base &to, uint64_t token_amount) +{ + return tx_destination_entry{token_amount, to.get_keys().m_account_address, false, tx_out_type::out_staked_token}; +} + +bool init_output_indices(map_hash2tx_t &txmap, map_output_idx_t &outs, std::map > &outs_mine, const std::vector &blockchain, + const cryptonote::account_base &from, cryptonote::tx_out_type out_type, const crypto::public_key& safex_account_pkey) +{ + + int output_id_counter = 0; + int block_height = 0; + BOOST_FOREACH (const block &blk, blockchain) + { + std::vector vtx; + vtx.push_back(&blk.miner_tx); + + BOOST_FOREACH(const crypto::hash &h, blk.tx_hashes) + { + const map_hash2tx_t::const_iterator cit = txmap.find(h); + if (txmap.end() == cit) + throw std::runtime_error("block contains an unknown tx hash"); + + vtx.push_back(&cit->second); + } + + + // TODO: add all other txes + for (size_t i = 0; i < vtx.size(); i++) + { + const transaction &tx = *vtx[i]; + + for (size_t j = 0; j < tx.vout.size(); ++j) + { + output_id_counter+=1; + const tx_out &out = tx.vout[j]; + const crypto::public_key &out_key = *boost::apply_visitor(cryptonote::destination_public_key_visitor(), out.target); + + if ((out_type == cryptonote::tx_out_type::out_token) || (out_type == cryptonote::tx_out_type::out_staked_token) + || (out_type == cryptonote::tx_out_type::out_safex_account) || (out_type == cryptonote::tx_out_type::out_safex_account_update) + || (out_type == cryptonote::tx_out_type::out_safex_offer) || (out_type == cryptonote::tx_out_type::out_safex_offer_update) + || (out_type == cryptonote::tx_out_type::out_safex_price_peg) || (out_type == cryptonote::tx_out_type::out_safex_price_peg_update)) + { + if (out.target.type() == typeid(cryptonote::txout_token_to_key)) + { + output_index oi(out.target, out.amount, out.token_amount, boost::get(*blk.miner_tx.vin.begin()).height, i, j, &blk, vtx[i]); + outs[out.token_amount].push_back(oi); + size_t tx_global_idx = outs[out.token_amount].size() - 1; + outs[out.token_amount][tx_global_idx].idx = tx_global_idx; + // Is out to me? + if (is_out_to_acc(from.get_keys(), out_key, get_tx_pub_key_from_extra(tx), get_additional_tx_pub_keys_from_extra(tx), j)) + { + outs_mine[out.token_amount].push_back(tx_global_idx); + } + } + else if (out.target.type() == typeid(cryptonote::txout_to_script)) + { + const txout_to_script &temp = boost::get(out.target); + if (temp.output_type == static_cast(tx_out_type::out_staked_token) + || temp.output_type == static_cast(tx_out_type::out_safex_account) + || temp.output_type == static_cast(tx_out_type::out_safex_offer) + || temp.output_type == static_cast(tx_out_type::out_safex_purchase) + || temp.output_type == static_cast(tx_out_type::out_safex_price_peg)) + { + //cast tx_out_type and use it as imaginary amount for advanced outputs + output_index oi(out.target, out.amount, out.token_amount, boost::get(*blk.miner_tx.vin.begin()).height, i, j, &blk, vtx[i]); + outs[static_cast(temp.output_type)].push_back(oi); + size_t tx_global_idx = outs[static_cast(temp.output_type)].size() - 1; + outs[static_cast(temp.output_type)][tx_global_idx].idx = tx_global_idx; + outs[static_cast(temp.output_type)][tx_global_idx].advanced_output_id = output_id_counter-1; + outs[static_cast(temp.output_type)][tx_global_idx].blk_height = block_height; + outs[static_cast(temp.output_type)][tx_global_idx].out_type = static_cast(temp.output_type); + + // Is out to me? + if (is_safex_out_to_acc(safex_account_pkey, out_key)) { + outs_mine[static_cast(temp.output_type)].push_back(tx_global_idx); + } + else if (is_out_to_acc(from.get_keys(), out_key, get_tx_pub_key_from_extra(tx), get_additional_tx_pub_keys_from_extra(tx), j)) + { + outs_mine[static_cast(temp.output_type)].push_back(tx_global_idx); + } + } + } + } + else if ((out_type == cryptonote::tx_out_type::out_cash) || (out_type == cryptonote::tx_out_type::out_network_fee) + || (out_type == cryptonote::tx_out_type::out_safex_purchase)) + { + if (out.target.type() == typeid(cryptonote::txout_to_key) || (out.target.type() == typeid(cryptonote::txout_to_script) && out_type == cryptonote::tx_out_type::out_safex_purchase)) + { // out_to_key + output_index oi(out.target, out.amount, out.token_amount, boost::get(*blk.miner_tx.vin.begin()).height, i, j, &blk, vtx[i]); + outs[out.amount].push_back(oi); + size_t tx_global_idx = outs[out.amount].size() - 1; + outs[out.amount][tx_global_idx].idx = tx_global_idx; + // Is out to me? + if (is_out_to_acc(from.get_keys(), out_key, get_tx_pub_key_from_extra(tx), get_additional_tx_pub_keys_from_extra(tx), j)) + { + outs_mine[out.amount].push_back(tx_global_idx); + } + } + + } + else if (out_type == cryptonote::tx_out_type::out_safex_feedback && out.target.type() == typeid(cryptonote::txout_to_script)) + { + const txout_to_script &temp = boost::get(out.target); + if(temp.output_type == static_cast(tx_out_type::out_safex_feedback_token)) + { + output_index oi(out.target, out.amount, out.token_amount, boost::get(*blk.miner_tx.vin.begin()).height, i, j, &blk, vtx[i]); + outs[static_cast(temp.output_type)].push_back(oi); + size_t tx_global_idx = outs[static_cast(temp.output_type)].size() - 1; + outs[static_cast(temp.output_type)][tx_global_idx].idx = tx_global_idx; + outs[static_cast(temp.output_type)][tx_global_idx].advanced_output_id = output_id_counter-1; + outs[static_cast(temp.output_type)][tx_global_idx].blk_height = block_height; + outs[static_cast(temp.output_type)][tx_global_idx].out_type = static_cast(temp.output_type); + if (is_out_to_acc(from.get_keys(), out_key, get_tx_pub_key_from_extra(tx), get_additional_tx_pub_keys_from_extra(tx), j)) + { + outs_mine[static_cast(temp.output_type)].push_back(tx_global_idx); + } + } + } + } + } + block_height++; + } + + + return true; +} + + +bool init_spent_output_indices(map_hash2tx_t &txmap, map_output_idx_t &outs, map_output_t &outs_mine, const std::vector &blockchain, + const cryptonote::account_base &from) +{ + + BOOST_FOREACH (const map_output_t::value_type &o, outs_mine) + { + for (size_t i = 0; i < o.second.size(); ++i) //go through my output indexes, o.first = amount, o.second="indexes of my outputs" + { + output_index &oi = outs[o.first][o.second[i]]; //full data about the utxo + + if(oi.out_type == cryptonote::tx_out_type::out_safex_account || oi.out_type == cryptonote::tx_out_type::out_safex_offer || + oi.out_type == cryptonote::tx_out_type::out_safex_price_peg) + continue; + + // construct key image for this output + crypto::key_image img; + keypair in_ephemeral; + const crypto::public_key &out_key = *boost::apply_visitor(destination_public_key_visitor(), oi.out); + std::unordered_map subaddresses; + subaddresses[from.get_keys().m_account_address.m_spend_public_key] = {0, 0}; + generate_key_image_helper(from.get_keys(), subaddresses, out_key, get_tx_pub_key_from_extra(*oi.p_tx), get_additional_tx_pub_keys_from_extra(*oi.p_tx), oi.out_no, in_ephemeral, img, hw::get_device(("default"))); + + // lookup for this key image in the events vector + BOOST_FOREACH(auto &tx_pair, txmap) + { + const transaction &tx = tx_pair.second; + BOOST_FOREACH(const txin_v &in, tx.vin) + { + auto k_image_opt = boost::apply_visitor(key_image_visitor(), in); + if (!k_image_opt) + continue; + const crypto::key_image &k_image = *k_image_opt; + if (k_image == img) + { + oi.spent = true; + } + } + } + } + } + + return true; +} + + +bool fill_output_entries(std::vector &out_indices, size_t sender_out, size_t nmix, size_t &real_entry_idx, std::vector &output_entries) +{ + if (out_indices.size() <= nmix) + return false; + + bool sender_out_found = false; + size_t rest = nmix; + for (size_t i = 0; i < out_indices.size() && (0 < rest || !sender_out_found); ++i) + { + const output_index &oi = out_indices[i]; + if (oi.spent) + continue; + + bool append = false; + if (i == sender_out) + { + append = true; + sender_out_found = true; + real_entry_idx = output_entries.size(); + } + else if (0 < rest) + { + --rest; + append = true; + } + + if (append) + { + const crypto::public_key &key = *boost::apply_visitor(destination_public_key_visitor(), oi.out); + output_entries.push_back(tx_source_entry::output_entry(oi.idx, rct::ctkey({rct::pk2rct(key), rct::identity()}))); + } + } + + return 0 == rest && sender_out_found; +} + +bool fill_output_entries_advanced(std::vector& out_indices, size_t sender_out, size_t nmix, size_t& real_entry_idx, std::vector& output_entries) +{ + if (out_indices.size() <= nmix) + return false; + + bool sender_out_found = false; + size_t rest = nmix; + for (size_t i = 0; i < out_indices.size() && (0 < rest || !sender_out_found); ++i) + { + const output_index& oi = out_indices[i]; + if (oi.spent) + continue; + + bool append = false; + if (i == sender_out) + { + append = true; + sender_out_found = true; + real_entry_idx = output_entries.size(); + } + else if (0 < rest) + { + --rest; + append = true; + } + + if (append) + { + if (oi.out_type == tx_out_type::out_safex_account) { + crypto::public_key key{}; + if (!safex::parse_safex_account_key(oi.out, key)) { + return false; + } + output_entries.push_back(tx_source_entry::output_entry(oi.idx, rct::ctkey({rct::pk2rct(key), rct::identity()}))); + + } + else + { + const crypto::public_key &key = *boost::apply_visitor(destination_public_key_visitor(), oi.out); + output_entries.push_back(tx_source_entry::output_entry(oi.idx, rct::ctkey({rct::pk2rct(key), rct::identity()}))); + } + } + } + + return 0 == rest && sender_out_found; +} + + +bool fill_unlock_token_sources(map_hash2tx_t &txmap, std::vector &blocks, std::vector &sources, const cryptonote::account_base &from, uint64_t value_amount, size_t nmix, + cryptonote::tx_out_type out_type) +{ + map_output_idx_t outs; + map_output_t outs_mine; + if (!init_output_indices(txmap, outs, outs_mine, blocks, from, cryptonote::tx_out_type::out_staked_token)) + return false; + + if (!init_spent_output_indices(txmap, outs, outs_mine, blocks, from)) + return false; + + // Iterate in reverse is more efficiency + uint64_t sources_locked_token_amount = 0; + bool sources_found = false; + BOOST_REVERSE_FOREACH(const map_output_t::value_type o, outs_mine) + { + for (size_t i = 0; i < o.second.size() && !sources_found; ++i) + { + size_t sender_out = o.second[i]; + const output_index &oi = outs[o.first][sender_out]; + if ((oi.spent) || (oi.token_amount > 0 && out_type == cryptonote::tx_out_type::out_cash) + || (oi.amount > 0 && (out_type == cryptonote::tx_out_type::out_token || out_type == cryptonote::tx_out_type::out_staked_token)) + || (oi.out.type() != typeid(txout_to_script))) + continue; + + + const cryptonote::txout_to_script &out = boost::get(oi.out); + + if (out.output_type != static_cast(cryptonote::tx_out_type::out_staked_token)) + continue; + + cryptonote::tx_source_entry ts = AUTO_VAL_INIT(ts); + ts.token_amount = oi.token_amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_staked_token; + ts.command_type = safex::command_t::token_unstake; + + ts.real_output_in_tx_index = oi.out_no; + ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // incoming tx public key + size_t realOutput; + if (!fill_output_entries(outs[o.first], sender_out, nmix, realOutput, ts.outputs)) + continue; + + ts.real_output = realOutput; + + sources_locked_token_amount = ts.token_amount; + sources_found = value_amount == sources_locked_token_amount; + + if (sources_found) sources.push_back(ts); + + + } + + if (sources_found) + break; + } + + return sources_found; +} + + + + +bool fill_migration_tx_sources(map_hash2tx_t &txmap, std::vector &blocks, std::vector &sources, const cryptonote::account_base &from, + uint64_t token_amount, uint64_t cash_airdrop_amount, const crypto::hash &bitcoin_transaction_hash) +{ + map_output_idx_t outs; + map_output_t outs_mine; + + if (!init_output_indices(txmap, outs, outs_mine, blocks, from)) + return false; + + if (!init_spent_output_indices(txmap, outs, outs_mine, blocks, from)) + return false; + + // Iterate in reverse is more efficiency to get cash for migration transaction + uint64_t sources_cash_amount = 0; + bool sources_found = false; + BOOST_REVERSE_FOREACH(const map_output_t::value_type o, outs_mine) + { + for (size_t i = 0; i < o.second.size() && !sources_found; ++i) + { + size_t sender_out = o.second[i]; + const output_index &oi = outs[o.first][sender_out]; + if (oi.spent) + continue; + + cryptonote::tx_source_entry ts = AUTO_VAL_INIT(ts); + ts.amount = oi.amount; + ts.real_output_in_tx_index = oi.out_no; + ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // incoming tx public key + size_t realOutput; + if (!fill_output_entries(outs[o.first], sender_out, 0 /*nmix*/, realOutput, ts.outputs)) + continue; + + ts.real_output = realOutput; + + sources.push_back(ts); + + sources_cash_amount += ts.amount; + sources_found = cash_airdrop_amount <= sources_cash_amount; + } + + if (sources_found) + break; + } + + //add one migration input + sources.resize(sources.size() + 1); + cryptonote::tx_source_entry &src = sources.back(); + src = boost::value_initialized(); + //Only migration account could sign txin_token_migration + auto output = cryptonote::generate_migration_bitcoin_transaction_output(from.get_keys(), bitcoin_transaction_hash, token_amount); + src.outputs.push_back(output); + src.token_amount = token_amount; + src.referenced_output_type = cryptonote::tx_out_type::out_bitcoin_migration; + + + return sources_found; +} + +void fill_migration_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, const cryptonote::account_base &to, + uint64_t token_amount, uint64_t fee, std::vector &sources, + std::vector &destinations, const crypto::hash &bitcoin_transaction_hash) +{ + sources.clear(); + destinations.clear(); + + const uint64_t cash_airdrop_amount = cryptonote::get_airdrop_cash(token_amount); + + if (!fill_migration_tx_sources(txmap,blocks, sources, from, token_amount, cash_airdrop_amount + fee, bitcoin_transaction_hash)) + throw std::runtime_error("couldn't fill transaction sources"); + + tx_destination_entry de_cash = create_tx_destination(to, cash_airdrop_amount); + destinations.push_back(de_cash); + + + uint64_t cache_back = get_inputs_amount(sources) - (cash_airdrop_amount + fee); + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + tx_destination_entry de_token = create_token_tx_destination(to, token_amount); + destinations.push_back(de_token); + +} + +bool fill_tx_sources(map_hash2tx_t &txmap, std::vector &blocks,std::vector &sources, + const cryptonote::account_base &from, uint64_t value_amount, size_t nmix, + cryptonote::tx_out_type out_type = cryptonote::tx_out_type::out_cash, const crypto::public_key& safex_account_pkey = {}) +{ + map_output_idx_t outs; + map_output_t outs_mine; + if (!init_output_indices(txmap, outs, outs_mine, blocks, from, out_type, safex_account_pkey)) + return false; + + if (!init_spent_output_indices(txmap, outs, outs_mine, blocks, from)) + return false; + + // Iterate in reverse is more efficiency + uint64_t sources_cash_amount = 0; + uint64_t sources_token_amount = 0; + bool sources_found = false; + BOOST_REVERSE_FOREACH(const map_output_t::value_type o, outs_mine) + { + for (size_t i = 0; i < o.second.size() && !sources_found; ++i) + { + size_t sender_out = o.second[i]; + const output_index &oi = outs[o.first][sender_out]; + if ((oi.spent) || (oi.token_amount > 0 && (out_type == cryptonote::tx_out_type::out_cash || out_type == cryptonote::tx_out_type::out_network_fee || out_type == cryptonote::tx_out_type::out_safex_purchase)) || + (oi.amount > 0 && (out_type == cryptonote::tx_out_type::out_token || out_type == cryptonote::tx_out_type::out_staked_token || out_type == cryptonote::tx_out_type::out_safex_account))) + continue; + + if ((out_type == cryptonote::tx_out_type::out_safex_account_update || out_type == cryptonote::tx_out_type::out_safex_offer || out_type == cryptonote::tx_out_type::out_safex_price_peg) + && oi.out_type != cryptonote::tx_out_type::out_safex_account) + continue; + + if (out_type == cryptonote::tx_out_type::out_safex_offer_update && oi.out_type != cryptonote::tx_out_type::out_safex_offer) + continue; + + if(out_type == cryptonote::tx_out_type::out_safex_feedback && oi.out_type != cryptonote::tx_out_type::out_safex_feedback_token) + continue; + + if(out_type == cryptonote::tx_out_type::out_safex_price_peg_update && oi.out_type != cryptonote::tx_out_type::out_safex_price_peg) + continue; + + cryptonote::tx_source_entry ts = AUTO_VAL_INIT(ts); + if (out_type == cryptonote::tx_out_type::out_cash) + { + ts.amount = oi.amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_cash; + } + else if (out_type == cryptonote::tx_out_type::out_token) + { + ts.token_amount = oi.token_amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_token; + } + else if (out_type == cryptonote::tx_out_type::out_staked_token) + { + ts.token_amount = oi.token_amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_token; + ts.command_type = safex::command_t::token_stake; + } + else if (out_type == cryptonote::tx_out_type::out_network_fee) + { + ts.amount = oi.amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_cash; + ts.command_type = safex::command_t::donate_network_fee; + } + else if (out_type == cryptonote::tx_out_type::out_safex_account) + { + ts.token_amount = oi.token_amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_token; + ts.command_type = safex::command_t::create_account; + } + else if (out_type == cryptonote::tx_out_type::out_safex_account_update) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_account; + ts.command_type = safex::command_t::edit_account; + } + else if (out_type == cryptonote::tx_out_type::out_safex_offer) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_account; + ts.command_type = safex::command_t::create_offer; + } + else if (out_type == cryptonote::tx_out_type::out_safex_offer_update) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_offer; + ts.command_type = safex::command_t::edit_offer; + } + else if (out_type == cryptonote::tx_out_type::out_safex_purchase) + { + ts.amount = oi.amount; + ts.referenced_output_type = cryptonote::tx_out_type::out_cash; + ts.command_type = safex::command_t::simple_purchase; + } + else if (out_type == cryptonote::tx_out_type::out_safex_feedback) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_feedback_token; + ts.command_type = safex::command_t::create_feedback; + } + else if (out_type == cryptonote::tx_out_type::out_safex_price_peg) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_account; + ts.command_type = safex::command_t::create_price_peg; + } + else if (out_type == cryptonote::tx_out_type::out_safex_price_peg_update) + { + ts.referenced_output_type = cryptonote::tx_out_type::out_safex_price_peg; + ts.command_type = safex::command_t::update_price_peg; + } + else + { + throw std::runtime_error("unknown referenced output type"); + } + ts.real_output_in_tx_index = oi.out_no; + ts.real_out_tx_key = get_tx_pub_key_from_extra(*oi.p_tx); // incoming tx public key + size_t realOutput; + + switch (out_type) { + case cryptonote::tx_out_type::out_safex_account_update: + case cryptonote::tx_out_type::out_safex_offer: + case cryptonote::tx_out_type::out_safex_offer_update: + case cryptonote::tx_out_type::out_safex_price_peg: + case cryptonote::tx_out_type::out_safex_price_peg_update: + { + if (!fill_output_entries_advanced(outs[static_cast(ts.referenced_output_type)], sender_out, nmix, realOutput, ts.outputs)) + continue; + sources_found = true; + } + break; + + case cryptonote::tx_out_type::out_cash: + case cryptonote::tx_out_type::out_token: + case cryptonote::tx_out_type::out_network_fee: + case cryptonote::tx_out_type::out_staked_token: + case cryptonote::tx_out_type::out_safex_account: + case cryptonote::tx_out_type::out_safex_purchase: + default: + { + if (!fill_output_entries(outs[o.first], sender_out, nmix, realOutput, ts.outputs)) + continue; + } + break; + } + + ts.real_output = realOutput; + + sources.push_back(ts); + + if ((out_type == cryptonote::tx_out_type::out_cash) + || (out_type == cryptonote::tx_out_type::out_network_fee) + || (out_type == cryptonote::tx_out_type::out_safex_purchase)) + { + sources_cash_amount += ts.amount; + sources_found = value_amount <= sources_cash_amount; + } + else if ((out_type == cryptonote::tx_out_type::out_token) + || (out_type == cryptonote::tx_out_type::out_staked_token) + || (out_type == cryptonote::tx_out_type::out_safex_account) + ) + { + sources_token_amount += ts.token_amount; + sources_found = value_amount <= sources_token_amount; + } + else if (out_type == cryptonote::tx_out_type::out_safex_feedback) + sources_found = true; + + + } + + if (sources_found) + break; + } + + return sources_found; +} + +void fill_token_unlock_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, const cryptonote::account_base &to, + uint64_t token_amount, uint64_t fee, size_t nmix, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + //locked token source + if (!fill_unlock_token_sources(txmap, blocks, sources, from, token_amount, nmix)) + throw std::runtime_error("couldn't fill token transaction sources for tokens to unlock"); + + //interest calculation should go here, that will be tested in core tests + + + //locked token destination, there is no token change, all tokens are unlocked + tx_destination_entry de_token = create_token_tx_destination(to, token_amount); + destinations.push_back(de_token); + + //sender change for fee + + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } +} + +void fill_create_account_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const std::string &username, const crypto::public_key &pkey, const std::vector &account_data, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //token amount is amount of tokens we want to lock for a period for creating account + + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + //locked token source + if (!fill_tx_sources(txmap, blocks, sources, from, token_amount, nmix, cryptonote::tx_out_type::out_safex_account)) + throw std::runtime_error("couldn't fill token transaction sources for create account"); + + //update source with new account data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::create_account) { + safex::create_account_data account{username, pkey, account_data}; + ts.command_safex_data = t_serializable_object_to_blob(account); + } + + } + + //destinations + + //locked token destination + tx_destination_entry de_token = create_token_tx_destination(to, token_amount); + destinations.push_back(de_token); + + //destination token change + uint64_t token_back = get_inputs_token_amount(sources) - token_amount; + if (0 < token_back) + { + tx_destination_entry de_token_change = create_token_tx_destination(from, token_back); + destinations.push_back(de_token_change); + } + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //account + tx_destination_entry de_account = create_safex_account_destination(from.get_keys().m_account_address, username, pkey, account_data); + destinations.push_back(de_account); +} + +void fill_edit_account_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const std::string &username, const std::vector &new_account_data, std::vector &sources, + std::vector &destinations, const crypto::public_key& safex_account_pkey = {}) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + if (!fill_tx_sources(txmap, blocks, sources, from, 0, nmix, cryptonote::tx_out_type::out_safex_account_update, safex_account_pkey)) + throw std::runtime_error("couldn't fill token transaction sources for edit account"); + + //update source with new account data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::edit_account) { + safex::edit_account_data editaccount{username, new_account_data}; + ts.command_safex_data = t_serializable_object_to_blob(editaccount); + } + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //new_account + tx_destination_entry de_account = edit_safex_account_destination(from.get_keys().m_account_address, username, new_account_data); + destinations.push_back(de_account); +} + +void fill_create_offer_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const crypto::public_key &pkey, const safex::safex_offer &sfx_offer, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + if (!fill_tx_sources(txmap, blocks, sources, from, 0, nmix, cryptonote::tx_out_type::out_safex_offer, pkey)) + throw std::runtime_error("couldn't fill token transaction sources for create offer"); + + //update source with new offer data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::create_offer) { + safex::create_offer_data offer_data{sfx_offer}; + ts.command_safex_data = t_serializable_object_to_blob(offer_data); + } + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //offer + tx_destination_entry de_offer = create_safex_offer_destination(from.get_keys().m_account_address, sfx_offer); + destinations.push_back(de_offer); +} + +void fill_edit_offer_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const crypto::public_key &pkey, const safex::safex_offer &sfx_offer, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + if (!fill_tx_sources(txmap, blocks, sources, from, 0, nmix, cryptonote::tx_out_type::out_safex_offer_update, pkey)) + throw std::runtime_error("couldn't fill token transaction sources for edit offer"); + + //update source with new edited offer data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::edit_offer) { + safex::edit_offer_data offer_data{sfx_offer}; + ts.command_safex_data = t_serializable_object_to_blob(offer_data); + } + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //offer + tx_destination_entry de_offer = edit_safex_offer_destination(from.get_keys().m_account_address, sfx_offer); + destinations.push_back(de_offer); +} + +void fill_create_purchase_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, uint64_t cash_amount, + uint64_t fee, size_t nmix, const safex::safex_purchase &sfx_purchase, const cryptonote::account_public_address seller_address, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee +// if (!fill_tx_sources(txmap, blocks, sources, from, sfx_purchase.price.price*5/100, nmix, cryptonote::tx_out_type::out_network_fee)) +// throw std::runtime_error("couldn't fill transaction sources"); + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, 0, nmix, cryptonote::tx_out_type::out_safex_purchase)) + throw std::runtime_error("couldn't fill transaction sources for create purchase"); + + + + //update source with create purchase data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::simple_purchase) { + safex::create_purchase_data purchase_data{sfx_purchase}; + ts.command_safex_data = t_serializable_object_to_blob(purchase_data); + } + } + + //destinations + + //fee donation, txout_to_script + + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee - cash_amount; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //purchase + tx_destination_entry de_purchase = create_safex_purchase_destination(seller_address, sfx_purchase); + destinations.push_back(de_purchase); + + //feedback_token + safex::safex_feedback_token sfx_feedback_token; + sfx_feedback_token.offer_id = sfx_purchase.offer_id; + tx_destination_entry de_feedback_token = create_safex_feedback_token_destination(from.get_keys().m_account_address, sfx_feedback_token); + destinations.push_back(de_feedback_token); + + + tx_destination_entry de_donation_fee = AUTO_VAL_INIT(de_donation_fee); + de_donation_fee.addr = from.get_keys().m_account_address; + de_donation_fee.amount = calculate_safex_network_fee(sfx_purchase.price, FAKECHAIN, safex::command_t::simple_purchase); + de_donation_fee.script_output = true; + de_donation_fee.output_type = tx_out_type::out_network_fee; + destinations.push_back(de_donation_fee); + + cryptonote::tx_destination_entry item_purchase_fee = AUTO_VAL_INIT(item_purchase_fee); + item_purchase_fee.addr = seller_address; + item_purchase_fee.amount = sfx_purchase.price - de_donation_fee.amount; + item_purchase_fee.output_type = tx_out_type::out_cash; + destinations.push_back(item_purchase_fee); + +} + +void fill_create_feedback_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, uint64_t cash_amount, + uint64_t fee, size_t nmix, const safex::safex_feedback &sfx_feedback, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + //fill cache sources for feedback token + if (!fill_tx_sources(txmap, blocks, sources, from, 0, nmix, cryptonote::tx_out_type::out_safex_feedback)) + throw std::runtime_error("couldn't fill transaction sources for create feedback"); + + + + //update source with create purchase data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::create_feedback) { + safex::create_feedback_data feedback_data{sfx_feedback}; + ts.command_safex_data = t_serializable_object_to_blob(feedback_data); + } + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //feedback + tx_destination_entry de_feedback = create_safex_feedback_destination(from.get_keys().m_account_address,sfx_feedback); + destinations.push_back(de_feedback); +} + +void fill_create_price_peg_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const crypto::public_key &pkey, const safex::safex_price_peg &sfx_price_peg, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + if (!fill_tx_sources(txmap, blocks, sources, from, 0, nmix, cryptonote::tx_out_type::out_safex_price_peg, pkey)) + throw std::runtime_error("couldn't fill token transaction sources for create price peg"); + + //update source with new price peg data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::create_price_peg) { + safex::create_price_peg_data price_peg_data{sfx_price_peg}; + ts.command_safex_data = t_serializable_object_to_blob(price_peg_data); + } + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //offer + tx_destination_entry de_price_peg = create_safex_price_peg_destination(from.get_keys().m_account_address, sfx_price_peg); + destinations.push_back(de_price_peg); +} + +void fill_update_price_peg_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, uint64_t token_amount, + uint64_t fee, size_t nmix, const crypto::public_key &pkey, const safex::safex_price_peg &sfx_price_peg, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + const cryptonote::account_base &to = from; + + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + if (!fill_tx_sources(txmap, blocks, sources, from, 0, nmix, cryptonote::tx_out_type::out_safex_price_peg_update, pkey)) + throw std::runtime_error("couldn't fill transaction sources for update price peg"); + + //update source with new price peg data + for (auto &ts: sources) { + if (ts.command_type == safex::command_t::update_price_peg) { + safex::update_price_peg_data price_peg_data{sfx_price_peg}; + ts.command_safex_data = t_serializable_object_to_blob(price_peg_data); + } + } + + //destinations + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } + + //offer + tx_destination_entry de_price_peg = update_safex_price_peg_destination(from.get_keys().m_account_address, sfx_price_peg); + destinations.push_back(de_price_peg); +} + +void fill_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, const cryptonote::account_base &to, + uint64_t amount, uint64_t fee, size_t nmix, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + if (!fill_tx_sources(txmap, blocks, sources, from, amount + fee, nmix)) + throw std::runtime_error("couldn't fill transaction sources"); + + tx_destination_entry de = create_tx_destination(to, amount); + destinations.push_back(de); + + uint64_t cache_back = get_inputs_amount(sources) - (amount + fee); + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } +} + +void fill_token_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, const cryptonote::account_base &to, + uint64_t token_amount, uint64_t fee, size_t nmix, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + //token source + if (!fill_tx_sources(txmap, blocks, sources, from, token_amount, nmix, cryptonote::tx_out_type::out_token)) + throw std::runtime_error("couldn't fill token transaction sources"); + + //token destination + tx_destination_entry de = create_token_tx_destination(to, token_amount); + destinations.push_back(de); + + //destination token change + + uint64_t token_back = get_inputs_token_amount(sources) - token_amount; + if (0 < token_back) + { + tx_destination_entry de_token_change = create_token_tx_destination(from, token_back); + destinations.push_back(de_token_change); + } + + //sender change for fee + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } +} + + +void fill_token_lock_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, const cryptonote::account_base &to, + uint64_t token_amount, uint64_t fee, size_t nmix, std::vector &sources, + std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, fee, nmix, cryptonote::tx_out_type::out_cash)) + throw std::runtime_error("couldn't fill transaction sources"); + + //token source + if (!fill_tx_sources(txmap, blocks, sources, from, token_amount, nmix, cryptonote::tx_out_type::out_staked_token)) + throw std::runtime_error("couldn't fill token transaction sources for tokens to lock"); + + //locked token destination + tx_destination_entry de = create_locked_token_tx_destination(to, token_amount); + destinations.push_back(de); + + //destination token change + + uint64_t token_back = get_inputs_token_amount(sources) - token_amount; + if (0 < token_back) + { + tx_destination_entry de_token_change = create_token_tx_destination(from, token_back); + destinations.push_back(de_token_change); + } + + //sender change for fee + + uint64_t cache_back = get_inputs_amount(sources) - fee; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } +} + +uint64_t get_inputs_amount(const std::vector &s) +{ + uint64_t r = 0; + BOOST_FOREACH(const tx_source_entry &e, s) + { + r += e.amount; + } + + return r; +} + + + +void fill_donation_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, uint64_t cash_amount, uint64_t fee, size_t nmix, + std::vector &sources, std::vector &destinations) +{ + sources.clear(); + destinations.clear(); + + //fill cache sources for fee + if (!fill_tx_sources(txmap, blocks, sources, from, fee+cash_amount, nmix, cryptonote::tx_out_type::out_network_fee)) + throw std::runtime_error("couldn't fill transaction sources"); + + //fee donation, txout_to_script + tx_destination_entry de_donation_fee = create_network_fee_tx_destination(cash_amount); + destinations.push_back(de_donation_fee); + + //sender change for fee + + uint64_t cache_back = get_inputs_amount(sources) - fee - cash_amount; + if (0 < cache_back) + { + tx_destination_entry de_change = create_tx_destination(from, cache_back); + destinations.push_back(de_change); + } +} + +crypto::hash get_hash_from_string(const std::string hashstr) +{ + //parse bitcoin transaction hash + cryptonote::blobdata expected_bitcoin_hash_data; + if (!epee::string_tools::parse_hexstr_to_binbuff(std::string(hashstr), expected_bitcoin_hash_data) || expected_bitcoin_hash_data.size() != sizeof(crypto::hash)) + { + std::cerr << "failed to parse bitcoin transaction hash" << std::endl; + return boost::value_initialized(); + } + const crypto::hash bitcoin_transaction_hash = *reinterpret_cast(expected_bitcoin_hash_data.data()); + return bitcoin_transaction_hash; +} + + +bool construct_tx_to_key(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, const cryptonote::account_base &to, uint64_t amount, + uint64_t fee, size_t nmix) +{ + std::vector sources; + std::vector destinations; + fill_tx_sources_and_destinations(txmap, blocks, from, to, amount, fee, nmix, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0); +} + +bool construct_token_tx_to_key(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, const cryptonote::account_base &to, + uint64_t token_amount, uint64_t fee, size_t nmix) +{ + std::vector sources; + std::vector destinations; + fill_token_tx_sources_and_destinations(txmap, blocks, from, to, token_amount, fee, nmix, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0); +} + +bool construct_migration_tx_to_key(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, const cryptonote::account_base &to, uint64_t token_amount, + uint64_t fee, const crypto::hash &bitcoin_hash) +{ + std::vector sources; + std::vector destinations; + fill_migration_tx_sources_and_destinations(txmap, blocks, from, to, token_amount, fee, sources, destinations, bitcoin_hash); + + std::vector extra; + add_bitcoin_hash_to_extra(extra, bitcoin_hash); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, extra, tx, 0); +} + +bool construct_token_stake_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, const cryptonote::account_base &to, + uint64_t token_amount, uint64_t fee, size_t nmix) +{ + std::vector sources; + std::vector destinations; + fill_token_lock_tx_sources_and_destinations(txmap, blocks, from, to, token_amount, fee, nmix, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0); +} + +bool construct_token_unstake_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, + const cryptonote::account_base &from, const cryptonote::account_base &to, uint64_t token_amount, uint64_t fee, size_t nmix) +{ + std::vector sources; + std::vector destinations; + fill_token_unlock_tx_sources_and_destinations(txmap, blocks, from, to, token_amount, fee, nmix, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0); +} + +bool construct_fee_donation_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, + const cryptonote::account_base &from, uint64_t cash_amount, uint64_t fee, size_t nmix) +{ + std::vector sources; + std::vector destinations; + + fill_donation_tx_sources_and_destinations(txmap, blocks, from, cash_amount, fee, nmix, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0); +} + + +bool construct_create_account_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const std::string &username, const crypto::public_key &pkey, const std::vector &account_data, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_create_account_tx_sources_and_destinations(txmap, blocks, from, SAFEX_CREATE_ACCOUNT_TOKEN_LOCK_FEE, fee, nmix, username, pkey, account_data, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0, sfx_acc_keys); +} + +bool construct_edit_account_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const std::string &username, const std::vector &new_account_data, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_edit_account_tx_sources_and_destinations(txmap, blocks, from, 0, fee, nmix, username, new_account_data, sources, destinations, sfx_acc_keys.m_public_key); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0, sfx_acc_keys); +} + +bool construct_create_offer_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_offer &sfx_offer, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_create_offer_tx_sources_and_destinations(txmap, blocks, from, 0, fee, nmix, pkey, sfx_offer, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0, sfx_acc_keys); +} + +bool construct_edit_offer_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_offer &sfx_offer, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_edit_offer_tx_sources_and_destinations(txmap, blocks, from, 0, fee, nmix, pkey, sfx_offer, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0, sfx_acc_keys); +} + +bool construct_create_purchase_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, + uint64_t fee, size_t nmix, const safex::safex_purchase &sfx_purchase, const cryptonote::account_public_address seller_address) +{ + std::vector sources; + std::vector destinations; + fill_create_purchase_tx_sources_and_destinations(txmap, blocks, from, sfx_purchase.price, fee, nmix, sfx_purchase, seller_address, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0); +} + +bool construct_create_feedback_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, + uint64_t fee, size_t nmix, const safex::safex_feedback &sfx_feedback) +{ + std::vector sources; + std::vector destinations; + fill_create_feedback_tx_sources_and_destinations(txmap, blocks, from, 0, fee, nmix, sfx_feedback, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0); +} + +bool construct_create_price_peg_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_price_peg &sfx_price_peg, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_create_price_peg_tx_sources_and_destinations(txmap, blocks, from, 0, fee, nmix, pkey, sfx_price_peg, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0, sfx_acc_keys); +} + +bool construct_update_price_peg_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_price_peg &sfx_price_peg, const safex::safex_account_keys &sfx_acc_keys) +{ + std::vector sources; + std::vector destinations; + fill_update_price_peg_tx_sources_and_destinations(txmap, blocks, from, 0, fee, nmix, pkey, sfx_price_peg, sources, destinations); + + return construct_tx(from.get_keys(), sources, destinations, from.get_keys().m_account_address, std::vector(), tx, 0, sfx_acc_keys); +} + +uint64_t get_inputs_token_amount(const std::vector &s) +{ + uint64_t r = 0; + BOOST_FOREACH(const tx_source_entry &e, s) + { + r += e.token_amount; + } + + return r; +} + + + + +bool construct_block(cryptonote::block &blk, uint64_t height, const crypto::hash &prev_id, + const cryptonote::account_base &miner_acc, uint64_t timestamp, uint64_t already_generated_coins, + std::vector &block_sizes, const std::list &tx_list, size_t &actual_block_size) +{ + blk.major_version = CURRENT_BLOCK_MAJOR_VERSION; + blk.minor_version = CURRENT_BLOCK_MINOR_VERSION; + blk.timestamp = timestamp; + blk.prev_id = prev_id; + + blk.tx_hashes.reserve(tx_list.size()); + BOOST_FOREACH(const transaction &tx, tx_list) + { + crypto::hash tx_hash; + get_transaction_hash(tx, tx_hash); + blk.tx_hashes.push_back(tx_hash); + } + + uint64_t total_fee = 0; + size_t txs_size = 0; + BOOST_FOREACH(auto &tx, tx_list) + { + uint64_t fee = 0; + bool r = get_tx_fee(tx, fee); + CHECK_AND_ASSERT_MES(r, false, "wrong transaction passed to construct_block"); + total_fee += fee; + txs_size += get_object_blobsize(tx); + } + + blk.miner_tx = AUTO_VAL_INIT(blk.miner_tx); + size_t target_block_size = txs_size + get_object_blobsize(blk.miner_tx); + while (true) + { + if (!construct_miner_tx(height, epee::misc_utils::median(block_sizes), already_generated_coins, target_block_size, total_fee, miner_acc.get_keys().m_account_address, blk.miner_tx, blobdata(), 10)) + return false; + + actual_block_size = txs_size + get_object_blobsize(blk.miner_tx); + if (target_block_size < actual_block_size) + { + target_block_size = actual_block_size; + } + else if (actual_block_size < target_block_size) + { + size_t delta = target_block_size - actual_block_size; + blk.miner_tx.extra.resize(blk.miner_tx.extra.size() + delta, 0); + actual_block_size = txs_size + get_object_blobsize(blk.miner_tx); + if (actual_block_size == target_block_size) + { + break; + } + else + { + CHECK_AND_ASSERT_MES(target_block_size < actual_block_size, false, "Unexpected block size"); + delta = actual_block_size - target_block_size; + blk.miner_tx.extra.resize(blk.miner_tx.extra.size() - delta); + actual_block_size = txs_size + get_object_blobsize(blk.miner_tx); + if (actual_block_size == target_block_size) + { + break; + } + else + { + CHECK_AND_ASSERT_MES(actual_block_size < target_block_size, false, "Unexpected block size"); + blk.miner_tx.extra.resize(blk.miner_tx.extra.size() + delta, 0); + target_block_size = txs_size + get_object_blobsize(blk.miner_tx); + } + } + } + else + { + break; + } + } + + // Nonce search... + blk.nonce = 0; + while (!find_nonce_for_given_block(blk, 1 /*test difficulty*/, height)) + { + blk.timestamp++; + } + + return true; +} + +bool construct_block(cryptonote::block &blk, uint64_t height, const crypto::hash &prev_id, const cryptonote::account_base &miner_acc, uint64_t timestamp, size_t &block_size, std::list tx_list) +{ + std::vector block_sizes; + return construct_block(blk, height, prev_id, miner_acc, timestamp, 0, block_sizes, tx_list, block_size); +} + +void remove_files(std::vector filenames, std::string prefix) +{ + // remove each file the db created, making sure it starts with fname. + for (auto &f : filenames) + { + if (boost::starts_with(f, prefix)) + { + boost::filesystem::remove(f); + } + else + { + std::cerr << "File created by test not to be removed (for safety): " << f << std::endl; + } + } + + // remove directory if it still exists + boost::filesystem::remove_all(prefix); +} diff --git a/tests/unit_tests/safex_db/simple_purchase.cpp b/tests/unit_tests/safex_db/simple_purchase.cpp new file mode 100644 index 000000000..d130ebbca --- /dev/null +++ b/tests/unit_tests/safex_db/simple_purchase.cpp @@ -0,0 +1,900 @@ +// Copyright (c) 2018, The Safex 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) 2014-2018 The Monero Project + +#include +#include +#include +#include + +#include "gtest/gtest.h" + +#include "string_tools.h" +#include "blockchain_db/blockchain_db.h" +#include "blockchain_db/lmdb/db_lmdb.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "safex/safex_account.h" +#include "safex/safex_offer.h" +#include "safex/safex_purchase.h" +#include "safex/safex_feedback.h" +#include "../safex_test_common.h" + + +using namespace cryptonote; +using epee::string_tools::pod_to_hex; + +#define ASSERT_HASH_EQ(a, b) ASSERT_EQ(pod_to_hex(a), pod_to_hex(b)) + +namespace +{ // anonymous namespace + + const int NUMBER_OF_BLOCKS = 30; + const int NUMBER_OF_BLOCKS1 = 15; + const int NUMBER_OF_BLOCKS2 = 20; + const int NUMBER_OF_BLOCKS3 = 30; + const uint64_t default_miner_fee = ((uint64_t) 500000000); + const std::string bitcoin_tx_hashes_str[6] = {"3b7ac2a66eded32dcdc61f0fec7e9ddb30ccb3c6f5f06c0743c786e979130c5f", "3c904e67190d2d8c5cc93147c1a3ead133c61fc3fa578915e9bf95544705e63c", + "2d825e690c4cb904556285b74a6ce565f16ba9d2f09784a7e5be5f7cdb05ae1d", "89352ec1749c872146eabddd56cd0d1492a3be6d2f9df98f6fbbc0d560120182"}; + + class SafexPurchaseCommand : public ::testing::Test + { + public: + SafexPurchaseCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + class SafexFeedbackCommand : public ::testing::Test + { + public: + SafexFeedbackCommand() { + crypto::public_key pubKey; + epee::string_tools::hex_to_pod("229d8c9229ba7aaadcd575cc825ac2bd0301fff46cc05bd01110535ce43a15d1", pubKey); + keys.push_back(pubKey); + } + protected: + std::vector keys; + TestDB m_db; + }; + + template + class SimplePurchaseTest : public testing::Test + { + protected: + + SimplePurchaseTest() : m_db(new T(false, cryptonote::network_type::FAKECHAIN)), m_hardfork(*m_db, 1, 0) + { + m_test_sizes = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_coins = std::vector(NUMBER_OF_BLOCKS, 60); + m_test_coins[0] = 2000 * SAFEX_CASH_COIN; //genesis tx airdrop + m_test_tokens = std::vector(NUMBER_OF_BLOCKS, 0); + m_test_tokens[0] = 4000 * SAFEX_TOKEN; + m_test_diffs = std::vector(NUMBER_OF_BLOCKS, 200); + m_test_diffs[0] = 1; + m_test_diffs[1] = 100; + m_test_diffs[2] = 180; + + m_miner_acc.generate(); + m_users_acc[0].generate(); + m_users_acc[1].generate(); + + m_safex_account1_keys.generate(); + m_safex_account2_keys.generate(); + + + + m_safex_account1.username = "user1"; + m_safex_account1.pkey = m_safex_account1_keys.get_keys().m_public_key; + m_safex_account1.account_data = {'s','m','o','r'}; + m_safex_account2.username = "user2"; + m_safex_account2.pkey = m_safex_account2_keys.get_keys().m_public_key; + + std::cout << "Alice public key: " << epee::string_tools::pod_to_hex(m_safex_account1_keys.get_keys().m_public_key) << std::endl; + std::cout << "Alice private key: " << epee::string_tools::pod_to_hex(m_safex_account1_keys.get_keys().m_secret_key) << std::endl; + + const std::string data1_new_str = "Another data tesst for edit"; + data1_new = std::vector(data1_new_str.begin(), data1_new_str.end()); + + + m_safex_offer[0] = safex::safex_offer("Apple", 10, 10*SAFEX_CASH_COIN,"This is an apple", m_safex_account1.username,m_users_acc[0].get_keys().m_view_secret_key,m_users_acc[0].get_keys().m_account_address); + m_safex_offer[1] = safex::safex_offer("Barbie", 30, 50*SAFEX_CASH_COIN,"This is a Barbie", m_safex_account2.username,m_users_acc[0].get_keys().m_view_secret_key,m_users_acc[0].get_keys().m_account_address); + + m_safex_purchase = safex::safex_purchase{1, m_safex_offer[0].price, m_safex_offer[0].offer_id, m_safex_offer[0].get_hash(), true}; + + m_safex_feedback = safex::safex_feedback{3,"Eating it all day", m_safex_offer[0].offer_id}; + + offers_total_fee = calculate_safex_network_fee(m_safex_purchase.price, FAKECHAIN, safex::command_t::simple_purchase); + + + std::string new_str_desc{"Now without worms!!"}; + std::vector new_desc{new_str_desc.begin(),new_str_desc.end()}; + m_edited_safex_offer = m_safex_offer[1]; + m_edited_safex_offer.description = new_desc; + m_edited_safex_offer.active = false; + + + for (int i = 0; i < NUMBER_OF_BLOCKS; i++) + { + block blk; + std::list tx_list; // fill tx list with transactions for that block + crypto::hash prev_hash = boost::value_initialized();/* null hash*/ + + if (i > 0) prev_hash = cryptonote::get_block_hash(m_blocks[i - 1]); + + if (i == 0) + { + //skip, genesis block + } + else if (i == 1) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_migration_tx_to_key(m_txmap, m_blocks, tx, m_miner_acc, m_users_acc[0], m_test_tokens[0], default_miner_fee, get_hash_from_string(bitcoin_tx_hashes_str[0])); + m_txmap[get_transaction_hash(tx)] = tx; + } + else if (i == 2) + { + //distribute tokens and coins to accounts as starter + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_token_tx_to_key(m_txmap, m_blocks, tx, m_users_acc[0], m_users_acc[1], 1000 * SAFEX_TOKEN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_tx_to_key(m_txmap, m_blocks, tx2, m_miner_acc, m_users_acc[0], 100 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx2)] = tx2; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx3 = tx_list.back(); \ + construct_tx_to_key(m_txmap, m_blocks, tx3, m_miner_acc, m_users_acc[1], 200 * SAFEX_CASH_COIN, default_miner_fee, 0); + m_txmap[get_transaction_hash(tx3)] = tx3; + } + else if (i == 5) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_account_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.username, m_safex_account1.pkey, m_safex_account1.account_data, m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_create_account_transaction(m_txmap, m_blocks, tx2, m_users_acc[1], default_miner_fee, 0, m_safex_account2.username, m_safex_account2.pkey, m_safex_account2.account_data, m_safex_account2_keys.get_keys()); + m_txmap[get_transaction_hash(tx2)] = tx2; + } + else if (i == 7) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_offer_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_account1.pkey, m_safex_offer[0], m_safex_account1_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_create_offer_transaction(m_txmap, m_blocks, tx2, m_users_acc[1], default_miner_fee, 0, m_safex_account2.pkey, m_safex_offer[1], m_safex_account2_keys.get_keys()); + m_txmap[get_transaction_hash(tx2)] = tx2; + } + else if (i == 12) + { + + } + else if (i == 14) + { + + } + else if (i == 16) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_edit_offer_transaction(m_txmap, m_blocks, tx, m_users_acc[1], default_miner_fee, 0, m_safex_account2.pkey, m_edited_safex_offer, m_safex_account2_keys.get_keys()); + m_txmap[get_transaction_hash(tx)] = tx; + + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx2 = tx_list.back(); \ + construct_create_purchase_transaction(m_txmap, m_blocks, tx2, m_users_acc[0], default_miner_fee, 0, m_safex_purchase,m_users_acc[1].get_keys().m_account_address); + m_txmap[get_transaction_hash(tx2)] = tx2; + } + else if (i == 25) + { + tx_list.resize(tx_list.size() + 1); + cryptonote::transaction &tx = tx_list.back(); \ + construct_create_feedback_transaction(m_txmap, m_blocks, tx, m_users_acc[0], default_miner_fee, 0, m_safex_feedback); + m_txmap[get_transaction_hash(tx)] = tx; + } + + + construct_block(blk, i, prev_hash, m_miner_acc, 0, m_test_sizes[i], tx_list); + + m_txs.push_back(std::vector{tx_list.begin(), tx_list.end()}); + m_blocks.push_back(blk); + } + } + + + ~SimplePurchaseTest() + { + delete m_db; + remove_files(m_filenames, m_prefix); + } + + BlockchainDB *m_db; + HardFork m_hardfork; + std::string m_prefix; + std::vector m_blocks; + //std::unordered_map + map_hash2tx_t m_txmap; //vector of all transactions + std::vector > m_txs; + std::vector m_filenames; + + cryptonote::account_base m_miner_acc; + cryptonote::account_base m_users_acc[2]; + + std::vector m_test_sizes; + std::vector m_test_coins; + std::vector m_test_tokens; + std::vector m_test_diffs; + + safex::safex_account_key_handler m_safex_account1_keys{}; + safex::safex_account_key_handler m_safex_account2_keys{}; + safex::safex_account m_safex_account1; + safex::safex_account m_safex_account2; + + safex::safex_offer m_safex_offer[2]; + + safex::safex_offer m_edited_safex_offer; + + safex::safex_purchase m_safex_purchase; + + safex::safex_feedback m_safex_feedback; + + std::vector data1_new; + + uint64_t offers_total_fee; + + + void init_hard_fork() + { + m_hardfork.init(); + m_db->set_hard_fork(&m_hardfork); + } + + void get_filenames() + { + m_filenames = m_db->get_filenames(); + for (auto &f : m_filenames) + { + std::cerr << "File created by test: " << f << std::endl; + } + } + + + void set_prefix(const std::string &prefix) + { + m_prefix = prefix; + } + }; + + using testing::Types; + + typedef Types implementations; + + TYPED_TEST_CASE(SimplePurchaseTest, implementations); + +#if 1 + + TEST_F(SafexPurchaseCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::simple_purchase), safex::command_exception); + + } + + TEST_F(SafexFeedbackCommand, HandlesCorruptedArrayOfBytes) + { + + std::vector serialized_command = {0x32, 0x32, 0x13, 0x43, 0x12, 0x3, 0x4, 0x5, 0x5, 0x6, 0x32, 0x12, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16}; + + //deserialize + EXPECT_THROW(safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_feedback), safex::command_exception); + + } + + TEST_F(SafexPurchaseCommand, HandlesUnknownProtocolVersion) + { + + safex::create_purchase_data purchase_data{}; + try + { + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, purchase_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexFeedbackCommand, HandlesUnknownProtocolVersion) + { + + safex::create_feedback_data feedback_data{}; + try + { + safex::create_feedback command1{SAFEX_COMMAND_PROTOCOL_VERSION + 1, feedback_data}; + FAIL() << "Should throw exception with message invalid command"; + } + catch (safex::command_exception &exception) + { + ASSERT_STREQ(std::string(("Unsupported command protocol version " + std::to_string(SAFEX_COMMAND_PROTOCOL_VERSION + 1))).c_str(), std::string(exception.what()).c_str()); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + } + + TEST_F(SafexPurchaseCommand, HandlesCommandParsing) + { + + crypto::hash offer_id; + crypto::hash offer_hash; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(1, 100, offer_id, offer_hash, false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::simple_purchase) << "Safex purchase command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::simple_purchase); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_offerid(), dynamic_cast(command2.get())->get_offerid()) << "Original and deserialized command must have same offer ID"; + ASSERT_EQ(command1.get_quantity(), dynamic_cast(command2.get())->get_quantity()) << "Original and deserialized command must have same quantity"; + ASSERT_EQ(command1.get_price(), dynamic_cast(command2.get())->get_price()) << "Original and deserialized command must have same price"; + ASSERT_EQ(command1.get_shipping(), dynamic_cast(command2.get())->get_shipping()) << "Original and deserialized command must have same shipping"; + + } + + TEST_F(SafexFeedbackCommand, HandlesCommandParsing) + { + + crypto::hash offer_id; + + safex::safex_feedback sfx_feedback = safex::safex_feedback(1, "100", offer_id); + + safex::create_feedback_data feedback_data{sfx_feedback}; + + safex::create_feedback command1{SAFEX_COMMAND_PROTOCOL_VERSION , feedback_data}; + //serialize + std::vector serialized_command; + safex::safex_command_serializer::serialize_safex_object(command1, serialized_command); + + safex::command_t command_type = safex::safex_command_serializer::get_command_type(serialized_command); + ASSERT_EQ(command_type, safex::command_t::create_feedback) << "Safex feedback command type not properly parsed from binary blob"; + + //deserialize + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(serialized_command, safex::command_t::create_feedback); + + ASSERT_EQ(command1.get_version(), command2->get_version()) << "Original and deserialized command must have same version"; + ASSERT_EQ(command1.get_command_type(), command2->get_command_type()) << "Original and deserialized command must have same command type"; + ASSERT_EQ(command1.get_offerid(), dynamic_cast(command2.get())->get_offerid()) << "Original and deserialized command must have same offer ID"; + ASSERT_EQ(command1.get_stars_given(), dynamic_cast(command2.get())->get_stars_given()) << "Original and deserialized command must have same rating"; + ASSERT_EQ(command1.get_comment(), dynamic_cast(command2.get())->get_comment()) << "Original and deserialized command must have same comment"; + + } + + TYPED_TEST(SimplePurchaseTest, CreatePurchaseCommand) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + bool result; + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS1; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + //Checking created offers + for (auto safex_offer: this->m_safex_offer) { + + safex::safex_offer saved_offer; + result = this->m_db->get_offer(safex_offer.offer_id,saved_offer); + ASSERT_TRUE(result); + ASSERT_TRUE(std::equal(safex_offer.description.begin(), safex_offer.description.end(), + saved_offer.description.begin())); + ASSERT_EQ(safex_offer.title,saved_offer.title); + + std::string username; + result = this->m_db->get_offer_seller(safex_offer.offer_id, username); + ASSERT_TRUE(result); + ASSERT_EQ(username.compare(safex_offer.seller), 0); + + uint64_t price; + result = this->m_db->get_offer_price(safex_offer.offer_id, price); + ASSERT_TRUE(result); + ASSERT_EQ(price, safex_offer.price); + + uint64_t quantity; + result = this->m_db->get_offer_quantity(safex_offer.offer_id, quantity); + ASSERT_TRUE(result); + ASSERT_EQ(safex_offer.quantity, quantity); + + bool active; + result = this->m_db->get_offer_active_status(safex_offer.offer_id, active); + ASSERT_TRUE(result); + ASSERT_EQ(safex_offer.active, active); + + } + + for (int i = NUMBER_OF_BLOCKS1; i < NUMBER_OF_BLOCKS2; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + //Checking the quantity for purchased offer is reduced + safex::safex_offer purchased_offer; + result = this->m_db->get_offer(this->m_safex_purchase.offer_id,purchased_offer); + ASSERT_TRUE(result); + ASSERT_EQ(this->m_safex_offer[0].quantity-this->m_safex_purchase.quantity, purchased_offer.quantity); + //Checking edited offer + safex::safex_offer saved_offer; + + for (int i = NUMBER_OF_BLOCKS2; i < NUMBER_OF_BLOCKS3; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + uint64_t stars_given; + result = this->m_db->get_offer_stars_given(this->m_safex_purchase.offer_id, stars_given); + ASSERT_TRUE(result); + ASSERT_EQ(this->m_safex_feedback.stars_given*COIN, stars_given); + + uint64_t fee_sum = 0; + + for(int i=0;im_db->get_network_fee_sum_for_interval(i); + } + ASSERT_EQ(fee_sum,this->offers_total_fee); + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SimplePurchaseTest, CreatePurchaseExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS2; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex offer doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::simple_purchase; + + crypto::hash offer_id{}; + crypto::hash offer_hash{}; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(1, 100, offer_id, offer_hash, false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::simple_purchase); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer isn't active + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::simple_purchase; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(1, 100, this->m_edited_safex_offer.offer_id, this->m_edited_safex_offer.get_hash(), false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::simple_purchase); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_purchase_offer_not_active); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer isn't active"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex offer doesn't have enough in stock + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::simple_purchase; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(this->m_safex_offer[0].quantity + 1, 100, this->m_safex_offer[0].offer_id, this->m_safex_offer[0].get_hash(), false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::simple_purchase); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_purchase_out_of_stock); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer doesn't have enough"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex purchase quantity cannot be zero + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::simple_purchase; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(0, 100, this->m_safex_offer[0].offer_id, this->m_safex_offer[0].get_hash(), false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::simple_purchase); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_purchase_quantity_zero); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex purchase quantity is zero"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex purchase not enough funds registred + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::simple_purchase; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(1, this->m_safex_offer[0].price-1, this->m_safex_offer[0].offer_id, this->m_safex_offer[0].get_hash(), false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::simple_purchase); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_purchase_not_enough_funds); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex purchase given not enough funds"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex purchase wrong offer hash + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::simple_purchase; + + safex::safex_purchase sfx_purchase = safex::safex_purchase(1, this->m_safex_offer[0].price, this->m_safex_offer[0].offer_id, this->m_safex_offer[1].get_hash(), false); + + safex::create_purchase_data purchase_data{sfx_purchase}; + + safex::simple_purchase command1{SAFEX_COMMAND_PROTOCOL_VERSION , purchase_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::simple_purchase); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_purchase_wrong_hash); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex purchase given not enough funds"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + + TYPED_TEST(SimplePurchaseTest, CreateFeedbackExceptions) { + boost::filesystem::path tempPath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path(); + std::string dirPath = tempPath.string(); + + this->set_prefix(dirPath); + + // make sure open does not throw + ASSERT_NO_THROW(this->m_db->open(dirPath)); + this->get_filenames(); + this->init_hard_fork(); + + for (int i = 0; i < NUMBER_OF_BLOCKS2; i++) { + ASSERT_NO_THROW(this->m_db->add_block(this->m_blocks[i], this->m_test_sizes[i], this->m_test_diffs[i], + this->m_test_coins[i], this->m_test_tokens[i], this->m_txs[i])); + } + + // Safex offer doesn't exist + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_feedback; + txinput.key_offsets.push_back(0); + + crypto::hash offer_id{}; + + safex::safex_feedback sfx_feedback = safex::safex_feedback(1, "100", offer_id); + + safex::create_feedback_data feedback_data{sfx_feedback}; + + safex::create_feedback command1{SAFEX_COMMAND_PROTOCOL_VERSION , feedback_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_feedback); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_offer_non_existant); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex offer doesn't exist"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Given rating is higher than valid + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_feedback; + txinput.key_offsets.push_back(0); + + safex::safex_feedback sfx_feedback = safex::safex_feedback(4, "100", this->m_edited_safex_offer.offer_id); + + safex::create_feedback_data feedback_data{sfx_feedback}; + + safex::create_feedback command1{SAFEX_COMMAND_PROTOCOL_VERSION , feedback_data}; + + + safex::safex_command_serializer::serialize_safex_object(command1, txinput.script); + + std::unique_ptr command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_feedback); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_feedback_invalid_rating); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex feedback ratign higher than valid"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + // Safex feedback comment is too big + try + { + cryptonote::txin_to_script txinput = AUTO_VAL_INIT(txinput); + txinput.command_type = safex::command_t::create_feedback; + txinput.key_offsets.push_back(0); + + safex::safex_feedback sfx_feedback = safex::safex_feedback(3, "100", this->m_edited_safex_offer.offer_id); + + sfx_feedback.comment = ""; + for(int i=0; i command2 = safex::safex_command_serializer::parse_safex_object(txinput.script, safex::command_t::create_feedback); + + safex::execution_status status = command2->validate(*(this->m_db), txinput); + ASSERT_EQ(status, safex::execution_status::error_feedback_data_too_big); + + std::unique_ptr result{command2->execute(*(this->m_db), txinput)}; + FAIL() << "Should throw exception with Safex feedback comment is too big"; + + } + catch (safex::command_exception &exception) + { + + } + catch (std::exception &exception) + { + FAIL() << "Exception happened " << exception.what(); + } + catch (...) + { + FAIL() << "Unexpected exception"; + } + + ASSERT_NO_THROW(this->m_db->close()); + + } + +#endif + +} // anonymous namespace diff --git a/tests/unit_tests/safex_test_common.h b/tests/unit_tests/safex_test_common.h new file mode 100644 index 000000000..6a039f741 --- /dev/null +++ b/tests/unit_tests/safex_test_common.h @@ -0,0 +1,298 @@ +// +// Created by amarko on 19.4.19.. +// + +#ifndef SAFEX_SAFEX_TEST_COMMON_H +#define SAFEX_SAFEX_TEST_COMMON_H + +#include "blockchain_db/blockchain_db.h" +#include "blockchain_db/lmdb/db_lmdb.h" +#include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/cryptonote_tx_utils.h" +#include "safex/safex_account.h" +#include "safex/safex_offer.h" +#include "safex/safex_purchase.h" +#include "safex/safex_feedback.h" + +using namespace cryptonote; + +class TestDB: public BlockchainDB { +public: + TestDB() {}; + virtual void open(const std::string& filename, const int db_flags = 0) override{ } + virtual void close() override{} + virtual void sync() override{} + virtual void safesyncmode(const bool onoff) override{} + virtual void reset() override{} + virtual std::vector get_filenames() const override{ return std::vector(); } + virtual std::string get_db_name() const override{ return std::string(); } + virtual bool lock() override{ return true; } + virtual void unlock() override{ } + virtual bool batch_start(uint64_t batch_num_blocks=0, uint64_t batch_bytes=0) override{ return true; } + virtual void batch_stop() override{} + virtual void batch_abort() override{} + virtual void set_batch_transactions(bool) override{} + virtual void block_txn_start(bool readonly=false) override{} + virtual void block_txn_stop() override{} + virtual void block_txn_abort() override{} + virtual void drop_hard_fork_info() override{} + virtual bool block_exists(const crypto::hash& h, uint64_t *height) const override{ return false; } + virtual blobdata get_block_blob_from_height(const uint64_t& height) const override{ return cryptonote::t_serializable_object_to_blob(get_block_from_height(height)); } + virtual blobdata get_block_blob(const crypto::hash& h) const override{ return blobdata(); } + virtual bool get_tx_blob(const crypto::hash& h, cryptonote::blobdata &tx) const override{ return false; } + virtual uint64_t get_block_height(const crypto::hash& h) const override{ return 0; } + virtual block_header get_block_header(const crypto::hash& h) const override{ return block_header(); } + virtual uint64_t get_block_timestamp(const uint64_t& height) const override{ return 0; } + virtual uint64_t get_top_block_timestamp() const override{ return 0; } + virtual size_t get_block_size(const uint64_t& height) const override{ return 128; } + virtual difficulty_type get_block_cumulative_difficulty(const uint64_t& height) const override{ return 10; } + virtual difficulty_type get_block_difficulty(const uint64_t& height) const override{ return 0; } + virtual uint64_t get_block_already_generated_coins(const uint64_t& height) const override{ return 10000000000; } + virtual uint64_t get_block_already_migrated_tokens(const uint64_t& height) const override{ return 10000000000; } + virtual crypto::hash get_block_hash_from_height(const uint64_t& height) const override{ return crypto::hash(); } + virtual std::vector get_blocks_range(const uint64_t& h1, const uint64_t& h2) const override{ return std::vector(); } + virtual std::vector get_hashes_range(const uint64_t& h1, const uint64_t& h2) const override{ return std::vector(); } + virtual crypto::hash top_block_hash() const override{ return crypto::hash(); } + virtual block get_top_block() const override{ return block(); } + virtual uint64_t height() const override{ return blocks.size(); } + virtual bool tx_exists(const crypto::hash& h) const override{ return false; } + virtual bool tx_exists(const crypto::hash& h, uint64_t& tx_index) const override{ return false; } + virtual uint64_t get_tx_unlock_time(const crypto::hash& h) const override{ return 0; } + virtual transaction get_tx(const crypto::hash& h) const override{ return transaction(); } + virtual bool get_tx(const crypto::hash& h, transaction &tx) const override{ return false; } + virtual uint64_t get_tx_count() const override{ return 0; } + virtual std::vector get_tx_list(const std::vector& hlist) const override{ return std::vector(); } + virtual uint64_t get_tx_block_height(const crypto::hash& h) const override{ return 0; } + virtual uint64_t get_num_outputs(const uint64_t& amount, const tx_out_type output_type) const override{ return 1; } + virtual uint64_t get_num_outputs(const tx_out_type output_type) const override{return 1;} + virtual uint64_t get_indexing_base() const override{ return 0; } + virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const override{ return output_data_t(); } + virtual output_advanced_data_t get_output_advanced_data(const tx_out_type output_type, const uint64_t output_index) const override{ return output_advanced_data_t{}; } + virtual bool get_output_id(const tx_out_type output_type, const uint64_t output_index, uint64_t& output_id) const override{ return 0; } + virtual tx_out_index get_output_tx_and_index_from_global(const uint64_t& index) const override{ return tx_out_index(); } + virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index, const tx_out_type output_type) const override{ return tx_out_index(); } + virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices, const tx_out_type output_type) const override{} + virtual void get_amount_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs, const tx_out_type output_type, bool allow_partial = false) const override{} + virtual void get_advanced_output_key(const std::vector &output_indexes, std::vector &outputs, const tx_out_type output_type, bool allow_partial = false) const override{} + virtual bool can_thread_bulk_indices() const override{ return false; } + virtual std::vector get_tx_output_indices(const crypto::hash& h) const { return std::vector(); } + virtual std::vector get_tx_amount_output_indices(const uint64_t tx_index) const override{ return std::vector(); } + virtual bool has_key_image(const crypto::key_image& img) const override{ return false; } + virtual void remove_block() override{ blocks.pop_back(); } + virtual uint64_t add_transaction_data(const crypto::hash& blk_hash, const transaction& tx, const crypto::hash& tx_hash) override{return 0;} + virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) override{} + virtual void remove_unstake_token(const crypto::hash& tx_hash, const transaction& tx) override{} + virtual uint64_t add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time, const rct::key *commitment) override{return 0;} + virtual void add_tx_amount_output_indices(const uint64_t tx_index, const std::vector& amount_output_indices) override{} + virtual void add_spent_key(const crypto::key_image& k_image) override{} + virtual void remove_spent_key(const crypto::key_image& k_image) override{} + virtual void process_command_input(const cryptonote::txin_to_script &txin) override{} + virtual uint64_t update_staked_token_sum_for_interval(const uint64_t interval_starting_block, const int64_t delta) {return 0;} + virtual uint64_t update_staked_token_for_interval(const uint64_t interval, const uint64_t new_staked_tokens_in_interval) override{ return 0;} + virtual bool remove_staked_token_for_interval(const uint64_t interval) override{return true;}; + virtual uint64_t update_network_fee_sum_for_interval(const uint64_t interval_starting_block, const uint64_t collected_fee) override{return 0;} + virtual bool get_account_key(const safex::account_username &username, crypto::public_key &pkey) const override{ return true;} + virtual bool get_account_data(const safex::account_username &username, std::vector &data) const override{ return false;} + virtual bool get_offer(const crypto::hash offer_id, safex::safex_offer &offer) const override{ return true;} + virtual bool get_offer_seller(const crypto::hash offer_id, std::string &username) const override{ return true; }; + virtual bool get_offer_price(const crypto::hash offer_id, uint64_t &price) const override{ return true; }; + virtual bool get_offer_quantity(const crypto::hash offer_id, uint64_t &quantity) const override{ return true; }; + virtual bool get_offer_active_status(const crypto::hash offer_id, bool &active) const override{ return true; }; + virtual bool get_safex_accounts(std::vector> &accounts) const override{ return true; }; + virtual bool get_safex_offers(std::vector &offers) const override{ return true; }; + virtual bool get_safex_offer_height( crypto::hash &offer_id, uint64_t& height) const override{ return true; }; + virtual bool get_offer_stars_given(const crypto::hash offer_id, uint64_t &stars_received) const override{ return true; }; + virtual bool get_safex_feedbacks( std::vector &safex_feedbacks, const crypto::hash& offer_id) const override{ return true; }; + virtual bool get_safex_price_pegs( std::vector &safex_price_pegs, const std::string& currency) const override{ return true; }; + virtual bool get_safex_price_peg( const crypto::hash& price_peg_id,safex::safex_price_peg &safex_price_peg) const override{ return true; }; + + virtual bool get_table_sizes( std::vector &table_sizes) const override{ return true; }; + + + virtual bool for_all_key_images(std::function) const override{ return true; } + virtual bool for_blocks_range(const uint64_t&, const uint64_t&, std::function) const override{ return true; } + virtual bool for_all_transactions(std::function) const override{ return true; } + virtual bool for_all_outputs(std::function f, const tx_out_type output_type) const override{ return true; } + virtual bool for_all_outputs(uint64_t amount, const std::function &f, const tx_out_type output_type) const override{ return true; } + virtual bool for_all_advanced_outputs(std::function f, const tx_out_type output_type) const override{ return true;} + virtual bool is_read_only() const override{ return false; } + virtual std::map> get_output_histogram(const std::vector &amounts, bool unlocked, uint64_t recent_cutoff, const tx_out_type output_type) const override{ return std::map>(); } + + virtual void add_txpool_tx(const transaction &tx, const txpool_tx_meta_t& details) override{} + virtual void update_txpool_tx(const crypto::hash &txid, const txpool_tx_meta_t& details) override{} + virtual uint64_t get_txpool_tx_count(bool include_unrelayed_txes = true) const override{ return 0; } + virtual bool txpool_has_tx(const crypto::hash &txid) const override{ return false; } + virtual void remove_txpool_tx(const crypto::hash& txid) override{} + virtual bool get_txpool_tx_meta(const crypto::hash& txid, txpool_tx_meta_t &meta) const override{ return false; } + virtual bool get_txpool_tx_blob(const crypto::hash& txid, cryptonote::blobdata &bd) const override{ return false; } + virtual cryptonote::blobdata get_txpool_tx_blob(const crypto::hash& txid) const override{ return ""; } + virtual bool for_all_txpool_txes(std::function, bool include_blob = false, bool include_unrelayed_txes = false) const override{ return false; } + + virtual uint64_t get_current_staked_token_sum() const override{ return 0;} + virtual uint64_t get_staked_token_sum_for_interval(const uint64_t interval_starting_block) const override{ return 0;}; + virtual uint64_t get_network_fee_sum_for_interval(const uint64_t interval) const override{return 0;} + virtual std::vector get_token_stake_expiry_outputs(const uint64_t block_height) const override{return std::vector{};} + virtual bool get_interval_interest_map(const uint64_t start_height, const uint64_t end_height, safex::map_interval_interest &map) const override{return true;} + virtual uint64_t calculate_staked_token_interest_for_output(const txin_to_script &txin, const uint64_t unlock_height) const override{ return 0; } + + virtual void add_block( const block& blk + , const size_t& block_size + , const difficulty_type& cumulative_difficulty + , const uint64_t& coins_generated + , const uint64_t& tokens_migrated + , const crypto::hash& blk_hash + ) override{ + blocks.push_back(blk); + } + virtual block get_block_from_height(const uint64_t& height) const override{ + return blocks.at(height); + } + virtual void set_hard_fork_version(uint64_t height, uint8_t version) override{ + if (versions.size() <= height) + versions.resize(height+1); + versions[height] = version; + } + virtual uint8_t get_hard_fork_version(uint64_t height) const override{ + return versions.at(height); + } + virtual void check_hard_fork_info() override{} + +private: + std::vector blocks; + std::deque versions; +}; + + +struct output_index +{ + const cryptonote::txout_target_v out; + uint64_t amount; + uint64_t token_amount; + size_t blk_height; // block height + size_t tx_no; // index of transaction in block + size_t out_no; // index of out in transaction + size_t idx; + size_t advanced_output_id{0}; + bool spent; + const cryptonote::block *p_blk; + const cryptonote::transaction *p_tx; + cryptonote::tx_out_type out_type{cryptonote::tx_out_type::out_invalid}; + + output_index(const cryptonote::txout_target_v &_out, uint64_t _a, uint64_t _t_a, size_t _h, size_t tno, size_t ono, const cryptonote::block *_pb, const cryptonote::transaction *_pt) + : out(_out), amount(_a), token_amount(_t_a), blk_height(_h), tx_no(tno), out_no(ono), idx(0), spent(false), p_blk(_pb), p_tx(_pt) + {} + + output_index(const output_index &other) + : out(other.out), amount(other.amount), token_amount(other.token_amount), blk_height(other.blk_height), tx_no(other.tx_no), out_no(other.out_no), + idx(other.idx), spent(other.spent), p_blk(other.p_blk), p_tx(other.p_tx), advanced_output_id{other.advanced_output_id}, out_type{other.out_type} + {} + + const std::string toString() const + { + std::stringstream ss; + + ss << "output_index{blk_height=" << blk_height + << " tx_no=" << tx_no + << " out_no=" << out_no + << " amount=" << amount + << " token_amount=" << token_amount + << " idx=" << idx + << " spent=" << spent + << "}"; + + return ss.str(); + } + + output_index &operator=(const output_index &other) + { + new(this) output_index(other); + return *this; + } +}; + + +typedef std::unordered_map map_hash2tx_t; +typedef std::map > map_output_t; +typedef std::map > map_output_idx_t; + + +bool find_nonce_for_given_block(cryptonote::block &bl, const cryptonote::difficulty_type &diffic, uint64_t height); +bool compare_blocks(const cryptonote::block &a, const cryptonote::block &b); + +cryptonote::tx_destination_entry create_tx_destination(const cryptonote::account_base &to, uint64_t amount); +cryptonote::tx_destination_entry create_token_tx_destination(const cryptonote::account_base &to, uint64_t token_amount); +cryptonote::tx_destination_entry create_locked_token_tx_destination(const cryptonote::account_base &to, uint64_t token_amount); + +uint64_t get_inputs_amount(const std::vector &s); +uint64_t get_inputs_token_amount(const std::vector &s); + + +bool fill_output_entries(std::vector &out_indices, size_t sender_out, size_t nmix, size_t &real_entry_idx, std::vector &output_entries); + +bool init_output_indices(map_hash2tx_t &txmap, map_output_idx_t &outs, std::map > &outs_mine, const std::vector &blockchain, + const cryptonote::account_base &from, cryptonote::tx_out_type out_type = cryptonote::tx_out_type::out_cash, const crypto::public_key& safex_account_pkey = {}); + +bool init_spent_output_indices(map_hash2tx_t &txmap, map_output_idx_t &outs, map_output_t &outs_mine, const std::vector &blockchain, + const cryptonote::account_base &from); + +bool fill_unlock_token_sources(map_hash2tx_t &txmap, std::vector &blocks, std::vector &sources, const cryptonote::account_base &from, + uint64_t value_amount, size_t nmix, cryptonote::tx_out_type out_type = cryptonote::tx_out_type::out_staked_token); + +bool fill_migration_tx_sources(map_hash2tx_t &txmap, std::vector &blocks, std::vector &sources, const cryptonote::account_base &from, + uint64_t token_amount, uint64_t cash_airdrop_amount, const crypto::hash &bitcoin_transaction_hash); + +void fill_migration_tx_sources_and_destinations(map_hash2tx_t &txmap, std::vector &blocks, const cryptonote::account_base &from, const cryptonote::account_base &to, + uint64_t token_amount, uint64_t fee, std::vector &sources, + std::vector &destinations, const crypto::hash &bitcoin_transaction_hash); + +crypto::hash get_hash_from_string(const std::string hashstr); + +bool construct_tx_to_key(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, + const cryptonote::account_base &to, uint64_t amount, uint64_t fee, size_t nmix); + +bool construct_migration_tx_to_key(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, + const cryptonote::account_base &to, uint64_t token_amount, uint64_t fee, const crypto::hash &bitcoin_hash); + + +bool construct_token_tx_to_key(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, const cryptonote::account_base &to, + uint64_t token_amount, uint64_t fee, size_t nmix); + +bool construct_token_stake_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, const cryptonote::account_base &to, + uint64_t token_amount, uint64_t fee, size_t nmix); + +bool construct_token_unstake_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, + const cryptonote::account_base &from, const cryptonote::account_base &to, uint64_t token_amount, uint64_t fee, size_t nmix); + +bool construct_fee_donation_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, + const cryptonote::account_base &from, uint64_t cash_amount, uint64_t fee, size_t nmix); + +bool construct_create_account_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const std::string &username, const crypto::public_key &pkey, const std::vector &account_data, const safex::safex_account_keys &sfx_acc_keys); + +bool construct_edit_account_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const std::string &username, const std::vector &new_account_data, const safex::safex_account_keys &sfx_acc_keys); + +bool construct_create_offer_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_offer& sfx_offer, const safex::safex_account_keys &sfx_acc_keys); + +bool construct_edit_offer_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_offer &sfx_offer, const safex::safex_account_keys &sfx_acc_keys); + +bool construct_create_purchase_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, + uint64_t fee, size_t nmix, const safex::safex_purchase &sfx_purchase, const cryptonote::account_public_address seller_address); + +bool construct_create_feedback_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, + uint64_t fee, size_t nmix, const safex::safex_feedback &sfx_feedback); + +bool construct_create_price_peg_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_price_peg& sfx_price_peg, const safex::safex_account_keys &sfx_acc_keys); + +bool construct_update_price_peg_transaction(map_hash2tx_t &txmap, std::vector &blocks, cryptonote::transaction &tx, const cryptonote::account_base &from, uint64_t fee, + size_t nmix, const crypto::public_key &pkey, const safex::safex_price_peg& sfx_price_peg, const safex::safex_account_keys &sfx_acc_keys); + +bool construct_block(cryptonote::block &blk, uint64_t height, const crypto::hash &prev_id, const cryptonote::account_base &miner_acc, + uint64_t timestamp, size_t &block_size, std::list tx_list); + +void remove_files(std::vector filenames, std::string prefix); + +#endif //SAFEX_SAFEX_TEST_COMMON_H diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 0b83f8e9b..1db99d728 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -472,211 +472,6 @@ TEST(Serialization, serializes_transacion_signatures_correctly) ASSERT_FALSE(serialization::parse_binary(blob, tx1)); } -#if (CURRENT_TRANSACTION_VERSION >= 2) -TEST(Serialization, serializes_ringct_types) -{ - string blob; - rct::key key0, key1; - rct::keyV keyv0, keyv1; - rct::keyM keym0, keym1; - rct::ctkey ctkey0, ctkey1; - rct::ctkeyV ctkeyv0, ctkeyv1; - rct::ctkeyM ctkeym0, ctkeym1; - rct::ecdhTuple ecdh0, ecdh1; - rct::boroSig boro0, boro1; - rct::mgSig mg0, mg1; - rct::rangeSig rg0, rg1; - rct::rctSig s0, s1; - cryptonote::transaction tx0, tx1; - - key0 = rct::skGen(); - ASSERT_TRUE(serialization::dump_binary(key0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, key1)); - ASSERT_TRUE(key0 == key1); - - keyv0 = rct::skvGen(30); - for (size_t n = 0; n < keyv0.size(); ++n) - keyv0[n] = rct::skGen(); - ASSERT_TRUE(serialization::dump_binary(keyv0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, keyv1)); - ASSERT_TRUE(keyv0.size() == keyv1.size()); - for (size_t n = 0; n < keyv0.size(); ++n) - { - ASSERT_TRUE(keyv0[n] == keyv1[n]); - } - - keym0 = rct::keyMInit(9, 12); - for (size_t n = 0; n < keym0.size(); ++n) - for (size_t i = 0; i < keym0[n].size(); ++i) - keym0[n][i] = rct::skGen(); - ASSERT_TRUE(serialization::dump_binary(keym0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, keym1)); - ASSERT_TRUE(keym0.size() == keym1.size()); - for (size_t n = 0; n < keym0.size(); ++n) - { - ASSERT_TRUE(keym0[n].size() == keym1[n].size()); - for (size_t i = 0; i < keym0[n].size(); ++i) - { - ASSERT_TRUE(keym0[n][i] == keym1[n][i]); - } - } - - rct::skpkGen(ctkey0.dest, ctkey0.mask); - ASSERT_TRUE(serialization::dump_binary(ctkey0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, ctkey1)); - ASSERT_TRUE(!memcmp(&ctkey0, &ctkey1, sizeof(ctkey0))); - - ctkeyv0 = std::vector(14); - for (size_t n = 0; n < ctkeyv0.size(); ++n) - rct::skpkGen(ctkeyv0[n].dest, ctkeyv0[n].mask); - ASSERT_TRUE(serialization::dump_binary(ctkeyv0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, ctkeyv1)); - ASSERT_TRUE(ctkeyv0.size() == ctkeyv1.size()); - for (size_t n = 0; n < ctkeyv0.size(); ++n) - { - ASSERT_TRUE(!memcmp(&ctkeyv0[n], &ctkeyv1[n], sizeof(ctkeyv0[n]))); - } - - ctkeym0 = std::vector(9); - for (size_t n = 0; n < ctkeym0.size(); ++n) - { - ctkeym0[n] = std::vector(11); - for (size_t i = 0; i < ctkeym0[n].size(); ++i) - rct::skpkGen(ctkeym0[n][i].dest, ctkeym0[n][i].mask); - } - ASSERT_TRUE(serialization::dump_binary(ctkeym0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, ctkeym1)); - ASSERT_TRUE(ctkeym0.size() == ctkeym1.size()); - for (size_t n = 0; n < ctkeym0.size(); ++n) - { - ASSERT_TRUE(ctkeym0[n].size() == ctkeym1[n].size()); - for (size_t i = 0; i < ctkeym0.size(); ++i) - { - ASSERT_TRUE(!memcmp(&ctkeym0[n][i], &ctkeym1[n][i], sizeof(ctkeym0[n][i]))); - } - } - - ecdh0.mask = rct::skGen(); - ecdh0.amount = rct::skGen(); - ecdh0.senderPk = rct::skGen(); - ASSERT_TRUE(serialization::dump_binary(ecdh0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, ecdh1)); - ASSERT_TRUE(!memcmp(&ecdh0.mask, &ecdh1.mask, sizeof(ecdh0.mask))); - ASSERT_TRUE(!memcmp(&ecdh0.amount, &ecdh1.amount, sizeof(ecdh0.amount))); - // senderPk is not serialized - - for (size_t n = 0; n < 64; ++n) - { - boro0.s0[n] = rct::skGen(); - boro0.s1[n] = rct::skGen(); - } - boro0.ee = rct::skGen(); - ASSERT_TRUE(serialization::dump_binary(boro0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, boro1)); - ASSERT_TRUE(!memcmp(&boro0, &boro1, sizeof(boro0))); - - // create a full rct signature to use its innards - rct::ctkeyV sc, pc; - rct::ctkey sctmp, pctmp; - tie(sctmp, pctmp) = rct::ctskpkGen(6000); - sc.push_back(sctmp); - pc.push_back(pctmp); - tie(sctmp, pctmp) = rct::ctskpkGen(7000); - sc.push_back(sctmp); - pc.push_back(pctmp); - vector amounts; - rct::keyV amount_keys; - //add output 500 - amounts.push_back(500); - amount_keys.push_back(rct::hash_to_scalar(rct::zero())); - rct::keyV destinations; - rct::key Sk, Pk; - rct::skpkGen(Sk, Pk); - destinations.push_back(Pk); - //add output for 12500 - amounts.push_back(12500); - amount_keys.push_back(rct::hash_to_scalar(rct::zero())); - rct::skpkGen(Sk, Pk); - destinations.push_back(Pk); - //compute rct data with mixin 500 - s0 = rct::genRct(rct::zero(), sc, pc, destinations, amounts, amount_keys, NULL, NULL, 3, hw::get_device("default")); - - mg0 = s0.p.MGs[0]; - ASSERT_TRUE(serialization::dump_binary(mg0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, mg1)); - ASSERT_TRUE(mg0.ss.size() == mg1.ss.size()); - for (size_t n = 0; n < mg0.ss.size(); ++n) - { - ASSERT_TRUE(mg0.ss[n] == mg1.ss[n]); - } - ASSERT_TRUE(mg0.cc == mg1.cc); - - // mixRing and II are not serialized, they are meant to be reconstructed - ASSERT_TRUE(mg1.II.empty()); - - rg0 = s0.p.rangeSigs.front(); - ASSERT_TRUE(serialization::dump_binary(rg0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, rg1)); - ASSERT_TRUE(!memcmp(&rg0, &rg1, sizeof(rg0))); - -#if 0 - ASSERT_TRUE(serialization::dump_binary(s0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, s1)); - ASSERT_TRUE(s0.type == s1.type); - ASSERT_TRUE(s0.p.rangeSigs.size() == s1.p.rangeSigs.size()); - for (size_t n = 0; n < s0.p.rangeSigs.size(); ++n) - { - ASSERT_TRUE(!memcmp(&s0.p.rangeSigs[n], &s1.p.rangeSigs[n], sizeof(s0.p.rangeSigs[n]))); - } - ASSERT_TRUE(s0.p.MGs.size() == s1.p.MGs.size()); - ASSERT_TRUE(s0.p.MGs[0].ss.size() == s1.p.MGs[0].ss.size()); - for (size_t n = 0; n < s0.p.MGs[0].ss.size(); ++n) - { - ASSERT_TRUE(s0.p.MGs[0].ss[n] == s1.p.MGs[0].ss[n]); - } - ASSERT_TRUE(s0.p.MGs[0].cc == s1.p.MGs[0].cc); - // mixRing and II are not serialized, they are meant to be reconstructed - ASSERT_TRUE(s1.p.MGs[0].II.empty()); - - // mixRing and II are not serialized, they are meant to be reconstructed - ASSERT_TRUE(s1.mixRing.size() == 0); - - ASSERT_TRUE(s0.ecdhInfo.size() == s1.ecdhInfo.size()); - for (size_t n = 0; n < s0.ecdhInfo.size(); ++n) - { - ASSERT_TRUE(!memcmp(&s0.ecdhInfo[n], &s1.ecdhInfo[n], sizeof(s0.ecdhInfo[n]))); - } - ASSERT_TRUE(s0.outPk.size() == s1.outPk.size()); - for (size_t n = 0; n < s0.outPk.size(); ++n) - { - // serialization only does the mask - ASSERT_TRUE(!memcmp(&s0.outPk[n].mask, &s1.outPk[n].mask, sizeof(s0.outPk[n].mask))); - } -#endif - - tx0.set_null(); - tx0.version = 2; - cryptonote::txin_to_key txin_to_key1{}; - txin_to_key1.amount = 100; - txin_to_key1.key_offsets.resize(4); - cryptonote::txin_to_key txin_to_key2{}; - txin_to_key2.amount = 200; - txin_to_key2.key_offsets.resize(4); - tx0.vin.push_back(txin_to_key1); - tx0.vin.push_back(txin_to_key2); - tx0.vout.push_back(cryptonote::tx_out()); - tx0.vout.push_back(cryptonote::tx_out()); - tx0.rct_signatures = s0; - ASSERT_EQ(tx0.rct_signatures.p.rangeSigs.size(), 2); - ASSERT_TRUE(serialization::dump_binary(tx0, blob)); - ASSERT_TRUE(serialization::parse_binary(blob, tx1)); - ASSERT_EQ(tx1.rct_signatures.p.rangeSigs.size(), 2); - std::string blob2; - ASSERT_TRUE(serialization::dump_binary(tx1, blob2)); - ASSERT_TRUE(blob == blob2); -} -#endif - static boost::optional password_prompter(const char *prompt, bool verify) { tools::password_container pwd_container{"test"}; @@ -691,7 +486,7 @@ static void serialize_wallet_test_init_vm(boost::program_options::variables_map boost::program_options::options_description desc_params("Allowed options"); tools::wallet::init_options(desc_params); const int argc = 4; - const char* argv[] = {"wallet","--testnet","--shared-ringdb-dir", dir.string().c_str()}; + const char* argv[] = {"wallet","--testnet","--password","","--shared-ringdb-dir", dir.string().c_str()}; bool r = command_line::handle_error_helper(desc_params, [&]() { boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc_params), vm); @@ -1180,8 +975,7 @@ namespace { epee::string_tools::hex_to_pod("4d86c7ba1c285fe4bc1cd7b54ba894fa89fa02fc6b0bbeea67d53251acd14a05", tse.real_out_tx_key); tse.real_output_in_tx_index = 1; tse.amount = 11066009260865; - tse.rct = true; - epee::string_tools::hex_to_pod("789bafff169ef206aa21219342c69ca52ce1d78d776c10b21d14bdd960fc7703", tse.mask); + // tcd.change_dts tcd.change_dts.amount = 9631208773403; @@ -1375,8 +1169,6 @@ TEST(Serialization, portability_unsigned_tx) ASSERT_TRUE(epee::string_tools::pod_to_hex(tse.real_out_tx_key) == "4d86c7ba1c285fe4bc1cd7b54ba894fa89fa02fc6b0bbeea67d53251acd14a05"); ASSERT_TRUE(tse.real_output_in_tx_index == 1); ASSERT_TRUE(tse.amount == 11066009260865); - ASSERT_TRUE(tse.rct); - ASSERT_TRUE(epee::string_tools::pod_to_hex(tse.mask) == "789bafff169ef206aa21219342c69ca52ce1d78d776c10b21d14bdd960fc7703"); // tcd.change_dts ASSERT_TRUE(tcd.change_dts.amount == 9631208773403); ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, tcd.change_dts.addr) == "SFXtzUpLfKDTSBG1KEydRqTmac2vvvpXZU6yx4Yct1dHUSPJ6AJqCj1Umne7mznPpjV7Bz9PgjavTVSbLB1Ngn2BVmzgCdUvvDW"); @@ -1524,8 +1316,6 @@ namespace { epee::string_tools::hex_to_pod("4d86c7ba1c285fe4bc1cd7b54ba894fa89fa02fc6b0bbeea67d53251acd14a05", tse.real_out_tx_key); tse.real_output_in_tx_index = 1; tse.amount = 11066009260865; - tse.rct = true; - epee::string_tools::hex_to_pod("789bafff169ef206aa21219342c69ca52ce1d78d776c10b21d14bdd960fc7703", tse.mask); // ptx.construction_data.change_dts tcd.change_dts.amount = 9631208773403; @@ -1691,8 +1481,6 @@ TEST(Serialization, portability_signed_tx) ASSERT_TRUE(epee::string_tools::pod_to_hex(tse.real_out_tx_key) == "4d86c7ba1c285fe4bc1cd7b54ba894fa89fa02fc6b0bbeea67d53251acd14a05"); ASSERT_TRUE(tse.real_output_in_tx_index == 1); ASSERT_TRUE(tse.amount == 11066009260865); - ASSERT_TRUE(tse.rct); - ASSERT_TRUE(epee::string_tools::pod_to_hex(tse.mask) == "789bafff169ef206aa21219342c69ca52ce1d78d776c10b21d14bdd960fc7703"); // ptx.construction_data.change_dts ASSERT_TRUE(tcd.change_dts.amount == 9631208773403); ASSERT_TRUE(cryptonote::get_account_address_as_str(nettype, false, tcd.change_dts.addr) == "SFXtzUpLfKDTSBG1KEydRqTmac2vvvpXZU6yx4Yct1dHUSPJ6AJqCj1Umne7mznPpjV7Bz9PgjavTVSbLB1Ngn2BVmzgCdUvvDW");