diff --git a/CMakeLists.txt b/CMakeLists.txt index e112bd28c..e4dbd9457 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,40 @@ function (die msg) message(FATAL_ERROR "${BoldRed}${msg}${ColourReset}") endfunction () +if (NOT ${ARCH} STREQUAL "") + string(SUBSTRING ${ARCH} 0 3 IS_ARM) + string(TOLOWER ${IS_ARM} IS_ARM) + + if (${IS_ARM} STREQUAL "arm") + string(SUBSTRING ${ARCH} 0 5 ARM_TEST) + string(TOLOWER ${ARM_TEST} ARM_TEST) + + if (${ARM_TEST} STREQUAL "armv6") + set(ARM6 1) + else() + set(ARM6 0) + endif() + + if (${ARM_TEST} STREQUAL "armv7") + set(ARM7 1) + else() + set(ARM7 0) + endif() + endif() +endif() + +if(WIN32 OR ARM7 OR ARM6) + set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG") + set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") +endif() + +# set this to 0 if per-block checkpoint needs to be disabled +set(PER_BLOCK_CHECKPOINT 1) + +if(PER_BLOCK_CHECKPOINT) + add_definitions("-DPER_BLOCK_CHECKPOINT") +endif() + list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake") @@ -127,16 +161,16 @@ endif() option(STATIC "Link libraries statically" ${DEFAULT_STATIC}) if(MINGW) - get_filename_component(msys2_install_path "[HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MSYS2 ${ARCH_WIDTH}bit;InstallLocation]" ABSOLUTE) + string(REGEX MATCH "^[^/]:/[^/]*" msys2_install_path "${CMAKE_C_COMPILER}") + message(STATUS "MSYS location: ${msys2_install_path}") set(CMAKE_INCLUDE_PATH "${msys2_install_path}/mingw${ARCH_WIDTH}/include") # This is necessary because otherwise CMake will make Boost libraries -lfoo # rather than a full path. Unfortunately, this makes the shared libraries get # linked due to a bug in CMake which misses putting -static flags around the # -lfoo arguments. - list(REMOVE_ITEM CMAKE_C_IMPLICIT_LINK_DIRECTORIES - "${msys2_install_path}/mingw${ARCH_WIDTH}/lib") - list(REMOVE_ITEM CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES - "${msys2_install_path}/mingw${ARCH_WIDTH}/lib") + set(DEFLIB ${msys2_install_path}/mingw${ARCH_WIDTH}/lib) + list(REMOVE_ITEM CMAKE_C_IMPLICIT_LINK_DIRECTORIES ${DEFLIB}) + list(REMOVE_ITEM CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES ${DEFLIB}) endif() if(STATIC) @@ -158,18 +192,47 @@ if (DEFINED ENV{DATABASE}) else() message(STATUS "Could not find DATABASE in env (not required unless you want to change database type from default: ${DATABASE})") endif() + +set(BERKELEY_DB 0) if (DATABASE STREQUAL "lmdb") set(BLOCKCHAIN_DB DB_LMDB) + + # temporarily allow mingw to compile with berkeley_db, + # regardless if building static or not + if(NOT STATIC OR MINGW) + find_package(BerkeleyDB) + + if(NOT BERKELEY_DB_LIBRARIES) + message(STATUS "BerkeleyDB not found and has been disabled.") + else() + message(STATUS "Found BerkeleyDB include (db.h) in ${BERKELEY_DB_INCLUDE_DIR}") + if(BERKELEY_DB_LIBRARIES) + message(STATUS "Found BerkeleyDB shared library") + set(BDB_STATIC false CACHE BOOL "BDB Static flag") + set(BDB_INCLUDE ${BERKELEY_DB_INCLUDE_DIR} CACHE STRING "BDB include path") + set(BDB_LIBRARY ${BERKELEY_DB_LIBRARIES} CACHE STRING "BDB library name") + set(BDB_LIBRARY_DIRS "" CACHE STRING "BDB Library dirs") + set(BERKELEY_DB 1) + else() + message(STATUS "Found BerkeleyDB includes, but could not find BerkeleyDB library. Please make sure you have installed libdb and libdb-dev or the equivalent") + endif() + endif() + endif() elseif (DATABASE STREQUAL "memory") set(BLOCKCHAIN_DB DB_MEMORY) else() die("Invalid database type: ${DATABASE}") endif() +if(BERKELEY_DB) + add_definitions("-DBERKELEY_DB") +endif() + add_definitions("-DBLOCKCHAIN_DB=${BLOCKCHAIN_DB}") if (UNIX AND NOT APPLE) # Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail + set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads) endif() @@ -194,7 +257,7 @@ include_directories(external/rapidjson) include_directories(${LMDB_INCLUDE}) # Final setup for Berkeley DB -if (NOT STATIC) +if (BERKELEY_DB) include_directories(${BDB_INCLUDE}) endif() @@ -210,10 +273,15 @@ if(MSVC) include_directories(SYSTEM src/platform/msc) else() set(ARCH native CACHE STRING "CPU to build for: -march value or default") - if(ARCH STREQUAL "default") + # -march=armv7-a conflicts with -mcpu=cortex-a7 + if(ARCH STREQUAL "default" OR ARM7) set(ARCH_FLAG "") else() - set(ARCH_FLAG "-march=${ARCH}") + if(ARCH STREQUAL "x86_64") + set(ARCH_FLAG "-march=x86-64") + else() + set(ARCH_FLAG "-march=${ARCH}") + endif() endif() set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wundef -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-error=undef -Wno-error=uninitialized") if(CMAKE_C_COMPILER_ID STREQUAL "Clang") @@ -256,14 +324,18 @@ else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GNU_SOURCE ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG} -maes") endif() - string(SUBSTRING ${ARCH} 0 3 ARM_TEST) - string(TOLOWER ${ARM_TEST} ARM_TEST) - if(${ARM_TEST} STREQUAL "arm") - message(STATUS "Setting ARM C and C++ flags") + if(ARM6) + message(STATUS "Setting ARM6 C and C++ flags") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpu=vfp -mfloat-abi=hard") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpu=vfp -mfloat-abi=hard") endif() + if(ARM7) + message(STATUS "Setting ARM7 C and C++ flags") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=vfpv4 -funsafe-math-optimizations -mtune=cortex-a7") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2 -mcpu=cortex-a7 -mfloat-abi=hard -mfpu=vfpv4 -funsafe-math-optimizations -mtune=cortex-a7") + endif() + if(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_HAS_TR1_TUPLE=0") endif() @@ -341,7 +413,7 @@ elseif(APPLE OR FREEBSD) set(EXTRA_LIBRARIES "") elseif(NOT MSVC) find_library(RT rt) - set(EXTRA_LIBRARIES ${RT} ${PTHREAD} ${DL}) + set(EXTRA_LIBRARIES ${RT} ${DL}) endif() include(version.cmake) diff --git a/Makefile b/Makefile index 329f9c4ac..dda8663b7 100644 --- a/Makefile +++ b/Makefile @@ -58,6 +58,14 @@ release-all: mkdir -p build/release cd build/release && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE) +release-arm6: + mkdir -p build/release + cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv6zk" -D BUILD_64=OFF -D NO_AES=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE) + +release-arm7: + mkdir -p build/release + cd build/release && cmake -D BUILD_TESTS=OFF -D ARCH="armv7-a" -D BUILD_64=OFF -D NO_AES=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE) + release-static: release-static-64 release-static-64: @@ -68,10 +76,6 @@ release-static-32: mkdir -p build/release cd build/release && cmake -D STATIC=ON -D ARCH="i686" -D BUILD_64=OFF -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE) -release-static-arm6: - mkdir -p build/release - cd build/release && cmake -D STATIC=ON -D ARCH="armv6zk" -D BUILD_64=OFF -D NO_AES=ON -D CMAKE_BUILD_TYPE=release ../.. && $(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 CMAKE_TOOLCHAIN_FILE=../../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 ../.. && $(MAKE) diff --git a/README.i18n b/README.i18n new file mode 100644 index 000000000..2b913f7d8 --- /dev/null +++ b/README.i18n @@ -0,0 +1,45 @@ +The Monero command line tools can be translated in various languages. +In order to use the same translation workflow as the future GUI, they +use Qt Linguist translation files. However, to avoid the dependencies +on Qt this normally implies, they use a custom loader to read those +files at runtime. In order to update, or build translations files, you +do need to have Qt tools installed, however. For translating, you need +either the Qt Linguist GUI, or another tool that supports Qt ts files, +such as Transifex. To run, you do not need anything Qt. + +To update ts files after changing source code: + + ./utils/translations/update-translations.sh + +To add a new language, eg Spanish (ISO code es): + + cp transations/monero.ts transations/monero_es.ts + +To edit translations for Spanish: + + linguist translations/monero_es.ts + +To build translations after modiying them: + + ./utils/translations/build-translations.sh + +To test a translation: + + LANG=es ./build/release/bin/simplewallet + +To add new translatable sources in the source: + + Use the tr(string) function if possible. If the code is in a class, + and this class doesn't already have a tr() static function, add one, + which uses a context named after what lupdate uses for the context, + usually the fully qualified class name (eg, cryptonote::simple_wallet). + If you need to use tr in code that's not in a class, you can use the + fully qualified version (eg, simple_wallet::tr) of the one matching + the context you want. + Use QT_TRANSLATE_NOOP(string) if you want to specify a context manually. + +If you're getting messages of the form: + + Class 'cryptonote::simple_wallet' lacks Q_OBJECT macro + +all is fine, we don't actually need that here. diff --git a/README.md b/README.md index aedd9174a..e2ba191da 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ cd build ``` * If you are on a 64-bit system, run: ``` -cmake -G "MSYS Makefiles" -D CMAKE_BUILD_TYPE=Release -D ARCH="x86_64" -D BUILD_64=ON -D CMAKE_TOOLCHAIN_FILE=../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 .. +cmake -G "MSYS Makefiles" -D CMAKE_BUILD_TYPE=Release -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_TOOLCHAIN_FILE=../cmake/64-bit-toolchain.cmake -D MSYS2_FOLDER=c:/msys64 .. ``` * If you are on a 32-bit system, run: ``` @@ -167,3 +167,8 @@ Dependencies: Doxygen 1.8.0 or later, Graphviz 2.28 or later (optional). * To build, change to the root of the source code directory, and run `doxygen Doxyfile` * If you have installed Graphviz, you can also generate in-doc diagrams by instead running `HAVE_DOT=YES doxygen Doxyfile` * The output will be built in doc/html/ + +## Internationalization + +See README.i18n + diff --git a/contrib/epee/include/console_handler.h b/contrib/epee/include/console_handler.h index 952fc3c96..5dd3eaba9 100644 --- a/contrib/epee/include/console_handler.h +++ b/contrib/epee/include/console_handler.h @@ -274,14 +274,15 @@ namespace epee } std::string command; - if(!m_stdin_reader.get_line(command)) - { - LOG_PRINT("Failed to read line.", LOG_LEVEL_0); - } + bool get_line_ret = m_stdin_reader.get_line(command); if (m_stdin_reader.eos()) { break; } + if (!get_line_ret) + { + LOG_PRINT("Failed to read line.", LOG_LEVEL_0); + } string_tools::trim(command); LOG_PRINT_L2("Read command: " << command); @@ -303,7 +304,8 @@ namespace epee std::cout << usage; } } - exit_handler(); + if (exit_handler) + exit_handler(); return true; CATCH_ENTRY_L0("console_handler", false); } diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index 42adc7c43..2adac7f2f 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -861,7 +861,8 @@ namespace log_space std::string::size_type a = m_default_log_file.rfind('.'); if ( a != std::string::npos ) m_default_log_file.erase( a, m_default_log_file.size()); - m_default_log_file += ".log"; + if ( ! m_default_log_file.empty() ) + m_default_log_file += ".log"; return true; } diff --git a/external/db_drivers/CMakeLists.txt b/external/db_drivers/CMakeLists.txt index cd7479724..4d1b95c94 100644 --- a/external/db_drivers/CMakeLists.txt +++ b/external/db_drivers/CMakeLists.txt @@ -31,24 +31,4 @@ message(STATUS "Using ${ARCH_WIDTH}-bit LMDB from source tree") add_subdirectory(liblmdb${ARCH_WIDTH}) set(LMDB_INCLUDE "${CMAKE_CURRENT_SOURCE_DIR}/liblmdb${ARCH_WIDTH}" CACHE STRING "LMDB Include path") - set(LMDB_LIBRARY "lmdb" CACHE STRING "LMDB Library name") - -if (NOT STATIC) - find_package(BerkeleyDB) - - if(NOT BERKELEY_DB_LIBRARIES) - die("BerkeleyDB not found. At this time it should be installed in your system for a non-static build.") - else() - message(STATUS "Found BerkeleyDB include (db.h) in ${BERKELEY_DB_INCLUDE_DIR}") - if(BERKELEY_DB_LIBRARIES) - message(STATUS "Found BerkeleyDB shared library") - set(BDB_STATIC false CACHE BOOL "BDB Static flag") - set(BDB_INCLUDE ${BERKELEY_DB_INCLUDE_DIR} CACHE STRING "BDB include path") - set(BDB_LIBRARY ${BERKELEY_DB_LIBRARIES} CACHE STRING "BDB library name") - set(BDB_LIBRARY_DIRS "" CACHE STRING "BDB Library dirs") - else() - die("Found BerkeleyDB includes, but could not find BerkeleyDB library. Please make sure you have installed libdb and libdb-dev or the equivalent") - endif() - endif() -endif() diff --git a/external/db_drivers/liblmdb32/CHANGES b/external/db_drivers/liblmdb32/CHANGES index 34049ba7a..957742e75 100644 --- a/external/db_drivers/liblmdb32/CHANGES +++ b/external/db_drivers/liblmdb32/CHANGES @@ -1,5 +1,33 @@ LMDB 0.9 Change Log +LMDB 0.9.15 Release (2015/06/19) + Fix txn init (ITS#7961,#7987) + Fix MDB_PREV_DUP (ITS#7955,#7671) + Fix compact of empty env (ITS#7956) + Fix mdb_copy file mode + Fix mdb_env_close() after failed mdb_env_open() + Fix mdb_rebalance collapsing root (ITS#8062) + Fix mdb_load with large values (ITS#8066) + Fix to retry writes on EINTR (ITS#8106) + Fix mdb_cursor_del on empty DB (ITS#8109) + Fix MDB_INTEGERDUP key compare (ITS#8117) + Fix error handling (ITS#7959,#8157,etc.) + Fix race conditions (ITS#7969,7970) + Added workaround for fdatasync bug in ext3fs + Build + Don't use -fPIC for static lib + Update .gitignore (ITS#7952,#7953) + Cleanup for "make test" (ITS#7841), "make clean", mtest*.c + Misc. Android/Windows cleanup + Documentation + Fix MDB_APPEND doc + Fix MDB_MAXKEYSIZE doc (ITS#8156) + Fix mdb_cursor_put,mdb_cursor_del EACCES description + Fix mdb_env_sync(MDB_RDONLY env) doc (ITS#8021) + Clarify MDB_WRITEMAP doc (ITS#8021) + Clarify mdb_env_open doc + Clarify mdb_dbi_open doc + LMDB 0.9.14 Release (2014/09/20) Fix to support 64K page size (ITS#7713) Fix to persist decreased as well as increased mapsizes (ITS#7789) diff --git a/external/db_drivers/liblmdb32/CMakeLists.txt b/external/db_drivers/liblmdb32/CMakeLists.txt index 62b800135..293da1039 100644 --- a/external/db_drivers/liblmdb32/CMakeLists.txt +++ b/external/db_drivers/liblmdb32/CMakeLists.txt @@ -26,6 +26,13 @@ # 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. +if(FREEBSD) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DMDB_DSYNC=O_SYNC") +endif() + +# pass the VL32 flag so that we actually invoke the VL32 extensions +set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DVL32") + set (lmdb_sources mdb.c midl.c) diff --git a/external/db_drivers/liblmdb32/COPYRIGHT b/external/db_drivers/liblmdb32/COPYRIGHT index e0eb484c7..722d1a515 100644 --- a/external/db_drivers/liblmdb32/COPYRIGHT +++ b/external/db_drivers/liblmdb32/COPYRIGHT @@ -1,4 +1,4 @@ -Copyright 2011-2014 Howard Chu, Symas Corp. +Copyright 2011-2015 Howard Chu, Symas Corp. All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/external/db_drivers/liblmdb32/Makefile b/external/db_drivers/liblmdb32/Makefile index 095e65587..26b6203af 100644 --- a/external/db_drivers/liblmdb32/Makefile +++ b/external/db_drivers/liblmdb32/Makefile @@ -11,6 +11,7 @@ # - MDB_USE_POSIX_SEM # - MDB_DSYNC # - MDB_FDATASYNC +# - MDB_FDATASYNC_WORKS # - MDB_USE_PWRITEV # # There may be other macros in mdb.c of interest. You should @@ -42,18 +43,18 @@ install: $(ILIBS) $(IPROGS) $(IHDRS) for f in $(IDOCS); do cp $$f $(DESTDIR)$(prefix)/man/man1; done clean: - rm -rf $(PROGS) *.[ao] *.so *~ testdb + rm -rf $(PROGS) *.[ao] *.[ls]o *~ testdb test: all - mkdir testdb + rm -rf testdb && mkdir testdb ./mtest && ./mdb_stat testdb liblmdb.a: mdb.o midl.o ar rs $@ mdb.o midl.o -liblmdb.so: mdb.o midl.o +liblmdb.so: mdb.lo midl.lo # $(CC) $(LDFLAGS) -pthread -shared -Wl,-Bsymbolic -o $@ mdb.o midl.o $(SOLIBS) - $(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.o midl.o $(SOLIBS) + $(CC) $(LDFLAGS) -pthread -shared -o $@ mdb.lo midl.lo $(SOLIBS) mdb_stat: mdb_stat.o liblmdb.a mdb_copy: mdb_copy.o liblmdb.a @@ -67,10 +68,16 @@ mtest5: mtest5.o liblmdb.a mtest6: mtest6.o liblmdb.a mdb.o: mdb.c lmdb.h midl.h - $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c mdb.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c mdb.c midl.o: midl.c midl.h - $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c midl.c + $(CC) $(CFLAGS) $(CPPFLAGS) -c midl.c + +mdb.lo: mdb.c lmdb.h midl.h + $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c mdb.c -o $@ + +midl.lo: midl.c midl.h + $(CC) $(CFLAGS) -fPIC $(CPPFLAGS) -c midl.c -o $@ %: %.o $(CC) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@ diff --git a/external/db_drivers/liblmdb32/lmdb.h b/external/db_drivers/liblmdb32/lmdb.h index bdbb0b909..2f523579c 100644 --- a/external/db_drivers/liblmdb32/lmdb.h +++ b/external/db_drivers/liblmdb32/lmdb.h @@ -119,7 +119,7 @@ * * @author Howard Chu, Symas Corporation. * - * @copyright Copyright 2011-2014 Howard Chu, Symas Corp. All rights reserved. + * @copyright Copyright 2011-2015 Howard Chu, Symas Corp. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted only as authorized by the OpenLDAP @@ -184,7 +184,7 @@ typedef int mdb_filehandle_t; /** Library minor version */ #define MDB_VERSION_MINOR 9 /** Library patch version */ -#define MDB_VERSION_PATCH 14 +#define MDB_VERSION_PATCH 15 /** Combine args a,b,c into a single integer for easy version comparisons */ #define MDB_VERINT(a,b,c) (((a) << 24) | ((b) << 16) | (c)) @@ -194,7 +194,7 @@ typedef int mdb_filehandle_t; MDB_VERINT(MDB_VERSION_MAJOR,MDB_VERSION_MINOR,MDB_VERSION_PATCH) /** The release date of this library version */ -#define MDB_VERSION_DATE "September 20, 2014" +#define MDB_VERSION_DATE "June 19, 2015" /** A stringifier for the version info */ #define MDB_VERSTR(a,b,c,d) "LMDB " #a "." #b "." #c ": (" d ")" @@ -296,12 +296,12 @@ typedef void (MDB_rel_func)(MDB_val *item, void *oldptr, void *newptr, void *rel #define MDB_REVERSEKEY 0x02 /** use sorted duplicates */ #define MDB_DUPSORT 0x04 - /** numeric keys in native byte order. + /** numeric keys in native byte order: either unsigned int or size_t. * The keys must all be of the same size. */ #define MDB_INTEGERKEY 0x08 /** with #MDB_DUPSORT, sorted dup items have fixed size */ #define MDB_DUPFIXED 0x10 - /** with #MDB_DUPSORT, dups are numeric in native byte order */ + /** with #MDB_DUPSORT, dups are #MDB_INTEGERKEY-style integers */ #define MDB_INTEGERDUP 0x20 /** with #MDB_DUPSORT, use reverse string dups */ #define MDB_REVERSEDUP 0x40 @@ -516,8 +516,8 @@ int mdb_env_create(MDB_env **env); * and uses fewer mallocs, but loses protection from application bugs * like wild pointer writes and other bad updates into the database. * Incompatible with nested transactions. - * Processes with and without MDB_WRITEMAP on the same environment do - * not cooperate well. + * Do not mix processes with and without MDB_WRITEMAP on the same + * environment. This can defeat durability (#mdb_env_sync etc). *
  • #MDB_NOMETASYNC * Flush system buffers to disk only once per transaction, omit the * metadata flush. Defer that until the system flushes files to disk, @@ -588,8 +588,8 @@ int mdb_env_create(MDB_env **env); * reserved in that case. * This flag may be changed at any time using #mdb_env_set_flags(). * - * @param[in] mode The UNIX permissions to set on created files. This parameter - * is ignored on Windows. + * @param[in] mode The UNIX permissions to set on created files and semaphores. + * This parameter is ignored on Windows. * @return A non-zero error value on failure and 0 on success. Some possible * errors are: * * @return A non-zero error value on failure and 0 on success. Some possible @@ -1449,7 +1452,7 @@ int mdb_cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data, * */ @@ -1469,7 +1472,7 @@ int mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data, * @return A non-zero error value on failure and 0 on success. Some possible * errors are: * */ diff --git a/external/db_drivers/liblmdb32/mdb.c b/external/db_drivers/liblmdb32/mdb.c index 63fece3d7..dd3d5848f 100644 --- a/external/db_drivers/liblmdb32/mdb.c +++ b/external/db_drivers/liblmdb32/mdb.c @@ -5,7 +5,7 @@ * BerkeleyDB API, but much simplified. */ /* - * Copyright 2011-2014 Howard Chu, Symas Corp. + * Copyright 2011-2015 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -79,6 +79,14 @@ extern int cacheflush(char *addr, int nbytes, int cache); #define CACHEFLUSH(addr, bytes, cache) #endif +#if defined(__linux) && !defined(MDB_FDATASYNC_WORKS) +/** fdatasync is broken on ext3/ext4fs on older kernels, see + * description in #mdb_env_open2 comments. You can safely + * define MDB_FDATASYNC_WORKS if this code will only be run + * on kernels 3.6 and newer. + */ +#define BROKEN_FDATASYNC +#endif #include #include @@ -438,12 +446,17 @@ static txnid_t mdb_debug_start; /** The version number for a database's lockfile format. */ #define MDB_LOCK_VERSION 1 - /** @brief The max size of a key we can write, or 0 for dynamic max. + /** @brief The max size of a key we can write, or 0 for computed max. * - * Define this as 0 to compute the max from the page size. 511 - * is default for backwards compat: liblmdb <= 0.9.10 can break - * when modifying a DB with keys/dupsort data bigger than its max. - * #MDB_DEVEL sets the default to 0. + * This macro should normally be left alone or set to 0. + * Note that a database with big keys or dupsort data cannot be + * reliably modified by a liblmdb which uses a smaller max. + * The default is 511 for backwards compat, or 0 when #MDB_DEVEL. + * + * Other values are allowed, for backwards compat. However: + * A value bigger than the computed max can break if you do not + * know what you are doing, and liblmdb <= 0.9.10 can break when + * modifying a DB with keys/dupsort data bigger than its max. * * Data items in an #MDB_DUPSORT database are also limited to * this size, since they're actually keys of a sub-DB. Keys and @@ -580,11 +593,11 @@ typedef struct MDB_rxbody { * started from so we can avoid overwriting any data used in that * particular version. */ - txnid_t mrb_txnid; + volatile txnid_t mrb_txnid; /** The process ID of the process owning this reader txn. */ - MDB_PID_T mrb_pid; + volatile MDB_PID_T mrb_pid; /** The thread ID of the thread owning this txn. */ - MDB_THR_T mrb_tid; + volatile MDB_THR_T mrb_tid; } MDB_rxbody; /** The actual reader record, with cacheline padding. */ @@ -632,12 +645,12 @@ typedef struct MDB_txbody { * This is recorded here only for convenience; the value can always * be determined by reading the main database meta pages. */ - txnid_t mtb_txnid; + volatile txnid_t mtb_txnid; /** The number of slots that have been used in the reader table. * This always records the maximum count, it is not decremented * when readers release their slots. */ - unsigned mtb_numreaders; + volatile unsigned mtb_numreaders; } MDB_txbody; /** The actual reader table definition. */ @@ -898,7 +911,7 @@ typedef struct MDB_meta { /** Stamp identifying this as an LMDB file. It must be set * to #MDB_MAGIC. */ uint32_t mm_magic; - /** Version number of this lock file. Must be set to #MDB_DATA_VERSION. */ + /** Version number of this file. Must be set to #MDB_DATA_VERSION. */ uint32_t mm_version; void *mm_address; /**< address for fixed mapping */ size_t mm_mapsize; /**< size of mmap region */ @@ -908,7 +921,7 @@ typedef struct MDB_meta { /** Any persistent environment flags. @ref mdb_env */ #define mm_flags mm_dbs[0].md_flags pgno_t mm_last_pg; /**< last used page in file */ - txnid_t mm_txnid; /**< txnid that committed this page */ + volatile txnid_t mm_txnid; /**< txnid that committed this page */ } MDB_meta; /** Buffer for a stack-allocated meta page. @@ -991,7 +1004,7 @@ struct MDB_txn { #ifdef VL32 /** List of read-only pages */ MDB_ID2L mt_rpages; -#endif +#endif /** Number of DB records in use. This number only ever increments; * we don't decrement it when individual DB handles are closed. */ @@ -1103,6 +1116,8 @@ struct MDB_env { #define MDB_ENV_ACTIVE 0x20000000U /** me_txkey is set */ #define MDB_ENV_TXKEY 0x10000000U + /** fdatasync is unreliable */ +#define MDB_FSYNCONLY 0x08000000U uint32_t me_flags; /**< @ref mdb_env */ unsigned int me_psize; /**< DB page size, inited from me_os_psize */ unsigned int me_os_psize; /**< OS page size, from #GET_PAGESIZE */ @@ -1242,6 +1257,13 @@ static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi); static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long; /** @endcond */ +/** Compare two items pointing at size_t's of unknown alignment. */ +#ifdef MISALIGNED_OK +# define mdb_cmp_clong mdb_cmp_long +#else +# define mdb_cmp_clong mdb_cmp_cint +#endif + #ifdef _WIN32 static SECURITY_DESCRIPTOR mdb_null_sd; static SECURITY_ATTRIBUTES mdb_all_sa; @@ -1323,7 +1345,7 @@ mdb_strerror(int err) buf[0] = 0; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, 0, ptr, sizeof(buf), pad); + NULL, err, 0, ptr, sizeof(buf), (va_list *)pad); return ptr; #else return strerror(err); @@ -1555,7 +1577,12 @@ mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) int mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) { - return txn->mt_dbxs[dbi].md_dcmp(a, b); + MDB_cmp_func *dcmp = txn->mt_dbxs[dbi].md_dcmp; +#if UINT_MAX < SIZE_MAX + if (dcmp == mdb_cmp_int && a->mv_size == sizeof(size_t)) + dcmp = mdb_cmp_clong; +#endif + return dcmp(a, b); } /** Allocate memory for a page. @@ -2323,6 +2350,8 @@ int mdb_env_sync(MDB_env *env, int force) { int rc = 0; + if (env->me_flags & MDB_RDONLY) + return EACCES; if (force || !F_ISSET(env->me_flags, MDB_NOSYNC)) { if (env->me_flags & MDB_WRITEMAP) { int flags = ((env->me_flags & MDB_MAPASYNC) && !force) @@ -2334,6 +2363,12 @@ mdb_env_sync(MDB_env *env, int force) rc = ErrCode(); #endif } else { +#ifdef BROKEN_FDATASYNC + if (env->me_flags & MDB_FSYNCONLY) { + if (fsync(env->me_fd)) + rc = ErrCode(); + } else +#endif if (MDB_FDATASYNC(env->me_fd)) rc = ErrCode(); } @@ -2489,15 +2524,11 @@ mdb_txn_renew0(MDB_txn *txn) MDB_env *env = txn->mt_env; MDB_txninfo *ti = env->me_txns; MDB_meta *meta; - unsigned int i, nr; + unsigned int i, nr, flags = txn->mt_flags; uint16_t x; int rc, new_notls = 0; - /* Setup db info */ - txn->mt_numdbs = env->me_numdbs; - txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */ - - if (txn->mt_flags & MDB_TXN_RDONLY) { + if ((flags &= MDB_TXN_RDONLY) != 0) { if (!ti) { meta = env->me_metas[ mdb_env_pick_meta(env) ]; txn->mt_txnid = meta->mm_txnid; @@ -2543,10 +2574,14 @@ mdb_txn_renew0(MDB_txn *txn) return rc; } } - txn->mt_txnid = r->mr_txnid = ti->mti_txnid; + do /* LY: Retry on a race, ITS#7970. */ + r->mr_txnid = ti->mti_txnid; + while(r->mr_txnid != ti->mti_txnid); + txn->mt_txnid = r->mr_txnid; txn->mt_u.reader = r; meta = env->me_metas[txn->mt_txnid & 1]; } + txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */ } else { if (ti) { LOCK_MUTEX_W(env); @@ -2562,6 +2597,9 @@ mdb_txn_renew0(MDB_txn *txn) if (txn->mt_txnid == mdb_debug_start) mdb_debug = 1; #endif + txn->mt_child = NULL; + txn->mt_loose_pgs = NULL; + txn->mt_loose_count = 0; txn->mt_dirty_room = MDB_IDL_UM_MAX; txn->mt_u.dirty_list = env->me_dirty_list; txn->mt_u.dirty_list[0].mid = 0; @@ -2578,6 +2616,10 @@ mdb_txn_renew0(MDB_txn *txn) /* Moved to here to avoid a data race in read TXNs */ txn->mt_next_pgno = meta->mm_last_pg+1; + txn->mt_flags = flags; + + /* Setup db info */ + txn->mt_numdbs = env->me_numdbs; for (i=2; imt_numdbs; i++) { x = env->me_dbflags[i]; txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS; @@ -2643,18 +2685,16 @@ mdb_txn_begin(MDB_env *env, MDB_txn *parent, unsigned int flags, MDB_txn **ret) } tsize = sizeof(MDB_ntxn); } - size = tsize + env->me_maxdbs * (sizeof(MDB_db)+1); + size = tsize; if (!(flags & MDB_RDONLY)) { if (!parent) { - txn = env->me_txn0; - txn->mt_flags = 0; + txn = env->me_txn0; /* just reuse preallocated write txn */ goto ok; } + /* child txns use own copy of cursors */ size += env->me_maxdbs * sizeof(MDB_cursor *); - /* child txns use parent's dbiseqs */ - if (!parent) - size += env->me_maxdbs * sizeof(unsigned int); } + size += env->me_maxdbs * (sizeof(MDB_db)+1); if ((txn = calloc(1, size)) == NULL) { DPRINTF(("calloc: %s", strerror(errno))); @@ -2807,38 +2847,40 @@ mdb_txn_reset0(MDB_txn *txn, const char *act) txn->mt_numdbs = 0; /* close nothing if called again */ txn->mt_dbxs = NULL; /* mark txn as reset */ } else { - mdb_cursors_close(txn, 0); + pgno_t *pghead = env->me_pghead; + mdb_cursors_close(txn, 0); if (!(env->me_flags & MDB_WRITEMAP)) { mdb_dlist_free(txn); } - mdb_midl_free(env->me_pghead); - if (txn->mt_parent) { + if (!txn->mt_parent) { + if (mdb_midl_shrink(&txn->mt_free_pgs)) + env->me_free_pgs = txn->mt_free_pgs; + /* me_pgstate: */ + env->me_pghead = NULL; + env->me_pglast = 0; + + env->me_txn = NULL; + /* The writer mutex was locked in mdb_txn_begin. */ + if (env->me_txns) + UNLOCK_MUTEX_W(env); + } else { txn->mt_parent->mt_child = NULL; env->me_pgstate = ((MDB_ntxn *)txn)->mnt_pgstate; mdb_midl_free(txn->mt_free_pgs); mdb_midl_free(txn->mt_spill_pgs); free(txn->mt_u.dirty_list); - return; } - if (mdb_midl_shrink(&txn->mt_free_pgs)) - env->me_free_pgs = txn->mt_free_pgs; - env->me_pghead = NULL; - env->me_pglast = 0; - - env->me_txn = NULL; - /* The writer mutex was locked in mdb_txn_begin. */ - if (env->me_txns) - UNLOCK_MUTEX_W(env); + mdb_midl_free(pghead); } #ifdef VL32 { unsigned i, n = txn->mt_rpages[0].mid; for (i = 1; i <= n; i++) { #ifdef _WIN32 - UnmapViewOfFile(txn->mt_rpages[i].mptr);) + UnmapViewOfFile(txn->mt_rpages[i].mptr); #else MDB_page *mp = txn->mt_rpages[i].mptr; int size = txn->mt_env->me_psize; @@ -3159,6 +3201,7 @@ mdb_page_flush(MDB_txn *txn, int keep) /* Write up to MDB_COMMIT_PAGES dirty pages at a time. */ if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE) { if (n) { +retry_write: /* Write previous page(s) */ #ifdef MDB_USE_PWRITEV wres = pwritev(env->me_fd, iov, n, wpos); @@ -3166,8 +3209,11 @@ mdb_page_flush(MDB_txn *txn, int keep) if (n == 1) { wres = pwrite(env->me_fd, iov[0].iov_base, wsize, wpos); } else { +retry_seek: if (lseek(env->me_fd, wpos, SEEK_SET) == -1) { rc = ErrCode(); + if (rc == EINTR) + goto retry_seek; DPRINTF(("lseek: %s", strerror(rc))); return rc; } @@ -3177,6 +3223,8 @@ mdb_page_flush(MDB_txn *txn, int keep) if (wres != wsize) { if (wres < 0) { rc = ErrCode(); + if (rc == EINTR) + goto retry_write; DPRINTF(("Write error: %s", strerror(rc))); } else { rc = EIO; /* TODO: Use which error code? */ @@ -3546,7 +3594,8 @@ mdb_env_init_meta(MDB_env *env, MDB_meta *meta) int len; #define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \ len = pwrite(fd, ptr, size, pos); \ - rc = (len >= 0); } while(0) + if (len == -1 && ErrCode() == EINTR) continue; \ + rc = (len >= 0); break; } while(1) #endif DPUTS("writing new meta page"); @@ -3651,6 +3700,7 @@ mdb_env_write_meta(MDB_txn *txn) /* Write to the SYNC fd */ mfd = env->me_flags & (MDB_NOSYNC|MDB_NOMETASYNC) ? env->me_fd : env->me_mfd; +retry_write: #ifdef _WIN32 { memset(&ov, 0, sizeof(ov)); @@ -3663,6 +3713,8 @@ mdb_env_write_meta(MDB_txn *txn) #endif if (rc != len) { rc = rc < 0 ? ErrCode() : EIO; + if (rc == EINTR) + goto retry_write; DPUTS("write failed, disk error?"); /* On a failure, the pagecache still contains the new data. * Write some old data back, to prevent it from being used. @@ -3894,6 +3946,32 @@ mdb_env_get_maxreaders(MDB_env *env, unsigned int *readers) return MDB_SUCCESS; } +static int ESECT +mdb_fsize(HANDLE fd, size_t *size) +{ +#ifdef _WIN32 + LARGE_INTEGER fsize; + + if (!GetFileSizeEx(fd, &fsize)) + return ErrCode(); + + *size = fsize.QuadPart; +#else + struct stat st; + + if (fstat(fd, &st)) + return ErrCode(); + + *size = st.st_size; +#endif + return MDB_SUCCESS; +} + +#ifdef BROKEN_FDATASYNC +#include +#include +#endif + /** Further setup required for opening an LMDB environment */ static int ESECT @@ -3911,6 +3989,53 @@ mdb_env_open2(MDB_env *env) else env->me_pidquery = PROCESS_QUERY_INFORMATION; #endif /* _WIN32 */ +#ifdef BROKEN_FDATASYNC + /* ext3/ext4 fdatasync is broken on some older Linux kernels. + * https://lkml.org/lkml/2012/9/3/83 + * Kernels after 3.6-rc6 are known good. + * https://lkml.org/lkml/2012/9/10/556 + * See if the DB is on ext3/ext4, then check for new enough kernel + * Kernels 2.6.32.60, 2.6.34.15, 3.2.30, and 3.5.4 are also known + * to be patched. + */ + { + struct statfs st; + fstatfs(env->me_fd, &st); + while (st.f_type == 0xEF53) { + struct utsname uts; + int i; + uname(&uts); + if (uts.release[0] < '3') { + if (!strncmp(uts.release, "2.6.32.", 7)) { + i = atoi(uts.release+7); + if (i >= 60) + break; /* 2.6.32.60 and newer is OK */ + } else if (!strncmp(uts.release, "2.6.34.", 7)) { + i = atoi(uts.release+7); + if (i >= 15) + break; /* 2.6.34.15 and newer is OK */ + } + } else if (uts.release[0] == '3') { + i = atoi(uts.release+2); + if (i > 5) + break; /* 3.6 and newer is OK */ + if (i == 5) { + i = atoi(uts.release+4); + if (i >= 4) + break; /* 3.5.4 and newer is OK */ + } else if (i == 2) { + i = atoi(uts.release+4); + if (i >= 30) + break; /* 3.2.30 and newer is OK */ + } + } else { /* 4.x and newer is OK */ + break; + } + env->me_flags |= MDB_FSYNCONLY; + break; + } + } +#endif memset(&meta, 0, sizeof(meta)); @@ -4042,7 +4167,7 @@ PIMAGE_TLS_CALLBACK mdb_tls_cbp __attribute__((section (".CRT$XLB"))) = mdb_tls_ extern const PIMAGE_TLS_CALLBACK mdb_tls_cbp; const PIMAGE_TLS_CALLBACK mdb_tls_cbp = mdb_tls_callback; #pragma const_seg() -#else /* WIN32 */ +#else /* _WIN32 */ #pragma comment(linker, "/INCLUDE:__tls_used") #pragma comment(linker, "/INCLUDE:_mdb_tls_cbp") #pragma data_seg(".CRT$XLB") @@ -4092,7 +4217,7 @@ mdb_env_share_locks(MDB_env *env, int *excl) return rc; } -/** Try to get exlusive lock, otherwise shared. +/** Try to get exclusive lock, otherwise shared. * Maintain *excl = -1: no/unknown lock, 0: shared, 1: exclusive. */ static int ESECT @@ -4233,7 +4358,6 @@ mdb_hash_enc(MDB_val *val, char *encbuf) * @param[in] env The LMDB environment. * @param[in] lpath The pathname of the file used for the lock region. * @param[in] mode The Unix permissions for the file, if we create it. - * @param[out] excl Resulting file lock type: -1 none, 0 shared, 1 exclusive * @param[in,out] excl In -1, out lock type: -1 none, 0 shared, 1 exclusive * @return 0 on success, non-zero on failure. */ @@ -4599,7 +4723,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode if (!(flags & MDB_RDONLY)) { MDB_txn *txn; int tsize = sizeof(MDB_txn), size = tsize + env->me_maxdbs * - (sizeof(MDB_db)+sizeof(MDB_cursor)+sizeof(unsigned int)+1); + (sizeof(MDB_db)+sizeof(MDB_cursor *)+sizeof(unsigned int)+1); txn = calloc(1, size); if (txn) { txn->mt_dbs = (MDB_db *)((char *)txn + tsize); @@ -4607,6 +4731,7 @@ mdb_env_open(MDB_env *env, const char *path, unsigned int flags, mdb_mode_t mode txn->mt_dbiseqs = (unsigned int *)(txn->mt_cursors + env->me_maxdbs); txn->mt_dbflags = (unsigned char *)(txn->mt_dbiseqs + env->me_maxdbs); txn->mt_env = env; + txn->mt_dbxs = env->me_dbxs; #ifdef VL32 txn->mt_rpages = calloc(MDB_IDL_UM_SIZE, sizeof(MDB_ID2)); if (!txn->mt_rpages) { @@ -4639,13 +4764,15 @@ mdb_env_close0(MDB_env *env, int excl) return; /* Doing this here since me_dbxs may not exist during mdb_env_close */ - for (i = env->me_maxdbs; --i > MAIN_DBI; ) - free(env->me_dbxs[i].md_name.mv_data); + if (env->me_dbxs) { + for (i = env->me_maxdbs; --i > MAIN_DBI; ) + free(env->me_dbxs[i].md_name.mv_data); + free(env->me_dbxs); + } free(env->me_pbuf); free(env->me_dbiseqs); free(env->me_dbflags); - free(env->me_dbxs); free(env->me_path); free(env->me_dirty_list); free(env->me_txn0); @@ -4752,7 +4879,11 @@ mdb_cmp_long(const MDB_val *a, const MDB_val *b) *(size_t *)a->mv_data > *(size_t *)b->mv_data; } -/** Compare two items pointing at aligned unsigned int's */ +/** Compare two items pointing at aligned unsigned int's. + * + * This is also set as #MDB_INTEGERDUP|#MDB_DUPFIXED's #MDB_dbx.%md_dcmp, + * but #mdb_cmp_clong() is called instead if the data type is size_t. + */ static int mdb_cmp_int(const MDB_val *a, const MDB_val *b) { @@ -4790,13 +4921,6 @@ mdb_cmp_cint(const MDB_val *a, const MDB_val *b) #endif } -/** Compare two items pointing at size_t's of unknown alignment. */ -#ifdef MISALIGNED_OK -# define mdb_cmp_clong mdb_cmp_long -#else -# define mdb_cmp_clong mdb_cmp_cint -#endif - /** Compare two items lexically */ static int mdb_cmp_memn(const MDB_val *a, const MDB_val *b) @@ -5432,6 +5556,7 @@ mdb_cursor_sibling(MDB_cursor *mc, int move_right) #ifdef VL32 op = mc->mc_pg[mc->mc_top]; #endif + mdb_cursor_pop(mc); DPRINTF(("parent page is page %"Z"u, index %u", mc->mc_pg[mc->mc_top]->mp_pgno, mc->mc_ki[mc->mc_top])); @@ -5590,11 +5715,11 @@ mdb_cursor_prev(MDB_cursor *mc, MDB_val *key, MDB_val *data, MDB_cursor_op op) } return rc; } - } else { - mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); - if (op == MDB_PREV_DUP) - return MDB_NOTFOUND; } + } else { + mc->mc_xcursor->mx_cursor.mc_flags &= ~(C_INITIALIZED|C_EOF); + if (op == MDB_PREV_DUP) + return MDB_NOTFOUND; } } @@ -5806,15 +5931,21 @@ set1: return rc; } } else if (op == MDB_GET_BOTH || op == MDB_GET_BOTH_RANGE) { - MDB_val d2; - if ((rc = mdb_node_read(mc->mc_txn, leaf, &d2)) != MDB_SUCCESS) + MDB_val olddata; + MDB_cmp_func *dcmp; + if ((rc = mdb_node_read(mc->mc_txn, leaf, &olddata)) != MDB_SUCCESS) return rc; - rc = mc->mc_dbx->md_dcmp(data, &d2); + dcmp = mc->mc_dbx->md_dcmp; +#if UINT_MAX < SIZE_MAX + if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) + dcmp = mdb_cmp_clong; +#endif + rc = dcmp(data, &olddata); if (rc) { if (op == MDB_GET_BOTH || rc > 0) return MDB_NOTFOUND; rc = 0; - *data = d2; + *data = olddata; } } else { @@ -6324,16 +6455,17 @@ more: /* Was a single item before, must convert now */ if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { + MDB_cmp_func *dcmp; /* Just overwrite the current item */ if (flags == MDB_CURRENT) goto current; - + dcmp = mc->mc_dbx->md_dcmp; #if UINT_MAX < SIZE_MAX - if (mc->mc_dbx->md_dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) - mc->mc_dbx->md_dcmp = mdb_cmp_clong; + if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) + dcmp = mdb_cmp_clong; #endif /* does data match? */ - if (!mc->mc_dbx->md_dcmp(data, &olddata)) { + if (!dcmp(data, &olddata)) { if (flags & MDB_NODUPDATA) return MDB_KEYEXIST; /* overwrite it */ @@ -7153,6 +7285,7 @@ mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx) mc->mc_snum = 0; mc->mc_top = 0; mc->mc_pg[0] = 0; + mc->mc_ki[0] = 0; mc->mc_flags = 0; if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { mdb_tassert(txn, mx != NULL); @@ -7526,7 +7659,7 @@ mdb_node_move(MDB_cursor *csrc, MDB_cursor *cdst) cdst->mc_ki[cdst->mc_top] = 0; rc = mdb_update_key(cdst, &nullkey); cdst->mc_ki[cdst->mc_top] = ix; - mdb_cassert(csrc, rc == MDB_SUCCESS); + mdb_cassert(cdst, rc == MDB_SUCCESS); } } @@ -7782,12 +7915,12 @@ mdb_rebalance(MDB_cursor *mc) m3 = m2; if (m3 == mc || m3->mc_snum < mc->mc_snum) continue; if (m3->mc_pg[0] == mp) { - m3->mc_snum--; - m3->mc_top--; for (i=0; imc_snum; i++) { m3->mc_pg[i] = m3->mc_pg[i+1]; m3->mc_ki[i] = m3->mc_ki[i+1]; } + m3->mc_snum--; + m3->mc_top--; } } } @@ -7855,9 +7988,23 @@ mdb_rebalance(MDB_cursor *mc) if (mc->mc_ki[ptop] == 0) { rc = mdb_page_merge(&mn, mc); } else { + MDB_cursor dummy; oldki += NUMKEYS(mn.mc_pg[mn.mc_top]); mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1; + /* We want mdb_rebalance to find mn when doing fixups */ + if (mc->mc_flags & C_SUB) { + dummy.mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi]; + mc->mc_txn->mt_cursors[mc->mc_dbi] = &dummy; + dummy.mc_xcursor = (MDB_xcursor *)&mn; + } else { + mn.mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi]; + mc->mc_txn->mt_cursors[mc->mc_dbi] = &mn; + } rc = mdb_page_merge(mc, &mn); + if (mc->mc_flags & C_SUB) + mc->mc_txn->mt_cursors[mc->mc_dbi] = dummy.mc_next; + else + mc->mc_txn->mt_cursors[mc->mc_dbi] = mn.mc_next; mdb_cursor_copy(&mn, mc); } mc->mc_flags &= ~C_EOF; @@ -7884,6 +8031,13 @@ mdb_cursor_del0(MDB_cursor *mc) MDB_cursor *m2, *m3; MDB_dbi dbi = mc->mc_dbi; + /* DB is totally empty now, just bail out. + * Other cursors adjustments were already done + * by mdb_rebalance and aren't needed here. + */ + if (!mc->mc_snum) + return rc; + mp = mc->mc_pg[mc->mc_top]; nkeys = NUMKEYS(mp); @@ -8751,8 +8905,12 @@ mdb_env_copyfd1(MDB_env *env, HANDLE fd) /* Set metapage 1 */ mm->mm_last_pg = txn->mt_next_pgno - freecount - 1; mm->mm_dbs[1] = txn->mt_dbs[1]; - mm->mm_dbs[1].md_root = mm->mm_last_pg; - mm->mm_txnid = 1; + if (mm->mm_last_pg > 1) { + mm->mm_dbs[1].md_root = mm->mm_last_pg; + mm->mm_txnid = 1; + } else { + mm->mm_dbs[1].md_root = P_INVALID; + } } my.mc_wlen[0] = env->me_psize * 2; my.mc_txn = txn; @@ -8847,21 +9005,13 @@ mdb_env_copyfd0(MDB_env *env, HANDLE fd) goto leave; w2 = txn->mt_next_pgno * env->me_psize; -#ifdef WIN32 { - LARGE_INTEGER fsize; - GetFileSizeEx(env->me_fd, &fsize); - if (w2 > fsize.QuadPart) - w2 = fsize.QuadPart; + size_t fsize = 0; + if ((rc = mdb_fsize(env->me_fd, &fsize))) + goto leave; + if (w2 > fsize) + w2 = fsize; } -#else - { - struct stat st; - fstat(env->me_fd, &st); - if (w2 > (size_t)st.st_size) - w2 = st.st_size; - } -#endif wsize = w2 - wsize; while (wsize > 0) { if (wsize > MAX_WRITE) diff --git a/external/db_drivers/liblmdb32/mdb_copy.1 b/external/db_drivers/liblmdb32/mdb_copy.1 index 094b26056..1e2a97694 100644 --- a/external/db_drivers/liblmdb32/mdb_copy.1 +++ b/external/db_drivers/liblmdb32/mdb_copy.1 @@ -1,5 +1,5 @@ .TH MDB_COPY 1 "2014/06/20" "LMDB 0.9.14" -.\" Copyright 2012-2014 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME mdb_copy \- LMDB environment copy tool diff --git a/external/db_drivers/liblmdb32/mdb_copy.c b/external/db_drivers/liblmdb32/mdb_copy.c index e7f965c03..f37ccbcc2 100644 --- a/external/db_drivers/liblmdb32/mdb_copy.c +++ b/external/db_drivers/liblmdb32/mdb_copy.c @@ -1,6 +1,6 @@ /* mdb_copy.c - memory-mapped database backup tool */ /* - * Copyright 2012 Howard Chu, Symas Corp. + * Copyright 2012-2015 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -64,7 +64,7 @@ int main(int argc,char * argv[]) act = "opening environment"; rc = mdb_env_create(&env); if (rc == MDB_SUCCESS) { - rc = mdb_env_open(env, argv[1], flags, 0664); + rc = mdb_env_open(env, argv[1], flags, 0600); } if (rc == MDB_SUCCESS) { act = "copying"; diff --git a/external/db_drivers/liblmdb32/mdb_dump.1 b/external/db_drivers/liblmdb32/mdb_dump.1 index 6fcc93081..dd545049b 100644 --- a/external/db_drivers/liblmdb32/mdb_dump.1 +++ b/external/db_drivers/liblmdb32/mdb_dump.1 @@ -1,5 +1,5 @@ .TH MDB_DUMP 1 "2014/06/20" "LMDB 0.9.14" -.\" Copyright 2014 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME mdb_dump \- LMDB environment export tool diff --git a/external/db_drivers/liblmdb32/mdb_dump.c b/external/db_drivers/liblmdb32/mdb_dump.c index 0eb85fd20..7202d865b 100644 --- a/external/db_drivers/liblmdb32/mdb_dump.c +++ b/external/db_drivers/liblmdb32/mdb_dump.c @@ -1,6 +1,6 @@ /* mdb_dump.c - memory-mapped database dump tool */ /* - * Copyright 2011-2014 Howard Chu, Symas Corp. + * Copyright 2011-2015 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/external/db_drivers/liblmdb32/mdb_load.1 b/external/db_drivers/liblmdb32/mdb_load.1 index 728024010..511ec552b 100644 --- a/external/db_drivers/liblmdb32/mdb_load.1 +++ b/external/db_drivers/liblmdb32/mdb_load.1 @@ -1,5 +1,5 @@ .TH MDB_LOAD 1 "2014/06/20" "LMDB 0.9.14" -.\" Copyright 2014 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copyright 2014-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME mdb_load \- LMDB environment import tool diff --git a/external/db_drivers/liblmdb32/mdb_load.c b/external/db_drivers/liblmdb32/mdb_load.c index e0d95e13c..1f6ce0b7e 100644 --- a/external/db_drivers/liblmdb32/mdb_load.c +++ b/external/db_drivers/liblmdb32/mdb_load.c @@ -1,6 +1,6 @@ /* mdb_load.c - memory-mapped database load tool */ /* - * Copyright 2011-2014 Howard Chu, Symas Corp. + * Copyright 2011-2015 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -176,7 +176,7 @@ static int unhex(unsigned char *c2) static int readline(MDB_val *out, MDB_val *buf) { unsigned char *c1, *c2, *end; - size_t len; + size_t len, l2; int c; if (!(mode & NOHDR)) { @@ -206,6 +206,7 @@ badend: c1 = buf->mv_data; len = strlen((char *)c1); + l2 = len; /* Is buffer too short? */ while (c1[len-1] != '\n') { @@ -217,17 +218,18 @@ badend: return EOF; } c1 = buf->mv_data; - c1 += buf->mv_size; - if (fgets((char *)c1, buf->mv_size, stdin) == NULL) { + c1 += l2; + if (fgets((char *)c1, buf->mv_size+1, stdin) == NULL) { Eof = 1; badend(); return EOF; } buf->mv_size *= 2; len = strlen((char *)c1); + l2 += len; } c1 = c2 = buf->mv_data; - len = strlen((char *)c1); + len = l2; c1[--len] = '\0'; end = c1 + len; diff --git a/external/db_drivers/liblmdb32/mdb_stat.1 b/external/db_drivers/liblmdb32/mdb_stat.1 index 3d8d461d9..e6ee5ad58 100644 --- a/external/db_drivers/liblmdb32/mdb_stat.1 +++ b/external/db_drivers/liblmdb32/mdb_stat.1 @@ -1,5 +1,5 @@ .TH MDB_STAT 1 "2014/06/20" "LMDB 0.9.14" -.\" Copyright 2012-2014 Howard Chu, Symas Corp. All Rights Reserved. +.\" Copyright 2012-2015 Howard Chu, Symas Corp. All Rights Reserved. .\" Copying restrictions apply. See COPYRIGHT/LICENSE. .SH NAME mdb_stat \- LMDB environment status tool diff --git a/external/db_drivers/liblmdb32/mdb_stat.c b/external/db_drivers/liblmdb32/mdb_stat.c index 1e9229296..210609b32 100644 --- a/external/db_drivers/liblmdb32/mdb_stat.c +++ b/external/db_drivers/liblmdb32/mdb_stat.c @@ -1,6 +1,6 @@ /* mdb_stat.c - memory-mapped database status tool */ /* - * Copyright 2011-2013 Howard Chu, Symas Corp. + * Copyright 2011-2015 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/external/db_drivers/liblmdb32/midl.c b/external/db_drivers/liblmdb32/midl.c index 88a3aff10..16782dcaf 100644 --- a/external/db_drivers/liblmdb32/midl.c +++ b/external/db_drivers/liblmdb32/midl.c @@ -3,7 +3,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 2000-2014 The OpenLDAP Foundation. + * Copyright 2000-2015 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/external/db_drivers/liblmdb32/midl.h b/external/db_drivers/liblmdb32/midl.h index f23d7d3f3..1e5fee797 100644 --- a/external/db_drivers/liblmdb32/midl.h +++ b/external/db_drivers/liblmdb32/midl.h @@ -11,7 +11,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 2000-2014 The OpenLDAP Foundation. + * Copyright 2000-2015 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -58,7 +58,7 @@ typedef MDB_ID *MDB_IDL; #ifdef VL32 #define MDB_IDL_LOGN 10 /* DB_SIZE is 2^10, UM_SIZE is 2^11 */ #else -#define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */ + #define MDB_IDL_LOGN 16 /* DB_SIZE is 2^16, UM_SIZE is 2^17 */ #endif #define MDB_IDL_DB_SIZE (1< in each iteration, since MDB_NOOVERWRITE may modify it */ + data.mv_size = sizeof(sval); + data.mv_data = sval; if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) { j++; data.mv_size = sizeof(sval); @@ -68,7 +71,7 @@ int main(int argc,char * argv[]) E(mdb_txn_commit(txn)); E(mdb_env_stat(env, &mst)); - E(mdb_txn_begin(env, NULL, 1, &txn)); + E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { printf("key: %p %.*s, data: %p %.*s\n", @@ -97,7 +100,7 @@ int main(int argc,char * argv[]) printf("Deleted %d values\n", j); E(mdb_env_stat(env, &mst)); - E(mdb_txn_begin(env, NULL, 1, &txn)); + E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); printf("Cursor next\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { @@ -128,6 +131,7 @@ int main(int argc,char * argv[]) (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); + mdb_cursor_close(cursor); mdb_txn_abort(txn); printf("Deleting with cursor\n"); @@ -164,9 +168,9 @@ int main(int argc,char * argv[]) data.mv_data, (int) data.mv_size, (char *) data.mv_data); } mdb_cursor_close(cursor); - mdb_close(env, dbi); - mdb_txn_abort(txn); + + mdb_dbi_close(env, dbi); mdb_env_close(env); return 0; diff --git a/external/db_drivers/liblmdb32/mtest2.c b/external/db_drivers/liblmdb32/mtest2.c index f1a3dbd6c..eacbe59d5 100644 --- a/external/db_drivers/liblmdb32/mtest2.c +++ b/external/db_drivers/liblmdb32/mtest2.c @@ -1,6 +1,6 @@ /* mtest2.c - memory-mapped database tester/toy */ /* - * Copyright 2011-2014 Howard Chu, Symas Corp. + * Copyright 2011-2015 Howard Chu, Symas Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -47,20 +47,22 @@ int main(int argc,char * argv[]) } E(mdb_env_create(&env)); + E(mdb_env_set_maxreaders(env, 1)); E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); + E(mdb_txn_begin(env, NULL, 0, &txn)); - E(mdb_open(txn, "id1", MDB_CREATE, &dbi)); + E(mdb_dbi_open(txn, "id1", MDB_CREATE, &dbi)); key.mv_size = sizeof(int); key.mv_data = sval; - data.mv_size = sizeof(sval); - data.mv_data = sval; printf("Adding %d values\n", count); for (i=0;i - * @param[in] mode The UNIX permissions to set on created files. This parameter - * is ignored on Windows. + * @param[in] mode The UNIX permissions to set on created files and semaphores. + * This parameter is ignored on Windows. * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
      @@ -1021,14 +1021,16 @@ int mdb_txn_renew(MDB_txn *txn); * The database handle may be discarded by calling #mdb_dbi_close(). * The old database handle is returned if the database was already open. * The handle may only be closed once. + * * The database handle will be private to the current transaction until * the transaction is successfully committed. If the transaction is * aborted the handle will be closed automatically. - * After a successful commit the - * handle will reside in the shared environment, and may be used - * by other transactions. This function must not be called from - * multiple concurrent transactions in the same process. A transaction - * that uses this function must finish (either commit or abort) before + * After a successful commit the handle will reside in the shared + * environment, and may be used by other transactions. + * + * This function must not be called from multiple concurrent + * transactions in the same process. A transaction that uses + * this function must finish (either commit or abort) before * any other transaction in the process may use this function. * * To use named databases (with name != NULL), #mdb_env_set_maxdbs() @@ -1050,9 +1052,9 @@ int mdb_txn_renew(MDB_txn *txn); * keys may have multiple data items, stored in sorted order.) By default * keys must be unique and may have only a single data item. *
    • #MDB_INTEGERKEY - * Keys are binary integers in native byte order. Setting this option - * requires all keys to be the same size, typically sizeof(int) - * or sizeof(size_t). + * Keys are binary integers in native byte order, either unsigned int + * or size_t, and will be sorted as such. + * The keys must all be of the same size. *
    • #MDB_DUPFIXED * This flag may only be used in combination with #MDB_DUPSORT. This option * tells the library that the data items for this database are all the same @@ -1060,8 +1062,8 @@ int mdb_txn_renew(MDB_txn *txn); * all data items are the same size, the #MDB_GET_MULTIPLE and #MDB_NEXT_MULTIPLE * cursor operations may be used to retrieve multiple items at once. *
    • #MDB_INTEGERDUP - * This option specifies that duplicate data items are also integers, and - * should be sorted as such. + * This option specifies that duplicate data items are binary integers, + * similar to #MDB_INTEGERKEY keys. *
    • #MDB_REVERSEDUP * This option specifies that duplicate data items should be compared as * strings in reverse order. @@ -1450,7 +1452,7 @@ int mdb_cursor_get(MDB_cursor *cursor, MDB_val *key, MDB_val *data, *
        *
      • #MDB_MAP_FULL - the database is full, see #mdb_env_set_mapsize(). *
      • #MDB_TXN_FULL - the transaction has too many dirty pages. - *
      • EACCES - an attempt was made to modify a read-only database. + *
      • EACCES - an attempt was made to write in a read-only transaction. *
      • EINVAL - an invalid parameter was specified. *
      */ @@ -1470,7 +1472,7 @@ int mdb_cursor_put(MDB_cursor *cursor, MDB_val *key, MDB_val *data, * @return A non-zero error value on failure and 0 on success. Some possible * errors are: *
        - *
      • EACCES - an attempt was made to modify a read-only database. + *
      • EACCES - an attempt was made to write in a read-only transaction. *
      • EINVAL - an invalid parameter was specified. *
      */ diff --git a/external/db_drivers/liblmdb64/mdb.c b/external/db_drivers/liblmdb64/mdb.c index c788b8534..6bdf3151d 100644 --- a/external/db_drivers/liblmdb64/mdb.c +++ b/external/db_drivers/liblmdb64/mdb.c @@ -446,12 +446,17 @@ static txnid_t mdb_debug_start; /** The version number for a database's lockfile format. */ #define MDB_LOCK_VERSION 1 - /** @brief The max size of a key we can write, or 0 for dynamic max. + /** @brief The max size of a key we can write, or 0 for computed max. * - * Define this as 0 to compute the max from the page size. 511 - * is default for backwards compat: liblmdb <= 0.9.10 can break - * when modifying a DB with keys/dupsort data bigger than its max. - * #MDB_DEVEL sets the default to 0. + * This macro should normally be left alone or set to 0. + * Note that a database with big keys or dupsort data cannot be + * reliably modified by a liblmdb which uses a smaller max. + * The default is 511 for backwards compat, or 0 when #MDB_DEVEL. + * + * Other values are allowed, for backwards compat. However: + * A value bigger than the computed max can break if you do not + * know what you are doing, and liblmdb <= 0.9.10 can break when + * modifying a DB with keys/dupsort data bigger than its max. * * Data items in an #MDB_DUPSORT database are also limited to * this size, since they're actually keys of a sub-DB. Keys and @@ -1245,6 +1250,13 @@ static void mdb_default_cmp(MDB_txn *txn, MDB_dbi dbi); static MDB_cmp_func mdb_cmp_memn, mdb_cmp_memnr, mdb_cmp_int, mdb_cmp_cint, mdb_cmp_long; /** @endcond */ +/** Compare two items pointing at size_t's of unknown alignment. */ +#ifdef MISALIGNED_OK +# define mdb_cmp_clong mdb_cmp_long +#else +# define mdb_cmp_clong mdb_cmp_cint +#endif + #ifdef _WIN32 static SECURITY_DESCRIPTOR mdb_null_sd; static SECURITY_ATTRIBUTES mdb_all_sa; @@ -1558,7 +1570,12 @@ mdb_cmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) int mdb_dcmp(MDB_txn *txn, MDB_dbi dbi, const MDB_val *a, const MDB_val *b) { - return txn->mt_dbxs[dbi].md_dcmp(a, b); + MDB_cmp_func *dcmp = txn->mt_dbxs[dbi].md_dcmp; +#if UINT_MAX < SIZE_MAX + if (dcmp == mdb_cmp_int && a->mv_size == sizeof(size_t)) + dcmp = mdb_cmp_clong; +#endif + return dcmp(a, b); } /** Allocate memory for a page. @@ -2486,14 +2503,11 @@ mdb_txn_renew0(MDB_txn *txn) MDB_env *env = txn->mt_env; MDB_txninfo *ti = env->me_txns; MDB_meta *meta; - unsigned int i, nr; + unsigned int i, nr, flags = txn->mt_flags; uint16_t x; int rc, new_notls = 0; - if (txn->mt_flags & MDB_TXN_RDONLY) { - /* Setup db info */ - txn->mt_numdbs = env->me_numdbs; - txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */ + if ((flags &= MDB_TXN_RDONLY) != 0) { if (!ti) { meta = env->me_metas[ mdb_env_pick_meta(env) ]; txn->mt_txnid = meta->mm_txnid; @@ -2546,6 +2560,7 @@ mdb_txn_renew0(MDB_txn *txn) txn->mt_u.reader = r; meta = env->me_metas[txn->mt_txnid & 1]; } + txn->mt_dbxs = env->me_dbxs; /* mostly static anyway */ } else { if (ti) { LOCK_MUTEX_W(env); @@ -2556,14 +2571,11 @@ mdb_txn_renew0(MDB_txn *txn) meta = env->me_metas[ mdb_env_pick_meta(env) ]; txn->mt_txnid = meta->mm_txnid; } - /* Setup db info */ - txn->mt_numdbs = env->me_numdbs; txn->mt_txnid++; #if MDB_DEBUG if (txn->mt_txnid == mdb_debug_start) mdb_debug = 1; #endif - txn->mt_flags = 0; txn->mt_child = NULL; txn->mt_loose_pgs = NULL; txn->mt_loose_count = 0; @@ -2583,6 +2595,10 @@ mdb_txn_renew0(MDB_txn *txn) /* Moved to here to avoid a data race in read TXNs */ txn->mt_next_pgno = meta->mm_last_pg+1; + txn->mt_flags = flags; + + /* Setup db info */ + txn->mt_numdbs = env->me_numdbs; for (i=2; imt_numdbs; i++) { x = env->me_dbflags[i]; txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS; @@ -3132,6 +3148,7 @@ mdb_page_flush(MDB_txn *txn, int keep) /* Write up to MDB_COMMIT_PAGES dirty pages at a time. */ if (pos!=next_pos || n==MDB_COMMIT_PAGES || wsize+size>MAX_WRITE) { if (n) { +retry_write: /* Write previous page(s) */ #ifdef MDB_USE_PWRITEV wres = pwritev(env->me_fd, iov, n, wpos); @@ -3139,8 +3156,11 @@ mdb_page_flush(MDB_txn *txn, int keep) if (n == 1) { wres = pwrite(env->me_fd, iov[0].iov_base, wsize, wpos); } else { +retry_seek: if (lseek(env->me_fd, wpos, SEEK_SET) == -1) { rc = ErrCode(); + if (rc == EINTR) + goto retry_seek; DPRINTF(("lseek: %s", strerror(rc))); return rc; } @@ -3150,6 +3170,8 @@ mdb_page_flush(MDB_txn *txn, int keep) if (wres != wsize) { if (wres < 0) { rc = ErrCode(); + if (rc == EINTR) + goto retry_write; DPRINTF(("Write error: %s", strerror(rc))); } else { rc = EIO; /* TODO: Use which error code? */ @@ -3519,7 +3541,8 @@ mdb_env_init_meta(MDB_env *env, MDB_meta *meta) int len; #define DO_PWRITE(rc, fd, ptr, size, len, pos) do { \ len = pwrite(fd, ptr, size, pos); \ - rc = (len >= 0); } while(0) + if (len == -1 && ErrCode() == EINTR) continue; \ + rc = (len >= 0); break; } while(1) #endif DPUTS("writing new meta page"); @@ -3624,6 +3647,7 @@ mdb_env_write_meta(MDB_txn *txn) /* Write to the SYNC fd */ mfd = env->me_flags & (MDB_NOSYNC|MDB_NOMETASYNC) ? env->me_fd : env->me_mfd; +retry_write: #ifdef _WIN32 { memset(&ov, 0, sizeof(ov)); @@ -3636,6 +3660,8 @@ mdb_env_write_meta(MDB_txn *txn) #endif if (rc != len) { rc = rc < 0 ? ErrCode() : EIO; + if (rc == EINTR) + goto retry_write; DPUTS("write failed, disk error?"); /* On a failure, the pagecache still contains the new data. * Write some old data back, to prevent it from being used. @@ -4761,7 +4787,11 @@ mdb_cmp_long(const MDB_val *a, const MDB_val *b) *(size_t *)a->mv_data > *(size_t *)b->mv_data; } -/** Compare two items pointing at aligned unsigned int's */ +/** Compare two items pointing at aligned unsigned int's. + * + * This is also set as #MDB_INTEGERDUP|#MDB_DUPFIXED's #MDB_dbx.%md_dcmp, + * but #mdb_cmp_clong() is called instead if the data type is size_t. + */ static int mdb_cmp_int(const MDB_val *a, const MDB_val *b) { @@ -4799,13 +4829,6 @@ mdb_cmp_cint(const MDB_val *a, const MDB_val *b) #endif } -/** Compare two items pointing at size_t's of unknown alignment. */ -#ifdef MISALIGNED_OK -# define mdb_cmp_clong mdb_cmp_long -#else -# define mdb_cmp_clong mdb_cmp_cint -#endif - /** Compare two items lexically */ static int mdb_cmp_memn(const MDB_val *a, const MDB_val *b) @@ -5741,15 +5764,21 @@ set1: return rc; } } else if (op == MDB_GET_BOTH || op == MDB_GET_BOTH_RANGE) { - MDB_val d2; - if ((rc = mdb_node_read(mc->mc_txn, leaf, &d2)) != MDB_SUCCESS) + MDB_val olddata; + MDB_cmp_func *dcmp; + if ((rc = mdb_node_read(mc->mc_txn, leaf, &olddata)) != MDB_SUCCESS) return rc; - rc = mc->mc_dbx->md_dcmp(data, &d2); + dcmp = mc->mc_dbx->md_dcmp; +#if UINT_MAX < SIZE_MAX + if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) + dcmp = mdb_cmp_clong; +#endif + rc = dcmp(data, &olddata); if (rc) { if (op == MDB_GET_BOTH || rc > 0) return MDB_NOTFOUND; rc = 0; - *data = d2; + *data = olddata; } } else { @@ -6259,16 +6288,17 @@ more: /* Was a single item before, must convert now */ if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) { + MDB_cmp_func *dcmp; /* Just overwrite the current item */ if (flags == MDB_CURRENT) goto current; - + dcmp = mc->mc_dbx->md_dcmp; #if UINT_MAX < SIZE_MAX - if (mc->mc_dbx->md_dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) - mc->mc_dbx->md_dcmp = mdb_cmp_clong; + if (dcmp == mdb_cmp_int && olddata.mv_size == sizeof(size_t)) + dcmp = mdb_cmp_clong; #endif /* does data match? */ - if (!mc->mc_dbx->md_dcmp(data, &olddata)) { + if (!dcmp(data, &olddata)) { if (flags & MDB_NODUPDATA) return MDB_KEYEXIST; /* overwrite it */ @@ -7088,6 +7118,7 @@ mdb_cursor_init(MDB_cursor *mc, MDB_txn *txn, MDB_dbi dbi, MDB_xcursor *mx) mc->mc_snum = 0; mc->mc_top = 0; mc->mc_pg[0] = 0; + mc->mc_ki[0] = 0; mc->mc_flags = 0; if (txn->mt_dbs[dbi].md_flags & MDB_DUPSORT) { mdb_tassert(txn, mx != NULL); @@ -7717,12 +7748,12 @@ mdb_rebalance(MDB_cursor *mc) m3 = m2; if (m3 == mc || m3->mc_snum < mc->mc_snum) continue; if (m3->mc_pg[0] == mp) { - m3->mc_snum--; - m3->mc_top--; for (i=0; imc_snum; i++) { m3->mc_pg[i] = m3->mc_pg[i+1]; m3->mc_ki[i] = m3->mc_ki[i+1]; } + m3->mc_snum--; + m3->mc_top--; } } } @@ -7790,9 +7821,23 @@ mdb_rebalance(MDB_cursor *mc) if (mc->mc_ki[ptop] == 0) { rc = mdb_page_merge(&mn, mc); } else { + MDB_cursor dummy; oldki += NUMKEYS(mn.mc_pg[mn.mc_top]); mn.mc_ki[mn.mc_top] += mc->mc_ki[mn.mc_top] + 1; + /* We want mdb_rebalance to find mn when doing fixups */ + if (mc->mc_flags & C_SUB) { + dummy.mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi]; + mc->mc_txn->mt_cursors[mc->mc_dbi] = &dummy; + dummy.mc_xcursor = (MDB_xcursor *)&mn; + } else { + mn.mc_next = mc->mc_txn->mt_cursors[mc->mc_dbi]; + mc->mc_txn->mt_cursors[mc->mc_dbi] = &mn; + } rc = mdb_page_merge(mc, &mn); + if (mc->mc_flags & C_SUB) + mc->mc_txn->mt_cursors[mc->mc_dbi] = dummy.mc_next; + else + mc->mc_txn->mt_cursors[mc->mc_dbi] = mn.mc_next; mdb_cursor_copy(&mn, mc); } mc->mc_flags &= ~C_EOF; @@ -7819,6 +7864,13 @@ mdb_cursor_del0(MDB_cursor *mc) MDB_cursor *m2, *m3; MDB_dbi dbi = mc->mc_dbi; + /* DB is totally empty now, just bail out. + * Other cursors adjustments were already done + * by mdb_rebalance and aren't needed here. + */ + if (!mc->mc_snum) + return rc; + mp = mc->mc_pg[mc->mc_top]; nkeys = NUMKEYS(mp); diff --git a/external/db_drivers/liblmdb64/mtest.c b/external/db_drivers/liblmdb64/mtest.c index 66dabc752..9d15088b0 100644 --- a/external/db_drivers/liblmdb64/mtest.c +++ b/external/db_drivers/liblmdb64/mtest.c @@ -45,19 +45,22 @@ int main(int argc,char * argv[]) } E(mdb_env_create(&env)); + E(mdb_env_set_maxreaders(env, 1)); E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP /*|MDB_NOSYNC*/, 0664)); + E(mdb_txn_begin(env, NULL, 0, &txn)); - E(mdb_open(txn, NULL, 0, &dbi)); + E(mdb_dbi_open(txn, NULL, 0, &dbi)); key.mv_size = sizeof(int); key.mv_data = sval; - data.mv_size = sizeof(sval); - data.mv_data = sval; printf("Adding %d values\n", count); for (i=0;i in each iteration, since MDB_NOOVERWRITE may modify it */ + data.mv_size = sizeof(sval); + data.mv_data = sval; if (RES(MDB_KEYEXIST, mdb_put(txn, dbi, &key, &data, MDB_NOOVERWRITE))) { j++; data.mv_size = sizeof(sval); @@ -68,7 +71,7 @@ int main(int argc,char * argv[]) E(mdb_txn_commit(txn)); E(mdb_env_stat(env, &mst)); - E(mdb_txn_begin(env, NULL, 1, &txn)); + E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { printf("key: %p %.*s, data: %p %.*s\n", @@ -97,7 +100,7 @@ int main(int argc,char * argv[]) printf("Deleted %d values\n", j); E(mdb_env_stat(env, &mst)); - E(mdb_txn_begin(env, NULL, 1, &txn)); + E(mdb_txn_begin(env, NULL, MDB_RDONLY, &txn)); E(mdb_cursor_open(txn, dbi, &cursor)); printf("Cursor next\n"); while ((rc = mdb_cursor_get(cursor, &key, &data, MDB_NEXT)) == 0) { @@ -128,6 +131,7 @@ int main(int argc,char * argv[]) (int) key.mv_size, (char *) key.mv_data, (int) data.mv_size, (char *) data.mv_data); + mdb_cursor_close(cursor); mdb_txn_abort(txn); printf("Deleting with cursor\n"); @@ -164,9 +168,9 @@ int main(int argc,char * argv[]) data.mv_data, (int) data.mv_size, (char *) data.mv_data); } mdb_cursor_close(cursor); - mdb_close(env, dbi); - mdb_txn_abort(txn); + + mdb_dbi_close(env, dbi); mdb_env_close(env); return 0; diff --git a/external/db_drivers/liblmdb64/mtest2.c b/external/db_drivers/liblmdb64/mtest2.c index 33e0e741c..eacbe59d5 100644 --- a/external/db_drivers/liblmdb64/mtest2.c +++ b/external/db_drivers/liblmdb64/mtest2.c @@ -47,20 +47,22 @@ int main(int argc,char * argv[]) } E(mdb_env_create(&env)); + E(mdb_env_set_maxreaders(env, 1)); E(mdb_env_set_mapsize(env, 10485760)); E(mdb_env_set_maxdbs(env, 4)); E(mdb_env_open(env, "./testdb", MDB_FIXEDMAP|MDB_NOSYNC, 0664)); + E(mdb_txn_begin(env, NULL, 0, &txn)); - E(mdb_open(txn, "id1", MDB_CREATE, &dbi)); + E(mdb_dbi_open(txn, "id1", MDB_CREATE, &dbi)); key.mv_size = sizeof(int); key.mv_data = sval; - data.mv_size = sizeof(sval); - data.mv_data = sval; printf("Adding %d values\n", count); for (i=0;i. # @@ -590,8 +590,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='unbound' PACKAGE_TARNAME='unbound' -PACKAGE_VERSION='1.5.4' -PACKAGE_STRING='unbound 1.5.4' +PACKAGE_VERSION='1.5.5' +PACKAGE_STRING='unbound 1.5.5' PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl' PACKAGE_URL='' @@ -1389,7 +1389,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures unbound 1.5.4 to adapt to many kinds of systems. +\`configure' configures unbound 1.5.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1454,7 +1454,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of unbound 1.5.4:";; + short | recursive ) echo "Configuration of unbound 1.5.5:";; esac cat <<\_ACEOF @@ -1629,7 +1629,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -unbound configure 1.5.4 +unbound configure 1.5.5 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2338,7 +2338,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by unbound $as_me 1.5.4, which was +It was created by unbound $as_me 1.5.5, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2690,7 +2690,7 @@ UNBOUND_VERSION_MAJOR=1 UNBOUND_VERSION_MINOR=5 -UNBOUND_VERSION_MICRO=4 +UNBOUND_VERSION_MICRO=5 LIBUNBOUND_CURRENT=5 @@ -16684,7 +16684,7 @@ rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LibreSSL" >&5 $as_echo_n "checking for LibreSSL... " >&6; } -if grep OPENSSL_VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then +if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } @@ -16845,6 +16845,36 @@ fi cat >>confdefs.h <<_ACEOF #define HAVE_DECL_SK_SSL_COMP_POP_FREE $ac_have_decl _ACEOF +ac_fn_c_check_decl "$LINENO" "SSL_CTX_set_ecdh_auto" "ac_cv_have_decl_SSL_CTX_set_ecdh_auto" " +$ac_includes_default +#ifdef HAVE_OPENSSL_ERR_H +#include +#endif + +#ifdef HAVE_OPENSSL_RAND_H +#include +#endif + +#ifdef HAVE_OPENSSL_CONF_H +#include +#endif + +#ifdef HAVE_OPENSSL_ENGINE_H +#include +#endif +#include +#include + +" +if test "x$ac_cv_have_decl_SSL_CTX_set_ecdh_auto" = xyes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_SSL_CTX_SET_ECDH_AUTO $ac_have_decl +_ACEOF fi @@ -18150,6 +18180,8 @@ esac fi +LIBOBJ_WITHOUT_CTIMEARC4="$LIBOBJS" + ac_fn_c_check_func "$LINENO" "reallocarray" "ac_cv_func_reallocarray" if test "x$ac_cv_func_reallocarray" = xyes; then : $as_echo "#define HAVE_REALLOCARRAY 1" >>confdefs.h @@ -18164,8 +18196,6 @@ esac fi -LIBOBJ_WITHOUT_CTIMEARC4="$LIBOBJS" - if test "$USE_NSS" = "no"; then ac_fn_c_check_func "$LINENO" "arc4random" "ac_cv_func_arc4random" if test "x$ac_cv_func_arc4random" = xyes; then : @@ -18890,7 +18920,7 @@ _ACEOF -version=1.5.4 +version=1.5.5 date=`date +'%b %e, %Y'` @@ -19405,7 +19435,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by unbound $as_me 1.5.4, which was +This file was extended by unbound $as_me 1.5.5, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -19471,7 +19501,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -unbound config.status 1.5.4 +unbound config.status 1.5.5 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/external/unbound/configure.ac b/external/unbound/configure.ac index de809afdd..5ad39c7d5 100644 --- a/external/unbound/configure.ac +++ b/external/unbound/configure.ac @@ -10,7 +10,7 @@ sinclude(dnstap/dnstap.m4) # must be numbers. ac_defun because of later processing m4_define([VERSION_MAJOR],[1]) m4_define([VERSION_MINOR],[5]) -m4_define([VERSION_MICRO],[4]) +m4_define([VERSION_MICRO],[5]) AC_INIT(unbound, m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]), unbound-bugs@nlnetlabs.nl, unbound) AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR]) AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR]) @@ -566,7 +566,7 @@ if test $USE_NSS = "no"; then ACX_WITH_SSL ACX_LIB_SSL AC_MSG_CHECKING([for LibreSSL]) -if grep OPENSSL_VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then +if grep VERSION_TEXT $ssldir/include/openssl/opensslv.h | grep "LibreSSL" >/dev/null; then AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_LIBRESSL], [1], [Define if we have LibreSSL]) # libressl provides these compat functions, but they may also be @@ -578,7 +578,7 @@ fi AC_CHECK_HEADERS([openssl/conf.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_HEADERS([openssl/engine.h],,, [AC_INCLUDES_DEFAULT]) AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode]) -AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free], [], [], [ +AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto], [], [], [ AC_INCLUDES_DEFAULT #ifdef HAVE_OPENSSL_ERR_H #include @@ -998,9 +998,10 @@ AC_REPLACE_FUNCS(strlcat) AC_REPLACE_FUNCS(strlcpy) AC_REPLACE_FUNCS(memmove) AC_REPLACE_FUNCS(gmtime_r) -AC_REPLACE_FUNCS(reallocarray) +dnl without CTIME, ARC4-functions and without reallocarray. LIBOBJ_WITHOUT_CTIMEARC4="$LIBOBJS" AC_SUBST(LIBOBJ_WITHOUT_CTIMEARC4) +AC_REPLACE_FUNCS(reallocarray) if test "$USE_NSS" = "no"; then AC_REPLACE_FUNCS(arc4random) AC_REPLACE_FUNCS(arc4random_uniform) diff --git a/external/unbound/daemon/daemon.c b/external/unbound/daemon/daemon.c index 0cd37ae82..e763f724e 100644 --- a/external/unbound/daemon/daemon.c +++ b/external/unbound/daemon/daemon.c @@ -399,6 +399,12 @@ daemon_create_workers(struct daemon* daemon) verbose(VERB_ALGO, "total of %d outgoing ports available", numport); daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1); + if(daemon->reuseport && (int)daemon->num < (int)daemon->num_ports) { + log_warn("cannot reduce num-threads to %d because so-reuseport " + "so continuing with %d threads.", (int)daemon->num, + (int)daemon->num_ports); + daemon->num = (int)daemon->num_ports; + } daemon->workers = (struct worker**)calloc((size_t)daemon->num, sizeof(struct worker*)); if(daemon->cfg->dnstap) { @@ -464,7 +470,7 @@ thread_start(void* arg) #endif #ifdef SO_REUSEPORT if(worker->daemon->cfg->so_reuseport) - port_num = worker->thread_num; + port_num = worker->thread_num % worker->daemon->num_ports; else port_num = 0; #endif diff --git a/external/unbound/daemon/remote.c b/external/unbound/daemon/remote.c index 93d0eda28..300948b32 100644 --- a/external/unbound/daemon/remote.c +++ b/external/unbound/daemon/remote.c @@ -243,9 +243,9 @@ daemon_remote_create(struct config_file* cfg) goto setup_error; } verbose(VERB_ALGO, "setup SSL certificates"); - if (!SSL_CTX_use_certificate_file(rc->ctx,s_cert,SSL_FILETYPE_PEM)) { + if (!SSL_CTX_use_certificate_chain_file(rc->ctx,s_cert)) { log_err("Error for server-cert-file: %s", s_cert); - log_crypto_err("Error in SSL_CTX use_certificate_file"); + log_crypto_err("Error in SSL_CTX use_certificate_chain_file"); goto setup_error; } if(!SSL_CTX_use_PrivateKey_file(rc->ctx,s_key,SSL_FILETYPE_PEM)) { @@ -258,6 +258,23 @@ daemon_remote_create(struct config_file* cfg) log_crypto_err("Error in SSL_CTX check_private_key"); goto setup_error; } +#if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO + if(!SSL_CTX_set_ecdh_auto(rc->ctx,1)) { + log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE"); + } +#elif defined(USE_ECDSA) + if(1) { + EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1); + if (!ecdh) { + log_crypto_err("could not find p256, not enabling ECDHE"); + } else { + if (1 != SSL_CTX_set_tmp_ecdh (rc->ctx, ecdh)) { + log_crypto_err("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE"); + } + EC_KEY_free (ecdh); + } + } +#endif if(!SSL_CTX_load_verify_locations(rc->ctx, s_cert, NULL)) { log_crypto_err("Error setting up SSL_CTX verify locations"); setup_error: @@ -1683,6 +1700,7 @@ parse_delegpt(SSL* ssl, char* args, uint8_t* nm, int allow_names) } } } + dp->has_parent_side_NS = 1; return dp; } diff --git a/external/unbound/daemon/worker.c b/external/unbound/daemon/worker.c index f4e87289a..79aec4d3a 100644 --- a/external/unbound/daemon/worker.c +++ b/external/unbound/daemon/worker.c @@ -568,7 +568,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo, if(rep->an_numrrsets > 0 && (rep->rrsets[0]->rk.type == htons(LDNS_RR_TYPE_CNAME) || rep->rrsets[0]->rk.type == htons(LDNS_RR_TYPE_DNAME))) { - if(!reply_check_cname_chain(rep)) { + if(!reply_check_cname_chain(qinfo, rep)) { /* cname chain invalid, redo iterator steps */ verbose(VERB_ALGO, "Cache reply: cname chain broken"); bail_out: diff --git a/external/unbound/doc/Changelog b/external/unbound/doc/Changelog index f06654de4..35f67c113 100644 --- a/external/unbound/doc/Changelog +++ b/external/unbound/doc/Changelog @@ -1,3 +1,73 @@ +13 August 2015: Wouter + - 5011 implementation does not insist on all algorithms, when + harden-algo-downgrade is turned off. + - Reap the child process that libunbound spawns. + +11 August 2015: Wouter + - Fix #694: configure script does not detect LibreSSL 2.2.2 + +4 August 2015: Wouter + - Document that local-zone nodefault matches exactly and transparent + can be used to release a subzone. + +3 August 2015: Wouter + - Document in the manual more text about configuring locally served + zones. + - Fix 5011 anchor update timer after reload. + - Fix mktime in unbound-anchor not using UTC. + +30 July 2015: Wouter + - please afl-gcc (llvm) for uninitialised variable warning. + - Added permit-small-holddown config to debug fast 5011 rollover. + +24 July 2015: Wouter + - Fix #690: Reload fails when so-reuseport is yes after changing + num-threads. + - iana portlist update. + +21 July 2015: Wouter + - Fix configure to detect SSL_CTX_set_ecdh_auto. + - iana portlist update. + +20 July 2015: Wouter + - Enable ECDHE for servers. Where available, use + SSL_CTX_set_ecdh_auto() for TLS-wrapped server configurations to + enable ECDHE. Otherwise, manually offer curve p256. + Client connections should automatically use ECDHE when available. + (thanks Daniel Kahn Gillmor) + +18 July 2015: Willem + - Allow certificate chain files to allow for intermediate certificates. + (thanks Daniel Kahn Gillmor) + +13 July 2015: Wouter + - makedist produces sha1 and sha256 files for created binaries too. + +9 July 2015: Wouter + - 1.5.4 release tag + - trunk has 1.5.5 in development. + - Fix #681: Setting forwarders with unbound-control forward + implicitly turns on forward-first. + +29 June 2015: Wouter + - iana portlist update. + - Fix alloc with log for allocation size checks. + +26 June 2015: Wouter + - Fix #677 Fix DNAME responses from cache that failed internal chain + test. + - iana portlist update. + +22 June 2015: Wouter + - Fix #677 Fix CNAME corresponding to a DNAME was checked incorrectly + and was therefore always synthesized (thanks to Valentin Dietrich). + +4 June 2015: Wouter + - RFC 7553 RR type URI support, is now enabled by default. + +2 June 2015: Wouter + - Fix #674: Do not free pointers given by getenv. + 29 May 2015: Wouter - Fix that unparseable error responses are ratelimited. - SOA negative TTL is capped at minimumttl in its rdata section. diff --git a/external/unbound/doc/example.conf.in b/external/unbound/doc/example.conf.in index efe64f394..90491119e 100644 --- a/external/unbound/doc/example.conf.in +++ b/external/unbound/doc/example.conf.in @@ -444,6 +444,9 @@ server: # If the value 0 is given, missing anchors are not removed. # keep-missing: 31622400 # 366 days + # debug option that allows very small holddown times for key rollover + # permit-small-holddown: no + # the amount of memory to use for the key cache. # plain value in bytes or you can append k, m or G. default is "4Mb". # key-cache-size: 4m @@ -623,6 +626,8 @@ remote-control: # nameservers by hostname or by ipaddress. If you set stub-prime to yes, # the list is treated as priming hints (default is no). # With stub-first yes, it attempts without the stub if it fails. +# Consider adding domain-insecure: name and local-zone: name nodefault +# to the server: section if the stub is a locally served zone. # stub-zone: # name: "example.com" # stub-addr: 192.0.2.68 diff --git a/external/unbound/doc/unbound.conf.5.in b/external/unbound/doc/unbound.conf.5.in index 8836ed50c..cfbedd7d0 100644 --- a/external/unbound/doc/unbound.conf.5.in +++ b/external/unbound/doc/unbound.conf.5.in @@ -801,6 +801,10 @@ mechanism work with zones that perform regular (non\-5011) rollovers. The default is 366 days. The value 0 does not remove missing anchors, as per the RFC. .TP +.B permit\-small\-holddown: \fI +Debug option that allows the autotrust 5011 rollover timers to assume +very small values. Default is no. +.TP .B key\-cache\-size: \fI Number of bytes size of the key cache. Default is 4 megabytes. A plain number is in bytes, append 'k', 'm' or 'g' for kilobytes, megabytes @@ -895,7 +899,8 @@ infected machines without answering the queries. Used to turn off default contents for AS112 zones. The other types also turn off default contents for the zone. The 'nodefault' option has no other effect than turning off default contents for the -given zone. +given zone. Use \fInodefault\fR if you use exactly that zone, if you want to +use a subzone, use \fItransparent\fR. .P The default zones are localhost, reverse 127.0.0.1 and ::1, and the AS112 zones. The AS112 zones are reverse DNS zones for private use and reserved @@ -1124,6 +1129,12 @@ bit on replies for the private zone (authoritative servers do not set the AD bit). This setup makes unbound capable of answering queries for the private zone, and can even set the AD bit ('authentic'), but the AA ('authoritative') bit is not set on these replies. +.P +Consider adding \fBserver:\fR statements for \fBdomain\-insecure:\fR and +for \fBlocal\-zone:\fI name nodefault\fR for the zone if it is a locally +served zone. The insecure clause stops DNSSEC from invalidating the +zone. The local zone nodefault (or \fItransparent\fR) clause makes the +(reverse\-) zone bypass unbound's filtering of RFC1918 zones. .TP .B name: \fI Name of the stub zone. diff --git a/external/unbound/iterator/iter_scrub.c b/external/unbound/iterator/iter_scrub.c index e9db19482..cc05867c0 100644 --- a/external/unbound/iterator/iter_scrub.c +++ b/external/unbound/iterator/iter_scrub.c @@ -372,7 +372,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg, /* check next cname */ uint8_t* t = NULL; size_t tlen = 0; - if(!parse_get_cname_target(rrset, &t, &tlen)) + if(!parse_get_cname_target(nx, &t, &tlen)) return 0; if(dname_pkt_compare(pkt, alias, t) == 0) { /* it's OK and better capitalized */ diff --git a/external/unbound/libunbound/libunbound.c b/external/unbound/libunbound/libunbound.c index b3a4c2ba7..e96b3528a 100644 --- a/external/unbound/libunbound/libunbound.c +++ b/external/unbound/libunbound/libunbound.c @@ -65,6 +65,9 @@ #ifdef HAVE_PTHREAD #include #endif +#ifdef HAVE_SYS_WAIT_H +#include +#endif #if defined(UB_ON_WINDOWS) && defined (HAVE_WINDOWS_H) #include @@ -218,6 +221,12 @@ static void ub_stop_bg(struct ub_ctx* ctx) ub_thread_join(ctx->bg_tid); } else { lock_basic_unlock(&ctx->cfglock); +#ifndef UB_ON_WINDOWS + if(waitpid(ctx->bg_pid, NULL, 0) == -1) { + if(verbosity > 2) + log_err("waitpid: %s", strerror(errno)); + } +#endif } } else { @@ -1028,6 +1037,7 @@ ub_ctx_hosts(struct ub_ctx* ctx, const char* fname) "\\hosts"); retval=ub_ctx_hosts(ctx, buf); } + free(name); return retval; } return UB_READFILE; diff --git a/external/unbound/makedist.sh b/external/unbound/makedist.sh index f06017668..23c89fc3d 100755 --- a/external/unbound/makedist.sh +++ b/external/unbound/makedist.sh @@ -136,6 +136,43 @@ create_temp_dir () { cd $temp_dir } +# pass filename as $1 arg. +# creates file.sha1 and file.sha256 +storehash () { + case $OSTYPE in + linux*) + sha=`sha1sum $1 | awk '{ print $1 }'` + sha256=`sha256sum $1 | awk '{ print $1 }'` + ;; + freebsd*) + sha=`sha1 $1 | awk '{ print $5 }'` + sha256=`sha256 $1 | awk '{ print $5 }'` + ;; + *) + # in case $OSTYPE is gone. + case `uname` in + Linux*) + sha=`sha1sum $1 | awk '{ print $1 }'` + sha256=`sha256sum $1 | awk '{ print $1 }'` + ;; + FreeBSD*) + sha=`sha1 $1 | awk '{ print $5 }'` + sha256=`sha256 $1 | awk '{ print $5 }'` + ;; + *) + sha=`sha1sum $1 | awk '{ print $1 }'` + sha256=`sha256sum $1 | awk '{ print $1 }'` + ;; + esac + ;; + esac + echo $sha > $1.sha1 + echo $sha256 > $1.sha256 + echo "hash of $1.{sha1,sha256}" + echo "sha1 $sha" + echo "sha256 $sha256" +} + SNAPSHOT="no" RC="no" @@ -311,6 +348,8 @@ if [ "$DOWIN" = "yes" ]; then mv unbound-$version.zip $cwd/. cleanup fi + storehash unbound_setup_$version.exe + storehash unbound-$version.zip ls -lG unbound_setup_$version.exe ls -lG unbound-$version.zip info "Done" @@ -411,36 +450,7 @@ tar czf ../unbound-$version.tar.gz unbound-$version || error_cleanup "Failed to cleanup -case $OSTYPE in - linux*) - sha=`sha1sum unbound-$version.tar.gz | awk '{ print $1 }'` - sha256=`sha256sum unbound-$version.tar.gz | awk '{ print $1 }'` - ;; - freebsd*) - sha=`sha1 unbound-$version.tar.gz | awk '{ print $5 }'` - sha256=`sha256 unbound-$version.tar.gz | awk '{ print $5 }'` - ;; - *) - # in case $OSTYPE is gone. - case `uname` in - Linux*) - sha=`sha1sum unbound-$version.tar.gz | awk '{ print $1 }'` - sha256=`sha256sum unbound-$version.tar.gz | awk '{ print $1 }'` - ;; - FreeBSD*) - sha=`sha1 unbound-$version.tar.gz | awk '{ print $5 }'` - sha256=`sha256 unbound-$version.tar.gz | awk '{ print $5 }'` - ;; - *) - sha=`sha1sum unbound-$version.tar.gz | awk '{ print $1 }'` - sha256=`sha256sum unbound-$version.tar.gz | awk '{ print $1 }'` - ;; - esac - ;; -esac -echo $sha > unbound-$version.tar.gz.sha1 -echo $sha256 > unbound-$version.tar.gz.sha256 +storehash unbound-$version.tar.gz info "Unbound distribution created successfully." -info "SHA1sum: $sha" diff --git a/external/unbound/services/cache/dns.c b/external/unbound/services/cache/dns.c index 53127ce59..ba81afde4 100644 --- a/external/unbound/services/cache/dns.c +++ b/external/unbound/services/cache/dns.c @@ -505,7 +505,7 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r, return NULL; if(r->an_numrrsets > 0 && (r->rrsets[0]->rk.type == htons( LDNS_RR_TYPE_CNAME) || r->rrsets[0]->rk.type == htons( - LDNS_RR_TYPE_DNAME)) && !reply_check_cname_chain(r)) { + LDNS_RR_TYPE_DNAME)) && !reply_check_cname_chain(q, r)) { /* cname chain is now invalid, reconstruct msg */ rrset_array_unlock(r->ref, r->rrset_count); return NULL; diff --git a/external/unbound/sldns/rrdef.c b/external/unbound/sldns/rrdef.c index 72161d7b6..a8c6229b9 100644 --- a/external/unbound/sldns/rrdef.c +++ b/external/unbound/sldns/rrdef.c @@ -213,13 +213,11 @@ static const sldns_rdf_type type_eui48_wireformat[] = { static const sldns_rdf_type type_eui64_wireformat[] = { LDNS_RDF_TYPE_EUI64 }; -#ifdef DRAFT_RRTYPES static const sldns_rdf_type type_uri_wireformat[] = { LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_INT16, LDNS_RDF_TYPE_LONG_STR }; -#endif static const sldns_rdf_type type_caa_wireformat[] = { LDNS_RDF_TYPE_INT8, LDNS_RDF_TYPE_TAG, @@ -590,12 +588,8 @@ static sldns_rr_descriptor rdata_field_descriptors[] = { /* ANY: A request for all (available) records */ {LDNS_RR_TYPE_ANY, "ANY", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -#ifdef DRAFT_RRTYPES /* 256 */ {LDNS_RR_TYPE_URI, "URI", 3, 3, type_uri_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -#else -{LDNS_RR_TYPE_NULL, "TYPE256", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, -#endif /* 257 */ {LDNS_RR_TYPE_CAA, "CAA", 3, 3, type_caa_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 }, diff --git a/external/unbound/sldns/rrdef.h b/external/unbound/sldns/rrdef.h index 933bcdfbf..678d2bc79 100644 --- a/external/unbound/sldns/rrdef.h +++ b/external/unbound/sldns/rrdef.h @@ -220,8 +220,7 @@ enum sldns_enum_rr_type LDNS_RR_TYPE_MAILA = 254, /** any type (wildcard) */ LDNS_RR_TYPE_ANY = 255, - /** draft-faltstrom-uri-06 */ - LDNS_RR_TYPE_URI = 256, + LDNS_RR_TYPE_URI = 256, /* RFC 7553 */ LDNS_RR_TYPE_CAA = 257, /* RFC 6844 */ /** DNSSEC Trust Authorities */ diff --git a/external/unbound/smallapp/unbound-anchor.c b/external/unbound/smallapp/unbound-anchor.c index 576a30f64..92bfa8428 100644 --- a/external/unbound/smallapp/unbound-anchor.c +++ b/external/unbound/smallapp/unbound-anchor.c @@ -117,6 +117,7 @@ #include "config.h" #include "libunbound/unbound.h" #include "sldns/rrdef.h" +#include "sldns/parseutil.h" #include #ifndef HAVE_EXPAT_H #error "need libexpat to parse root-anchors.xml file." @@ -1328,7 +1329,7 @@ xml_convertdate(const char* str) /* but ignore, (lenient) */ } - t = mktime(&tm); + t = sldns_mktime_from_utc(&tm); if(t == (time_t)-1) { if(verb) printf("xml_convertdate mktime failure\n"); return 0; diff --git a/external/unbound/smallapp/unbound-control.c b/external/unbound/smallapp/unbound-control.c index d4b147d67..571b4d0b0 100644 --- a/external/unbound/smallapp/unbound-control.c +++ b/external/unbound/smallapp/unbound-control.c @@ -161,7 +161,7 @@ setup_ctx(struct config_file* cfg) if(cfg->remote_control_use_cert) { if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3) & SSL_OP_NO_SSLv3)) ssl_err("could not set SSL_OP_NO_SSLv3"); - if(!SSL_CTX_use_certificate_file(ctx,c_cert,SSL_FILETYPE_PEM) || + if(!SSL_CTX_use_certificate_chain_file(ctx,c_cert) || !SSL_CTX_use_PrivateKey_file(ctx,c_key,SSL_FILETYPE_PEM) || !SSL_CTX_check_private_key(ctx)) ssl_err("Error setting up SSL_CTX client key and cert"); diff --git a/external/unbound/testcode/petal.c b/external/unbound/testcode/petal.c index 964735b39..a54181c37 100644 --- a/external/unbound/testcode/petal.c +++ b/external/unbound/testcode/petal.c @@ -236,12 +236,28 @@ setup_ctx(char* key, char* cert) if(!ctx) print_exit("out of memory"); (void)SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); (void)SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3); - if(!SSL_CTX_use_certificate_file(ctx, cert, SSL_FILETYPE_PEM)) + if(!SSL_CTX_use_certificate_chain_file(ctx, cert)) print_exit("cannot read cert"); if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) print_exit("cannot read key"); if(!SSL_CTX_check_private_key(ctx)) print_exit("private key is not correct"); +#if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO + if (!SSL_CTX_set_ecdh_auto(ctx,1)) + if(verb>=1) printf("failed to set_ecdh_auto, not enabling ECDHE\n"); +#elif defined(USE_ECDSA) + if(1) { + EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1); + if (!ecdh) { + if(verb>=1) printf("could not find p256, not enabling ECDHE\n"); + } else { + if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) { + if(verb>=1) printf("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE\n"); + } + EC_KEY_free(ecdh); + } + } +#endif if(!SSL_CTX_load_verify_locations(ctx, cert, NULL)) print_exit("cannot load cert verify locations"); return ctx; diff --git a/external/unbound/testdata/ctrl_pipe.tpkg b/external/unbound/testdata/ctrl_pipe.tpkg deleted file mode 100644 index 877fcf901..000000000 Binary files a/external/unbound/testdata/ctrl_pipe.tpkg and /dev/null differ diff --git a/external/unbound/testdata/fwd_any.rpl b/external/unbound/testdata/fwd_any.rpl deleted file mode 100644 index 4284ee79e..000000000 --- a/external/unbound/testdata/fwd_any.rpl +++ /dev/null @@ -1,161 +0,0 @@ -; This is a comment. -; config options go here. -forward-zone: name: "." forward-addr: 216.0.0.1 -CONFIG_END - -SCENARIO_BEGIN Test query and cache with type ANY -RANGE_BEGIN 0 1000 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR RD RA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. IN A 10.20.30.40 -SECTION AUTHORITY -www.example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 10.20.30.50 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR RD RA NOERROR -SECTION QUESTION -www.example.com. IN ANY -SECTION ANSWER -;; different type in this answer. -www.example.com. IN TXT "text" -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR RD RA NOERROR -SECTION QUESTION -www.example.com. IN AAAA -SECTION ANSWER -www.example.com. IN AAAA ::5 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qname qtype -ADJUST copy_id -REPLY QR RD RA NOERROR -SECTION QUESTION -www.foo.com. IN ANY -SECTION ANSWER -www.foo.com. IN A 1.2.3.77 -www.foo.com. IN AAAA ::77 -ENTRY_END - -RANGE_END - -STEP 10 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.example.com. IN A -ENTRY_END -; unneccesary nothing steps. -STEP 20 NOTHING -STEP 30 CHECK_ANSWER -ENTRY_BEGIN -MATCH opcode qname qtype -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. IN A 10.20.30.40 -ENTRY_END - -; test cache synthesis -STEP 40 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.example.com. IN ANY -ENTRY_END -STEP 50 NOTHING -STEP 60 CHECK_ANSWER -ENTRY_BEGIN -MATCH opcode qname qtype -SECTION QUESTION -www.example.com. IN ANY -SECTION ANSWER -www.example.com. IN A 10.20.30.40 -ENTRY_END - -; and again -; the synthesized result itself is not added to the cache -STEP 62 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.example.com. IN ANY -ENTRY_END -STEP 63 NOTHING -STEP 64 CHECK_ANSWER -ENTRY_BEGIN -MATCH opcode qname qtype -SECTION QUESTION -www.example.com. IN ANY -SECTION ANSWER -www.example.com. IN A 10.20.30.40 -ENTRY_END - -; AAAA lookup to add more data in cache -STEP 70 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.example.com. IN AAAA -ENTRY_END -STEP 80 NOTHING -STEP 90 CHECK_ANSWER -ENTRY_BEGIN -MATCH opcode qname qtype -SECTION QUESTION -www.example.com. IN AAAA -SECTION ANSWER -www.example.com. IN AAAA ::5 -ENTRY_END - -; test cache synthesis of AAAA, and two rrsets. -STEP 100 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.example.com. IN ANY -ENTRY_END -STEP 110 NOTHING -STEP 120 CHECK_ANSWER -ENTRY_BEGIN -MATCH opcode qname qtype -SECTION QUESTION -www.example.com. IN ANY -SECTION ANSWER -www.example.com. IN A 10.20.30.40 -www.example.com. IN AAAA ::5 -ENTRY_END - -; test query that is not synthesized from cache. -STEP 130 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.foo.com. IN ANY -ENTRY_END -STEP 140 NOTHING -STEP 150 CHECK_ANSWER -ENTRY_BEGIN -MATCH opcode qname qtype -SECTION QUESTION -www.foo.com. IN ANY -SECTION ANSWER -www.foo.com. IN A 1.2.3.77 -www.foo.com. IN AAAA ::77 -ENTRY_END - -SCENARIO_END diff --git a/external/unbound/testdata/fwd_capsid_strip.tpkg b/external/unbound/testdata/fwd_capsid_strip.tpkg deleted file mode 100644 index c0be8a3c5..000000000 Binary files a/external/unbound/testdata/fwd_capsid_strip.tpkg and /dev/null differ diff --git a/external/unbound/testdata/fwd_capsid_white.tpkg b/external/unbound/testdata/fwd_capsid_white.tpkg deleted file mode 100644 index 199befb56..000000000 Binary files a/external/unbound/testdata/fwd_capsid_white.tpkg and /dev/null differ diff --git a/external/unbound/testdata/iter_domain_sale.rpl b/external/unbound/testdata/iter_domain_sale.rpl deleted file mode 100644 index ff612780a..000000000 --- a/external/unbound/testdata/iter_domain_sale.rpl +++ /dev/null @@ -1,273 +0,0 @@ -; config options -server: - target-fetch-policy: "0 0 0 0 0" - -stub-zone: - name: "." - stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. -CONFIG_END - -SCENARIO_BEGIN Test resolver with a domain sale -; and the old operator is nasty, keeps running his server with the old data. -; and lots of lookups keep going towards the domain. -; eventually, the NS record has to timeout. - -; K.ROOT-SERVERS.NET. -RANGE_BEGIN 0 100 - ADDRESS 193.0.14.129 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -. IN NS -SECTION ANSWER -. IN NS K.ROOT-SERVERS.NET. -SECTION ADDITIONAL -K.ROOT-SERVERS.NET. IN A 193.0.14.129 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode subdomain -ADJUST copy_id copy_query -REPLY QR NOERROR -SECTION QUESTION -com. IN A -SECTION AUTHORITY -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END -RANGE_END - -; a.gtld-servers.net. (before sale of domain) -RANGE_BEGIN 0 20 - ADDRESS 192.5.6.30 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -com. IN NS -SECTION ANSWER -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode subdomain -ADJUST copy_id copy_query -REPLY QR NOERROR -SECTION QUESTION -example.com. IN A -SECTION AUTHORITY -example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ENTRY_END -RANGE_END - -; a.gtld-servers.net. (after sale of domain) -RANGE_BEGIN 30 200 - ADDRESS 192.5.6.30 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -com. IN NS -SECTION ANSWER -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode subdomain -ADJUST copy_id copy_query -REPLY QR NOERROR -SECTION QUESTION -example.com. IN A -SECTION AUTHORITY -example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 8.8.8.8 -ENTRY_END -RANGE_END - -; ns.example.com. first owner -RANGE_BEGIN 0 200 - ADDRESS 1.2.3.4 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR AA NOERROR -SECTION QUESTION -example.com. IN NS -SECTION ANSWER -example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qname -ADJUST copy_id copy_query -REPLY QR AA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 3600 IN A 10.20.30.40 -SECTION AUTHORITY -example.com. 3600 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 3600 IN A 1.2.3.4 -ENTRY_END - -; nxdomains for any name,type -; last in RANGE so that it matches everything left over. -; it includes the NS record. -ENTRY_BEGIN -MATCH opcode -ADJUST copy_id copy_query -REPLY QR AA NXDOMAIN -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -SECTION AUTHORITY -example.com. 3600 IN SOA a. b. 1 2 3 4 5 -example.com. 3600 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 3600 IN A 1.2.3.4 -ENTRY_END -RANGE_END - -; ns.example.com. new owner -RANGE_BEGIN 0 200 - ADDRESS 8.8.8.8 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR AA NOERROR -SECTION QUESTION -example.com. IN NS -SECTION ANSWER -example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 8.8.8.8 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR AA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 3600 IN A 88.88.88.88 -SECTION AUTHORITY -example.com. 3600 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 3600 IN A 8.8.8.8 -ENTRY_END -RANGE_END - -; Fetch the old record from the old owner. -STEP 1 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.example.com. IN A -ENTRY_END -; recursion happens here. -STEP 5 CHECK_ANSWER -ENTRY_BEGIN -MATCH all ttl -REPLY QR RD RA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 3600 IN A 10.20.30.40 -SECTION AUTHORITY -example.com. 3600 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 3600 IN A 1.2.3.4 -ENTRY_END - -; the domain is sold (right at this time). -; but the information stays in the cache. - -; after 1800 secs still the cached answer -STEP 20 TIME_PASSES ELAPSE 1800 - -STEP 30 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.example.com. IN A -ENTRY_END -; recursion happens here. -STEP 40 CHECK_ANSWER -ENTRY_BEGIN -MATCH all ttl -REPLY QR RD RA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 1800 IN A 10.20.30.40 -SECTION AUTHORITY -example.com. 1800 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 1800 IN A 1.2.3.4 -ENTRY_END - -; and ask another query -STEP 50 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -nx1.example.com. IN A -ENTRY_END -; recursion happens here. -STEP 60 CHECK_ANSWER -ENTRY_BEGIN -MATCH all ttl -REPLY QR RD RA NXDOMAIN -SECTION QUESTION -nx1.example.com. IN A -SECTION ANSWER -SECTION AUTHORITY -; at TTL 5 because TTL is capped at min-ttl of 5 in rdata of SOA -example.com. 5 IN SOA a. b. 1 2 3 4 5 -example.com. 1800 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 1800 IN A 1.2.3.4 -ENTRY_END - -; after another 1900 seconds the domain must have timed out. -STEP 70 TIME_PASSES ELAPSE 1900 - -; the NS record should have timed out. -STEP 80 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.example.com. IN A -ENTRY_END -; recursion happens here. -STEP 90 CHECK_ANSWER -ENTRY_BEGIN -MATCH all ttl -REPLY QR RD RA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 3600 IN A 88.88.88.88 -SECTION AUTHORITY -example.com. 3600 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 3600 IN A 8.8.8.8 -ENTRY_END - -SCENARIO_END diff --git a/external/unbound/testdata/iter_domain_sale_nschange.rpl b/external/unbound/testdata/iter_domain_sale_nschange.rpl deleted file mode 100644 index bc396f67c..000000000 --- a/external/unbound/testdata/iter_domain_sale_nschange.rpl +++ /dev/null @@ -1,342 +0,0 @@ -; config options -server: - target-fetch-policy: "0 0 0 0 0" - -stub-zone: - name: "." - stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. -CONFIG_END - -SCENARIO_BEGIN Test resolver with a domain sale and NS changes -; and the old operator is nasty, keeps running his server with the old data. -; and lots of lookups keep going towards the domain. -; and the old server is changing the NS record of the old domain. - -; K.ROOT-SERVERS.NET. -RANGE_BEGIN 0 100 - ADDRESS 193.0.14.129 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -. IN NS -SECTION ANSWER -. IN NS K.ROOT-SERVERS.NET. -SECTION ADDITIONAL -K.ROOT-SERVERS.NET. IN A 193.0.14.129 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode subdomain -ADJUST copy_id copy_query -REPLY QR NOERROR -SECTION QUESTION -com. IN A -SECTION AUTHORITY -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END -RANGE_END - -; a.gtld-servers.net. (before sale of domain) -RANGE_BEGIN 0 20 - ADDRESS 192.5.6.30 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -com. IN NS -SECTION ANSWER -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode subdomain -ADJUST copy_id copy_query -REPLY QR NOERROR -SECTION QUESTION -example.com. IN A -SECTION AUTHORITY -example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ENTRY_END -RANGE_END - -; a.gtld-servers.net. (after sale of domain) -RANGE_BEGIN 30 200 - ADDRESS 192.5.6.30 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -com. IN NS -SECTION ANSWER -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode subdomain -ADJUST copy_id copy_query -REPLY QR NOERROR -SECTION QUESTION -example.com. IN A -SECTION AUTHORITY -example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 8.8.8.8 -ENTRY_END -RANGE_END - -; ns.example.com. first owner -RANGE_BEGIN 0 30 - ADDRESS 1.2.3.4 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR AA NOERROR -SECTION QUESTION -example.com. IN NS -SECTION ANSWER -example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qname -ADJUST copy_id copy_query -REPLY QR AA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 3600 IN A 10.20.30.40 -SECTION AUTHORITY -example.com. 3600 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 3600 IN A 1.2.3.4 -ENTRY_END - -; nxdomains for any name,type -; last in RANGE so that it matches everything left over. -; it includes the NS record. -ENTRY_BEGIN -MATCH opcode -ADJUST copy_id copy_query -REPLY QR AA NXDOMAIN -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -SECTION AUTHORITY -example.com. 3600 IN SOA a. b. 1 2 3 4 5 -example.com. 3600 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 3600 IN A 1.2.3.4 -ENTRY_END -RANGE_END - -; ns.example.com. first owner, NS changed -RANGE_BEGIN 40 200 - ADDRESS 1.2.3.4 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR AA NOERROR -SECTION QUESTION -example.com. IN NS -SECTION ANSWER -example.com. IN NS nsb.example.com. -SECTION ADDITIONAL -nsb.example.com. IN A 1.2.3.4 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qname -ADJUST copy_id copy_query -REPLY QR AA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 3600 IN A 10.20.30.40 -SECTION AUTHORITY -example.com. 3600 IN NS nsb.example.com. -SECTION ADDITIONAL -nsb.example.com. 3600 IN A 1.2.3.4 -ENTRY_END - -; nxdomains for any name,type -; last in RANGE so that it matches everything left over. -; it includes the NS record. -ENTRY_BEGIN -MATCH opcode -ADJUST copy_id copy_query -REPLY QR AA NXDOMAIN -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -SECTION AUTHORITY -example.com. 3600 IN SOA a. b. 1 2 3 4 5 -example.com. 3600 IN NS nsb.example.com. -SECTION ADDITIONAL -nsb.example.com. 3600 IN A 1.2.3.4 -ENTRY_END -RANGE_END - -; ns.example.com. new owner -RANGE_BEGIN 0 200 - ADDRESS 8.8.8.8 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR AA NOERROR -SECTION QUESTION -example.com. IN NS -SECTION ANSWER -example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 8.8.8.8 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR AA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 3600 IN A 88.88.88.88 -SECTION AUTHORITY -example.com. 3600 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 3600 IN A 8.8.8.8 -ENTRY_END -RANGE_END - -; Fetch the old record from the old owner. -STEP 1 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.example.com. IN A -ENTRY_END -; recursion happens here. -STEP 5 CHECK_ANSWER -ENTRY_BEGIN -MATCH all ttl -REPLY QR RD RA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 3600 IN A 10.20.30.40 -SECTION AUTHORITY -example.com. 3600 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 3600 IN A 1.2.3.4 -ENTRY_END - -; the domain is sold (right at this time). -; but the information stays in the cache. - -; after 1800 secs still the cached answer -STEP 20 TIME_PASSES ELAPSE 1800 - -STEP 30 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.example.com. IN A -ENTRY_END -; recursion happens here. -STEP 40 CHECK_ANSWER -ENTRY_BEGIN -MATCH all ttl -REPLY QR RD RA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 1800 IN A 10.20.30.40 -SECTION AUTHORITY -example.com. 1800 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 1800 IN A 1.2.3.4 -ENTRY_END - -; and ask another query -STEP 50 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -nx1.example.com. IN A -ENTRY_END -; recursion happens here. -STEP 60 CHECK_ANSWER -ENTRY_BEGIN -MATCH all ttl -REPLY QR RD RA NXDOMAIN -SECTION QUESTION -nx1.example.com. IN A -SECTION ANSWER -SECTION AUTHORITY -; at TTL 5 because TTL capped at ttl of minttl in rdata of SOA. -example.com. 5 IN SOA a. b. 1 2 3 4 5 -example.com. 3600 IN NS nsb.example.com. -SECTION ADDITIONAL -nsb.example.com. 3600 IN A 1.2.3.4 -ENTRY_END - -STEP 62 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -nx1.example.com. IN A -ENTRY_END -; recursion happens here. -STEP 63 CHECK_ANSWER -ENTRY_BEGIN -MATCH all ttl -REPLY QR RD RA NXDOMAIN -SECTION QUESTION -nx1.example.com. IN A -SECTION ANSWER -SECTION AUTHORITY -; at TTL 5 because TTL capped at ttl of minttl in rdata of SOA. -example.com. 5 IN SOA a. b. 1 2 3 4 5 -example.com. 1800 IN NS nsb.example.com. -SECTION ADDITIONAL -nsb.example.com. 3600 IN A 1.2.3.4 -ENTRY_END - -; after another 1900 seconds the domain must have timed out. -STEP 70 TIME_PASSES ELAPSE 1900 - -; the NS record should have timed out. -STEP 80 QUERY -ENTRY_BEGIN -REPLY RD -SECTION QUESTION -www.example.com. IN A -ENTRY_END -; recursion happens here. -STEP 90 CHECK_ANSWER -ENTRY_BEGIN -MATCH all ttl -REPLY QR RD RA NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 3600 IN A 88.88.88.88 -SECTION AUTHORITY -example.com. 3600 IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. 3600 IN A 8.8.8.8 -ENTRY_END - -SCENARIO_END diff --git a/external/unbound/testdata/root_anchor.tpkg b/external/unbound/testdata/root_anchor.tpkg deleted file mode 100644 index dfb4c5a1c..000000000 Binary files a/external/unbound/testdata/root_anchor.tpkg and /dev/null differ diff --git a/external/unbound/testdata/val_spurious_ns.rpl b/external/unbound/testdata/val_spurious_ns.rpl deleted file mode 100644 index 741fd1aff..000000000 --- a/external/unbound/testdata/val_spurious_ns.rpl +++ /dev/null @@ -1,151 +0,0 @@ -; config options -; The island of trust is at example.com -server: - trust-anchor: "example.com. 3600 IN DS 2854 3 1 46e4ffc6e9a4793b488954bd3f0cc6af0dfb201b" - val-override-date: "20070916134226" - target-fetch-policy: "0 0 0 0 0" - -stub-zone: - name: "." - stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. -CONFIG_END - -SCENARIO_BEGIN Test validator with spurious unsigned NS in auth section - -; K.ROOT-SERVERS.NET. -RANGE_BEGIN 0 100 - ADDRESS 193.0.14.129 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -. IN NS -SECTION ANSWER -. IN NS K.ROOT-SERVERS.NET. -SECTION ADDITIONAL -K.ROOT-SERVERS.NET. IN A 193.0.14.129 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION AUTHORITY -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END -RANGE_END - -; a.gtld-servers.net. -RANGE_BEGIN 0 100 - ADDRESS 192.5.6.30 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -com. IN NS -SECTION ANSWER -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION AUTHORITY -example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ENTRY_END -RANGE_END - -; ns.example.com. -RANGE_BEGIN 0 100 - ADDRESS 1.2.3.4 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -example.com. IN NS -SECTION ANSWER -example.com. IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} -ENTRY_END - -; response to DNSKEY priming query -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -example.com. IN DNSKEY -SECTION ANSWER -example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJII s70j+sDS/UT2QRp61SE7S3E EXopNXoFE73JLRmvpi/UrOO/Vz4Se 6wXv/CYCKjGw06U4WRgR YXcpEhJROyNapmdIKSx hOzfLVE1gqA0PweZR8d tY3aNQSRn3sPpwJr6Mi /PqQKAMMrZ9ckJpf1+b QMOOvxgzz2U1GS18b3y ZKcgTMEaJzd/GZYzi/B N2DzQ0MsrSwYXfsNLFO Bbs8PJMW4LYIxeeOe6rUgkWOF 7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b} -example.com. 3600 IN RRSIG DNSKEY 3 2 3600 20070926134802 20070829134802 2854 example.com. MCwCFG1yhRNtTEa3Eno2zhVVuy2EJX3wAhQeLyUp6+UXcpC5qGNu9tkrTEgPUg== ;{id = 2854} -SECTION AUTHORITY -example.com. IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} -ENTRY_END - -; response to query of interest -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. IN A 10.20.30.40 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854} -SECTION AUTHORITY -example.com. IN NS ns.example.com. -;example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} -ENTRY_END -RANGE_END - -STEP 1 QUERY -ENTRY_BEGIN -REPLY RD DO -SECTION QUESTION -www.example.com. IN A -ENTRY_END - -; recursion happens here. -STEP 10 CHECK_ANSWER -ENTRY_BEGIN -MATCH all -REPLY QR RD RA AD DO NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. IN A 10.20.30.40 -www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} -SECTION AUTHORITY -; removed by spurious NS record removal code -;;example.com. IN NS ns.example.com. -;;example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854} -ENTRY_END - -SCENARIO_END diff --git a/external/unbound/testdata/val_ta_algo_dnskey_dp.rpl b/external/unbound/testdata/val_ta_algo_dnskey_dp.rpl deleted file mode 100644 index b23c0f1b0..000000000 --- a/external/unbound/testdata/val_ta_algo_dnskey_dp.rpl +++ /dev/null @@ -1,182 +0,0 @@ -; config options -; The island of trust is at example.com -server: - trust-anchor: "example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJIIs70j+sDS/UT2QRp61SE7S3EEXopNXoFE73JLRmvpi/UrOO/Vz4Se6wXv/CYCKjGw06U4WRgRYXcpEhJROyNapmdIKSxhOzfLVE1gqA0PweZR8dtY3aNQSRn3sPpwJr6Mi/PqQKAMMrZ9ckJpf1+bQMOOvxgzz2U1GS18b3yZKcgTMEaJzd/GZYzi/BN2DzQ0MsrSwYXfsNLFOBbs8PJMW4LYIxeeOe6rUgkWOF7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}" - trust-anchor: "example.com. 3600 IN DS 30899 5 1 d4bf9d2e10f6d76840d42ef5913022abcd0bf512" - val-override-date: "20070916134226" - target-fetch-policy: "0 0 0 0 0" - harden-algo-downgrade: no - -stub-zone: - name: "." - stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. -CONFIG_END - -SCENARIO_BEGIN Test validator with multiple algorithm trust anchor without harden - -; K.ROOT-SERVERS.NET. -RANGE_BEGIN 0 100 - ADDRESS 193.0.14.129 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -. IN NS -SECTION ANSWER -. IN NS K.ROOT-SERVERS.NET. -SECTION ADDITIONAL -K.ROOT-SERVERS.NET. IN A 193.0.14.129 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION AUTHORITY -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END -RANGE_END - -; a.gtld-servers.net. -RANGE_BEGIN 0 100 - ADDRESS 192.5.6.30 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -com. IN NS -SECTION ANSWER -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION AUTHORITY -example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ENTRY_END -RANGE_END - -; ns.example.com. -RANGE_BEGIN 0 100 - ADDRESS 1.2.3.4 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -example.com. IN NS -SECTION ANSWER -example.com. IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -example.com. 3600 IN RRSIG NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} -ns.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899} -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR AA NOERROR -SECTION QUESTION -ns.example.com. IN AAAA -SECTION ANSWER -SECTION AUTHORITY -example.com. IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -example.com. 3600 IN RRSIG NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} -ns.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899} -ENTRY_END - - -; response to DNSKEY priming query -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -example.com. IN DNSKEY -SECTION ANSWER -example.com. 3600 IN DNSKEY 256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b} -example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJIIs70j+sDS/UT2QRp61SE7S3EEXopNXoFE73JLRmvpi/UrOO/Vz4Se6wXv/CYCKjGw06U4WRgRYXcpEhJROyNapmdIKSxhOzfLVE1gqA0PweZR8dtY3aNQSRn3sPpwJr6Mi/PqQKAMMrZ9ckJpf1+bQMOOvxgzz2U1GS18b3yZKcgTMEaJzd/GZYzi/BN2DzQ0MsrSwYXfsNLFOBbs8PJMW4LYIxeeOe6rUgkWOF7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 512b} -example.com. 3600 IN RRSIG DNSKEY 3 2 3600 20070926134150 20070829134150 2854 example.com. AKIIYDOGHogglFqJK94ZtOnF7EfGikgAyloMNRSMCrQgFaFkmcOyjrc= ;{id = 2854} -example.com. 3600 IN RRSIG DNSKEY 5 2 3600 20070926134150 20070829134150 30899 example.com. J55fsz1GGMnngc4r50xvXDUdaVMlfcLKLVsfMhwNLF+ERac5XV/lLRAc/aSER+qQdsSo0CrjYjy1wat7YQpDAA== ;{id = 30899} -SECTION AUTHORITY -example.com. IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -example.com. 3600 IN RRSIG NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} -ns.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899} -ENTRY_END - -; response to query of interest -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. IN A 10.20.30.40 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854} -www.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. JNWECShNE+nCLQwOXJJ3xpUkh2G+FCh5nk8uYAHIVQRse/BIvCMSlvRrtVyw9RnXvk5RR2bEgN0pRdLWW7ug5Q== ;{id = 30899} -SECTION AUTHORITY -example.com. IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -example.com. 3600 IN RRSIG NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} -ns.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899} -ENTRY_END -RANGE_END - -STEP 1 QUERY -ENTRY_BEGIN -REPLY RD DO -SECTION QUESTION -www.example.com. IN A -ENTRY_END - -; recursion happens here. -STEP 10 CHECK_ANSWER -ENTRY_BEGIN -MATCH all -REPLY QR RD RA AD DO NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. IN A 10.20.30.40 -www.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. JNWECShNE+nCLQwOXJJ3xpUkh2G+FCh5nk8uYAHIVQRse/BIvCMSlvRrtVyw9RnXvk5RR2bEgN0pRdLWW7ug5Q== ;{id = 30899} -www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} -SECTION AUTHORITY -example.com. IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -example.com. 3600 IN RRSIG NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854} -ns.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899} -ENTRY_END - -SCENARIO_END diff --git a/external/unbound/testdata/val_ta_algo_missing_dp.rpl b/external/unbound/testdata/val_ta_algo_missing_dp.rpl deleted file mode 100644 index 2cf0556f5..000000000 --- a/external/unbound/testdata/val_ta_algo_missing_dp.rpl +++ /dev/null @@ -1,185 +0,0 @@ -; config options -; The island of trust is at example.com -server: - trust-anchor: "example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJIIs70j+sDS/UT2QRp61SE7S3EEXopNXoFE73JLRmvpi/UrOO/Vz4Se6wXv/CYCKjGw06U4WRgRYXcpEhJROyNapmdIKSxhOzfLVE1gqA0PweZR8dtY3aNQSRn3sPpwJr6Mi/PqQKAMMrZ9ckJpf1+bQMOOvxgzz2U1GS18b3yZKcgTMEaJzd/GZYzi/BN2DzQ0MsrSwYXfsNLFOBbs8PJMW4LYIxeeOe6rUgkWOF7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 1688b}" - trust-anchor: "example.com. 3600 IN DS 30899 5 1 d4bf9d2e10f6d76840d42ef5913022abcd0bf512" - trust-anchor: "example.com. 3600 IN DS 30899 7 1 d4bf9d2e10f6d76840d42ef5913022abcd0bf512" - val-override-date: "20070916134226" - target-fetch-policy: "0 0 0 0 0" - harden-algo-downgrade: no - -stub-zone: - name: "." - stub-addr: 193.0.14.129 # K.ROOT-SERVERS.NET. -CONFIG_END - -SCENARIO_BEGIN Test validator with multiple algorithm missing one - -; K.ROOT-SERVERS.NET. -RANGE_BEGIN 0 100 - ADDRESS 193.0.14.129 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -. IN NS -SECTION ANSWER -. IN NS K.ROOT-SERVERS.NET. -SECTION ADDITIONAL -K.ROOT-SERVERS.NET. IN A 193.0.14.129 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION AUTHORITY -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END -RANGE_END - -; a.gtld-servers.net. -RANGE_BEGIN 0 100 - ADDRESS 192.5.6.30 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -com. IN NS -SECTION ANSWER -com. IN NS a.gtld-servers.net. -SECTION ADDITIONAL -a.gtld-servers.net. IN A 192.5.6.30 -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION AUTHORITY -example.com. IN NS ns.example.com. -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ENTRY_END -RANGE_END - -; ns.example.com. -RANGE_BEGIN 0 100 - ADDRESS 1.2.3.4 -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -example.com. IN NS -SECTION ANSWER -example.com. IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -example.com. 3600 IN RRSIG NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} -ns.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899} -ENTRY_END - -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR AA NOERROR -SECTION QUESTION -ns.example.com. IN AAAA -SECTION ANSWER -SECTION AUTHORITY -example.com. IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -example.com. 3600 IN RRSIG NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} -ns.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899} -ENTRY_END - - -; response to DNSKEY priming query -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -example.com. IN DNSKEY -SECTION ANSWER -example.com. 3600 IN DNSKEY 256 3 5 AQPQ41chR9DEHt/aIzIFAqanbDlRflJoRs5yz1jFsoRIT7dWf0r+PeDuewdxkszNH6wnU4QL8pfKFRh5PIYVBLK3 ;{id = 30899 (zsk), size = 512b} -example.com. 3600 IN DNSKEY 256 3 3 ALXLUsWqUrY3JYER3T4TBJIIs70j+sDS/UT2QRp61SE7S3EEXopNXoFE73JLRmvpi/UrOO/Vz4Se6wXv/CYCKjGw06U4WRgRYXcpEhJROyNapmdIKSxhOzfLVE1gqA0PweZR8dtY3aNQSRn3sPpwJr6Mi/PqQKAMMrZ9ckJpf1+bQMOOvxgzz2U1GS18b3yZKcgTMEaJzd/GZYzi/BN2DzQ0MsrSwYXfsNLFOBbs8PJMW4LYIxeeOe6rUgkWOF7CC9Dh/dduQ1QrsJhmZAEFfd6ByYV+ ;{id = 2854 (zsk), size = 512b} -example.com. 3600 IN RRSIG DNSKEY 3 2 3600 20070926134150 20070829134150 2854 example.com. AKIIYDOGHogglFqJK94ZtOnF7EfGikgAyloMNRSMCrQgFaFkmcOyjrc= ;{id = 2854} -example.com. 3600 IN RRSIG DNSKEY 5 2 3600 20070926134150 20070829134150 30899 example.com. J55fsz1GGMnngc4r50xvXDUdaVMlfcLKLVsfMhwNLF+ERac5XV/lLRAc/aSER+qQdsSo0CrjYjy1wat7YQpDAA== ;{id = 30899} -SECTION AUTHORITY -example.com. IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -example.com. 3600 IN RRSIG NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926135752 20070829135752 2854 example.com. MC0CFQCMSWxVehgOQLoYclB9PIAbNP229AIUeH0vNNGJhjnZiqgIOKvs1EhzqAo= ;{id = 2854} -ns.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899} -ENTRY_END - -; response to query of interest -ENTRY_BEGIN -MATCH opcode qtype qname -ADJUST copy_id -REPLY QR NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. IN A 10.20.30.40 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854} -www.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. JNWECShNE+nCLQwOXJJ3xpUkh2G+FCh5nk8uYAHIVQRse/BIvCMSlvRrtVyw9RnXvk5RR2bEgN0pRdLWW7ug5Q== ;{id = 30899} -SECTION AUTHORITY -example.com. IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -example.com. 3600 IN RRSIG NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899} -SECTION ADDITIONAL -ns.example.com. IN A 1.2.3.4 -www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} -ns.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899} -ENTRY_END -RANGE_END - -STEP 1 QUERY -ENTRY_BEGIN -REPLY RD DO -SECTION QUESTION -www.example.com. IN A -ENTRY_END - -; recursion happens here. -STEP 10 CHECK_ANSWER -ENTRY_BEGIN -MATCH all -REPLY QR RD RA AD DO NOERROR -SECTION QUESTION -www.example.com. IN A -SECTION ANSWER -www.example.com. 3600 IN A 10.20.30.40 -www.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. JNWECShNE+nCLQwOXJJ3xpUkh2G+FCh5nk8uYAHIVQRse/BIvCMSlvRrtVyw9RnXvk5RR2bEgN0pRdLWW7ug5Q== ;{id = 30899} -www.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFC99iE9K5y2WNgI0gFvBWaTi9wm6AhUAoUqOpDtG5Zct+Qr9F3mSdnbc6V4= ;{id = 2854} - -SECTION AUTHORITY -example.com. 3600 IN NS ns.example.com. -example.com. 3600 IN RRSIG NS 3 2 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCN+qHdJxoI/2tNKwsb08pra/G7aAIUAWA5sDdJTbrXA1/3OaesGBAO3sI= ;{id = 2854} -example.com. 3600 IN RRSIG NS 5 2 3600 20070926134150 20070829134150 30899 example.com. YTqtYba73HIOQuPr5oDyIX9pfmz1ybEBjwlD/jUgcPmFINUOZ9FeqG6ywgRKwn4AizkKTK00p1sxZYMKxl91wg== ;{id = 30899} - -SECTION ADDITIONAL -ns.example.com. 3600 IN A 1.2.3.4 -ns.example.com. 3600 IN RRSIG A 3 3 3600 20070926134150 20070829134150 2854 example.com. MC0CFQCQMyTjn7WWwpwAR1LlVeLpRgZGuQIUCcJDEkwAuzytTDRlYK7nIMwH1CM= ;{id = 2854} -ns.example.com. 3600 IN RRSIG A 5 3 3600 20070926134150 20070829134150 30899 example.com. Dn1ziMKrc3NdJkSv8g61Y9WNk3+BAuwCwnYzAZiHmkejkSCPViLJN7+f4Conp9l8LkTl50ZnLgoYrrUYNhMj6w== ;{id = 30899} -ENTRY_END - -SCENARIO_END diff --git a/external/unbound/util/alloc.c b/external/unbound/util/alloc.c index 66bdc7db9..05d2fa362 100644 --- a/external/unbound/util/alloc.c +++ b/external/unbound/util/alloc.c @@ -364,6 +364,9 @@ void *unbound_stat_malloc(size_t size) #ifdef calloc #undef calloc #endif +#ifndef INT_MAX +#define INT_MAX (((int)-1)>>1) +#endif /** calloc with stats */ void *unbound_stat_calloc(size_t nmemb, size_t size) { diff --git a/external/unbound/util/config_file.c b/external/unbound/util/config_file.c index 5d31301fa..3ef545a7b 100644 --- a/external/unbound/util/config_file.c +++ b/external/unbound/util/config_file.c @@ -70,6 +70,8 @@ uid_t cfg_uid = (uid_t)-1; /** from cfg username, after daemonise setup performed */ gid_t cfg_gid = (gid_t)-1; +/** for debug allow small timeout values for fast rollovers */ +int autr_permit_small_holddown = 0; /** global config during parsing */ struct config_parser_state* cfg_parser = 0; @@ -200,6 +202,7 @@ config_create(void) cfg->add_holddown = 30*24*3600; cfg->del_holddown = 30*24*3600; cfg->keep_missing = 366*24*3600; /* one year plus a little leeway */ + cfg->permit_small_holddown = 0; cfg->key_cache_size = 4 * 1024 * 1024; cfg->key_cache_slabs = 4; cfg->neg_cache_size = 1 * 1024 * 1024; @@ -444,6 +447,9 @@ int config_set_option(struct config_file* cfg, const char* opt, else S_UNSIGNED_OR_ZERO("add-holddown:", add_holddown) else S_UNSIGNED_OR_ZERO("del-holddown:", del_holddown) else S_UNSIGNED_OR_ZERO("keep-missing:", keep_missing) + else if(strcmp(opt, "permit-small-holddown:") == 0) + { IS_YES_OR_NO; cfg->permit_small_holddown = (strcmp(val, "yes") == 0); + autr_permit_small_holddown = cfg->permit_small_holddown; } else S_MEMSIZE("key-cache-size:", key_cache_size) else S_POW2("key-cache-slabs:", key_cache_slabs) else S_MEMSIZE("neg-cache-size:", neg_cache_size) @@ -705,6 +711,7 @@ config_get_option(struct config_file* cfg, const char* opt, else O_UNS(opt, "add-holddown", add_holddown) else O_UNS(opt, "del-holddown", del_holddown) else O_UNS(opt, "keep-missing", keep_missing) + else O_YNO(opt, "permit-small-holddown", permit_small_holddown) else O_MEM(opt, "key-cache-size", key_cache_size) else O_DEC(opt, "key-cache-slabs", key_cache_slabs) else O_MEM(opt, "neg-cache-size", neg_cache_size) @@ -1243,6 +1250,7 @@ config_apply(struct config_file* config) MINIMAL_RESPONSES = config->minimal_responses; RRSET_ROUNDROBIN = config->rrset_roundrobin; log_set_time_asc(config->log_time_ascii); + autr_permit_small_holddown = config->permit_small_holddown; } void config_lookup_uid(struct config_file* cfg) diff --git a/external/unbound/util/config_file.h b/external/unbound/util/config_file.h index 1c3c31dcf..99b15e06e 100644 --- a/external/unbound/util/config_file.h +++ b/external/unbound/util/config_file.h @@ -269,6 +269,8 @@ struct config_file { unsigned int del_holddown; /** autotrust keep_missing time, in seconds. 0 is forever. */ unsigned int keep_missing; + /** permit small holddown values, allowing 5011 rollover very fast */ + int permit_small_holddown; /** size of the key cache */ size_t key_cache_size; @@ -368,6 +370,8 @@ struct config_file { extern uid_t cfg_uid; /** from cfg username, after daemonise setup performed */ extern gid_t cfg_gid; +/** debug and enable small timeouts */ +extern int autr_permit_small_holddown; /** * Stub config options diff --git a/external/unbound/util/configlexer.c b/external/unbound/util/configlexer.c index 83087781f..3ce3c0de3 100644 --- a/external/unbound/util/configlexer.c +++ b/external/unbound/util/configlexer.c @@ -363,8 +363,8 @@ static void yy_fatal_error (yyconst char msg[] ); *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 174 -#define YY_END_OF_BUFFER 175 +#define YY_NUM_RULES 175 +#define YY_END_OF_BUFFER 176 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -372,198 +372,201 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static yyconst flex_int16_t yy_accept[1731] = +static yyconst flex_int16_t yy_accept[1752] = { 0, - 1, 1, 156, 156, 160, 160, 164, 164, 168, 168, - 1, 1, 175, 172, 1, 154, 154, 173, 2, 173, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 156, - 157, 157, 158, 173, 160, 161, 161, 162, 173, 167, - 164, 165, 165, 166, 173, 168, 169, 169, 170, 173, - 171, 155, 2, 159, 173, 171, 172, 0, 1, 2, - 2, 2, 2, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 1, 1, 157, 157, 161, 161, 165, 165, 169, 169, + 1, 1, 176, 173, 1, 155, 155, 174, 2, 174, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 157, + 158, 158, 159, 174, 161, 162, 162, 163, 174, 168, + 165, 166, 166, 167, 174, 169, 170, 170, 171, 174, + 172, 156, 2, 160, 174, 172, 173, 0, 1, 2, + 2, 2, 2, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 156, 0, 160, 0, 167, 0, 164, - 168, 0, 171, 0, 2, 2, 171, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 171, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 157, 0, 161, 0, 168, 0, + 165, 169, 0, 172, 0, 2, 2, 172, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 172, 173, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 171, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 172, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 70, 172, 172, 172, 172, 172, 6, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 171, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 70, 173, 173, 173, + 173, 173, 173, 6, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 172, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 171, 172, 172, 172, 172, 172, 30, - 172, 172, 172, 172, 172, 172, 172, 172, 135, 172, - 12, 13, 172, 15, 14, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 172, 173, + 173, 173, 173, 173, 30, 173, 173, 173, 173, 173, + 173, 173, 173, 136, 173, 12, 13, 173, 15, 14, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 172, 172, 172, 128, 172, 172, 172, 172, 172, 172, - 3, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 171, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 163, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 33, 172, 172, 172, 172, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 129, + 173, 173, 173, 173, 173, 173, 3, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 172, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 164, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 33, 173, - 172, 172, 34, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 85, 163, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 84, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 34, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 85, + 164, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 84, 173, 173, 173, 173, 173, 173, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 68, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 20, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 31, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 32, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 68, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 20, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 31, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 32, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 22, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 148, 172, 172, - 172, 172, 172, 172, 26, 172, 27, 172, 172, 172, - 71, 172, 72, 172, 69, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 5, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 87, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 22, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 149, 173, 173, 173, + 173, 173, 173, 26, 173, 27, 173, 173, 173, 71, + 173, 72, 173, 69, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 5, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 87, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 23, 172, 172, 172, 172, 172, 112, 111, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 35, 172, 172, 172, 172, 172, 172, 172, 172, 74, - 73, 172, 172, 172, 172, 172, 172, 172, 108, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 53, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 23, + 173, 173, 173, 173, 173, 113, 112, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 35, 173, 173, 173, 173, 173, 173, 173, 173, 74, + 73, 173, 173, 173, 173, 173, 173, 173, 109, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 53, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 172, 172, 172, 172, 57, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 110, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 4, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 105, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 121, 172, 106, 172, 133, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 21, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 57, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 111, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 4, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 105, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 122, 173, 106, 173, 134, 173, 173, 173, - 172, 76, 172, 77, 75, 172, 172, 172, 172, 172, - 172, 172, 83, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 107, 172, 172, 172, 172, 132, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 67, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 28, 172, 172, 17, 172, - 172, 172, 16, 172, 92, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 42, - 44, 172, 172, 172, 172, 172, 172, 172, 172, 136, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 21, 173, 173, + 173, 173, 76, 173, 77, 75, 173, 173, 173, 173, + 173, 173, 173, 83, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 107, 173, 173, 173, 173, + 133, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 67, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 28, 173, 173, + 17, 173, 173, 173, 16, 173, 92, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 42, 44, 173, 173, 173, 173, 173, 173, 173, - 172, 172, 172, 78, 172, 172, 172, 172, 172, 172, - 82, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 86, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 127, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 96, 172, 100, 172, 172, 172, 172, 81, 172, - 172, 63, 172, 119, 172, 172, 172, 172, 134, 172, - 172, 172, 172, 172, 172, 172, 141, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 99, 172, + 173, 137, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 78, 173, 173, 173, 173, + 173, 173, 82, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 86, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 128, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 96, 173, 100, 173, 173, 173, + 173, 81, 173, 173, 63, 173, 120, 173, 173, 173, + 173, 135, 173, 173, 173, 173, 173, 173, 173, 142, - 172, 172, 172, 172, 45, 46, 172, 29, 52, 101, - 172, 113, 109, 172, 172, 38, 172, 103, 172, 172, - 172, 172, 172, 7, 172, 66, 172, 172, 172, 150, - 172, 118, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 88, - 140, 172, 172, 172, 172, 172, 172, 172, 172, 129, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 102, 172, 37, 39, 172, 172, - 172, 172, 172, 65, 172, 172, 172, 149, 172, 172, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 99, 173, 173, 173, 173, 173, 45, 46, 173, + 29, 52, 101, 173, 114, 110, 173, 173, 38, 173, + 103, 173, 173, 173, 173, 173, 7, 173, 173, 66, + 173, 173, 173, 151, 173, 119, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 88, 141, 173, 173, 173, 173, 173, + 173, 173, 173, 130, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 102, 173, - 172, 172, 123, 18, 19, 172, 172, 172, 172, 172, - 172, 172, 62, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 125, 122, 172, 172, 172, 172, 172, - 172, 172, 172, 36, 172, 172, 172, 172, 172, 172, - 172, 11, 172, 172, 172, 172, 172, 172, 172, 172, - 10, 172, 172, 172, 153, 172, 40, 172, 131, 124, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 95, 94, 172, 172, 126, 120, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 47, 172, 130, 172, 172, + 37, 39, 173, 173, 173, 173, 173, 173, 65, 173, + 173, 173, 150, 173, 173, 173, 173, 124, 18, 19, + 173, 173, 173, 173, 173, 173, 173, 62, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 126, 123, + 173, 173, 173, 173, 173, 173, 173, 173, 36, 173, + 173, 173, 173, 173, 173, 173, 11, 173, 173, 173, + 173, 173, 173, 173, 173, 10, 173, 173, 173, 173, + 154, 173, 40, 173, 132, 125, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 95, 94, 173, + 173, 127, 121, 173, 173, 173, 173, 173, 173, 173, - 172, 172, 172, 172, 41, 172, 172, 172, 89, 91, - 114, 172, 172, 172, 93, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 137, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 24, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 139, 172, - 172, 117, 172, 172, 172, 172, 172, 172, 172, 50, - 172, 25, 172, 9, 172, 172, 172, 172, 115, 54, - 172, 172, 172, 98, 172, 172, 172, 172, 172, 172, - 172, 138, 79, 172, 172, 172, 172, 56, 60, 55, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 47, 173, 131, 173, 173, 173, 173, 173, 173, + 173, 41, 173, 173, 173, 89, 91, 115, 173, 173, + 173, 93, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 138, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 24, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 140, 173, 173, 118, + 173, 173, 173, 173, 173, 173, 173, 50, 173, 25, + 173, 9, 173, 173, 173, 173, 173, 116, 54, 173, - 172, 48, 172, 8, 172, 151, 172, 172, 97, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 61, - 59, 172, 49, 172, 172, 116, 172, 172, 90, 43, - 172, 172, 172, 172, 172, 172, 80, 58, 51, 152, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 64, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 104, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, + 173, 173, 98, 173, 173, 173, 173, 173, 173, 173, + 139, 79, 173, 173, 173, 173, 56, 60, 55, 173, + 48, 173, 8, 173, 173, 152, 173, 173, 97, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 61, + 59, 173, 49, 173, 108, 173, 117, 173, 173, 90, + 43, 173, 173, 173, 173, 173, 173, 80, 58, 51, + 153, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 64, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, - 172, 172, 172, 172, 144, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 142, 172, - 145, 146, 172, 172, 172, 172, 172, 143, 147, 0 + 173, 173, 173, 173, 173, 173, 104, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 145, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 143, + 173, 146, 147, 173, 173, 173, 173, 173, 144, 148, + 0 } ; static yyconst flex_int32_t yy_ec[256] = @@ -606,784 +609,794 @@ static yyconst flex_int32_t yy_meta[40] = 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; -static yyconst flex_int16_t yy_base[1745] = +static yyconst flex_int16_t yy_base[1766] = { 0, 0, 0, 37, 40, 44, 51, 63, 75, 56, 68, - 87, 108, 2883, 2837, 50, 3431, 3431, 3431, 129, 94, + 87, 108, 2487, 2363, 50, 3475, 3475, 3475, 129, 94, 70, 104, 130, 90, 92, 115, 127, 95, 84, 111, - 137, 148, 50, 150, 161, 158, 154, 167, 182, 2287, - 3431, 3431, 3431, 70, 2251, 3431, 3431, 3431, 42, 1839, - 1625, 3431, 3431, 3431, 199, 1573, 3431, 3431, 3431, 141, - 1198, 3431, 203, 3431, 207, 122, 861, 213, 120, 0, - 224, 0, 0, 103, 147, 140, 206, 171, 170, 208, - 210, 211, 200, 226, 217, 214, 225, 227, 232, 180, - 230, 235, 242, 229, 246, 247, 240, 249, 252, 253, + 137, 148, 50, 170, 150, 157, 160, 140, 166, 2236, + 3475, 3475, 3475, 70, 2188, 3475, 3475, 3475, 42, 1913, + 1777, 3475, 3475, 3475, 192, 1681, 3475, 3475, 3475, 141, + 1627, 3475, 198, 3475, 202, 122, 1553, 208, 120, 0, + 219, 0, 0, 103, 201, 203, 206, 164, 212, 204, + 214, 125, 215, 225, 217, 221, 224, 227, 229, 230, + 236, 237, 244, 228, 246, 249, 248, 253, 254, 173, - 257, 258, 259, 261, 262, 267, 268, 269, 274, 275, - 276, 278, 280, 284, 283, 286, 282, 290, 292, 299, - 303, 293, 296, 812, 318, 609, 321, 447, 327, 359, - 174, 332, 164, 336, 340, 0, 317, 333, 341, 311, - 335, 337, 339, 342, 349, 346, 352, 355, 376, 357, - 345, 360, 49, 359, 361, 367, 368, 372, 370, 369, - 378, 371, 373, 382, 392, 399, 400, 401, 386, 408, - 404, 411, 417, 413, 415, 402, 418, 414, 419, 423, - 416, 425, 429, 426, 432, 435, 433, 302, 437, 443, - 439, 440, 441, 454, 460, 457, 456, 446, 461, 467, + 255, 259, 260, 261, 262, 265, 264, 270, 263, 274, + 276, 277, 278, 284, 290, 286, 287, 291, 158, 293, + 299, 295, 303, 305, 1394, 315, 1200, 319, 1040, 327, + 776, 615, 320, 539, 335, 339, 0, 317, 332, 340, + 334, 296, 325, 336, 338, 346, 343, 350, 354, 375, + 355, 342, 357, 49, 359, 360, 353, 366, 368, 364, + 371, 372, 370, 369, 391, 377, 393, 402, 394, 387, + 405, 401, 409, 412, 410, 398, 413, 414, 415, 416, + 418, 420, 422, 423, 424, 427, 428, 435, 431, 439, + 433, 450, 436, 432, 452, 459, 461, 460, 457, 448, - 466, 475, 463, 464, 473, 474, 477, 483, 488, 486, - 489, 479, 491, 493, 494, 492, 502, 500, 503, 505, - 512, 508, 509, 511, 513, 515, 517, 518, 519, 521, - 525, 531, 524, 523, 529, 530, 539, 541, 542, 547, - 554, 548, 549, 550, 556, 558, 560, 562, 566, 567, - 574, 570, 571, 579, 572, 573, 588, 580, 591, 581, - 583, 585, 593, 595, 599, 615, 601, 610, 604, 605, - 606, 608, 637, 612, 620, 611, 623, 641, 622, 633, - 644, 643, 645, 651, 646, 652, 653, 656, 655, 654, - 660, 661, 662, 663, 674, 673, 667, 685, 681, 682, + 458, 468, 465, 476, 472, 464, 473, 474, 475, 483, + 488, 489, 491, 480, 486, 494, 498, 495, 505, 493, + 508, 506, 515, 503, 512, 513, 514, 516, 518, 520, + 519, 521, 531, 522, 528, 529, 532, 535, 538, 542, + 545, 544, 550, 552, 555, 557, 558, 560, 563, 561, + 564, 565, 571, 578, 574, 575, 581, 576, 582, 583, + 593, 595, 585, 587, 589, 596, 599, 597, 619, 605, + 608, 609, 613, 612, 616, 628, 614, 624, 625, 626, + 647, 629, 639, 648, 645, 646, 657, 650, 652, 656, + 659, 658, 662, 663, 664, 665, 667, 675, 679, 677, - 664, 683, 689, 690, 697, 693, 694, 695, 696, 698, - 701, 704, 708, 3431, 710, 705, 712, 713, 715, 3431, - 716, 717, 718, 719, 724, 723, 735, 721, 733, 738, - 740, 734, 741, 742, 743, 763, 745, 750, 752, 748, - 753, 760, 756, 767, 770, 772, 775, 774, 754, 777, - 778, 780, 783, 788, 791, 794, 795, 796, 797, 801, - 802, 803, 804, 808, 816, 810, 822, 811, 828, 831, - 825, 833, 835, 841, 818, 837, 840, 843, 845, 846, - 847, 853, 850, 852, 856, 857, 854, 860, 870, 862, - 873, 875, 877, 878, 880, 881, 883, 889, 863, 887, + 689, 682, 690, 691, 693, 695, 696, 704, 685, 700, + 701, 703, 710, 712, 702, 714, 3475, 718, 705, 716, + 720, 721, 722, 3475, 725, 727, 728, 730, 731, 732, + 738, 735, 737, 743, 744, 746, 749, 750, 751, 771, + 755, 752, 762, 760, 756, 773, 758, 780, 769, 778, + 785, 782, 786, 788, 789, 791, 792, 795, 809, 794, + 796, 802, 803, 813, 805, 816, 818, 819, 820, 822, + 830, 824, 827, 832, 840, 843, 845, 851, 833, 847, + 849, 855, 856, 857, 839, 863, 861, 864, 865, 869, + 867, 872, 876, 874, 879, 880, 887, 875, 889, 881, - 893, 894, 886, 888, 898, 905, 906, 914, 907, 915, - 912, 916, 923, 924, 917, 925, 928, 929, 930, 931, - 933, 932, 935, 938, 939, 945, 942, 943, 948, 953, - 955, 957, 958, 959, 962, 963, 967, 965, 966, 975, - 976, 978, 980, 979, 982, 986, 981, 988, 991, 3431, - 1001, 995, 992, 998, 892, 1003, 1005, 1031, 3431, 1007, - 3431, 3431, 1006, 3431, 3431, 1008, 1009, 1010, 1018, 1054, - 1019, 1011, 1012, 1025, 1027, 1032, 1033, 1020, 1041, 1044, - 1046, 1038, 1045, 1048, 1052, 1062, 1049, 1059, 1069, 1071, - 1080, 1081, 1079, 1078, 1083, 1085, 1068, 1087, 1088, 1090, + 836, 895, 893, 898, 900, 891, 902, 904, 910, 907, + 908, 909, 922, 913, 924, 916, 927, 933, 669, 915, + 929, 923, 935, 936, 937, 938, 939, 943, 944, 946, + 952, 940, 949, 956, 954, 963, 951, 964, 966, 969, + 970, 971, 972, 980, 973, 974, 984, 982, 987, 986, + 990, 988, 997, 995, 3475, 1005, 999, 1001, 1002, 1007, + 1008, 1010, 1036, 3475, 1012, 3475, 3475, 1011, 3475, 3475, + 1014, 1016, 1017, 1024, 1059, 1025, 1029, 1018, 1031, 1033, + 1037, 1038, 1042, 1049, 1051, 1062, 1046, 1052, 1056, 1068, + 1069, 1064, 1073, 1080, 1082, 1088, 1089, 1087, 1086, 1093, - 1094, 1101, 1097, 3431, 1098, 1100, 1099, 1104, 1106, 1108, - 3431, 1109, 1110, 1112, 1114, 1117, 1118, 1120, 1122, 1123, - 1124, 1127, 1128, 1125, 1132, 1135, 1145, 1151, 1144, 1137, - 1147, 1150, 1153, 1157, 1165, 1161, 1154, 1162, 1168, 1166, - 1170, 1177, 1167, 1179, 1171, 1173, 1178, 1180, 1201, 1181, - 1184, 1188, 1187, 1189, 1191, 1193, 1211, 1203, 1209, 1216, - 1219, 1208, 1220, 1225, 1228, 1235, 1226, 1227, 1230, 1237, - 1195, 1240, 1239, 1242, 1246, 1251, 1248, 3431, 1258, 1254, - 1255, 1259, 1262, 1260, 1264, 1266, 1263, 1268, 1269, 1270, - 1276, 1283, 3431, 1271, 1277, 1281, 1286, 1287, 1288, 1294, + 1094, 1095, 1098, 1097, 1096, 1100, 1106, 1110, 1107, 3475, + 1108, 1109, 1111, 1118, 1116, 1121, 3475, 1053, 1122, 1120, + 1123, 1128, 1129, 1130, 1133, 1134, 1135, 1136, 1142, 1138, + 1140, 1147, 1151, 1153, 1155, 1157, 1158, 1162, 1163, 1164, + 1171, 1169, 1168, 1174, 1178, 1175, 1180, 1182, 1177, 1185, + 1183, 1188, 1190, 1191, 1213, 1193, 1194, 1196, 1199, 1198, + 1201, 1205, 1206, 1208, 1220, 1226, 1227, 1207, 1230, 1232, + 1242, 1239, 1236, 1246, 1243, 1249, 1252, 1250, 1254, 1256, + 1258, 1260, 1263, 3475, 1269, 1268, 1266, 1273, 1274, 1272, + 1217, 1275, 1276, 1278, 1280, 1282, 1281, 1292, 3475, 1288, - 1297, 1304, 3431, 1306, 1307, 1309, 1300, 1302, 1310, 1313, - 1314, 1318, 1319, 1315, 1322, 1325, 1327, 1328, 1329, 1333, - 1332, 1334, 1339, 1341, 1340, 1343, 1342, 1346, 1344, 1351, - 1357, 1361, 1358, 1365, 1362, 1366, 1367, 1372, 1369, 1374, - 1370, 1371, 3431, 125, 1376, 1377, 1375, 1391, 1393, 1394, - 1397, 1384, 1400, 1401, 1403, 1385, 1405, 1407, 1409, 1410, - 1411, 1412, 1415, 1419, 1422, 1413, 1430, 1421, 1425, 1431, - 1423, 1435, 1437, 1378, 1438, 1443, 1444, 1441, 1445, 1446, - 1449, 1450, 1454, 1451, 1452, 1453, 3431, 1469, 1461, 1455, - 1467, 1471, 1478, 1474, 1479, 1481, 1482, 1488, 1484, 1490, + 1293, 1289, 1294, 1297, 1298, 1301, 1305, 1313, 1309, 3475, + 1317, 1314, 1320, 1319, 1321, 1324, 1325, 1326, 1327, 1329, + 1331, 1330, 1335, 1343, 1340, 1333, 1345, 1338, 1350, 1352, + 1353, 1354, 1355, 1357, 1358, 1362, 1364, 1368, 1370, 1367, + 1378, 1371, 1374, 1379, 1384, 1381, 1383, 1385, 1386, 3475, + 442, 1387, 1393, 1389, 1400, 1402, 1398, 1405, 1406, 1407, + 1412, 1413, 1396, 1414, 1416, 1419, 1422, 1424, 1423, 1425, + 1427, 1431, 1433, 1434, 1436, 1439, 1441, 1442, 1444, 1445, + 1451, 1450, 1452, 1453, 1456, 1457, 1458, 1460, 1462, 1465, + 1470, 1466, 1473, 3475, 1479, 1475, 1476, 1472, 1478, 1495, - 1492, 1498, 1496, 1501, 1486, 1489, 1508, 1509, 1510, 1512, - 1511, 1502, 3431, 1514, 1517, 1519, 1531, 1521, 1522, 1528, - 1524, 1533, 1523, 1540, 1534, 1543, 3431, 1544, 1545, 1546, - 1553, 1554, 1556, 1557, 1559, 1560, 1561, 1563, 1564, 1567, - 1570, 1572, 1575, 3431, 1581, 1584, 1585, 1591, 1583, 1577, - 1587, 1594, 1589, 1595, 1602, 1599, 1600, 1603, 1604, 1605, - 1601, 1607, 1608, 1611, 1610, 1612, 3431, 1628, 1625, 1629, - 1636, 1630, 1640, 1639, 1631, 1641, 1624, 1645, 1646, 1647, - 1648, 1649, 1652, 1654, 1655, 1656, 1657, 1658, 1659, 1667, - 1661, 1662, 1675, 1676, 1679, 1678, 1681, 1687, 1688, 1689, + 1487, 1496, 1488, 1491, 1498, 1502, 1499, 1505, 1507, 1509, + 1511, 1512, 1513, 1519, 1520, 1517, 1521, 1523, 1527, 1524, + 3475, 1529, 1530, 1534, 1543, 1536, 1540, 1546, 1544, 1547, + 1548, 1556, 1549, 1561, 3475, 1563, 1557, 1551, 1568, 1569, + 1572, 1574, 1576, 1577, 1578, 1580, 1581, 1584, 1582, 1587, + 1591, 3475, 1595, 1599, 1596, 1607, 1603, 1592, 1604, 1606, + 1608, 1609, 1618, 1610, 1614, 1617, 1619, 1620, 1616, 1622, + 1623, 1626, 1625, 1633, 3475, 1640, 1642, 1644, 1643, 1646, + 1654, 1653, 1650, 1655, 1656, 1658, 1659, 1662, 1663, 1665, + 1666, 1667, 1671, 1672, 1673, 1670, 1690, 1668, 1691, 1679, - 3431, 1693, 1694, 1695, 1696, 1697, 1703, 1705, 1701, 1706, - 1707, 1708, 1709, 1718, 1711, 1717, 1719, 1721, 1714, 1722, - 1724, 1731, 1729, 1737, 1735, 1742, 1744, 3431, 1745, 1753, - 1749, 1755, 1747, 1761, 3431, 1757, 3431, 1764, 1770, 1773, - 3431, 1777, 3431, 1779, 3431, 1723, 1780, 1772, 1758, 1760, - 1784, 1782, 1786, 1788, 1790, 1792, 1793, 1762, 1794, 1795, - 3431, 1798, 1796, 1801, 1806, 1799, 1803, 1809, 1805, 1815, - 1807, 1826, 1820, 1827, 1824, 1829, 1830, 3431, 1831, 1832, - 1834, 1837, 1841, 1848, 1845, 1842, 1849, 1835, 1853, 1863, - 1861, 1852, 1864, 1865, 1866, 1872, 1868, 1869, 1876, 1873, + 1692, 1678, 1694, 1677, 1699, 1707, 1708, 1705, 3475, 1710, + 1711, 1712, 1713, 1714, 1720, 1722, 1716, 1718, 1723, 1724, + 1725, 1739, 1726, 1728, 1732, 1736, 1730, 1738, 1741, 1752, + 1742, 1757, 1746, 1748, 1758, 1763, 3475, 1740, 1771, 1768, + 1772, 1764, 1779, 3475, 1775, 3475, 1778, 1780, 1790, 3475, + 1787, 3475, 1789, 3475, 1791, 1795, 1777, 1797, 1798, 1799, + 1800, 1802, 1803, 1805, 1807, 1808, 1809, 1811, 1816, 3475, + 1810, 1817, 1824, 1827, 1814, 1818, 1826, 1820, 1837, 1836, + 1847, 1833, 1848, 1844, 1846, 1849, 3475, 1850, 1851, 1854, + 1856, 1857, 1864, 1862, 1861, 1868, 1865, 1869, 1882, 1878, - 1877, 1879, 1880, 1882, 1881, 1884, 1892, 1886, 1888, 1889, - 3431, 1898, 1890, 1894, 1902, 1904, 3431, 3431, 1913, 1915, - 1916, 1907, 1917, 1909, 1922, 1924, 1930, 1936, 1919, 1927, - 1929, 1932, 1937, 1938, 1941, 1943, 1944, 1950, 1945, 1948, - 3431, 1958, 1952, 1960, 1961, 1963, 1969, 1968, 1971, 3431, - 3431, 1976, 1972, 1973, 1975, 1982, 1979, 1978, 3431, 1986, - 1988, 1993, 1997, 1999, 2000, 1987, 1990, 2008, 1989, 2011, - 2001, 2012, 2014, 2020, 2016, 2017, 2019, 2022, 2023, 2030, - 3431, 2027, 2032, 2034, 2037, 2038, 2039, 2040, 2043, 2041, - 2044, 2045, 2053, 2054, 2056, 2057, 2058, 2062, 2059, 2066, + 1871, 1880, 1881, 1883, 1891, 1884, 1887, 1894, 1895, 1885, + 1896, 1897, 1898, 1902, 1905, 1909, 1906, 1908, 1910, 3475, + 1915, 1919, 1922, 1921, 1911, 3475, 3475, 1924, 1932, 1936, + 1937, 1938, 1925, 1939, 1940, 1950, 1943, 1946, 1952, 1954, + 1955, 1956, 1957, 1958, 1959, 1961, 1962, 1963, 1971, 1970, + 3475, 1979, 1973, 1986, 1984, 1975, 1992, 1985, 1993, 3475, + 3475, 1989, 1994, 1999, 2000, 2006, 2004, 2003, 3475, 2005, + 2008, 2009, 2010, 2011, 2013, 2018, 2023, 2027, 2028, 2024, + 2032, 2033, 2029, 2035, 2034, 2036, 2037, 2040, 2047, 2052, + 3475, 2049, 2056, 2053, 2057, 2059, 2060, 2061, 2064, 2066, - 2068, 2069, 2075, 2071, 3431, 2085, 2072, 2086, 2082, 2084, - 2087, 2094, 2091, 2092, 2093, 2095, 2097, 2096, 2099, 2100, - 2101, 2108, 3431, 2109, 2120, 2106, 2116, 2122, 2114, 2124, - 2127, 2129, 3431, 2130, 2137, 2134, 2136, 2139, 2141, 2133, - 2144, 2147, 2148, 2149, 2150, 2155, 2157, 2152, 2158, 2160, - 2161, 2163, 2168, 2175, 2165, 2169, 2182, 2181, 2190, 2192, - 2178, 2188, 2196, 2193, 2194, 2195, 2197, 2206, 2199, 2208, - 2202, 3431, 2209, 2210, 2216, 2218, 2213, 2219, 2223, 2220, - 2227, 3431, 2224, 3431, 2230, 3431, 2231, 2235, 2232, 2237, - 2238, 2239, 2240, 2245, 2253, 2241, 3431, 2259, 2247, 2254, + 2063, 2067, 2071, 2078, 2074, 2077, 2079, 2081, 2084, 2086, + 2090, 2087, 2097, 2098, 3475, 2105, 2093, 2107, 2094, 2109, + 2112, 2115, 2114, 2103, 2116, 2117, 2106, 2118, 2122, 2124, + 2129, 2125, 3475, 2131, 2135, 2132, 2141, 2142, 2138, 2143, + 2146, 2149, 3475, 2152, 2158, 2154, 2155, 2161, 2160, 2163, + 2166, 2167, 2169, 2170, 2171, 2176, 2177, 2179, 2180, 2182, + 2184, 2183, 2186, 2193, 2196, 2191, 2200, 2203, 2206, 2216, + 2213, 2201, 2207, 2222, 2218, 2220, 2221, 2210, 2228, 2225, + 2231, 2229, 3475, 2234, 2238, 2243, 2245, 2232, 2240, 2248, + 2249, 2250, 3475, 2251, 3475, 2254, 3475, 2257, 2261, 2258, - 2257, 3431, 2262, 3431, 3431, 2249, 2267, 2273, 2269, 2274, - 2270, 2277, 3431, 2278, 2279, 2282, 2280, 2284, 2288, 2290, - 2291, 2292, 2293, 2294, 3431, 2296, 2295, 2298, 2306, 3431, - 2304, 2309, 2310, 2312, 2319, 2320, 2322, 2311, 2323, 2331, - 2328, 3431, 2330, 2324, 2335, 2332, 2337, 2344, 2340, 2346, - 2341, 2342, 2350, 2355, 2356, 3431, 2358, 2360, 3431, 2359, - 2361, 2362, 3431, 2367, 3431, 2369, 2370, 2366, 2371, 2377, - 2374, 2387, 2379, 2384, 2389, 2382, 2393, 2396, 2390, 3431, - 3431, 2400, 2397, 2402, 2407, 2403, 2405, 2409, 2412, 3431, - 2413, 2416, 2417, 2418, 2419, 2425, 2420, 2427, 2428, 2422, + 2262, 2263, 2264, 2268, 2265, 2279, 2273, 3475, 2276, 2267, + 2275, 2280, 3475, 2291, 3475, 3475, 2282, 2286, 2298, 2292, + 2294, 2299, 2303, 3475, 2304, 2296, 2305, 2308, 2307, 2310, + 2312, 2313, 2314, 2315, 2318, 3475, 2321, 2330, 2319, 2327, + 3475, 2320, 2340, 2323, 2341, 2331, 2342, 2343, 2344, 2345, + 2355, 2351, 2352, 3475, 2353, 2354, 2358, 2359, 2361, 2369, + 2366, 2373, 2367, 2376, 2378, 2377, 2370, 3475, 2384, 2387, + 3475, 2383, 2390, 2391, 3475, 2393, 3475, 2394, 2397, 2395, + 2402, 2404, 2405, 2409, 2398, 2415, 2401, 2413, 2422, 2416, + 2418, 3475, 3475, 2428, 2423, 2430, 2433, 2425, 2431, 2435, - 2429, 2430, 2431, 3431, 2435, 2439, 2441, 2444, 2442, 2445, - 3431, 2447, 2448, 2449, 2453, 2455, 2469, 2472, 2474, 2464, - 2476, 2479, 2481, 2482, 2484, 2486, 2487, 3431, 2452, 2489, - 2490, 2492, 2493, 2494, 2495, 2496, 2503, 2499, 2505, 3431, - 2507, 2508, 2510, 2516, 2513, 2520, 2517, 2521, 2524, 2525, - 2526, 2527, 2528, 2529, 2534, 2536, 2535, 2538, 2540, 2553, - 2542, 3431, 2545, 3431, 2549, 2555, 2562, 2559, 3431, 2561, - 2563, 3431, 2566, 3431, 2564, 2569, 2570, 2580, 3431, 2582, - 2571, 2583, 2575, 2577, 2573, 2588, 3431, 2593, 2595, 2600, - 2596, 2586, 2594, 2603, 2602, 2604, 2610, 2611, 3431, 2612, + 2442, 3475, 2436, 2439, 2443, 2445, 2446, 2447, 2448, 2453, + 2450, 2455, 2457, 2456, 2458, 3475, 2463, 2459, 2468, 2467, + 2469, 2471, 3475, 2473, 2475, 2476, 2479, 2484, 2490, 2495, + 2499, 2496, 2501, 2503, 2505, 2506, 2508, 2511, 2512, 3475, + 2480, 2514, 2515, 2517, 2518, 2520, 2519, 2523, 2528, 2529, + 2521, 2533, 3475, 2530, 2535, 2537, 2543, 2538, 2546, 2547, + 2548, 2551, 2552, 2554, 2555, 2556, 2558, 2561, 2562, 2563, + 2565, 2567, 2575, 2578, 3475, 2568, 3475, 2576, 2583, 2591, + 2589, 3475, 2587, 2592, 3475, 2593, 3475, 2594, 2595, 2596, + 2604, 3475, 2607, 2599, 2608, 2610, 2611, 2612, 2614, 3475, - 2613, 2619, 2615, 2459, 3431, 3431, 2620, 3431, 3431, 3431, - 2625, 3431, 3431, 2626, 2630, 3431, 2633, 3431, 2639, 2635, - 2627, 2616, 2637, 3431, 2641, 3431, 2649, 2645, 2646, 3431, - 2648, 3431, 2650, 2651, 2652, 2654, 2657, 2665, 2668, 2658, - 2660, 2662, 2669, 2671, 2672, 2673, 2676, 2679, 2680, 2682, - 2684, 2685, 2686, 2687, 2689, 2690, 2691, 2699, 2704, 3431, - 3431, 2692, 2701, 2694, 2707, 2708, 2710, 2713, 2714, 3431, - 2721, 2723, 2718, 2722, 2724, 2726, 2729, 2728, 2734, 2740, - 2736, 2738, 2739, 2741, 3431, 2743, 3431, 3431, 2746, 2748, - 2750, 2752, 2755, 3431, 2756, 2764, 2757, 3431, 2769, 2759, + 2617, 2620, 2619, 2624, 2626, 2627, 2628, 2630, 2633, 2639, + 2636, 3475, 2635, 2640, 2648, 2644, 2647, 3475, 3475, 2653, + 3475, 3475, 3475, 2656, 3475, 3475, 2657, 2659, 3475, 2661, + 3475, 2668, 2664, 2666, 2667, 2669, 3475, 2671, 2673, 3475, + 2675, 2676, 2677, 3475, 2679, 3475, 2680, 2684, 2681, 2688, + 2691, 2697, 2699, 2700, 2687, 2701, 2702, 2703, 2704, 2706, + 2708, 2710, 2711, 2716, 2717, 2718, 2720, 2721, 2722, 2723, + 2724, 2732, 2741, 3475, 3475, 2725, 2733, 2727, 2735, 2738, + 2743, 2746, 2752, 3475, 2757, 2750, 2754, 2758, 2748, 2760, + 2765, 2767, 2769, 2775, 2762, 2772, 2771, 2774, 3475, 2776, - 2772, 2775, 3431, 3431, 3431, 2776, 2765, 2779, 2780, 2781, - 2782, 2783, 3431, 2784, 2789, 2790, 2792, 2797, 2803, 2798, - 2800, 2809, 2811, 3431, 3431, 2817, 2814, 2815, 2804, 2806, - 2816, 2822, 2819, 3431, 2823, 2825, 2828, 2829, 2830, 2832, - 2835, 3431, 2834, 2836, 2840, 2846, 2842, 2848, 2849, 2850, - 3431, 2852, 2854, 2858, 3431, 2862, 3431, 2865, 3431, 3431, - 2860, 2868, 2871, 2876, 2878, 2882, 2866, 2872, 2888, 2890, - 2887, 3431, 3431, 2879, 2897, 3431, 3431, 2893, 2894, 2895, - 2896, 2898, 2901, 2902, 2906, 2903, 2904, 2907, 2909, 2915, - 2917, 2918, 2919, 2923, 2926, 3431, 2924, 3431, 2929, 2931, + 3475, 3475, 2777, 2779, 2784, 2785, 2788, 2789, 3475, 2792, + 2799, 2791, 3475, 2802, 2803, 2808, 2810, 3475, 3475, 3475, + 2811, 2805, 2814, 2813, 2815, 2816, 2817, 3475, 2819, 2821, + 2824, 2828, 2831, 2833, 2841, 2837, 2839, 2845, 3475, 3475, + 2851, 2848, 2849, 2847, 2840, 2850, 2857, 2853, 3475, 2860, + 2859, 2861, 2864, 2866, 2867, 2869, 3475, 2870, 2871, 2876, + 2880, 2872, 2883, 2884, 2885, 3475, 2887, 2886, 2893, 2888, + 3475, 2900, 3475, 2905, 3475, 3475, 2894, 2906, 2908, 2910, + 2913, 2916, 2902, 2917, 2923, 2922, 2924, 3475, 3475, 2919, + 2932, 3475, 3475, 2926, 2929, 2930, 2933, 2935, 2937, 2938, - 2932, 2933, 2935, 2940, 3431, 2941, 2939, 2934, 3431, 3431, - 3431, 2952, 2953, 2955, 3431, 2956, 2958, 2945, 2960, 2963, - 2962, 2971, 2969, 2973, 3431, 2970, 2975, 2977, 2974, 2979, - 2982, 2983, 2984, 2986, 2985, 2996, 2987, 3000, 3003, 3431, - 3005, 2993, 3009, 3001, 2997, 3017, 3021, 3007, 3012, 3014, - 3023, 3018, 3025, 3027, 3028, 3036, 3033, 3038, 3431, 3040, - 3029, 3431, 3041, 3035, 3052, 3043, 3054, 3056, 3058, 3431, - 3060, 3431, 3061, 3431, 3065, 3066, 3068, 3069, 3431, 3431, - 3070, 3072, 3076, 3431, 3077, 3073, 3079, 3080, 3083, 3084, - 3086, 3431, 3431, 3087, 3089, 3093, 3090, 3431, 3431, 3431, + 2939, 2940, 2941, 2945, 2950, 2951, 2952, 2954, 2955, 2958, + 2961, 3475, 2960, 3475, 2965, 2968, 2969, 2962, 2970, 2974, + 2975, 3475, 2977, 2976, 2979, 3475, 3475, 3475, 2989, 2990, + 2992, 3475, 2993, 2996, 2982, 2995, 3003, 2997, 3011, 2999, + 3010, 3475, 3000, 3007, 3013, 3014, 3017, 3020, 3021, 3023, + 3025, 3027, 3029, 3032, 3034, 3037, 3475, 3039, 3035, 3041, + 3043, 3045, 3046, 3048, 3050, 3052, 3054, 3056, 3058, 3060, + 3061, 3062, 3063, 3070, 3069, 3074, 3475, 3078, 3075, 3475, + 3079, 3083, 3080, 3089, 3091, 3093, 3095, 3475, 3099, 3475, + 3101, 3475, 3104, 3096, 3105, 3107, 3108, 3475, 3475, 3109, - 3099, 3431, 3102, 3431, 3095, 3431, 3104, 3108, 3431, 3110, - 3112, 3114, 3115, 3116, 3117, 3119, 3120, 3118, 3122, 3431, - 3431, 3127, 3431, 3130, 3133, 3431, 3134, 3135, 3431, 3431, - 3144, 3141, 3142, 3143, 3145, 3148, 3431, 3431, 3431, 3431, - 3149, 3150, 3152, 3154, 3151, 3156, 3157, 3159, 3161, 3158, - 3166, 3175, 3168, 3176, 3183, 3181, 3431, 3177, 3179, 3189, - 3190, 3186, 3188, 3187, 3194, 3196, 3197, 3199, 3202, 3204, - 3211, 3203, 3213, 3218, 3219, 3220, 3207, 3232, 3229, 3230, - 3217, 3231, 3238, 3234, 3235, 3431, 3239, 3240, 3241, 3242, - 3245, 3247, 3243, 3256, 3263, 3249, 3251, 3261, 3266, 3267, + 3112, 3115, 3475, 3116, 3118, 3119, 3122, 3123, 3124, 3126, + 3475, 3475, 3127, 3129, 3133, 3135, 3475, 3475, 3475, 3143, + 3475, 3144, 3475, 3150, 3146, 3475, 3152, 3153, 3475, 3136, + 3156, 3158, 3134, 3161, 3162, 3164, 3165, 3163, 3167, 3475, + 3475, 3172, 3475, 3174, 3475, 3178, 3475, 3175, 3179, 3475, + 3475, 3186, 3184, 3185, 3188, 3191, 3189, 3475, 3475, 3475, + 3475, 3192, 3193, 3195, 3197, 3194, 3199, 3200, 3202, 3204, + 3201, 3206, 3214, 3218, 3220, 3226, 3222, 3475, 3223, 3227, + 3229, 3233, 3230, 3232, 3231, 3234, 3237, 3239, 3240, 3241, + 3242, 3249, 3251, 3257, 3259, 3261, 3262, 3255, 3268, 3272, - 3268, 3269, 3271, 3270, 3431, 3272, 3273, 3279, 3281, 3282, - 3284, 3285, 3286, 3291, 3292, 3294, 3296, 3301, 3431, 3297, - 3431, 3431, 3305, 3306, 3307, 3312, 3314, 3431, 3431, 3431, - 3339, 3346, 3353, 3360, 3367, 94, 3374, 3381, 3388, 3395, - 3402, 3409, 3416, 3423 + 3269, 3265, 3273, 3280, 3277, 3278, 3475, 3281, 3279, 3282, + 3287, 3288, 3285, 3283, 3293, 3303, 3305, 3299, 3295, 3308, + 3309, 3311, 3312, 3315, 3313, 3475, 3317, 3319, 3321, 3323, + 3325, 3327, 3328, 3329, 3334, 3336, 3338, 3345, 3341, 3475, + 3349, 3475, 3475, 3350, 3339, 3351, 3353, 3357, 3475, 3475, + 3475, 3383, 3390, 3397, 3404, 3411, 94, 3418, 3425, 3432, + 3439, 3446, 3453, 3460, 3467 } ; -static yyconst flex_int16_t yy_def[1745] = +static yyconst flex_int16_t yy_def[1766] = { 0, - 1730, 1, 1731, 1731, 1732, 1732, 1733, 1733, 1734, 1734, - 1735, 1735, 1730, 1736, 1730, 1730, 1730, 1730, 1737, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1738, - 1730, 1730, 1730, 1738, 1739, 1730, 1730, 1730, 1739, 1740, - 1730, 1730, 1730, 1730, 1740, 1741, 1730, 1730, 1730, 1741, - 1742, 1730, 1743, 1730, 1742, 1742, 1736, 1736, 1730, 1744, - 1737, 1744, 1737, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, + 1751, 1, 1752, 1752, 1753, 1753, 1754, 1754, 1755, 1755, + 1756, 1756, 1751, 1757, 1751, 1751, 1751, 1751, 1758, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1759, + 1751, 1751, 1751, 1759, 1760, 1751, 1751, 1751, 1760, 1761, + 1751, 1751, 1751, 1751, 1761, 1762, 1751, 1751, 1751, 1762, + 1763, 1751, 1764, 1751, 1763, 1763, 1757, 1757, 1751, 1765, + 1758, 1765, 1758, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1738, 1738, 1739, 1739, 1740, 1740, 1730, - 1741, 1741, 1742, 1742, 1743, 1743, 1742, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1742, 1736, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1759, 1759, 1760, 1760, 1761, 1761, + 1751, 1762, 1762, 1763, 1763, 1764, 1764, 1763, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1763, 1757, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1742, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1763, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1730, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1742, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, + 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1763, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1742, 1736, 1736, 1736, 1736, 1736, 1730, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, - 1730, 1730, 1736, 1730, 1730, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1763, 1757, + 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1751, 1757, 1751, 1751, 1757, 1751, 1751, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, - 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, - 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1742, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, + 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1763, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, - 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1730, 1742, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, + 1763, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, - 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, - 1736, 1736, 1736, 1736, 1730, 1736, 1730, 1736, 1736, 1736, - 1730, 1736, 1730, 1736, 1730, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, + 1757, 1757, 1757, 1751, 1757, 1751, 1757, 1757, 1757, 1751, + 1757, 1751, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1730, 1736, 1736, 1736, 1736, 1736, 1730, 1730, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, - 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, + 1757, 1757, 1757, 1757, 1757, 1751, 1751, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, + 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, - 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1730, 1736, 1730, 1736, 1730, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1751, 1757, 1751, 1757, 1751, 1757, 1757, 1757, - 1736, 1730, 1736, 1730, 1730, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1730, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1730, 1736, - 1736, 1736, 1730, 1736, 1730, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, - 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, + 1757, 1757, 1751, 1757, 1751, 1751, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, + 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, + 1751, 1757, 1757, 1757, 1751, 1757, 1751, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1751, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, - 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, - 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1730, 1736, 1730, 1736, 1736, 1736, 1736, 1730, 1736, - 1736, 1730, 1736, 1730, 1736, 1736, 1736, 1736, 1730, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, + 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, + 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1751, 1757, 1751, 1757, 1757, 1757, + 1757, 1751, 1757, 1757, 1751, 1757, 1751, 1757, 1757, 1757, + 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, - 1736, 1736, 1736, 1736, 1730, 1730, 1736, 1730, 1730, 1730, - 1736, 1730, 1730, 1736, 1736, 1730, 1736, 1730, 1736, 1736, - 1736, 1736, 1736, 1730, 1736, 1730, 1736, 1736, 1736, 1730, - 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, - 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1730, 1736, 1730, 1730, 1736, 1736, - 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1730, 1736, 1736, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1751, 1751, 1757, + 1751, 1751, 1751, 1757, 1751, 1751, 1757, 1757, 1751, 1757, + 1751, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1751, + 1757, 1757, 1757, 1751, 1757, 1751, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1751, 1751, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, - 1736, 1736, 1730, 1730, 1730, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1730, 1730, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1730, 1736, 1736, 1736, 1730, 1736, 1730, 1736, 1730, 1730, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1730, 1730, 1736, 1736, 1730, 1730, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1730, 1736, 1736, + 1751, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, + 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1751, 1751, 1751, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1751, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, + 1751, 1757, 1751, 1757, 1751, 1751, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1751, 1757, + 1757, 1751, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, - 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1730, 1730, - 1730, 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, - 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, - 1736, 1730, 1736, 1730, 1736, 1736, 1736, 1736, 1730, 1730, - 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1730, 1730, 1736, 1736, 1736, 1736, 1730, 1730, 1730, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1751, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1751, 1757, 1757, 1757, 1751, 1751, 1751, 1757, 1757, + 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1751, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1751, + 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1751, 1751, 1757, - 1736, 1730, 1736, 1730, 1736, 1730, 1736, 1736, 1730, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, - 1730, 1736, 1730, 1736, 1736, 1730, 1736, 1736, 1730, 1730, - 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1730, 1730, 1730, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, + 1757, 1757, 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1751, 1751, 1757, 1757, 1757, 1757, 1751, 1751, 1751, 1757, + 1751, 1757, 1751, 1757, 1757, 1751, 1757, 1757, 1751, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, + 1751, 1757, 1751, 1757, 1751, 1757, 1751, 1757, 1757, 1751, + 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1751, 1751, + 1751, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, - 1736, 1736, 1736, 1736, 1730, 1736, 1736, 1736, 1736, 1736, - 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1736, 1730, 1736, - 1730, 1730, 1736, 1736, 1736, 1736, 1736, 1730, 1730, 0, - 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, - 1730, 1730, 1730, 1730 + 1757, 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1751, 1757, 1757, 1757, 1757, + 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1757, 1751, + 1757, 1751, 1751, 1757, 1757, 1757, 1757, 1757, 1751, 1751, + 0, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, + 1751, 1751, 1751, 1751, 1751 } ; -static yyconst flex_int16_t yy_nxt[3471] = +static yyconst flex_int16_t yy_nxt[3515] = { 0, 14, 15, 16, 17, 18, 19, 18, 14, 14, 14, 14, 18, 20, 21, 14, 22, 23, 24, 25, 14, 26, 27, 28, 29, 30, 31, 32, 33, 34, 14, 35, 36, 37, 38, 39, 14, 14, 14, 14, 41, - 42, 43, 41, 42, 43, 126, 46, 47, 126, 44, + 42, 43, 41, 42, 43, 127, 46, 47, 127, 44, 48, 69, 44, 46, 47, 70, 49, 48, 57, 58, 59, 68, 68, 49, 51, 52, 53, 54, 60, 18, - 57, 58, 59, 124, 124, 55, 51, 52, 53, 54, - 60, 18, 68, 104, 219, 74, 75, 55, 15, 16, + 57, 58, 59, 125, 125, 55, 51, 52, 53, 54, + 60, 18, 68, 104, 221, 74, 75, 55, 15, 16, 17, 62, 63, 64, 67, 67, 68, 67, 67, 65, 67, 95, 68, 76, 68, 67, 85, 68, 66, 15, - 16, 17, 62, 63, 64, 68, 68, 77, 138, 87, + 16, 17, 62, 63, 64, 68, 68, 77, 139, 87, 65, 69, 94, 68, 78, 70, 86, 68, 88, 66, - 72, 79, 72, 72, 134, 72, 89, 134, 96, 68, - 72, 73, 68, 90, 131, 131, 91, 80, 137, 68, - 97, 81, 68, 92, 82, 93, 83, 84, 98, 68, - 68, 101, 68, 139, 99, 102, 68, 117, 100, 118, - 68, 105, 140, 68, 109, 113, 134, 106, 110, 68, - 107, 103, 68, 68, 119, 114, 132, 108, 111, 115, - 116, 112, 68, 120, 68, 122, 144, 156, 121, 123, + 72, 79, 72, 72, 135, 72, 89, 68, 96, 68, + 72, 73, 68, 90, 132, 132, 91, 80, 138, 68, + 97, 81, 68, 92, 82, 93, 83, 84, 98, 148, + 68, 101, 68, 110, 99, 102, 121, 111, 100, 68, + 68, 122, 68, 118, 114, 119, 68, 112, 68, 123, + 113, 103, 68, 124, 115, 68, 192, 105, 116, 117, + 120, 106, 171, 129, 144, 129, 129, 107, 129, 72, - 128, 143, 128, 128, 72, 128, 72, 72, 133, 72, - 133, 133, 68, 133, 67, 136, 67, 67, 68, 67, - 68, 141, 68, 68, 67, 72, 68, 72, 72, 68, - 72, 148, 145, 149, 142, 72, 73, 68, 68, 68, - 146, 68, 68, 151, 68, 147, 152, 68, 155, 161, - 158, 150, 68, 159, 68, 153, 157, 154, 68, 68, - 162, 68, 165, 163, 68, 68, 166, 160, 169, 68, - 68, 68, 170, 68, 68, 168, 167, 172, 175, 68, - 68, 68, 171, 164, 173, 177, 68, 68, 68, 178, - 68, 185, 68, 174, 68, 68, 68, 176, 68, 187, + 108, 72, 72, 134, 72, 134, 134, 109, 134, 67, + 137, 67, 67, 68, 67, 68, 68, 140, 68, 67, + 72, 142, 72, 72, 68, 72, 68, 68, 146, 68, + 72, 73, 150, 68, 143, 141, 68, 68, 145, 68, + 68, 68, 68, 152, 147, 156, 149, 157, 68, 68, + 151, 162, 159, 153, 154, 160, 68, 155, 68, 163, + 68, 68, 158, 164, 166, 68, 68, 68, 167, 161, + 170, 68, 68, 68, 68, 68, 68, 68, 173, 169, + 172, 177, 68, 165, 168, 174, 68, 179, 68, 68, + 68, 180, 176, 175, 178, 181, 68, 187, 68, 68, - 181, 179, 68, 182, 68, 68, 180, 186, 68, 183, - 184, 68, 189, 192, 68, 68, 258, 195, 190, 188, - 194, 124, 124, 68, 126, 191, 196, 126, 128, 134, - 128, 128, 197, 128, 193, 131, 131, 133, 200, 133, - 133, 72, 133, 72, 72, 68, 72, 68, 199, 68, - 198, 68, 136, 68, 68, 201, 205, 68, 68, 208, - 130, 68, 206, 207, 68, 209, 203, 68, 202, 68, - 216, 68, 68, 68, 204, 220, 217, 218, 221, 68, - 68, 68, 68, 68, 68, 68, 227, 210, 68, 232, - 68, 228, 211, 222, 68, 223, 224, 212, 68, 225, + 189, 183, 68, 68, 184, 68, 182, 68, 68, 185, + 188, 68, 196, 194, 186, 68, 203, 68, 125, 125, + 190, 191, 127, 132, 132, 127, 193, 197, 129, 135, + 129, 129, 199, 129, 195, 198, 134, 68, 134, 134, + 72, 134, 72, 72, 68, 72, 68, 201, 68, 200, + 68, 137, 68, 207, 68, 68, 204, 210, 68, 208, + 209, 202, 68, 205, 211, 68, 68, 68, 218, 68, + 206, 68, 68, 219, 220, 222, 68, 223, 68, 224, + 68, 68, 68, 68, 68, 230, 212, 68, 229, 68, + 235, 213, 226, 225, 228, 227, 214, 233, 234, 68, - 226, 231, 213, 230, 68, 233, 234, 236, 214, 215, - 229, 68, 68, 68, 68, 239, 68, 235, 241, 238, - 68, 240, 237, 68, 242, 68, 68, 68, 68, 68, - 68, 68, 243, 244, 245, 68, 246, 68, 68, 248, - 249, 68, 256, 250, 68, 68, 252, 68, 247, 68, - 260, 68, 68, 68, 263, 68, 259, 251, 68, 129, - 253, 264, 254, 255, 262, 257, 68, 266, 134, 68, - 261, 267, 68, 68, 272, 68, 68, 270, 68, 68, - 269, 271, 274, 273, 265, 68, 68, 68, 268, 68, - 275, 68, 279, 277, 276, 68, 280, 281, 68, 282, + 236, 215, 232, 68, 231, 68, 68, 216, 217, 238, + 68, 237, 241, 68, 68, 239, 243, 68, 242, 244, + 240, 68, 68, 246, 68, 68, 68, 68, 68, 245, + 68, 247, 68, 249, 68, 68, 68, 252, 251, 68, + 68, 255, 259, 68, 68, 68, 248, 68, 68, 253, + 250, 68, 262, 261, 135, 254, 265, 263, 257, 258, + 68, 256, 68, 260, 68, 266, 267, 264, 269, 135, + 68, 68, 68, 68, 270, 275, 68, 68, 274, 273, + 68, 272, 276, 277, 68, 68, 68, 68, 68, 268, + 282, 271, 68, 280, 279, 68, 283, 284, 68, 278, - 68, 68, 283, 68, 68, 68, 68, 284, 286, 289, - 287, 278, 68, 288, 68, 68, 291, 68, 285, 293, - 68, 68, 292, 68, 68, 68, 290, 68, 298, 68, - 68, 68, 303, 68, 300, 68, 68, 68, 297, 295, - 294, 68, 68, 68, 296, 302, 304, 299, 305, 301, - 308, 68, 306, 68, 68, 307, 312, 313, 314, 68, - 68, 68, 68, 309, 310, 311, 68, 320, 68, 315, - 68, 319, 68, 322, 68, 321, 318, 316, 68, 68, - 317, 326, 68, 68, 68, 68, 68, 336, 328, 323, - 324, 68, 68, 68, 329, 68, 330, 68, 331, 325, + 68, 68, 285, 68, 286, 68, 68, 68, 287, 289, + 68, 281, 292, 288, 290, 68, 291, 68, 68, 293, + 68, 294, 296, 295, 68, 68, 68, 68, 68, 301, + 68, 68, 68, 68, 68, 297, 303, 307, 306, 300, + 68, 68, 298, 68, 68, 305, 299, 68, 302, 304, + 68, 135, 308, 311, 68, 317, 68, 68, 309, 315, + 316, 310, 68, 313, 68, 318, 314, 68, 312, 68, + 68, 324, 68, 68, 326, 68, 68, 68, 322, 323, + 325, 319, 321, 68, 320, 330, 68, 68, 68, 328, + 68, 327, 332, 68, 68, 68, 333, 68, 334, 68, - 68, 332, 327, 68, 333, 68, 334, 68, 337, 335, - 342, 68, 340, 68, 338, 339, 134, 68, 68, 341, - 68, 127, 68, 68, 68, 344, 343, 68, 352, 345, - 346, 353, 68, 356, 68, 68, 355, 354, 361, 347, - 357, 348, 349, 350, 358, 68, 351, 359, 363, 68, - 362, 366, 360, 68, 364, 68, 68, 68, 68, 365, - 369, 370, 368, 68, 68, 68, 68, 68, 68, 375, - 376, 367, 68, 68, 68, 68, 68, 388, 371, 68, - 372, 373, 374, 379, 381, 68, 68, 378, 384, 383, - 377, 382, 385, 68, 68, 68, 380, 68, 387, 386, + 340, 68, 335, 329, 339, 68, 331, 68, 68, 68, + 336, 68, 341, 337, 346, 338, 344, 68, 342, 343, + 68, 135, 345, 348, 68, 68, 68, 133, 68, 357, + 347, 68, 356, 349, 350, 362, 68, 68, 68, 360, + 68, 68, 358, 351, 359, 352, 353, 354, 361, 363, + 355, 68, 365, 366, 367, 370, 364, 68, 68, 68, + 68, 368, 68, 372, 68, 369, 373, 374, 68, 68, + 68, 68, 379, 371, 68, 68, 68, 68, 380, 68, + 376, 68, 375, 518, 377, 378, 383, 68, 385, 68, + 382, 68, 386, 381, 68, 387, 389, 68, 388, 384, - 389, 68, 68, 391, 392, 68, 68, 68, 68, 68, - 68, 397, 396, 68, 390, 394, 68, 68, 398, 395, - 68, 400, 68, 401, 68, 68, 393, 68, 68, 68, - 68, 68, 403, 68, 404, 68, 68, 399, 402, 405, - 409, 410, 412, 411, 408, 68, 68, 68, 406, 407, - 68, 413, 68, 68, 68, 68, 416, 68, 418, 428, - 68, 417, 68, 430, 68, 68, 68, 414, 68, 429, - 419, 415, 68, 432, 420, 68, 421, 426, 427, 68, - 434, 422, 68, 423, 68, 431, 68, 68, 439, 68, - 68, 424, 68, 433, 440, 68, 436, 435, 445, 441, + 390, 68, 68, 68, 392, 68, 391, 68, 68, 395, + 393, 396, 68, 68, 68, 68, 68, 68, 397, 400, + 394, 398, 68, 401, 68, 399, 68, 404, 68, 402, + 68, 405, 68, 68, 68, 403, 407, 68, 406, 68, + 68, 408, 68, 68, 68, 417, 410, 68, 415, 68, + 68, 414, 416, 409, 413, 68, 68, 411, 68, 412, + 421, 68, 68, 68, 68, 418, 423, 68, 68, 433, + 68, 419, 68, 422, 68, 435, 420, 131, 424, 434, + 432, 68, 425, 68, 426, 68, 437, 431, 436, 427, + 68, 428, 68, 439, 68, 438, 440, 68, 68, 429, - 134, 425, 437, 68, 444, 438, 68, 68, 68, 68, - 443, 442, 450, 68, 68, 68, 68, 449, 446, 453, - 68, 448, 68, 68, 125, 447, 451, 452, 68, 458, - 68, 455, 463, 459, 68, 454, 460, 68, 456, 461, - 68, 457, 462, 68, 464, 68, 465, 68, 466, 68, - 470, 467, 68, 68, 468, 68, 469, 68, 68, 68, - 474, 471, 68, 472, 68, 68, 68, 475, 68, 68, - 480, 477, 68, 68, 68, 68, 478, 483, 476, 473, - 479, 494, 68, 484, 481, 68, 482, 68, 485, 68, - 68, 486, 68, 68, 488, 68, 493, 490, 68, 68, + 68, 68, 441, 68, 68, 445, 68, 135, 68, 430, + 446, 449, 442, 443, 68, 68, 450, 68, 451, 448, + 444, 68, 447, 454, 455, 68, 452, 453, 68, 456, + 68, 68, 68, 458, 68, 460, 68, 463, 466, 68, + 457, 464, 68, 467, 68, 68, 459, 468, 68, 465, + 461, 68, 68, 462, 469, 68, 470, 68, 471, 68, + 497, 68, 475, 68, 473, 474, 472, 68, 68, 68, + 479, 478, 476, 68, 477, 68, 68, 68, 480, 68, + 482, 68, 485, 488, 68, 483, 68, 68, 68, 484, + 481, 68, 68, 68, 490, 489, 491, 486, 487, 68, - 68, 68, 495, 489, 68, 68, 68, 492, 496, 491, - 68, 497, 553, 487, 499, 500, 498, 68, 68, 68, - 501, 503, 506, 502, 68, 504, 68, 68, 68, 68, - 510, 508, 505, 507, 511, 68, 68, 68, 512, 514, - 68, 68, 68, 68, 68, 68, 509, 68, 513, 519, - 68, 68, 524, 520, 68, 68, 526, 68, 515, 516, - 68, 517, 521, 518, 527, 68, 523, 68, 522, 68, - 68, 68, 529, 525, 68, 68, 528, 68, 68, 68, - 534, 533, 536, 537, 532, 530, 535, 68, 68, 531, - 68, 134, 68, 68, 68, 539, 542, 543, 68, 540, + 494, 68, 498, 68, 493, 68, 495, 68, 502, 496, + 68, 499, 68, 500, 68, 501, 68, 505, 492, 68, + 68, 68, 68, 507, 506, 68, 508, 68, 68, 509, + 504, 512, 503, 510, 68, 68, 68, 513, 511, 68, + 516, 68, 514, 520, 517, 68, 519, 68, 68, 68, + 68, 68, 68, 521, 525, 68, 68, 515, 68, 530, + 526, 68, 532, 68, 68, 522, 68, 523, 68, 524, + 527, 531, 533, 529, 528, 68, 68, 534, 68, 536, + 535, 68, 68, 68, 68, 68, 68, 540, 539, 542, + 541, 538, 68, 545, 68, 537, 68, 543, 68, 135, - 68, 546, 544, 68, 68, 538, 541, 68, 549, 547, - 68, 550, 548, 68, 545, 68, 551, 68, 68, 68, - 68, 68, 68, 68, 68, 566, 565, 564, 552, 563, - 68, 68, 68, 554, 561, 562, 574, 68, 578, 68, - 577, 575, 555, 68, 68, 68, 580, 581, 556, 576, - 68, 579, 557, 68, 582, 558, 68, 68, 68, 583, - 68, 68, 559, 584, 68, 560, 68, 567, 568, 585, - 569, 68, 588, 570, 68, 589, 590, 586, 571, 587, - 68, 68, 593, 68, 572, 573, 592, 594, 595, 591, - 68, 68, 68, 68, 596, 68, 597, 68, 600, 68, + 68, 549, 68, 544, 548, 546, 550, 68, 547, 68, + 552, 68, 555, 68, 68, 556, 554, 68, 553, 68, + 68, 551, 68, 68, 68, 557, 68, 559, 68, 68, + 68, 572, 558, 571, 570, 569, 68, 68, 560, 567, + 568, 68, 580, 68, 584, 68, 583, 561, 68, 68, + 68, 586, 130, 562, 68, 582, 585, 563, 68, 581, + 564, 68, 588, 68, 68, 68, 589, 565, 68, 587, + 566, 68, 573, 574, 68, 575, 68, 591, 576, 590, + 68, 68, 595, 577, 592, 68, 621, 593, 594, 578, + 579, 596, 68, 599, 68, 600, 601, 598, 68, 68, - 68, 603, 68, 598, 601, 599, 68, 602, 605, 68, - 68, 68, 68, 68, 604, 608, 68, 610, 68, 607, - 68, 68, 68, 612, 68, 609, 68, 615, 606, 68, - 68, 613, 68, 611, 68, 68, 68, 68, 621, 68, - 68, 620, 614, 626, 68, 616, 617, 68, 624, 68, - 619, 618, 629, 622, 625, 623, 68, 68, 630, 68, - 631, 628, 68, 68, 627, 68, 68, 634, 632, 68, - 636, 633, 637, 68, 68, 641, 638, 68, 68, 68, - 68, 643, 68, 68, 639, 68, 635, 640, 644, 134, - 68, 68, 68, 68, 645, 646, 68, 657, 642, 68, + 68, 68, 602, 597, 603, 68, 68, 68, 68, 68, + 68, 610, 68, 604, 605, 607, 608, 612, 68, 68, + 68, 68, 68, 68, 615, 606, 611, 609, 68, 614, + 68, 617, 68, 68, 68, 68, 619, 616, 613, 622, + 68, 68, 68, 618, 620, 68, 68, 68, 68, 628, + 68, 627, 68, 623, 68, 624, 633, 631, 636, 68, + 637, 626, 625, 68, 629, 68, 630, 68, 632, 68, + 68, 638, 634, 635, 68, 68, 68, 643, 644, 641, + 68, 68, 640, 68, 645, 648, 68, 68, 639, 68, + 68, 650, 68, 651, 135, 68, 642, 68, 646, 647, - 68, 68, 647, 68, 649, 68, 661, 68, 682, 648, - 134, 658, 650, 68, 660, 68, 651, 662, 652, 663, - 68, 68, 653, 68, 654, 659, 666, 664, 68, 655, - 665, 68, 68, 668, 656, 673, 667, 68, 68, 68, - 68, 670, 68, 672, 679, 669, 671, 68, 674, 68, - 678, 68, 68, 675, 68, 676, 680, 683, 68, 684, - 68, 681, 687, 68, 688, 689, 68, 68, 685, 690, - 68, 68, 68, 677, 68, 68, 68, 686, 68, 693, - 68, 68, 68, 68, 692, 698, 691, 696, 68, 68, - 702, 694, 695, 68, 697, 68, 700, 701, 68, 68, + 68, 653, 68, 68, 652, 68, 68, 649, 68, 664, + 68, 68, 128, 68, 654, 668, 656, 68, 68, 68, + 68, 665, 671, 657, 655, 68, 667, 669, 658, 68, + 659, 670, 68, 666, 660, 672, 661, 673, 68, 68, + 677, 662, 68, 675, 68, 702, 663, 674, 68, 680, + 679, 68, 681, 676, 68, 68, 678, 682, 68, 683, + 685, 68, 68, 686, 68, 689, 68, 690, 68, 687, + 68, 694, 68, 688, 691, 68, 696, 684, 68, 695, + 68, 68, 692, 697, 68, 68, 68, 68, 68, 693, + 68, 700, 68, 68, 68, 705, 703, 698, 699, 709, - 68, 699, 703, 706, 707, 708, 68, 704, 705, 68, - 710, 711, 68, 712, 68, 709, 68, 713, 68, 68, - 714, 68, 68, 715, 716, 68, 68, 68, 720, 718, - 68, 68, 717, 724, 68, 722, 723, 68, 727, 68, - 68, 68, 719, 726, 68, 68, 68, 721, 730, 728, - 725, 68, 68, 68, 68, 68, 68, 735, 68, 729, - 736, 738, 731, 68, 741, 732, 734, 739, 742, 68, - 68, 733, 737, 68, 68, 740, 744, 68, 68, 68, - 748, 68, 68, 68, 68, 743, 68, 68, 68, 68, - 68, 747, 746, 745, 782, 750, 68, 68, 756, 749, + 68, 68, 708, 701, 68, 68, 68, 704, 707, 68, + 68, 713, 706, 68, 714, 715, 712, 68, 717, 710, + 718, 68, 716, 711, 720, 68, 68, 722, 721, 68, + 723, 68, 68, 68, 719, 724, 68, 68, 68, 68, + 728, 68, 68, 68, 730, 68, 731, 68, 726, 732, + 68, 725, 68, 734, 735, 68, 727, 68, 733, 729, + 738, 736, 68, 737, 68, 68, 68, 68, 739, 68, + 68, 743, 744, 746, 68, 749, 68, 750, 742, 68, + 68, 740, 68, 68, 741, 747, 68, 745, 748, 752, + 68, 68, 756, 68, 751, 68, 68, 68, 68, 68, - 757, 751, 753, 68, 754, 68, 68, 755, 752, 68, - 760, 758, 68, 68, 759, 68, 764, 68, 762, 68, - 767, 68, 68, 68, 68, 68, 761, 68, 771, 769, - 763, 68, 765, 68, 68, 68, 772, 68, 766, 774, - 768, 773, 68, 68, 770, 775, 777, 68, 778, 68, - 68, 776, 780, 68, 779, 68, 68, 68, 68, 783, - 786, 68, 68, 68, 68, 68, 68, 68, 781, 787, - 784, 785, 791, 68, 794, 797, 795, 788, 792, 68, - 790, 68, 789, 68, 793, 800, 68, 796, 799, 801, - 68, 68, 803, 68, 68, 806, 68, 807, 68, 798, + 754, 68, 753, 755, 758, 68, 126, 764, 68, 765, + 68, 757, 68, 761, 68, 766, 759, 68, 68, 68, + 762, 763, 767, 760, 68, 68, 68, 772, 68, 770, + 775, 68, 768, 769, 68, 68, 68, 68, 779, 68, + 771, 773, 777, 68, 780, 68, 68, 774, 68, 783, + 781, 68, 776, 68, 68, 778, 68, 68, 786, 782, + 785, 788, 68, 68, 68, 68, 784, 790, 68, 68, + 68, 791, 68, 787, 68, 794, 789, 68, 68, 792, + 793, 795, 68, 799, 68, 68, 803, 68, 68, 796, + 68, 68, 798, 797, 802, 807, 805, 800, 801, 68, - 68, 68, 68, 805, 68, 802, 804, 808, 68, 809, - 68, 810, 813, 68, 68, 815, 816, 811, 812, 814, - 68, 68, 68, 68, 68, 823, 68, 817, 818, 68, - 824, 68, 819, 68, 68, 68, 68, 820, 827, 821, - 68, 822, 828, 68, 825, 68, 68, 829, 831, 826, - 832, 835, 68, 830, 837, 68, 68, 68, 68, 838, - 834, 836, 839, 833, 841, 68, 68, 843, 68, 68, - 845, 68, 68, 68, 844, 68, 68, 840, 847, 68, - 850, 849, 68, 848, 68, 132, 842, 68, 854, 68, - 852, 855, 846, 68, 853, 68, 68, 68, 857, 68, + 68, 804, 808, 68, 806, 814, 809, 68, 68, 811, + 68, 68, 813, 812, 68, 815, 816, 68, 810, 68, + 818, 68, 817, 68, 68, 68, 823, 824, 820, 68, + 819, 68, 68, 68, 825, 68, 68, 826, 821, 68, + 831, 68, 68, 822, 827, 833, 68, 832, 68, 828, + 836, 829, 68, 830, 837, 68, 68, 834, 68, 68, + 68, 68, 838, 68, 835, 68, 840, 844, 68, 68, + 841, 839, 846, 68, 848, 68, 845, 842, 847, 850, + 68, 68, 849, 852, 68, 843, 68, 854, 68, 68, + 68, 853, 68, 68, 68, 856, 68, 859, 858, 68, - 851, 68, 856, 68, 858, 861, 68, 68, 859, 864, - 860, 68, 68, 68, 68, 68, 68, 68, 870, 68, - 68, 862, 68, 68, 68, 865, 130, 868, 874, 876, - 863, 866, 867, 871, 869, 877, 68, 68, 873, 878, - 68, 68, 68, 68, 872, 875, 879, 883, 68, 880, - 881, 68, 68, 68, 885, 884, 882, 68, 68, 68, - 68, 68, 887, 889, 68, 892, 68, 68, 68, 68, - 68, 68, 886, 68, 68, 888, 899, 890, 901, 68, - 891, 895, 893, 896, 897, 894, 900, 68, 68, 898, - 68, 68, 902, 68, 908, 909, 903, 905, 907, 68, + 857, 851, 863, 68, 68, 861, 864, 68, 68, 855, + 862, 68, 860, 865, 866, 68, 68, 870, 68, 68, + 68, 68, 68, 868, 867, 873, 68, 869, 68, 68, + 68, 68, 68, 879, 68, 68, 874, 68, 68, 135, + 871, 877, 875, 883, 872, 68, 876, 886, 880, 878, + 885, 887, 68, 882, 68, 68, 68, 890, 68, 881, + 884, 892, 68, 888, 889, 68, 68, 68, 68, 893, + 68, 68, 891, 894, 68, 68, 898, 68, 68, 68, + 68, 901, 68, 68, 68, 68, 895, 909, 897, 68, + 68, 68, 899, 133, 896, 900, 902, 904, 903, 905, - 68, 68, 910, 904, 911, 68, 68, 68, 68, 68, - 916, 906, 913, 68, 917, 68, 918, 68, 68, 68, - 68, 68, 914, 68, 912, 924, 68, 923, 915, 68, - 68, 68, 919, 68, 68, 68, 68, 920, 952, 922, - 929, 68, 925, 68, 932, 921, 933, 68, 926, 68, - 927, 931, 928, 934, 68, 930, 68, 68, 937, 68, - 935, 68, 938, 936, 941, 68, 942, 68, 945, 68, - 68, 943, 68, 68, 68, 939, 68, 940, 964, 944, - 949, 947, 68, 948, 68, 68, 956, 946, 950, 68, - 951, 68, 68, 953, 68, 955, 68, 959, 68, 954, + 906, 907, 68, 68, 68, 913, 68, 908, 910, 911, + 915, 68, 914, 912, 917, 918, 916, 68, 919, 68, + 68, 920, 68, 68, 68, 68, 68, 925, 68, 922, + 68, 926, 68, 927, 68, 68, 68, 68, 68, 923, + 68, 921, 68, 932, 68, 924, 933, 928, 68, 929, + 68, 68, 68, 68, 68, 931, 938, 934, 68, 935, + 68, 930, 944, 936, 68, 941, 942, 937, 940, 68, + 68, 939, 950, 945, 943, 68, 68, 947, 131, 946, + 68, 948, 951, 68, 68, 952, 955, 68, 953, 68, + 68, 68, 68, 958, 949, 957, 954, 959, 960, 68, - 68, 957, 68, 961, 68, 68, 68, 68, 68, 958, - 68, 68, 966, 68, 969, 68, 963, 68, 68, 68, - 960, 68, 968, 970, 976, 965, 962, 68, 967, 975, - 973, 971, 68, 977, 979, 972, 68, 974, 68, 68, - 981, 68, 68, 68, 68, 984, 68, 68, 982, 68, - 980, 129, 978, 68, 68, 990, 987, 68, 985, 988, - 68, 68, 991, 992, 68, 68, 993, 983, 995, 986, - 996, 989, 994, 68, 997, 68, 68, 68, 68, 1002, - 68, 68, 998, 1001, 68, 68, 1004, 1005, 68, 68, - 1006, 68, 68, 68, 68, 999, 68, 1000, 68, 1013, + 961, 68, 68, 68, 964, 956, 962, 68, 963, 68, + 68, 68, 68, 969, 68, 68, 967, 68, 971, 68, + 68, 68, 68, 68, 966, 974, 68, 968, 68, 68, + 68, 973, 68, 976, 965, 970, 68, 979, 68, 68, + 977, 972, 975, 978, 980, 68, 981, 983, 68, 68, + 982, 985, 984, 986, 987, 989, 68, 991, 68, 68, + 68, 68, 68, 68, 994, 988, 68, 992, 68, 68, + 990, 1000, 997, 68, 68, 998, 68, 68, 995, 1001, + 68, 68, 1002, 68, 1005, 1003, 993, 999, 996, 1006, + 68, 1007, 68, 68, 68, 68, 68, 68, 1012, 68, - 68, 68, 68, 1003, 68, 1011, 68, 1007, 1010, 1012, - 68, 1008, 1009, 1019, 68, 1017, 68, 1018, 1014, 68, - 1015, 68, 1016, 1020, 1023, 68, 1021, 68, 68, 68, - 1024, 68, 1022, 1025, 68, 1026, 68, 1032, 1027, 68, - 1028, 68, 68, 1029, 68, 1031, 1030, 1033, 68, 68, - 68, 1034, 1035, 68, 1040, 68, 68, 68, 1037, 1036, - 68, 1042, 68, 1043, 68, 1048, 1045, 1050, 1039, 1046, - 68, 1041, 68, 68, 1038, 68, 1053, 1044, 1047, 1051, - 68, 68, 1049, 68, 68, 68, 1055, 68, 68, 1061, - 68, 68, 1056, 1054, 68, 1052, 1057, 1058, 68, 68, + 1011, 1008, 1004, 68, 1014, 1015, 68, 68, 68, 68, + 68, 1009, 1016, 1010, 68, 1017, 1023, 68, 68, 1013, + 68, 68, 68, 68, 1020, 130, 1021, 68, 1018, 1019, + 1022, 68, 1027, 68, 68, 1033, 68, 68, 1024, 1032, + 1025, 1029, 1030, 1026, 68, 1031, 1028, 1034, 68, 68, + 68, 68, 68, 1035, 1043, 68, 1038, 1042, 68, 1037, + 1039, 1041, 68, 1040, 68, 1036, 68, 68, 68, 68, + 68, 68, 1051, 68, 68, 68, 1054, 1045, 1044, 1053, + 1048, 1047, 68, 68, 1046, 68, 1059, 68, 1050, 1052, + 1055, 68, 1056, 1061, 1049, 1057, 68, 68, 68, 1064, - 68, 68, 68, 1059, 1065, 68, 1060, 1062, 1063, 68, - 1066, 68, 68, 68, 1067, 1073, 1068, 1071, 1064, 1072, - 68, 1069, 1070, 68, 68, 1075, 68, 1078, 68, 68, - 1074, 68, 68, 1082, 68, 68, 1076, 1081, 1083, 68, - 1079, 1084, 68, 1086, 68, 1077, 68, 1080, 1085, 68, - 68, 68, 68, 68, 1088, 68, 68, 68, 1087, 1089, - 1092, 1098, 1093, 1090, 1097, 68, 68, 1091, 68, 68, - 68, 68, 1096, 1102, 68, 1094, 1095, 1104, 68, 1105, - 68, 68, 1107, 68, 68, 1106, 1108, 68, 1100, 1099, - 1101, 1103, 1109, 1111, 68, 1113, 68, 68, 68, 68, + 1058, 68, 1062, 1060, 68, 68, 68, 1063, 1066, 1068, + 1065, 68, 68, 1072, 1067, 68, 68, 68, 68, 1069, + 68, 68, 68, 68, 1076, 68, 1077, 1078, 1079, 1070, + 68, 1071, 1073, 1074, 1080, 68, 68, 1075, 1083, 68, + 68, 68, 1089, 1085, 68, 68, 68, 68, 68, 68, + 1082, 1093, 68, 1081, 1084, 1092, 1086, 1087, 1090, 68, + 1088, 68, 1094, 1095, 68, 68, 1091, 1097, 68, 68, + 1096, 68, 68, 68, 1099, 68, 68, 1098, 68, 68, + 1100, 1103, 1108, 68, 1101, 1109, 68, 1104, 1102, 68, + 68, 68, 1113, 68, 1107, 1106, 68, 1115, 68, 68, - 1114, 1115, 1110, 68, 68, 68, 68, 68, 68, 68, - 1125, 68, 68, 68, 1127, 1116, 1117, 1118, 68, 1112, - 68, 68, 1119, 1123, 1120, 1121, 68, 1122, 68, 1124, - 1129, 1130, 68, 1131, 68, 1132, 68, 1135, 1126, 68, - 1128, 68, 68, 1133, 1139, 68, 68, 1138, 68, 68, - 1142, 68, 1134, 68, 1144, 1141, 68, 1137, 1143, 68, - 68, 68, 68, 1147, 68, 1136, 1140, 68, 1150, 68, - 68, 1146, 68, 68, 1156, 68, 1145, 68, 1154, 1148, - 68, 68, 1155, 1152, 1151, 1153, 1159, 68, 1149, 1162, - 68, 1157, 1163, 68, 68, 1161, 1158, 1164, 1160, 1166, + 1105, 1116, 68, 1117, 1118, 68, 68, 1110, 1111, 68, + 68, 1112, 1120, 1119, 1122, 68, 1114, 68, 68, 68, + 1124, 68, 1126, 1121, 68, 1125, 68, 68, 68, 68, + 68, 1123, 1134, 1136, 68, 1131, 68, 68, 1127, 1128, + 1129, 68, 1138, 68, 68, 1130, 1141, 68, 1132, 1133, + 68, 1135, 1140, 68, 68, 68, 1146, 1139, 68, 1142, + 1143, 68, 1137, 1144, 68, 1150, 68, 68, 1153, 1149, + 68, 1154, 68, 68, 1152, 68, 1145, 1148, 68, 68, + 1155, 68, 68, 68, 1147, 1159, 1151, 1156, 68, 68, + 1162, 68, 68, 1158, 68, 68, 68, 1168, 68, 1157, - 68, 1165, 68, 1169, 68, 68, 68, 68, 68, 68, - 1171, 68, 1168, 1174, 68, 1176, 1167, 1170, 68, 1172, - 68, 68, 68, 1179, 1178, 68, 1177, 1180, 68, 1181, - 68, 68, 68, 1175, 1173, 68, 68, 1183, 1185, 68, - 1184, 1187, 68, 68, 68, 1182, 1190, 68, 1186, 68, - 68, 68, 68, 68, 1188, 1189, 1195, 68, 1192, 68, - 1197, 68, 1196, 127, 1191, 68, 68, 1198, 1193, 68, - 1194, 68, 1199, 1204, 68, 1202, 1205, 1201, 1203, 68, - 1207, 68, 68, 1200, 1210, 68, 68, 1209, 1211, 68, - 68, 68, 68, 1206, 68, 1214, 68, 1212, 1208, 125, + 128, 1160, 1166, 68, 1167, 68, 1163, 1171, 68, 1165, + 1174, 1164, 68, 68, 1161, 68, 1169, 1175, 68, 68, + 1178, 1170, 68, 1176, 1172, 68, 1173, 1177, 68, 1181, + 68, 1180, 68, 68, 68, 1186, 1183, 68, 1188, 1179, + 68, 68, 1182, 68, 68, 1184, 68, 1185, 126, 1190, + 68, 1191, 68, 1189, 1192, 68, 1193, 68, 1195, 1187, + 68, 68, 68, 68, 1194, 1196, 68, 1197, 1199, 68, + 68, 1198, 1202, 68, 68, 68, 68, 68, 1200, 68, + 68, 1201, 1208, 1204, 1207, 68, 1209, 68, 68, 1211, + 1203, 68, 68, 1205, 68, 1206, 1214, 1213, 68, 1210, - 68, 1215, 68, 68, 68, 68, 68, 68, 68, 1224, - 68, 1213, 1217, 1223, 1218, 1219, 68, 1216, 68, 1220, - 1228, 68, 68, 68, 68, 1221, 1222, 1226, 1225, 1230, - 1227, 68, 68, 1231, 68, 68, 68, 1232, 1236, 1233, - 68, 1234, 68, 68, 68, 1237, 1240, 68, 1229, 68, - 1239, 1243, 68, 68, 68, 1235, 68, 1244, 68, 1241, - 1245, 1238, 68, 1247, 1249, 1246, 1248, 68, 68, 1242, - 68, 68, 68, 68, 68, 1252, 1250, 1253, 68, 68, - 1251, 68, 68, 68, 1254, 1257, 68, 1258, 1262, 68, - 1256, 68, 1261, 1255, 68, 1263, 68, 1259, 1264, 68, + 1212, 1215, 1216, 68, 68, 1219, 68, 1221, 68, 1217, + 68, 68, 1218, 1222, 1223, 68, 68, 68, 1226, 68, + 68, 1220, 68, 1224, 68, 68, 68, 68, 1225, 1227, + 68, 68, 68, 68, 1229, 68, 1230, 1231, 1235, 68, + 1228, 1232, 68, 68, 1236, 1243, 1239, 1233, 1238, 1237, + 1234, 1240, 68, 68, 68, 68, 68, 68, 1242, 1244, + 1245, 1241, 1248, 68, 68, 68, 68, 68, 1249, 1253, + 68, 68, 1250, 68, 1246, 68, 1256, 1247, 68, 68, + 1252, 68, 68, 1257, 1251, 68, 1254, 1258, 68, 68, + 68, 1259, 1262, 1255, 1264, 68, 68, 1260, 1263, 68, - 1266, 68, 68, 1260, 1269, 68, 1267, 1268, 68, 68, - 1265, 1272, 68, 1274, 68, 68, 1270, 68, 1273, 68, - 1275, 68, 1271, 1279, 68, 68, 1278, 1276, 68, 68, - 68, 68, 68, 1281, 68, 1277, 1284, 68, 1287, 68, - 68, 68, 68, 68, 1288, 1283, 1290, 68, 1286, 1289, - 1280, 68, 1282, 68, 68, 1285, 68, 68, 1299, 68, - 68, 68, 1292, 1300, 68, 68, 1297, 68, 1291, 1315, - 1293, 68, 1295, 1383, 1301, 1294, 68, 1296, 1298, 1302, - 1303, 68, 1304, 1305, 68, 1306, 68, 1308, 68, 1307, - 1309, 68, 1310, 68, 68, 1312, 68, 1313, 68, 68, + 1261, 1265, 68, 68, 1266, 68, 68, 68, 1267, 68, + 68, 1270, 1271, 68, 68, 1275, 68, 68, 1280, 1269, + 1277, 68, 1268, 1274, 1272, 68, 1276, 68, 68, 1278, + 68, 1279, 1273, 1282, 68, 68, 1283, 68, 1281, 1285, + 68, 1287, 68, 68, 1286, 68, 1288, 68, 68, 1289, + 1284, 68, 1291, 1292, 68, 68, 1294, 68, 68, 68, + 68, 1290, 68, 1297, 1300, 68, 1301, 68, 68, 68, + 68, 68, 1296, 1293, 1303, 68, 1299, 1298, 1295, 68, + 68, 68, 1302, 68, 1312, 68, 1751, 68, 68, 1305, + 1313, 68, 68, 1310, 1304, 1307, 68, 1328, 1306, 1308, - 1316, 68, 68, 1318, 68, 68, 68, 68, 68, 1322, - 1321, 68, 1320, 1311, 1324, 68, 1326, 68, 1314, 68, - 68, 1317, 68, 1319, 1323, 68, 1329, 1330, 68, 68, - 1325, 1332, 68, 68, 1334, 1328, 68, 68, 68, 68, - 68, 68, 1327, 1337, 1331, 1335, 68, 68, 68, 1336, - 68, 1341, 68, 1339, 68, 1333, 1343, 68, 1347, 1344, - 1346, 68, 1340, 1342, 1338, 68, 1345, 68, 1350, 1351, - 1349, 68, 1352, 68, 68, 68, 68, 1348, 68, 1357, - 1353, 68, 68, 68, 1355, 68, 1358, 68, 1354, 68, - 1356, 1360, 68, 1361, 68, 68, 1363, 1362, 68, 1364, + 1309, 1314, 68, 1317, 1311, 1315, 1318, 68, 68, 1316, + 1319, 68, 1321, 68, 1322, 68, 1323, 68, 68, 1325, + 68, 1320, 1326, 68, 68, 1329, 68, 68, 1331, 68, + 68, 68, 68, 68, 1334, 68, 1335, 1324, 1333, 1337, + 68, 68, 68, 1327, 1340, 68, 1330, 68, 1332, 68, + 68, 1336, 1339, 1343, 1344, 68, 1338, 1346, 68, 68, + 68, 1348, 1342, 68, 68, 1341, 68, 68, 68, 1345, + 68, 1351, 1349, 68, 68, 68, 1350, 68, 1355, 68, + 68, 1353, 1360, 1751, 1357, 1347, 1358, 68, 68, 1356, + 68, 1354, 1352, 1359, 1361, 68, 1364, 1363, 1365, 68, - 68, 1367, 1359, 1365, 1366, 68, 68, 68, 68, 1368, - 1369, 1370, 68, 1371, 68, 68, 68, 1377, 1372, 1374, - 1373, 1376, 68, 68, 68, 68, 1381, 68, 68, 1378, - 1380, 68, 68, 1384, 1375, 1382, 1385, 68, 68, 68, - 1379, 1387, 68, 1386, 1388, 68, 1389, 68, 1390, 68, - 1392, 68, 1394, 68, 1393, 1391, 1395, 68, 68, 1398, - 68, 68, 68, 68, 68, 1400, 68, 1399, 1403, 68, - 68, 1402, 68, 1397, 68, 1396, 1404, 68, 1401, 1405, - 68, 68, 1406, 68, 68, 68, 1408, 1413, 68, 1411, - 1407, 68, 68, 1409, 68, 1410, 68, 68, 68, 68, + 1362, 68, 1366, 68, 68, 68, 68, 68, 68, 1371, + 1367, 68, 1372, 1369, 1368, 1374, 68, 1370, 1375, 68, + 68, 1377, 68, 68, 68, 1376, 68, 1381, 1373, 68, + 1384, 68, 68, 1382, 1378, 1383, 68, 1379, 68, 68, + 68, 1385, 68, 1380, 1388, 68, 1391, 68, 68, 1751, + 1390, 68, 68, 1387, 1392, 1395, 68, 1394, 1386, 68, + 68, 1397, 1389, 1393, 1396, 68, 1398, 1399, 68, 68, + 1401, 68, 1402, 68, 1400, 1403, 68, 1404, 68, 68, + 68, 68, 1410, 68, 1409, 68, 1407, 68, 68, 68, + 1413, 68, 68, 68, 1405, 1408, 68, 1414, 1415, 68, - 1414, 68, 68, 68, 68, 1412, 68, 1422, 1423, 1417, - 1424, 68, 1419, 68, 1416, 1425, 68, 1420, 1415, 68, - 68, 1418, 68, 1421, 1426, 68, 68, 1433, 1428, 1430, - 68, 1427, 1434, 68, 68, 68, 68, 1436, 68, 1429, - 68, 68, 1431, 1432, 1435, 1442, 68, 1443, 68, 1437, - 68, 68, 68, 68, 1438, 68, 1439, 1440, 68, 1441, - 68, 1451, 68, 1450, 68, 1445, 1444, 68, 68, 68, - 1446, 68, 1454, 1447, 1448, 1455, 68, 68, 1449, 1452, - 1457, 68, 1456, 1459, 68, 1453, 1460, 68, 68, 1461, - 1458, 68, 68, 68, 68, 68, 68, 1464, 1465, 1462, + 68, 1406, 1418, 68, 1412, 1417, 1411, 1416, 1419, 68, + 1420, 68, 68, 68, 68, 68, 68, 1422, 68, 1428, + 68, 1426, 68, 68, 1421, 1423, 1424, 1425, 68, 68, + 68, 1429, 68, 68, 68, 68, 68, 68, 1427, 68, + 1437, 1438, 1432, 1439, 68, 68, 1434, 68, 1431, 1430, + 68, 1435, 1440, 68, 1433, 68, 1436, 1441, 68, 1445, + 68, 1443, 68, 1442, 68, 1448, 68, 1444, 1449, 68, + 68, 1450, 68, 1451, 68, 1446, 1447, 68, 1453, 68, + 1457, 68, 1458, 68, 68, 1452, 68, 68, 68, 68, + 1454, 68, 1459, 1455, 1465, 1466, 68, 68, 1456, 1460, - 1463, 68, 68, 1467, 68, 1474, 1469, 1470, 1472, 68, - 68, 1468, 68, 1466, 1473, 68, 68, 1475, 68, 1471, - 1476, 68, 1477, 68, 1478, 1481, 68, 68, 68, 68, - 1479, 68, 1480, 1482, 68, 68, 1483, 68, 1486, 1484, - 68, 68, 68, 1485, 68, 1491, 68, 68, 68, 68, - 1489, 1490, 68, 1488, 68, 1487, 1492, 1496, 68, 1498, - 68, 68, 68, 1497, 68, 1493, 68, 1500, 1494, 1499, - 68, 1495, 68, 1501, 68, 1504, 1505, 68, 68, 1502, - 68, 1507, 1730, 68, 68, 1503, 1508, 1509, 68, 1510, - 68, 68, 1506, 1511, 68, 1514, 1512, 1517, 1513, 68, + 68, 68, 1461, 68, 68, 1469, 1462, 1463, 1470, 1464, + 1471, 68, 1467, 1473, 68, 68, 1472, 68, 1468, 1475, + 68, 1476, 68, 68, 1477, 68, 68, 68, 68, 68, + 1480, 68, 1481, 68, 1474, 1479, 68, 1483, 1485, 1478, + 68, 1486, 1488, 68, 1489, 68, 1484, 1482, 1490, 68, + 1492, 68, 68, 68, 1491, 1487, 1493, 68, 1494, 68, + 68, 68, 68, 68, 1495, 68, 1496, 1498, 1497, 68, + 1499, 68, 68, 68, 1500, 1502, 68, 1501, 68, 68, + 1507, 68, 68, 68, 68, 1505, 1504, 1506, 68, 1503, + 1508, 1512, 68, 1513, 1514, 68, 68, 68, 68, 68, - 68, 1515, 68, 1516, 1518, 68, 68, 68, 68, 68, - 68, 1521, 1525, 68, 68, 68, 68, 1529, 68, 68, - 1530, 68, 1519, 1520, 1524, 1522, 1527, 68, 1523, 68, - 68, 68, 1532, 1526, 1528, 68, 68, 1531, 68, 1538, - 1535, 68, 1540, 68, 68, 68, 68, 68, 1541, 1533, - 1730, 68, 68, 68, 1542, 1536, 1534, 68, 1537, 1539, - 1543, 1544, 1545, 1546, 68, 68, 1549, 68, 68, 1548, - 68, 1547, 68, 1551, 68, 68, 1550, 1553, 1557, 1552, - 1555, 68, 68, 68, 1559, 68, 68, 68, 1562, 68, - 1563, 68, 1556, 1554, 68, 68, 68, 68, 68, 68, + 68, 1509, 1516, 1510, 1515, 68, 68, 1511, 1517, 1519, + 1751, 1518, 68, 1521, 68, 1520, 1522, 68, 68, 1524, + 68, 1526, 68, 1525, 1527, 68, 1523, 1528, 68, 68, + 1531, 68, 1529, 1532, 68, 68, 68, 1534, 68, 1535, + 1533, 68, 68, 1530, 68, 68, 1538, 68, 1542, 68, + 68, 68, 68, 68, 1546, 1536, 1537, 68, 1547, 1544, + 1539, 1541, 68, 68, 68, 1540, 68, 68, 1549, 1543, + 68, 1545, 68, 68, 68, 1555, 1552, 68, 1548, 1557, + 68, 68, 68, 1559, 1550, 1558, 68, 68, 68, 68, + 1553, 68, 1551, 1554, 68, 1556, 1562, 1560, 1563, 1561, - 1564, 1560, 1561, 1568, 1567, 68, 1558, 1570, 68, 68, - 1565, 1572, 68, 68, 1566, 68, 1574, 68, 1571, 68, - 1573, 68, 1576, 1569, 68, 1575, 68, 1577, 1579, 68, - 68, 1578, 1580, 68, 1584, 68, 1582, 68, 1581, 68, - 68, 68, 1585, 1589, 1587, 68, 1583, 68, 68, 1592, - 68, 1593, 68, 68, 1598, 68, 1730, 1586, 1595, 1588, - 1594, 1596, 1590, 1591, 68, 1599, 68, 1600, 68, 1597, - 68, 1602, 68, 68, 1603, 1601, 1604, 68, 68, 1606, - 68, 68, 68, 1609, 68, 68, 1607, 1605, 68, 68, - 1608, 68, 68, 1610, 1611, 68, 68, 1612, 68, 68, + 1564, 68, 68, 1567, 68, 68, 1566, 68, 68, 68, + 1569, 68, 68, 1568, 1571, 68, 1565, 1570, 1575, 68, + 1573, 1577, 68, 68, 1580, 68, 68, 1574, 1572, 68, + 1581, 1578, 68, 68, 1579, 68, 1576, 68, 1582, 68, + 1588, 68, 1586, 1585, 68, 1590, 68, 68, 1583, 68, + 1592, 68, 1584, 68, 1591, 68, 1595, 68, 68, 1598, + 68, 1599, 68, 1589, 68, 1587, 68, 1593, 68, 1603, + 68, 1596, 68, 68, 68, 68, 1594, 1608, 1601, 1606, + 1597, 68, 68, 1600, 1604, 1611, 68, 68, 1602, 1612, + 68, 68, 68, 1605, 1607, 68, 1614, 1616, 1609, 1610, - 1620, 68, 68, 1618, 1621, 68, 1622, 68, 1614, 1613, - 1623, 68, 1615, 1616, 68, 1626, 68, 1617, 1624, 1619, - 68, 1625, 68, 1629, 68, 1630, 68, 68, 68, 68, - 68, 68, 68, 1637, 68, 1627, 1634, 1635, 1638, 68, - 1628, 1639, 68, 1632, 1640, 68, 68, 68, 1642, 1636, - 1633, 1643, 1631, 68, 68, 68, 68, 68, 1641, 1645, - 68, 68, 68, 68, 68, 1649, 68, 1644, 68, 68, - 68, 68, 1657, 68, 1646, 1647, 1648, 1651, 68, 1658, - 68, 1653, 1650, 1659, 1654, 1652, 1656, 68, 68, 68, - 1663, 68, 1660, 68, 1655, 68, 1667, 1668, 68, 68, + 1617, 68, 1618, 68, 1619, 68, 1613, 68, 68, 1615, + 1621, 68, 1620, 68, 1622, 1623, 68, 68, 1626, 68, + 68, 68, 1624, 1629, 68, 1627, 1625, 68, 68, 1628, + 68, 68, 1630, 1631, 68, 68, 68, 1751, 68, 68, + 1640, 68, 1632, 1638, 1641, 68, 68, 68, 68, 1633, + 1634, 1642, 1635, 1636, 1643, 68, 68, 1637, 68, 1639, + 1644, 1645, 68, 1647, 68, 68, 1649, 1650, 68, 1651, + 68, 1652, 1646, 68, 68, 68, 68, 68, 1658, 68, + 1648, 1655, 1656, 1659, 68, 1660, 68, 68, 1653, 1661, + 68, 68, 1663, 1664, 1657, 1654, 68, 68, 68, 1662, - 68, 68, 68, 1662, 1665, 1661, 68, 1664, 68, 68, - 1666, 68, 1669, 1670, 68, 68, 68, 1730, 1671, 68, - 1672, 1677, 1674, 68, 1675, 68, 1680, 1673, 1678, 68, - 68, 68, 68, 1676, 1679, 1681, 1682, 1683, 1684, 1685, - 1686, 68, 68, 68, 68, 1690, 68, 68, 1688, 1687, - 68, 68, 68, 68, 68, 68, 1693, 68, 1697, 68, - 1692, 68, 1689, 68, 1698, 1691, 1702, 1696, 68, 1700, - 1703, 1694, 1695, 68, 1699, 68, 1701, 1705, 68, 68, - 68, 68, 68, 68, 68, 68, 1706, 1707, 1709, 1711, - 1712, 68, 1704, 68, 68, 1715, 68, 68, 68, 1718, + 68, 68, 1666, 68, 68, 68, 68, 68, 1670, 68, + 1665, 68, 68, 68, 68, 1678, 68, 1669, 68, 1667, + 1672, 1668, 1679, 1680, 1674, 1671, 68, 1675, 1673, 1677, + 68, 1681, 68, 1684, 68, 68, 1688, 1676, 68, 68, + 1689, 68, 68, 68, 68, 68, 68, 1683, 1685, 68, + 1686, 68, 68, 68, 68, 1682, 1690, 1691, 1687, 1698, + 1693, 68, 1692, 68, 1695, 1696, 1699, 68, 1694, 68, + 1701, 68, 1697, 68, 68, 1706, 1702, 68, 1703, 1704, + 68, 68, 1700, 1707, 68, 68, 1705, 1711, 1708, 68, + 68, 68, 68, 68, 68, 68, 1709, 68, 1714, 68, - 1708, 1710, 1719, 68, 68, 1721, 68, 1722, 68, 68, - 1713, 1720, 1714, 68, 1724, 1716, 1717, 68, 68, 68, - 1723, 1730, 1725, 1728, 68, 1729, 68, 1730, 1730, 1730, - 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1726, 1727, 40, - 40, 40, 40, 40, 40, 40, 45, 45, 45, 45, - 45, 45, 45, 50, 50, 50, 50, 50, 50, 50, - 56, 56, 56, 56, 56, 56, 56, 61, 61, 61, - 61, 61, 61, 61, 71, 71, 1730, 71, 71, 71, - 71, 124, 124, 1730, 1730, 1730, 124, 124, 126, 126, - 1730, 1730, 126, 1730, 126, 128, 1730, 1730, 1730, 1730, + 68, 1718, 1719, 1713, 1710, 68, 1721, 68, 1712, 1751, + 1715, 68, 1717, 1716, 1720, 68, 1722, 68, 1724, 1726, + 68, 68, 1723, 68, 68, 68, 1725, 68, 1727, 68, + 1728, 68, 1730, 68, 1732, 68, 1733, 68, 1736, 68, + 68, 68, 1739, 1729, 1731, 1740, 68, 1751, 68, 1742, + 68, 68, 1734, 68, 1735, 1741, 1743, 68, 1737, 1738, + 1744, 68, 68, 68, 1749, 68, 1745, 1746, 1750, 68, + 1747, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, + 1751, 1751, 1748, 40, 40, 40, 40, 40, 40, 40, + 45, 45, 45, 45, 45, 45, 45, 50, 50, 50, - 1730, 128, 131, 131, 1730, 1730, 1730, 131, 131, 133, - 1730, 1730, 1730, 1730, 1730, 133, 135, 135, 1730, 135, - 135, 135, 135, 72, 72, 1730, 72, 72, 72, 72, - 13, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, - 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, - 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, - 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730 + 50, 50, 50, 50, 56, 56, 56, 56, 56, 56, + 56, 61, 61, 61, 61, 61, 61, 61, 71, 71, + 1751, 71, 71, 71, 71, 125, 125, 1751, 1751, 1751, + 125, 125, 127, 127, 1751, 1751, 127, 1751, 127, 129, + 1751, 1751, 1751, 1751, 1751, 129, 132, 132, 1751, 1751, + 1751, 132, 132, 134, 1751, 1751, 1751, 1751, 1751, 134, + 136, 136, 1751, 136, 136, 136, 136, 72, 72, 1751, + 72, 72, 72, 72, 13, 1751, 1751, 1751, 1751, 1751, + 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, + 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, + + 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, + 1751, 1751, 1751, 1751 } ; -static yyconst flex_int16_t yy_chk[3471] = +static yyconst flex_int16_t yy_chk[3515] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -1391,381 +1404,387 @@ static yyconst flex_int16_t yy_chk[3471] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 4, 4, 4, 49, 5, 5, 49, 3, 5, 15, 4, 6, 6, 15, 5, 6, 9, 9, - 9, 153, 33, 6, 7, 7, 7, 7, 9, 7, + 9, 154, 33, 6, 7, 7, 7, 7, 9, 7, 10, 10, 10, 44, 44, 7, 8, 8, 8, 8, - 10, 8, 21, 33, 153, 21, 21, 8, 11, 11, - 11, 11, 11, 11, 1736, 20, 29, 20, 20, 11, + 10, 8, 21, 33, 154, 21, 21, 8, 11, 11, + 11, 11, 11, 11, 1757, 20, 29, 20, 20, 11, 20, 29, 24, 21, 25, 20, 24, 28, 11, 12, 12, 12, 12, 12, 12, 74, 22, 22, 74, 25, 12, 69, 28, 30, 22, 69, 24, 26, 26, 12, - 19, 22, 19, 19, 66, 19, 26, 644, 30, 27, + 19, 22, 19, 19, 66, 19, 26, 82, 30, 27, 19, 19, 23, 27, 60, 60, 27, 23, 66, 31, - 31, 23, 76, 27, 23, 27, 23, 23, 31, 75, - 32, 32, 34, 75, 31, 32, 37, 37, 31, 37, - 36, 34, 76, 35, 35, 36, 133, 34, 35, 38, - 34, 32, 79, 78, 37, 36, 131, 34, 35, 36, - 36, 35, 90, 38, 39, 39, 79, 90, 38, 39, + 31, 23, 38, 27, 23, 27, 23, 23, 31, 82, + 32, 32, 35, 35, 31, 32, 38, 35, 31, 36, + 119, 38, 37, 37, 36, 37, 78, 35, 39, 39, + 35, 32, 34, 39, 36, 100, 119, 34, 36, 36, + 37, 34, 100, 55, 78, 55, 55, 34, 55, 63, - 55, 78, 55, 55, 63, 55, 63, 63, 65, 63, - 65, 65, 83, 65, 68, 63, 68, 68, 77, 68, - 80, 77, 81, 82, 68, 71, 86, 71, 71, 85, - 71, 83, 80, 84, 77, 71, 71, 87, 84, 88, - 81, 94, 91, 85, 89, 82, 86, 92, 89, 93, - 92, 84, 97, 92, 93, 87, 91, 88, 95, 96, - 94, 98, 96, 95, 99, 100, 96, 92, 99, 101, - 102, 103, 100, 104, 105, 98, 97, 102, 105, 106, - 107, 108, 101, 95, 103, 107, 109, 110, 111, 107, - 112, 114, 113, 104, 117, 115, 114, 106, 116, 116, + 34, 63, 63, 65, 63, 65, 65, 34, 65, 68, + 63, 68, 68, 75, 68, 76, 80, 75, 77, 68, + 71, 77, 71, 71, 79, 71, 81, 83, 80, 85, + 71, 71, 84, 86, 77, 76, 87, 84, 79, 88, + 94, 89, 90, 85, 81, 89, 83, 90, 91, 92, + 84, 93, 92, 86, 87, 92, 93, 88, 95, 94, + 97, 96, 91, 95, 96, 98, 99, 101, 96, 92, + 99, 102, 103, 104, 105, 109, 107, 106, 102, 98, + 101, 106, 108, 95, 97, 103, 110, 108, 111, 112, + 113, 108, 105, 104, 107, 109, 114, 115, 116, 117, - 110, 108, 118, 111, 119, 122, 109, 115, 123, 112, - 113, 120, 117, 120, 188, 121, 188, 122, 118, 116, - 121, 125, 125, 140, 127, 119, 123, 127, 129, 137, - 129, 129, 137, 129, 120, 132, 132, 134, 140, 134, - 134, 135, 134, 135, 135, 138, 135, 141, 139, 142, - 138, 143, 135, 139, 144, 141, 145, 151, 146, 147, - 130, 145, 145, 146, 147, 148, 143, 148, 142, 150, - 150, 154, 152, 155, 144, 154, 151, 152, 155, 156, - 157, 160, 159, 162, 158, 163, 160, 148, 149, 164, - 161, 161, 149, 156, 164, 157, 158, 149, 169, 158, + 117, 111, 115, 118, 112, 120, 110, 122, 142, 113, + 116, 121, 122, 121, 114, 123, 142, 124, 126, 126, + 117, 118, 128, 133, 133, 128, 120, 123, 130, 138, + 130, 130, 138, 130, 121, 124, 135, 143, 135, 135, + 136, 135, 136, 136, 139, 136, 141, 140, 144, 139, + 145, 136, 140, 146, 152, 147, 143, 148, 146, 146, + 147, 141, 148, 144, 149, 157, 149, 151, 151, 153, + 145, 155, 156, 152, 153, 155, 160, 156, 158, 157, + 159, 164, 163, 161, 162, 162, 149, 150, 161, 166, + 166, 150, 159, 158, 160, 159, 150, 164, 165, 170, - 159, 163, 149, 162, 165, 165, 166, 167, 149, 149, - 161, 166, 167, 168, 176, 170, 171, 166, 172, 169, - 170, 171, 168, 172, 173, 174, 178, 175, 181, 173, - 177, 179, 174, 175, 176, 180, 177, 182, 184, 179, - 180, 183, 186, 181, 185, 187, 183, 186, 178, 189, - 190, 191, 192, 193, 193, 190, 189, 182, 198, 128, - 184, 194, 185, 185, 192, 187, 194, 195, 197, 196, - 191, 196, 195, 199, 200, 203, 204, 198, 201, 200, - 197, 199, 202, 201, 194, 205, 206, 202, 196, 207, - 203, 212, 207, 205, 204, 208, 208, 209, 210, 210, + 167, 150, 163, 165, 162, 167, 169, 150, 150, 168, + 176, 167, 171, 172, 168, 169, 173, 171, 172, 174, + 170, 173, 175, 176, 174, 177, 178, 179, 180, 175, + 181, 177, 182, 179, 183, 184, 185, 182, 181, 186, + 187, 185, 188, 189, 194, 191, 178, 188, 193, 183, + 180, 190, 191, 190, 651, 184, 194, 192, 187, 187, + 200, 186, 192, 189, 195, 195, 196, 193, 197, 199, + 201, 196, 198, 197, 198, 202, 206, 203, 201, 200, + 202, 199, 203, 204, 205, 207, 208, 209, 204, 196, + 209, 198, 214, 207, 206, 210, 210, 211, 215, 205, - 209, 211, 211, 213, 216, 214, 215, 212, 214, 217, - 215, 206, 218, 216, 217, 219, 219, 220, 213, 221, - 222, 223, 220, 224, 221, 225, 218, 226, 226, 227, - 228, 229, 231, 230, 228, 234, 233, 231, 225, 223, - 222, 235, 236, 232, 224, 230, 232, 227, 233, 229, - 235, 237, 234, 238, 239, 234, 239, 239, 240, 240, - 242, 243, 244, 236, 237, 238, 241, 245, 245, 241, - 246, 244, 247, 247, 248, 246, 243, 242, 249, 250, - 242, 251, 252, 253, 255, 256, 251, 258, 253, 248, - 249, 254, 258, 260, 254, 261, 254, 262, 255, 250, + 211, 212, 212, 213, 213, 220, 216, 218, 214, 216, + 217, 208, 219, 215, 217, 224, 218, 219, 222, 220, + 221, 221, 223, 222, 225, 226, 227, 223, 228, 228, + 229, 231, 230, 232, 234, 224, 230, 234, 233, 227, + 235, 236, 225, 233, 237, 232, 226, 238, 229, 231, + 239, 134, 235, 237, 240, 242, 242, 241, 236, 241, + 241, 236, 243, 239, 244, 243, 240, 245, 238, 246, + 247, 248, 248, 250, 250, 249, 251, 252, 246, 247, + 249, 244, 245, 253, 244, 254, 255, 256, 258, 252, + 254, 251, 256, 257, 259, 260, 257, 263, 257, 264, - 257, 256, 252, 259, 256, 263, 256, 264, 259, 257, - 264, 265, 262, 267, 260, 261, 269, 270, 271, 263, - 272, 126, 268, 276, 274, 265, 264, 266, 267, 266, - 266, 268, 275, 271, 279, 277, 270, 269, 276, 266, - 272, 266, 266, 266, 273, 280, 266, 274, 278, 273, - 277, 281, 275, 278, 279, 282, 281, 283, 285, 280, - 284, 284, 283, 284, 286, 287, 290, 289, 288, 289, - 290, 282, 291, 292, 293, 294, 301, 301, 285, 297, - 286, 287, 288, 293, 294, 296, 295, 292, 297, 296, - 291, 295, 298, 299, 300, 302, 293, 298, 300, 299, + 261, 265, 258, 253, 260, 261, 255, 262, 266, 268, + 259, 267, 262, 259, 267, 259, 265, 270, 263, 264, + 271, 272, 266, 268, 274, 273, 277, 132, 275, 271, + 267, 269, 270, 269, 269, 276, 278, 279, 280, 274, + 276, 282, 272, 269, 273, 269, 269, 269, 275, 277, + 269, 283, 279, 280, 281, 284, 278, 285, 286, 281, + 284, 282, 288, 286, 289, 283, 287, 287, 290, 287, + 292, 291, 292, 285, 293, 294, 295, 296, 293, 297, + 289, 419, 288, 419, 290, 291, 296, 298, 297, 300, + 295, 299, 298, 294, 302, 299, 301, 309, 300, 296, - 302, 303, 304, 304, 305, 306, 307, 308, 309, 305, - 310, 310, 309, 311, 303, 307, 312, 316, 311, 308, - 313, 313, 315, 315, 317, 318, 306, 319, 321, 322, - 323, 324, 317, 328, 318, 326, 325, 312, 316, 319, - 324, 325, 327, 326, 323, 329, 332, 327, 321, 322, - 330, 328, 331, 333, 334, 335, 331, 337, 333, 339, - 340, 332, 338, 340, 339, 341, 349, 329, 343, 339, - 334, 330, 342, 342, 335, 336, 336, 337, 338, 344, - 344, 336, 345, 336, 346, 341, 348, 347, 349, 350, - 351, 336, 352, 343, 350, 353, 346, 345, 355, 351, + 302, 301, 303, 304, 304, 305, 303, 306, 307, 307, + 305, 308, 310, 311, 315, 312, 308, 319, 309, 312, + 306, 310, 313, 313, 314, 311, 316, 316, 320, 314, + 318, 318, 321, 322, 323, 315, 320, 325, 319, 326, + 327, 321, 328, 329, 330, 331, 323, 332, 329, 333, + 331, 328, 330, 322, 327, 334, 335, 325, 336, 326, + 335, 337, 338, 339, 342, 332, 337, 341, 345, 343, + 347, 333, 344, 336, 343, 344, 334, 131, 338, 343, + 342, 349, 339, 340, 340, 346, 346, 341, 345, 340, + 350, 340, 348, 348, 352, 347, 349, 351, 353, 340, - 354, 336, 347, 355, 354, 348, 356, 357, 358, 359, - 353, 352, 360, 360, 361, 362, 363, 359, 356, 363, - 364, 358, 366, 368, 124, 357, 361, 362, 365, 367, - 375, 365, 371, 367, 367, 364, 368, 371, 366, 369, - 369, 366, 370, 370, 372, 372, 373, 373, 374, 376, - 378, 375, 377, 374, 376, 378, 377, 379, 380, 381, - 382, 379, 383, 380, 384, 382, 387, 383, 385, 386, - 386, 385, 388, 67, 390, 399, 385, 389, 384, 381, - 385, 399, 389, 390, 387, 391, 388, 392, 391, 393, - 394, 392, 395, 396, 393, 397, 398, 395, 403, 400, + 354, 355, 350, 356, 357, 354, 360, 358, 361, 340, + 355, 358, 351, 352, 362, 363, 359, 365, 360, 357, + 353, 359, 356, 363, 364, 364, 361, 362, 366, 365, + 367, 368, 369, 367, 370, 369, 372, 371, 373, 373, + 366, 371, 371, 374, 374, 379, 368, 375, 401, 372, + 370, 385, 375, 370, 376, 376, 377, 377, 378, 380, + 401, 381, 382, 378, 380, 381, 379, 382, 383, 384, + 386, 385, 383, 387, 384, 386, 388, 389, 387, 391, + 389, 390, 390, 393, 392, 389, 394, 398, 393, 389, + 388, 395, 396, 400, 395, 394, 396, 391, 392, 397, - 404, 398, 400, 394, 455, 401, 402, 397, 401, 396, - 405, 402, 455, 392, 404, 405, 403, 406, 407, 409, - 406, 408, 410, 407, 411, 408, 408, 410, 412, 415, - 413, 412, 409, 411, 413, 413, 414, 416, 414, 416, - 417, 418, 419, 420, 422, 421, 412, 423, 415, 421, - 424, 425, 426, 422, 427, 428, 428, 426, 417, 418, - 429, 419, 423, 420, 429, 430, 425, 431, 424, 432, - 433, 434, 431, 427, 435, 436, 430, 438, 439, 437, - 436, 435, 438, 439, 434, 432, 437, 440, 441, 433, - 442, 444, 443, 447, 445, 441, 444, 445, 446, 442, + 398, 399, 402, 406, 397, 403, 399, 402, 406, 400, + 404, 403, 405, 404, 407, 405, 408, 409, 396, 410, + 411, 412, 409, 411, 410, 414, 412, 420, 416, 413, + 408, 415, 407, 413, 413, 422, 415, 416, 414, 417, + 418, 421, 417, 421, 418, 418, 420, 423, 424, 425, + 426, 427, 432, 422, 426, 428, 429, 417, 430, 431, + 427, 433, 433, 437, 431, 423, 435, 424, 434, 425, + 428, 432, 434, 430, 429, 436, 438, 435, 439, 437, + 436, 440, 441, 442, 443, 445, 446, 441, 440, 443, + 442, 439, 444, 446, 448, 438, 447, 444, 450, 449, - 448, 448, 446, 449, 453, 440, 443, 452, 451, 448, - 454, 452, 449, 451, 447, 456, 453, 457, 463, 460, - 466, 467, 468, 472, 473, 469, 468, 467, 454, 466, - 469, 471, 478, 456, 460, 463, 471, 474, 475, 475, - 474, 472, 457, 458, 476, 477, 477, 478, 458, 473, - 482, 476, 458, 479, 479, 458, 480, 483, 481, 480, - 484, 487, 458, 481, 485, 458, 470, 470, 470, 482, - 470, 488, 485, 470, 486, 486, 487, 483, 470, 484, - 497, 489, 490, 490, 470, 470, 489, 491, 492, 488, - 494, 493, 491, 492, 493, 495, 494, 496, 497, 498, + 452, 450, 451, 445, 449, 447, 451, 454, 448, 453, + 453, 457, 456, 458, 459, 457, 454, 456, 453, 460, + 461, 452, 462, 468, 465, 458, 471, 460, 472, 473, + 478, 474, 459, 473, 472, 471, 474, 476, 461, 465, + 468, 477, 476, 479, 480, 480, 479, 462, 463, 481, + 482, 482, 129, 463, 483, 478, 481, 463, 487, 477, + 463, 484, 484, 485, 488, 518, 485, 463, 489, 483, + 463, 475, 475, 475, 486, 475, 492, 487, 475, 486, + 490, 491, 491, 475, 488, 493, 518, 489, 490, 475, + 475, 492, 494, 495, 495, 496, 497, 494, 499, 498, - 499, 500, 500, 495, 498, 496, 501, 499, 502, 503, - 505, 507, 506, 502, 501, 506, 508, 508, 509, 505, - 510, 512, 513, 510, 514, 507, 515, 513, 503, 516, - 517, 510, 518, 509, 519, 520, 521, 524, 519, 522, - 523, 518, 512, 524, 525, 514, 515, 526, 522, 530, - 517, 516, 527, 520, 523, 521, 529, 527, 528, 531, - 529, 526, 532, 528, 525, 533, 537, 532, 530, 534, - 534, 531, 535, 536, 538, 539, 536, 535, 540, 543, - 539, 541, 541, 545, 537, 546, 533, 538, 542, 542, - 547, 544, 548, 550, 543, 544, 551, 550, 540, 553, + 496, 497, 498, 493, 499, 500, 501, 502, 505, 504, + 503, 506, 506, 500, 501, 503, 504, 508, 507, 509, + 511, 512, 508, 513, 512, 502, 507, 505, 515, 511, + 514, 514, 520, 516, 519, 521, 516, 513, 509, 519, + 522, 523, 524, 515, 516, 525, 526, 527, 528, 525, + 530, 524, 531, 520, 529, 521, 530, 528, 533, 532, + 534, 523, 522, 533, 526, 534, 527, 535, 529, 536, + 537, 535, 531, 532, 538, 539, 540, 540, 541, 538, + 543, 542, 537, 541, 542, 545, 544, 546, 536, 549, + 545, 547, 547, 548, 548, 551, 539, 550, 543, 544, - 552, 554, 545, 555, 547, 556, 554, 571, 571, 546, - 61, 551, 548, 549, 553, 558, 549, 555, 549, 556, - 562, 559, 549, 557, 549, 552, 559, 557, 560, 549, - 558, 561, 563, 560, 549, 565, 559, 564, 567, 568, - 565, 562, 569, 564, 568, 561, 563, 566, 566, 570, - 567, 573, 572, 566, 574, 566, 569, 572, 575, 573, - 577, 570, 576, 576, 577, 579, 580, 581, 574, 580, - 579, 582, 584, 566, 583, 587, 585, 575, 586, 583, - 588, 589, 590, 594, 582, 588, 581, 586, 591, 595, - 592, 584, 585, 596, 587, 592, 590, 591, 597, 598, + 552, 550, 553, 554, 549, 556, 557, 546, 558, 556, + 560, 559, 127, 561, 551, 560, 553, 562, 563, 568, + 564, 557, 563, 554, 552, 555, 559, 561, 555, 591, + 555, 562, 565, 558, 555, 564, 555, 565, 566, 567, + 568, 555, 569, 566, 570, 591, 555, 565, 573, 571, + 570, 572, 572, 567, 571, 575, 569, 572, 574, 572, + 573, 576, 578, 574, 577, 577, 579, 578, 580, 575, + 581, 582, 582, 576, 579, 583, 585, 572, 587, 583, + 586, 585, 580, 586, 590, 588, 589, 592, 593, 581, + 594, 589, 595, 597, 596, 594, 592, 587, 588, 598, - 599, 589, 594, 597, 598, 599, 600, 595, 596, 601, - 601, 602, 607, 604, 608, 600, 602, 604, 604, 605, - 605, 606, 609, 605, 606, 610, 611, 614, 610, 608, - 612, 613, 607, 614, 615, 612, 613, 616, 617, 617, - 618, 619, 609, 616, 621, 620, 622, 611, 620, 618, - 615, 623, 625, 624, 627, 626, 629, 625, 628, 619, - 626, 628, 621, 630, 631, 622, 624, 629, 632, 631, - 633, 623, 627, 632, 635, 630, 634, 634, 636, 637, - 638, 639, 641, 642, 638, 633, 640, 647, 645, 646, - 674, 637, 636, 635, 674, 640, 652, 656, 648, 639, + 600, 602, 597, 590, 598, 601, 603, 593, 596, 604, + 605, 603, 595, 606, 604, 605, 602, 607, 607, 600, + 608, 609, 606, 601, 611, 608, 612, 612, 611, 611, + 612, 614, 613, 615, 609, 613, 616, 617, 618, 619, + 617, 620, 622, 621, 619, 626, 620, 623, 615, 621, + 628, 614, 625, 623, 624, 624, 616, 627, 622, 618, + 627, 625, 629, 626, 630, 631, 632, 633, 628, 634, + 635, 632, 633, 635, 636, 638, 637, 639, 631, 640, + 638, 629, 639, 642, 630, 636, 643, 634, 637, 641, + 641, 644, 645, 646, 640, 647, 645, 648, 649, 652, - 649, 641, 645, 648, 646, 649, 650, 647, 642, 651, - 652, 650, 653, 654, 651, 655, 656, 657, 654, 658, - 659, 659, 660, 661, 662, 666, 653, 663, 663, 661, - 655, 664, 657, 668, 665, 671, 664, 669, 658, 666, - 660, 665, 667, 670, 662, 667, 669, 672, 670, 673, - 675, 668, 672, 678, 671, 676, 677, 679, 680, 675, - 678, 681, 682, 684, 685, 686, 683, 690, 673, 679, - 676, 677, 683, 689, 686, 690, 688, 680, 684, 691, - 682, 688, 681, 692, 685, 693, 694, 689, 692, 693, - 693, 695, 695, 696, 697, 698, 699, 699, 705, 691, + 643, 654, 642, 644, 647, 653, 125, 655, 663, 656, + 657, 646, 655, 652, 656, 657, 648, 658, 659, 660, + 653, 654, 658, 649, 661, 662, 664, 663, 665, 661, + 666, 666, 659, 660, 667, 669, 668, 670, 670, 671, + 662, 664, 668, 672, 671, 673, 674, 665, 675, 674, + 672, 676, 667, 677, 678, 669, 679, 680, 677, 673, + 676, 679, 682, 681, 683, 684, 675, 681, 685, 686, + 687, 682, 688, 678, 689, 685, 680, 690, 692, 683, + 684, 686, 691, 690, 698, 693, 695, 696, 697, 687, + 699, 695, 689, 688, 693, 699, 697, 691, 692, 701, - 698, 706, 700, 697, 701, 694, 696, 700, 703, 701, - 702, 702, 705, 704, 712, 707, 708, 703, 704, 706, - 707, 708, 709, 711, 710, 712, 714, 709, 710, 715, - 714, 716, 711, 718, 719, 723, 721, 711, 717, 711, - 720, 711, 717, 717, 715, 722, 725, 718, 720, 716, - 721, 724, 724, 719, 726, 726, 728, 729, 730, 728, - 723, 725, 729, 722, 731, 731, 732, 733, 733, 734, - 735, 735, 736, 737, 734, 738, 739, 730, 737, 740, - 740, 739, 741, 738, 742, 56, 732, 743, 745, 750, - 742, 746, 736, 745, 743, 749, 746, 747, 748, 751, + 703, 696, 700, 704, 698, 705, 700, 700, 702, 702, + 705, 707, 704, 703, 706, 706, 707, 708, 701, 709, + 709, 710, 708, 711, 712, 713, 714, 715, 711, 716, + 710, 714, 715, 717, 716, 718, 720, 717, 712, 719, + 719, 722, 723, 713, 718, 722, 724, 720, 726, 718, + 725, 718, 727, 718, 725, 725, 729, 723, 728, 730, + 731, 733, 726, 738, 724, 67, 728, 732, 732, 737, + 729, 727, 734, 734, 737, 736, 733, 730, 736, 739, + 739, 740, 738, 741, 741, 731, 742, 743, 743, 744, + 745, 742, 746, 747, 749, 745, 748, 748, 747, 750, - 741, 753, 747, 748, 749, 752, 752, 754, 750, 755, - 751, 756, 757, 761, 755, 758, 759, 760, 760, 762, - 763, 753, 765, 764, 766, 756, 51, 758, 764, 766, - 754, 756, 757, 761, 759, 768, 777, 769, 763, 768, - 768, 770, 772, 775, 762, 765, 769, 773, 771, 770, - 771, 774, 773, 776, 775, 774, 772, 778, 779, 780, - 781, 782, 777, 779, 783, 782, 784, 785, 786, 787, - 788, 789, 776, 791, 792, 778, 789, 780, 791, 790, - 781, 785, 783, 786, 787, 784, 790, 793, 794, 788, - 796, 795, 792, 797, 798, 799, 793, 795, 797, 798, + 746, 740, 753, 751, 758, 750, 754, 753, 755, 744, + 751, 754, 749, 755, 756, 757, 759, 760, 760, 756, + 761, 762, 764, 758, 757, 763, 765, 759, 769, 766, + 763, 767, 768, 768, 770, 771, 764, 773, 772, 61, + 761, 766, 764, 772, 762, 774, 765, 776, 769, 767, + 774, 776, 776, 771, 777, 779, 778, 779, 780, 770, + 773, 781, 783, 777, 778, 782, 781, 784, 785, 782, + 786, 787, 780, 783, 788, 789, 787, 790, 791, 792, + 798, 790, 796, 793, 794, 795, 784, 798, 786, 804, + 802, 800, 788, 56, 785, 789, 791, 793, 792, 794, - 799, 800, 800, 794, 802, 802, 803, 804, 805, 806, - 807, 796, 804, 809, 807, 807, 808, 808, 810, 811, - 812, 813, 805, 815, 803, 814, 819, 813, 806, 816, - 814, 817, 809, 818, 820, 846, 821, 810, 846, 812, - 819, 823, 815, 822, 822, 811, 823, 825, 816, 824, - 817, 821, 818, 824, 826, 820, 827, 829, 827, 833, - 825, 831, 827, 826, 830, 830, 831, 832, 834, 836, - 849, 832, 850, 834, 858, 827, 838, 829, 858, 833, - 840, 838, 839, 839, 848, 840, 850, 836, 842, 842, - 844, 844, 847, 847, 852, 849, 851, 853, 853, 848, + 795, 796, 797, 799, 801, 802, 803, 797, 799, 800, + 804, 805, 803, 801, 806, 807, 805, 808, 808, 806, + 807, 810, 810, 811, 812, 813, 814, 815, 817, 812, + 818, 815, 815, 816, 816, 819, 820, 821, 823, 813, + 824, 811, 827, 821, 825, 814, 822, 817, 826, 818, + 828, 822, 838, 829, 831, 820, 827, 823, 833, 824, + 834, 819, 833, 825, 830, 830, 831, 826, 829, 832, + 835, 828, 838, 834, 832, 836, 842, 836, 51, 835, + 840, 836, 839, 839, 841, 840, 843, 845, 841, 857, + 847, 843, 848, 848, 836, 847, 842, 849, 851, 851, - 854, 851, 855, 855, 856, 857, 859, 860, 863, 852, - 862, 866, 860, 864, 864, 867, 857, 869, 865, 871, - 854, 868, 863, 865, 871, 859, 856, 870, 862, 870, - 868, 866, 873, 872, 874, 867, 875, 869, 872, 874, - 876, 876, 877, 879, 880, 880, 881, 888, 877, 882, - 875, 50, 873, 883, 886, 884, 883, 885, 881, 883, - 884, 887, 885, 886, 892, 889, 887, 879, 889, 882, - 890, 883, 888, 891, 891, 890, 893, 894, 895, 896, - 897, 898, 892, 895, 896, 900, 898, 899, 899, 901, - 900, 902, 903, 905, 904, 893, 906, 894, 908, 907, + 853, 853, 849, 855, 857, 845, 855, 856, 856, 858, + 859, 860, 861, 862, 862, 863, 860, 864, 864, 865, + 866, 867, 871, 868, 859, 867, 875, 861, 869, 872, + 876, 866, 878, 869, 858, 863, 873, 873, 877, 874, + 871, 865, 868, 872, 874, 882, 875, 877, 880, 879, + 876, 879, 878, 880, 881, 883, 884, 885, 885, 881, + 883, 886, 888, 889, 889, 882, 890, 886, 891, 892, + 884, 893, 892, 895, 894, 892, 893, 897, 890, 894, + 896, 898, 895, 901, 898, 896, 888, 892, 891, 899, + 900, 900, 902, 903, 899, 904, 906, 910, 905, 907, - 909, 910, 913, 897, 907, 905, 914, 901, 904, 906, - 912, 902, 903, 914, 915, 912, 916, 913, 908, 922, - 909, 924, 910, 915, 919, 919, 915, 920, 921, 923, - 920, 929, 916, 921, 925, 922, 926, 927, 923, 930, - 924, 931, 927, 925, 932, 926, 925, 928, 928, 933, - 934, 929, 930, 935, 935, 936, 937, 939, 932, 931, - 940, 937, 938, 938, 943, 942, 939, 944, 934, 939, - 942, 936, 944, 945, 933, 946, 947, 938, 940, 945, - 948, 947, 943, 949, 953, 954, 949, 955, 952, 956, - 958, 957, 949, 948, 956, 946, 952, 953, 960, 966, + 904, 901, 897, 905, 907, 908, 908, 909, 911, 912, + 913, 902, 909, 903, 914, 910, 916, 915, 917, 906, + 918, 916, 919, 925, 913, 50, 914, 921, 911, 912, + 915, 922, 921, 924, 923, 928, 928, 933, 917, 925, + 918, 923, 924, 919, 929, 924, 922, 929, 930, 931, + 932, 934, 935, 930, 937, 937, 933, 936, 938, 932, + 934, 935, 936, 934, 939, 931, 940, 941, 942, 943, + 944, 945, 945, 946, 947, 948, 948, 939, 938, 947, + 942, 941, 950, 949, 940, 953, 952, 956, 944, 946, + 948, 952, 949, 954, 943, 949, 955, 958, 954, 957, - 961, 969, 967, 954, 961, 962, 955, 957, 958, 963, - 962, 964, 965, 971, 963, 969, 964, 967, 960, 968, - 968, 965, 966, 970, 972, 971, 973, 974, 975, 976, - 970, 977, 974, 978, 978, 979, 972, 977, 979, 982, - 975, 980, 980, 983, 983, 973, 984, 976, 982, 985, - 986, 987, 988, 990, 985, 989, 991, 992, 984, 986, - 989, 994, 990, 987, 993, 993, 994, 988, 995, 996, - 997, 999, 992, 998, 998, 990, 991, 1000, 1000, 1001, - 1001, 1002, 1003, 1004, 1007, 1002, 1004, 1003, 996, 995, - 997, 999, 1006, 1008, 1009, 1010, 1010, 1006, 1008, 1011, + 950, 962, 955, 953, 957, 959, 963, 956, 959, 962, + 958, 964, 965, 966, 959, 968, 967, 970, 966, 963, + 971, 972, 973, 974, 971, 975, 972, 973, 974, 964, + 976, 965, 967, 968, 975, 977, 980, 970, 978, 978, + 979, 983, 984, 980, 981, 982, 985, 984, 986, 987, + 977, 988, 988, 976, 979, 987, 981, 982, 985, 989, + 983, 992, 989, 990, 990, 994, 986, 993, 993, 995, + 992, 996, 997, 998, 995, 1001, 999, 994, 1000, 1002, + 996, 999, 1003, 1003, 997, 1004, 1005, 1000, 998, 1006, + 1004, 1007, 1008, 1008, 1002, 1001, 1009, 1010, 1010, 1012, - 1011, 1012, 1007, 1013, 1014, 1015, 1012, 1016, 1018, 1017, - 1019, 1019, 1020, 1021, 1021, 1013, 1013, 1013, 1026, 1009, - 1022, 1024, 1013, 1017, 1014, 1015, 1029, 1016, 1027, 1018, - 1024, 1025, 1025, 1026, 1028, 1027, 1030, 1030, 1020, 1031, - 1022, 1032, 1034, 1028, 1035, 1040, 1036, 1034, 1037, 1035, - 1038, 1038, 1029, 1039, 1040, 1037, 1041, 1032, 1039, 1042, - 1043, 1044, 1045, 1043, 1048, 1031, 1036, 1046, 1046, 1047, - 1049, 1042, 1050, 1051, 1052, 1052, 1041, 1055, 1050, 1044, - 1053, 1056, 1051, 1048, 1047, 1049, 1054, 1054, 1045, 1057, - 1061, 1053, 1058, 1058, 1057, 1056, 1053, 1059, 1055, 1060, + 1000, 1011, 1011, 1012, 1013, 1017, 1019, 1005, 1006, 1013, + 1014, 1007, 1016, 1014, 1018, 1024, 1009, 1016, 1027, 1018, + 1020, 1020, 1022, 1017, 1021, 1021, 1023, 1022, 1025, 1026, + 1028, 1019, 1027, 1029, 1029, 1024, 1030, 1032, 1023, 1023, + 1023, 1031, 1031, 1034, 1036, 1023, 1035, 1035, 1025, 1026, + 1039, 1028, 1034, 1037, 1038, 1040, 1040, 1032, 1041, 1036, + 1037, 1042, 1030, 1038, 1044, 1045, 1046, 1047, 1048, 1044, + 1045, 1049, 1049, 1048, 1047, 1050, 1039, 1042, 1051, 1052, + 1050, 1053, 1054, 1055, 1041, 1054, 1046, 1051, 1056, 1057, + 1057, 1058, 1059, 1053, 1060, 1062, 1061, 1063, 1063, 1052, - 1062, 1059, 1059, 1063, 1060, 1064, 1065, 1066, 1063, 1067, - 1065, 1069, 1062, 1068, 1071, 1070, 1061, 1064, 1068, 1066, - 1070, 1073, 1074, 1074, 1073, 1077, 1071, 1075, 1075, 1076, - 1076, 1078, 1080, 1069, 1067, 1079, 1083, 1078, 1080, 1081, - 1079, 1083, 1085, 1087, 1089, 1077, 1088, 1088, 1081, 1090, - 1091, 1092, 1093, 1096, 1085, 1087, 1093, 1094, 1090, 1099, - 1095, 1106, 1094, 45, 1089, 1095, 1100, 1096, 1091, 1101, - 1092, 1098, 1098, 1103, 1103, 1100, 1106, 1099, 1101, 1107, - 1108, 1109, 1111, 1098, 1111, 1108, 1110, 1110, 1112, 1112, - 1114, 1115, 1117, 1107, 1116, 1116, 1118, 1114, 1109, 40, + 45, 1055, 1061, 1066, 1062, 1064, 1058, 1065, 1065, 1060, + 1068, 1059, 1067, 1072, 1056, 1068, 1064, 1069, 1069, 1073, + 1071, 1064, 1078, 1070, 1066, 1071, 1067, 1070, 1070, 1074, + 1075, 1073, 1076, 1077, 1074, 1079, 1076, 1080, 1081, 1072, + 1079, 1082, 1075, 1081, 1088, 1077, 1084, 1078, 40, 1084, + 1085, 1085, 1089, 1082, 1086, 1086, 1087, 1087, 1089, 1080, + 1090, 1091, 1092, 1094, 1088, 1090, 1096, 1091, 1094, 1098, + 1100, 1092, 1099, 1099, 1101, 1102, 1103, 1105, 1096, 1110, + 1104, 1098, 1105, 1101, 1104, 1107, 1106, 1111, 1109, 1109, + 1100, 1106, 1112, 1102, 1117, 1103, 1111, 1110, 1118, 1107, - 1119, 1117, 1120, 1121, 1122, 1123, 1124, 1127, 1126, 1127, - 1128, 1115, 1119, 1126, 1120, 1121, 1131, 1118, 1129, 1122, - 1132, 1132, 1133, 1138, 1134, 1123, 1124, 1129, 1128, 1134, - 1131, 1135, 1136, 1135, 1137, 1139, 1144, 1136, 1140, 1137, - 1141, 1138, 1143, 1140, 1146, 1141, 1145, 1145, 1133, 1147, - 1144, 1148, 1149, 1151, 1152, 1139, 1148, 1149, 1150, 1146, - 1150, 1143, 1153, 1152, 1153, 1151, 1152, 1154, 1155, 1147, - 1157, 1160, 1158, 1161, 1162, 1157, 1154, 1158, 1168, 1164, - 1155, 1166, 1167, 1169, 1160, 1164, 1171, 1166, 1170, 1170, - 1162, 1173, 1169, 1161, 1176, 1171, 1174, 1167, 1172, 1172, + 1109, 1112, 1114, 1114, 1120, 1119, 1121, 1121, 1126, 1117, + 1119, 1122, 1118, 1122, 1123, 1123, 1125, 1127, 1127, 1129, + 1128, 1120, 1130, 1125, 1131, 1132, 1133, 1134, 1126, 1128, + 1135, 1139, 1142, 1137, 1130, 1144, 1131, 1132, 1137, 1140, + 1129, 1133, 1138, 1146, 1138, 1146, 1142, 1134, 1140, 1139, + 1135, 1143, 1143, 1145, 1147, 1148, 1149, 1150, 1145, 1147, + 1148, 1144, 1151, 1152, 1153, 1155, 1156, 1151, 1152, 1157, + 1157, 1158, 1153, 1159, 1149, 14, 1160, 1150, 1161, 1163, + 1156, 1160, 1167, 1161, 1155, 1162, 1158, 1162, 1164, 1166, + 1165, 1163, 1165, 1159, 1167, 1172, 1169, 1164, 1166, 1170, - 1174, 1175, 1179, 1168, 1177, 1177, 1175, 1176, 1178, 1183, - 1173, 1182, 1182, 1184, 1184, 1186, 1178, 1187, 1183, 1185, - 1185, 1188, 1179, 1189, 1189, 1191, 1188, 1186, 1192, 1193, - 1194, 1195, 1197, 1192, 1200, 1187, 1195, 1196, 1198, 1198, - 1199, 1201, 1202, 1203, 1199, 1194, 1201, 1205, 1197, 1200, - 1191, 1206, 1193, 1207, 1209, 1196, 1208, 1210, 1212, 1212, - 1213, 1214, 1203, 1213, 1229, 1215, 1209, 1216, 1202, 1229, - 1205, 1304, 1207, 1304, 1214, 1206, 1220, 1208, 1210, 1215, - 1216, 1217, 1217, 1218, 1218, 1219, 1219, 1221, 1221, 1220, - 1222, 1222, 1223, 1223, 1224, 1225, 1225, 1226, 1226, 1227, + 1164, 1169, 1173, 1174, 1170, 1176, 1178, 1180, 1172, 1179, + 1185, 1176, 1178, 1187, 1181, 1182, 1182, 1183, 1187, 1174, + 1184, 1184, 1173, 1181, 1179, 1188, 1183, 1186, 1190, 1185, + 1191, 1186, 1180, 1189, 1189, 1195, 1190, 1198, 1188, 1194, + 1194, 1196, 1196, 1199, 1195, 1197, 1197, 1200, 1203, 1198, + 1191, 1204, 1200, 1201, 1201, 1205, 1204, 1206, 1207, 1208, + 1209, 1199, 1211, 1207, 1210, 1210, 1211, 1212, 1214, 1213, + 1215, 1218, 1206, 1203, 1213, 1217, 1209, 1208, 1205, 1220, + 1219, 1221, 1212, 1222, 1224, 1224, 13, 1225, 1226, 1215, + 1225, 1227, 1241, 1221, 1214, 1218, 1228, 1241, 1217, 1219, - 1230, 1230, 1231, 1232, 1232, 1233, 1234, 1235, 1236, 1236, - 1235, 1238, 1234, 1224, 1237, 1237, 1239, 1239, 1227, 1241, - 1242, 1231, 1243, 1233, 1236, 1245, 1243, 1244, 1244, 1247, - 1238, 1246, 1246, 1248, 1248, 1242, 1249, 1250, 1251, 1252, - 1253, 1254, 1241, 1251, 1245, 1249, 1255, 1257, 1256, 1250, - 1258, 1255, 1259, 1253, 1261, 1247, 1257, 1263, 1261, 1258, - 1260, 1265, 1254, 1256, 1252, 1260, 1259, 1266, 1266, 1267, - 1265, 1268, 1268, 1270, 1267, 1271, 1275, 1263, 1273, 1275, - 1268, 1276, 1277, 1281, 1271, 1285, 1276, 1283, 1270, 1284, - 1273, 1278, 1278, 1280, 1280, 1282, 1282, 1281, 1292, 1283, + 1220, 1226, 1229, 1229, 1222, 1227, 1230, 1230, 1232, 1228, + 1231, 1231, 1233, 1233, 1234, 1234, 1235, 1235, 1236, 1237, + 1237, 1232, 1238, 1238, 1239, 1242, 1242, 1243, 1244, 1244, + 1245, 1247, 1246, 1251, 1247, 1248, 1248, 1236, 1246, 1249, + 1249, 1250, 1254, 1239, 1252, 1252, 1243, 1255, 1245, 1256, + 1258, 1248, 1251, 1256, 1257, 1257, 1250, 1259, 1259, 1260, + 1261, 1261, 1255, 1262, 1263, 1254, 1264, 1265, 1266, 1258, + 1267, 1264, 1262, 1268, 1269, 1270, 1263, 1271, 1268, 1272, + 1276, 1266, 1273, 0, 1270, 1260, 1271, 1273, 1278, 1269, + 1274, 1267, 1265, 1272, 1274, 1279, 1279, 1278, 1280, 1283, - 1286, 1286, 1277, 1284, 1285, 1288, 1293, 1289, 1291, 1288, - 1289, 1290, 1290, 1291, 1295, 1294, 1296, 1297, 1292, 1294, - 1293, 1296, 1297, 1298, 1300, 1301, 1302, 1303, 1322, 1298, - 1301, 1302, 1307, 1307, 1295, 1303, 1311, 1311, 1314, 1321, - 1300, 1315, 1315, 1314, 1317, 1317, 1319, 1320, 1320, 1323, - 1322, 1319, 1325, 1325, 1323, 1321, 1327, 1328, 1329, 1331, - 1331, 1327, 1333, 1334, 1335, 1334, 1336, 1333, 1337, 1337, - 1340, 1336, 1341, 1329, 1342, 1328, 1338, 1338, 1335, 1339, - 1339, 1343, 1340, 1344, 1345, 1346, 1342, 1347, 1347, 1345, - 1341, 1348, 1349, 1343, 1350, 1344, 1351, 1352, 1353, 1354, + 1276, 1281, 1281, 1280, 1284, 1286, 1288, 1289, 1290, 1288, + 1281, 1294, 1289, 1284, 1283, 1291, 1291, 1286, 1293, 1293, + 1295, 1295, 1296, 1297, 1298, 1294, 1299, 1299, 1290, 1301, + 1303, 1303, 1302, 1301, 1296, 1302, 1304, 1297, 1305, 1306, + 1307, 1304, 1308, 1298, 1307, 1309, 1310, 1313, 1311, 0, + 1309, 1310, 1314, 1306, 1311, 1315, 1316, 1314, 1305, 1317, + 1315, 1317, 1308, 1313, 1316, 1320, 1320, 1324, 1324, 1327, + 1328, 1328, 1330, 1330, 1327, 1332, 1333, 1333, 1334, 1335, + 1332, 1336, 1341, 1338, 1339, 1339, 1336, 1341, 1342, 1343, + 1345, 1345, 1347, 1349, 1334, 1338, 1348, 1347, 1348, 1355, - 1348, 1355, 1356, 1357, 1362, 1346, 1364, 1356, 1357, 1351, - 1358, 1358, 1353, 1363, 1350, 1359, 1359, 1354, 1349, 1365, - 1366, 1352, 1367, 1355, 1362, 1368, 1369, 1369, 1364, 1366, - 1373, 1363, 1371, 1371, 1374, 1372, 1375, 1373, 1376, 1365, - 1378, 1377, 1367, 1368, 1372, 1379, 1379, 1380, 1381, 1374, - 1382, 1383, 1380, 1384, 1375, 1386, 1376, 1377, 1389, 1378, - 1390, 1391, 1391, 1390, 1392, 1382, 1381, 1393, 1395, 1397, - 1383, 1400, 1395, 1384, 1386, 1396, 1396, 1407, 1389, 1392, - 1399, 1399, 1397, 1401, 1401, 1393, 1402, 1402, 1406, 1406, - 1400, 1408, 1409, 1410, 1411, 1412, 1414, 1409, 1410, 1407, + 1350, 1335, 1351, 1351, 1343, 1350, 1342, 1349, 1352, 1352, + 1353, 1353, 1354, 1356, 1357, 1358, 1359, 1355, 1360, 1361, + 1361, 1359, 1362, 1363, 1354, 1356, 1357, 1358, 1364, 1365, + 1366, 1362, 1367, 1368, 1369, 1370, 1371, 1376, 1360, 1378, + 1370, 1371, 1365, 1372, 1372, 1377, 1367, 1379, 1364, 1363, + 1380, 1368, 1373, 1373, 1366, 1381, 1369, 1376, 1382, 1380, + 1389, 1378, 1386, 1377, 1383, 1383, 1387, 1379, 1385, 1385, + 1388, 1386, 1390, 1387, 1395, 1381, 1382, 1391, 1389, 1392, + 1393, 1393, 1394, 1397, 1396, 1388, 1398, 1394, 1400, 1403, + 1390, 1404, 1395, 1391, 1404, 1405, 1405, 1406, 1392, 1396, - 1408, 1415, 1416, 1412, 1417, 1420, 1415, 1416, 1418, 1418, - 1420, 1414, 1421, 1411, 1419, 1419, 1429, 1421, 1430, 1417, - 1422, 1422, 1423, 1423, 1426, 1429, 1427, 1428, 1431, 1426, - 1427, 1433, 1428, 1430, 1432, 1435, 1431, 1436, 1435, 1432, - 1437, 1438, 1439, 1433, 1440, 1440, 1443, 1441, 1444, 14, - 1438, 1439, 1445, 1437, 1447, 1436, 1441, 1446, 1446, 1448, - 1448, 1449, 1450, 1447, 1452, 1443, 1453, 1450, 1444, 1449, - 1454, 1445, 1461, 1452, 1456, 1456, 1458, 1458, 1467, 1453, - 1462, 1462, 13, 1463, 1468, 1454, 1463, 1464, 1464, 1465, - 1465, 1474, 1461, 1466, 1466, 1469, 1467, 1474, 1468, 1471, + 1407, 1408, 1397, 1412, 1410, 1408, 1398, 1400, 1410, 1403, + 1411, 1411, 1406, 1414, 1414, 1415, 1412, 1422, 1407, 1416, + 1416, 1417, 1417, 1421, 1421, 1424, 1423, 1425, 1426, 1427, + 1424, 1429, 1425, 1430, 1415, 1423, 1431, 1427, 1430, 1422, + 1432, 1431, 1433, 1433, 1434, 1434, 1429, 1426, 1435, 1436, + 1437, 1437, 1445, 1435, 1436, 1432, 1438, 1438, 1441, 1444, + 1442, 1443, 1446, 1441, 1442, 1448, 1443, 1445, 1444, 1447, + 1446, 1451, 1450, 1452, 1447, 1450, 1453, 1448, 1454, 1455, + 1455, 1456, 1458, 1459, 1462, 1453, 1452, 1454, 1460, 1451, + 1456, 1461, 1461, 1462, 1463, 1463, 1464, 1465, 1468, 1467, - 1469, 1470, 1470, 1471, 1475, 1478, 1479, 1480, 1481, 1475, - 1482, 1479, 1483, 1483, 1484, 1486, 1487, 1487, 1485, 1488, - 1488, 1489, 1478, 1478, 1482, 1480, 1485, 1490, 1481, 1491, - 1492, 1493, 1490, 1484, 1486, 1494, 1497, 1489, 1495, 1497, - 1493, 1499, 1500, 1500, 1501, 1502, 1508, 1503, 1501, 1491, - 0, 1507, 1504, 1506, 1502, 1494, 1492, 1518, 1495, 1499, - 1503, 1504, 1506, 1507, 1512, 1513, 1513, 1514, 1516, 1512, - 1517, 1508, 1519, 1516, 1521, 1520, 1514, 1518, 1522, 1517, - 1520, 1523, 1526, 1522, 1524, 1524, 1529, 1527, 1528, 1528, - 1529, 1530, 1521, 1519, 1531, 1532, 1533, 1535, 1534, 1537, + 1470, 1458, 1465, 1459, 1464, 1469, 1477, 1460, 1467, 1469, + 0, 1468, 1472, 1472, 1483, 1470, 1474, 1474, 1478, 1478, + 1479, 1480, 1480, 1479, 1481, 1481, 1477, 1482, 1482, 1484, + 1485, 1490, 1483, 1486, 1486, 1485, 1487, 1490, 1494, 1491, + 1487, 1495, 1496, 1484, 1491, 1497, 1495, 1498, 1499, 1499, + 1500, 1501, 1502, 1503, 1503, 1494, 1494, 1504, 1504, 1501, + 1496, 1498, 1505, 1506, 1507, 1497, 1508, 1509, 1506, 1500, + 1510, 1502, 1513, 1511, 1518, 1513, 1509, 1515, 1505, 1516, + 1516, 1517, 1519, 1518, 1507, 1517, 1520, 1521, 1524, 1523, + 1510, 1525, 1508, 1511, 1535, 1515, 1521, 1519, 1523, 1520, - 1530, 1526, 1527, 1534, 1533, 1542, 1523, 1536, 1536, 1545, - 1531, 1538, 1538, 1544, 1532, 1539, 1541, 1541, 1537, 1548, - 1539, 1543, 1543, 1535, 1549, 1542, 1550, 1544, 1546, 1546, - 1552, 1545, 1547, 1547, 1551, 1551, 1549, 1553, 1548, 1554, - 1555, 1561, 1552, 1556, 1554, 1557, 1550, 1564, 1556, 1558, - 1558, 1560, 1560, 1563, 1566, 1566, 0, 1553, 1563, 1555, - 1561, 1564, 1557, 1557, 1565, 1567, 1567, 1568, 1568, 1565, - 1569, 1571, 1571, 1573, 1573, 1569, 1575, 1575, 1576, 1577, - 1577, 1578, 1581, 1582, 1582, 1586, 1578, 1576, 1583, 1585, - 1581, 1587, 1588, 1583, 1585, 1589, 1590, 1586, 1591, 1594, + 1524, 1529, 1530, 1530, 1531, 1533, 1529, 1536, 1534, 1538, + 1533, 1540, 1543, 1531, 1535, 1537, 1525, 1534, 1539, 1544, + 1537, 1541, 1541, 1539, 1545, 1545, 1546, 1538, 1536, 1547, + 1546, 1543, 1548, 1549, 1544, 1550, 1540, 1551, 1547, 1552, + 1553, 1553, 1551, 1550, 1554, 1555, 1555, 1559, 1548, 1556, + 1558, 1558, 1549, 1560, 1556, 1561, 1561, 1562, 1563, 1564, + 1564, 1565, 1565, 1554, 1566, 1552, 1567, 1559, 1568, 1569, + 1569, 1562, 1570, 1571, 1572, 1573, 1560, 1574, 1567, 1572, + 1563, 1575, 1574, 1566, 1570, 1576, 1576, 1579, 1568, 1578, + 1578, 1581, 1583, 1571, 1573, 1582, 1581, 1583, 1575, 1575, - 1595, 1595, 1597, 1591, 1596, 1596, 1597, 1605, 1588, 1587, - 1601, 1601, 1589, 1589, 1603, 1607, 1607, 1590, 1603, 1594, - 1608, 1605, 1610, 1611, 1611, 1612, 1612, 1613, 1614, 1615, - 1618, 1616, 1617, 1619, 1619, 1608, 1616, 1617, 1622, 1622, - 1610, 1624, 1624, 1614, 1625, 1625, 1627, 1628, 1628, 1618, - 1615, 1631, 1613, 1632, 1633, 1634, 1631, 1635, 1627, 1633, - 1636, 1641, 1642, 1645, 1643, 1641, 1644, 1632, 1646, 1647, - 1650, 1648, 1649, 1649, 1634, 1635, 1636, 1643, 1651, 1650, - 1653, 1645, 1642, 1651, 1646, 1644, 1648, 1652, 1654, 1658, - 1655, 1659, 1652, 1656, 1647, 1655, 1660, 1661, 1662, 1664, + 1584, 1584, 1585, 1585, 1586, 1586, 1579, 1587, 1594, 1582, + 1589, 1589, 1587, 1591, 1591, 1593, 1593, 1595, 1596, 1596, + 1597, 1600, 1594, 1601, 1601, 1597, 1595, 1602, 1604, 1600, + 1605, 1606, 1602, 1604, 1607, 1608, 1609, 0, 1610, 1613, + 1614, 1614, 1605, 1610, 1615, 1615, 1633, 1616, 1630, 1606, + 1607, 1616, 1608, 1608, 1620, 1620, 1622, 1609, 1625, 1613, + 1622, 1624, 1624, 1627, 1627, 1628, 1630, 1631, 1631, 1632, + 1632, 1633, 1625, 1634, 1635, 1638, 1636, 1637, 1639, 1639, + 1628, 1636, 1637, 1642, 1642, 1644, 1644, 1648, 1634, 1646, + 1646, 1649, 1649, 1652, 1638, 1635, 1653, 1654, 1652, 1648, - 1663, 1660, 1661, 1654, 1658, 1653, 1665, 1656, 1666, 1667, - 1659, 1668, 1662, 1663, 1669, 1672, 1670, 0, 1664, 1677, - 1665, 1670, 1667, 1671, 1668, 1673, 1673, 1666, 1671, 1681, - 1674, 1675, 1676, 1669, 1672, 1674, 1675, 1676, 1677, 1678, - 1679, 1679, 1680, 1682, 1678, 1683, 1684, 1685, 1681, 1680, - 1683, 1687, 1688, 1689, 1690, 1693, 1687, 1691, 1691, 1692, - 1685, 1696, 1682, 1697, 1692, 1684, 1696, 1690, 1694, 1694, - 1697, 1688, 1689, 1698, 1693, 1695, 1695, 1699, 1699, 1700, - 1701, 1702, 1704, 1703, 1706, 1707, 1700, 1701, 1703, 1706, - 1707, 1708, 1698, 1709, 1710, 1710, 1711, 1712, 1713, 1713, + 1655, 1657, 1654, 1656, 1662, 1663, 1666, 1664, 1662, 1665, + 1653, 1667, 1668, 1671, 1669, 1670, 1670, 1657, 1672, 1655, + 1664, 1656, 1671, 1672, 1666, 1663, 1673, 1667, 1665, 1669, + 1674, 1673, 1675, 1676, 1677, 1679, 1681, 1668, 1676, 1680, + 1682, 1681, 1683, 1685, 1684, 1682, 1686, 1675, 1677, 1687, + 1679, 1688, 1689, 1690, 1691, 1674, 1683, 1684, 1680, 1691, + 1686, 1692, 1685, 1693, 1688, 1689, 1692, 1698, 1687, 1694, + 1694, 1695, 1690, 1696, 1697, 1699, 1695, 1702, 1696, 1697, + 1699, 1701, 1693, 1700, 1700, 1703, 1698, 1704, 1701, 1705, + 1706, 1709, 1704, 1708, 1710, 1714, 1702, 1713, 1708, 1711, - 1702, 1704, 1714, 1714, 1715, 1716, 1716, 1717, 1717, 1720, - 1708, 1715, 1709, 1718, 1720, 1711, 1712, 1723, 1724, 1725, - 1718, 0, 1723, 1726, 1726, 1727, 1727, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1724, 1725, 1731, - 1731, 1731, 1731, 1731, 1731, 1731, 1732, 1732, 1732, 1732, - 1732, 1732, 1732, 1733, 1733, 1733, 1733, 1733, 1733, 1733, - 1734, 1734, 1734, 1734, 1734, 1734, 1734, 1735, 1735, 1735, - 1735, 1735, 1735, 1735, 1737, 1737, 0, 1737, 1737, 1737, - 1737, 1738, 1738, 0, 0, 0, 1738, 1738, 1739, 1739, - 0, 0, 1739, 0, 1739, 1740, 0, 0, 0, 0, + 1712, 1712, 1713, 1706, 1703, 1715, 1715, 1719, 1705, 0, + 1709, 1718, 1711, 1710, 1714, 1716, 1716, 1717, 1718, 1720, + 1720, 1721, 1717, 1722, 1723, 1725, 1719, 1724, 1721, 1727, + 1722, 1728, 1724, 1729, 1727, 1730, 1728, 1731, 1731, 1732, + 1733, 1734, 1734, 1723, 1725, 1735, 1735, 0, 1736, 1737, + 1737, 1745, 1729, 1739, 1730, 1736, 1738, 1738, 1732, 1733, + 1739, 1741, 1744, 1746, 1747, 1747, 1741, 1744, 1748, 1748, + 1745, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1746, 1752, 1752, 1752, 1752, 1752, 1752, 1752, + 1753, 1753, 1753, 1753, 1753, 1753, 1753, 1754, 1754, 1754, - 0, 1740, 1741, 1741, 0, 0, 0, 1741, 1741, 1742, - 0, 0, 0, 0, 0, 1742, 1743, 1743, 0, 1743, - 1743, 1743, 1743, 1744, 1744, 0, 1744, 1744, 1744, 1744, - 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, - 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, - 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, - 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730, 1730 + 1754, 1754, 1754, 1754, 1755, 1755, 1755, 1755, 1755, 1755, + 1755, 1756, 1756, 1756, 1756, 1756, 1756, 1756, 1758, 1758, + 0, 1758, 1758, 1758, 1758, 1759, 1759, 0, 0, 0, + 1759, 1759, 1760, 1760, 0, 0, 1760, 0, 1760, 1761, + 0, 0, 0, 0, 0, 1761, 1762, 1762, 0, 0, + 0, 1762, 1762, 1763, 0, 0, 0, 0, 0, 1763, + 1764, 1764, 0, 1764, 1764, 1764, 1764, 1765, 1765, 0, + 1765, 1765, 1765, 1765, 1751, 1751, 1751, 1751, 1751, 1751, + 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, + 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, + + 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, 1751, + 1751, 1751, 1751, 1751 } ; static yy_state_type yy_last_accepting_state; @@ -1966,7 +1985,7 @@ static void config_end_include(void) #define YY_NO_INPUT 1 #endif -#line 1968 "" +#line 1987 "" #define INITIAL 0 #define quotedstring 1 @@ -2153,7 +2172,7 @@ YY_DECL #line 197 "./util/configlexer.lex" -#line 2155 "" +#line 2174 "" if ( !(yy_init) ) { @@ -2212,13 +2231,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 1731 ) + if ( yy_current_state >= 1752 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 3431 ); + while ( yy_base[yy_current_state] != 3475 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -2784,274 +2803,279 @@ YY_RULE_SETUP case 108: YY_RULE_SETUP #line 309 "./util/configlexer.lex" -{ YDVAR(1, VAR_USE_SYSLOG) } +{ YDVAR(1, VAR_PERMIT_SMALL_HOLDDOWN) } YY_BREAK case 109: YY_RULE_SETUP #line 310 "./util/configlexer.lex" -{ YDVAR(1, VAR_LOG_TIME_ASCII) } +{ YDVAR(1, VAR_USE_SYSLOG) } YY_BREAK case 110: YY_RULE_SETUP #line 311 "./util/configlexer.lex" -{ YDVAR(1, VAR_LOG_QUERIES) } +{ YDVAR(1, VAR_LOG_TIME_ASCII) } YY_BREAK case 111: YY_RULE_SETUP #line 312 "./util/configlexer.lex" -{ YDVAR(2, VAR_LOCAL_ZONE) } +{ YDVAR(1, VAR_LOG_QUERIES) } YY_BREAK case 112: YY_RULE_SETUP #line 313 "./util/configlexer.lex" -{ YDVAR(1, VAR_LOCAL_DATA) } +{ YDVAR(2, VAR_LOCAL_ZONE) } YY_BREAK case 113: YY_RULE_SETUP #line 314 "./util/configlexer.lex" -{ YDVAR(1, VAR_LOCAL_DATA_PTR) } +{ YDVAR(1, VAR_LOCAL_DATA) } YY_BREAK case 114: YY_RULE_SETUP #line 315 "./util/configlexer.lex" -{ YDVAR(1, VAR_UNBLOCK_LAN_ZONES) } +{ YDVAR(1, VAR_LOCAL_DATA_PTR) } YY_BREAK case 115: YY_RULE_SETUP #line 316 "./util/configlexer.lex" -{ YDVAR(1, VAR_STATISTICS_INTERVAL) } +{ YDVAR(1, VAR_UNBLOCK_LAN_ZONES) } YY_BREAK case 116: YY_RULE_SETUP #line 317 "./util/configlexer.lex" -{ YDVAR(1, VAR_STATISTICS_CUMULATIVE) } +{ YDVAR(1, VAR_STATISTICS_INTERVAL) } YY_BREAK case 117: YY_RULE_SETUP #line 318 "./util/configlexer.lex" -{ YDVAR(1, VAR_EXTENDED_STATISTICS) } +{ YDVAR(1, VAR_STATISTICS_CUMULATIVE) } YY_BREAK case 118: YY_RULE_SETUP #line 319 "./util/configlexer.lex" -{ YDVAR(0, VAR_REMOTE_CONTROL) } +{ YDVAR(1, VAR_EXTENDED_STATISTICS) } YY_BREAK case 119: YY_RULE_SETUP #line 320 "./util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_ENABLE) } +{ YDVAR(0, VAR_REMOTE_CONTROL) } YY_BREAK case 120: YY_RULE_SETUP #line 321 "./util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_INTERFACE) } +{ YDVAR(1, VAR_CONTROL_ENABLE) } YY_BREAK case 121: YY_RULE_SETUP #line 322 "./util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_PORT) } +{ YDVAR(1, VAR_CONTROL_INTERFACE) } YY_BREAK case 122: YY_RULE_SETUP #line 323 "./util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_USE_CERT) } +{ YDVAR(1, VAR_CONTROL_PORT) } YY_BREAK case 123: YY_RULE_SETUP #line 324 "./util/configlexer.lex" -{ YDVAR(1, VAR_SERVER_KEY_FILE) } +{ YDVAR(1, VAR_CONTROL_USE_CERT) } YY_BREAK case 124: YY_RULE_SETUP #line 325 "./util/configlexer.lex" -{ YDVAR(1, VAR_SERVER_CERT_FILE) } +{ YDVAR(1, VAR_SERVER_KEY_FILE) } YY_BREAK case 125: YY_RULE_SETUP #line 326 "./util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_KEY_FILE) } +{ YDVAR(1, VAR_SERVER_CERT_FILE) } YY_BREAK case 126: YY_RULE_SETUP #line 327 "./util/configlexer.lex" -{ YDVAR(1, VAR_CONTROL_CERT_FILE) } +{ YDVAR(1, VAR_CONTROL_KEY_FILE) } YY_BREAK case 127: YY_RULE_SETUP #line 328 "./util/configlexer.lex" -{ YDVAR(1, VAR_PYTHON_SCRIPT) } +{ YDVAR(1, VAR_CONTROL_CERT_FILE) } YY_BREAK case 128: YY_RULE_SETUP #line 329 "./util/configlexer.lex" -{ YDVAR(0, VAR_PYTHON) } +{ YDVAR(1, VAR_PYTHON_SCRIPT) } YY_BREAK case 129: YY_RULE_SETUP #line 330 "./util/configlexer.lex" -{ YDVAR(1, VAR_DOMAIN_INSECURE) } +{ YDVAR(0, VAR_PYTHON) } YY_BREAK case 130: YY_RULE_SETUP #line 331 "./util/configlexer.lex" -{ YDVAR(1, VAR_MINIMAL_RESPONSES) } +{ YDVAR(1, VAR_DOMAIN_INSECURE) } YY_BREAK case 131: YY_RULE_SETUP #line 332 "./util/configlexer.lex" -{ YDVAR(1, VAR_RRSET_ROUNDROBIN) } +{ YDVAR(1, VAR_MINIMAL_RESPONSES) } YY_BREAK case 132: YY_RULE_SETUP #line 333 "./util/configlexer.lex" -{ YDVAR(1, VAR_MAX_UDP_SIZE) } +{ YDVAR(1, VAR_RRSET_ROUNDROBIN) } YY_BREAK case 133: YY_RULE_SETUP #line 334 "./util/configlexer.lex" -{ YDVAR(1, VAR_DNS64_PREFIX) } +{ YDVAR(1, VAR_MAX_UDP_SIZE) } YY_BREAK case 134: YY_RULE_SETUP #line 335 "./util/configlexer.lex" -{ YDVAR(1, VAR_DNS64_SYNTHALL) } +{ YDVAR(1, VAR_DNS64_PREFIX) } YY_BREAK case 135: YY_RULE_SETUP #line 336 "./util/configlexer.lex" -{ YDVAR(0, VAR_DNSTAP) } +{ YDVAR(1, VAR_DNS64_SYNTHALL) } YY_BREAK case 136: YY_RULE_SETUP #line 337 "./util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_ENABLE) } +{ YDVAR(0, VAR_DNSTAP) } YY_BREAK case 137: YY_RULE_SETUP #line 338 "./util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_SOCKET_PATH) } +{ YDVAR(1, VAR_DNSTAP_ENABLE) } YY_BREAK case 138: YY_RULE_SETUP #line 339 "./util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_SEND_IDENTITY) } +{ YDVAR(1, VAR_DNSTAP_SOCKET_PATH) } YY_BREAK case 139: YY_RULE_SETUP #line 340 "./util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_SEND_VERSION) } +{ YDVAR(1, VAR_DNSTAP_SEND_IDENTITY) } YY_BREAK case 140: YY_RULE_SETUP #line 341 "./util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_IDENTITY) } +{ YDVAR(1, VAR_DNSTAP_SEND_VERSION) } YY_BREAK case 141: YY_RULE_SETUP #line 342 "./util/configlexer.lex" -{ YDVAR(1, VAR_DNSTAP_VERSION) } +{ YDVAR(1, VAR_DNSTAP_IDENTITY) } YY_BREAK case 142: YY_RULE_SETUP #line 343 "./util/configlexer.lex" -{ - YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES) } +{ YDVAR(1, VAR_DNSTAP_VERSION) } YY_BREAK case 143: YY_RULE_SETUP -#line 345 "./util/configlexer.lex" +#line 344 "./util/configlexer.lex" { - YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES) } + YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES) } YY_BREAK case 144: YY_RULE_SETUP -#line 347 "./util/configlexer.lex" +#line 346 "./util/configlexer.lex" { - YDVAR(1, VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES) } + YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES) } YY_BREAK case 145: YY_RULE_SETUP -#line 349 "./util/configlexer.lex" +#line 348 "./util/configlexer.lex" { - YDVAR(1, VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES) } + YDVAR(1, VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES) } YY_BREAK case 146: YY_RULE_SETUP -#line 351 "./util/configlexer.lex" +#line 350 "./util/configlexer.lex" { - YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES) } + YDVAR(1, VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES) } YY_BREAK case 147: YY_RULE_SETUP -#line 353 "./util/configlexer.lex" +#line 352 "./util/configlexer.lex" { - YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) } + YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES) } YY_BREAK case 148: YY_RULE_SETUP -#line 355 "./util/configlexer.lex" -{ YDVAR(1, VAR_RATELIMIT) } +#line 354 "./util/configlexer.lex" +{ + YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) } YY_BREAK case 149: YY_RULE_SETUP #line 356 "./util/configlexer.lex" -{ YDVAR(1, VAR_RATELIMIT_SLABS) } +{ YDVAR(1, VAR_RATELIMIT) } YY_BREAK case 150: YY_RULE_SETUP #line 357 "./util/configlexer.lex" -{ YDVAR(1, VAR_RATELIMIT_SIZE) } +{ YDVAR(1, VAR_RATELIMIT_SLABS) } YY_BREAK case 151: YY_RULE_SETUP #line 358 "./util/configlexer.lex" -{ YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) } +{ YDVAR(1, VAR_RATELIMIT_SIZE) } YY_BREAK case 152: YY_RULE_SETUP #line 359 "./util/configlexer.lex" -{ YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) } +{ YDVAR(2, VAR_RATELIMIT_FOR_DOMAIN) } YY_BREAK case 153: YY_RULE_SETUP #line 360 "./util/configlexer.lex" -{ YDVAR(1, VAR_RATELIMIT_FACTOR) } +{ YDVAR(2, VAR_RATELIMIT_BELOW_DOMAIN) } YY_BREAK case 154: -/* rule 154 can match eol */ YY_RULE_SETUP #line 361 "./util/configlexer.lex" +{ YDVAR(1, VAR_RATELIMIT_FACTOR) } + YY_BREAK +case 155: +/* rule 155 can match eol */ +YY_RULE_SETUP +#line 362 "./util/configlexer.lex" { LEXOUT(("NL\n")); cfg_parser->line++; } YY_BREAK /* Quoted strings. Strip leading and ending quotes */ -case 155: +case 156: YY_RULE_SETUP -#line 364 "./util/configlexer.lex" +#line 365 "./util/configlexer.lex" { BEGIN(quotedstring); LEXOUT(("QS ")); } YY_BREAK case YY_STATE_EOF(quotedstring): -#line 365 "./util/configlexer.lex" +#line 366 "./util/configlexer.lex" { yyerror("EOF inside quoted string"); if(--num_args == 0) { BEGIN(INITIAL); } else { BEGIN(val); } } YY_BREAK -case 156: -YY_RULE_SETUP -#line 370 "./util/configlexer.lex" -{ LEXOUT(("STR(%s) ", yytext)); yymore(); } - YY_BREAK case 157: -/* rule 157 can match eol */ YY_RULE_SETUP #line 371 "./util/configlexer.lex" +{ LEXOUT(("STR(%s) ", yytext)); yymore(); } + YY_BREAK +case 158: +/* rule 158 can match eol */ +YY_RULE_SETUP +#line 372 "./util/configlexer.lex" { yyerror("newline inside quoted string, no end \""); cfg_parser->line++; BEGIN(INITIAL); } YY_BREAK -case 158: +case 159: YY_RULE_SETUP -#line 373 "./util/configlexer.lex" +#line 374 "./util/configlexer.lex" { LEXOUT(("QE ")); if(--num_args == 0) { BEGIN(INITIAL); } @@ -3064,34 +3088,34 @@ YY_RULE_SETUP } YY_BREAK /* Single Quoted strings. Strip leading and ending quotes */ -case 159: +case 160: YY_RULE_SETUP -#line 385 "./util/configlexer.lex" +#line 386 "./util/configlexer.lex" { BEGIN(singlequotedstr); LEXOUT(("SQS ")); } YY_BREAK case YY_STATE_EOF(singlequotedstr): -#line 386 "./util/configlexer.lex" +#line 387 "./util/configlexer.lex" { yyerror("EOF inside quoted string"); if(--num_args == 0) { BEGIN(INITIAL); } else { BEGIN(val); } } YY_BREAK -case 160: -YY_RULE_SETUP -#line 391 "./util/configlexer.lex" -{ LEXOUT(("STR(%s) ", yytext)); yymore(); } - YY_BREAK case 161: -/* rule 161 can match eol */ YY_RULE_SETUP #line 392 "./util/configlexer.lex" +{ LEXOUT(("STR(%s) ", yytext)); yymore(); } + YY_BREAK +case 162: +/* rule 162 can match eol */ +YY_RULE_SETUP +#line 393 "./util/configlexer.lex" { yyerror("newline inside quoted string, no end '"); cfg_parser->line++; BEGIN(INITIAL); } YY_BREAK -case 162: +case 163: YY_RULE_SETUP -#line 394 "./util/configlexer.lex" +#line 395 "./util/configlexer.lex" { LEXOUT(("SQE ")); if(--num_args == 0) { BEGIN(INITIAL); } @@ -3104,38 +3128,38 @@ YY_RULE_SETUP } YY_BREAK /* include: directive */ -case 163: +case 164: YY_RULE_SETUP -#line 406 "./util/configlexer.lex" +#line 407 "./util/configlexer.lex" { LEXOUT(("v(%s) ", yytext)); inc_prev = YYSTATE; BEGIN(include); } YY_BREAK case YY_STATE_EOF(include): -#line 408 "./util/configlexer.lex" +#line 409 "./util/configlexer.lex" { yyerror("EOF inside include directive"); BEGIN(inc_prev); } YY_BREAK -case 164: -YY_RULE_SETUP -#line 412 "./util/configlexer.lex" -{ LEXOUT(("ISP ")); /* ignore */ } - YY_BREAK case 165: -/* rule 165 can match eol */ YY_RULE_SETUP #line 413 "./util/configlexer.lex" -{ LEXOUT(("NL\n")); cfg_parser->line++;} +{ LEXOUT(("ISP ")); /* ignore */ } YY_BREAK case 166: +/* rule 166 can match eol */ YY_RULE_SETUP #line 414 "./util/configlexer.lex" -{ LEXOUT(("IQS ")); BEGIN(include_quoted); } +{ LEXOUT(("NL\n")); cfg_parser->line++;} YY_BREAK case 167: YY_RULE_SETUP #line 415 "./util/configlexer.lex" +{ LEXOUT(("IQS ")); BEGIN(include_quoted); } + YY_BREAK +case 168: +YY_RULE_SETUP +#line 416 "./util/configlexer.lex" { LEXOUT(("Iunquotedstr(%s) ", yytext)); config_start_include_glob(yytext); @@ -3143,27 +3167,27 @@ YY_RULE_SETUP } YY_BREAK case YY_STATE_EOF(include_quoted): -#line 420 "./util/configlexer.lex" +#line 421 "./util/configlexer.lex" { yyerror("EOF inside quoted string"); BEGIN(inc_prev); } YY_BREAK -case 168: -YY_RULE_SETUP -#line 424 "./util/configlexer.lex" -{ LEXOUT(("ISTR(%s) ", yytext)); yymore(); } - YY_BREAK case 169: -/* rule 169 can match eol */ YY_RULE_SETUP #line 425 "./util/configlexer.lex" +{ LEXOUT(("ISTR(%s) ", yytext)); yymore(); } + YY_BREAK +case 170: +/* rule 170 can match eol */ +YY_RULE_SETUP +#line 426 "./util/configlexer.lex" { yyerror("newline before \" in include name"); cfg_parser->line++; BEGIN(inc_prev); } YY_BREAK -case 170: +case 171: YY_RULE_SETUP -#line 427 "./util/configlexer.lex" +#line 428 "./util/configlexer.lex" { LEXOUT(("IQE ")); yytext[yyleng - 1] = '\0'; @@ -3173,7 +3197,7 @@ YY_RULE_SETUP YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(val): -#line 433 "./util/configlexer.lex" +#line 434 "./util/configlexer.lex" { LEXOUT(("LEXEOF ")); yy_set_bol(1); /* Set beginning of line, so "^" rules match. */ @@ -3185,33 +3209,33 @@ case YY_STATE_EOF(val): } } YY_BREAK -case 171: +case 172: YY_RULE_SETUP -#line 444 "./util/configlexer.lex" +#line 445 "./util/configlexer.lex" { LEXOUT(("unquotedstr(%s) ", yytext)); if(--num_args == 0) { BEGIN(INITIAL); } yylval.str = strdup(yytext); return STRING_ARG; } YY_BREAK -case 172: +case 173: YY_RULE_SETUP -#line 448 "./util/configlexer.lex" +#line 449 "./util/configlexer.lex" { ub_c_error_msg("unknown keyword '%s'", yytext); } YY_BREAK -case 173: +case 174: YY_RULE_SETUP -#line 452 "./util/configlexer.lex" +#line 453 "./util/configlexer.lex" { ub_c_error_msg("stray '%s'", yytext); } YY_BREAK -case 174: +case 175: YY_RULE_SETUP -#line 456 "./util/configlexer.lex" +#line 457 "./util/configlexer.lex" ECHO; YY_BREAK -#line 3213 "" +#line 3237 "" case YY_END_OF_BUFFER: { @@ -3501,7 +3525,7 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 1731 ) + if ( yy_current_state >= 1752 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; @@ -3529,11 +3553,11 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 1731 ) + if ( yy_current_state >= 1752 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 1730); + yy_is_jam = (yy_current_state == 1751); return yy_is_jam ? 0 : yy_current_state; } @@ -4166,7 +4190,7 @@ void yyfree (void * ptr ) #define YYTABLES_NAME "yytables" -#line 456 "./util/configlexer.lex" +#line 457 "./util/configlexer.lex" diff --git a/external/unbound/util/configlexer.lex b/external/unbound/util/configlexer.lex index 5622f2170..a776c766f 100644 --- a/external/unbound/util/configlexer.lex +++ b/external/unbound/util/configlexer.lex @@ -306,6 +306,7 @@ val-nsec3-keysize-iterations{COLON} { add-holddown{COLON} { YDVAR(1, VAR_ADD_HOLDDOWN) } del-holddown{COLON} { YDVAR(1, VAR_DEL_HOLDDOWN) } keep-missing{COLON} { YDVAR(1, VAR_KEEP_MISSING) } +permit-small-holddown{COLON} { YDVAR(1, VAR_PERMIT_SMALL_HOLDDOWN) } use-syslog{COLON} { YDVAR(1, VAR_USE_SYSLOG) } log-time-ascii{COLON} { YDVAR(1, VAR_LOG_TIME_ASCII) } log-queries{COLON} { YDVAR(1, VAR_LOG_QUERIES) } diff --git a/external/unbound/util/configparser.c b/external/unbound/util/configparser.c index f7ebd5d51..a571f5c7f 100644 --- a/external/unbound/util/configparser.c +++ b/external/unbound/util/configparser.c @@ -284,7 +284,8 @@ extern int yydebug; VAR_RATELIMIT_BELOW_DOMAIN = 412, VAR_RATELIMIT_FACTOR = 413, VAR_CAPS_WHITELIST = 414, - VAR_CACHE_MAX_NEGATIVE_TTL = 415 + VAR_CACHE_MAX_NEGATIVE_TTL = 415, + VAR_PERMIT_SMALL_HOLDDOWN = 416 }; #endif /* Tokens. */ @@ -446,6 +447,7 @@ extern int yydebug; #define VAR_RATELIMIT_FACTOR 413 #define VAR_CAPS_WHITELIST 414 #define VAR_CACHE_MAX_NEGATIVE_TTL 415 +#define VAR_PERMIT_SMALL_HOLDDOWN 416 @@ -459,7 +461,7 @@ typedef union YYSTYPE /* Line 387 of yacc.c */ -#line 463 "util/configparser.c" +#line 465 "util/configparser.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ @@ -487,7 +489,7 @@ int yyparse (); /* Copy the second part of user declarations. */ /* Line 390 of yacc.c */ -#line 491 "util/configparser.c" +#line 493 "util/configparser.c" #ifdef short # undef short @@ -707,20 +709,20 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 301 +#define YYLAST 303 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 161 +#define YYNTOKENS 162 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 166 +#define YYNNTS 167 /* YYNRULES -- Number of rules. */ -#define YYNRULES 317 +#define YYNRULES 319 /* YYNRULES -- Number of states. */ -#define YYNSTATES 467 +#define YYNSTATES 470 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 415 +#define YYMAXUTOK 416 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -769,7 +771,7 @@ static const yytype_uint8 yytranslate[] = 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160 + 155, 156, 157, 158, 159, 160, 161 }; #if YYDEBUG @@ -790,109 +792,110 @@ static const yytype_uint16 yyprhs[] = 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255, 257, 259, 261, 263, - 266, 267, 269, 271, 273, 275, 277, 279, 282, 283, - 285, 287, 289, 291, 294, 297, 300, 303, 306, 309, - 312, 315, 318, 321, 324, 327, 330, 333, 336, 339, - 342, 345, 348, 351, 354, 357, 360, 363, 366, 369, - 372, 375, 378, 381, 384, 387, 390, 393, 396, 399, - 402, 405, 408, 411, 414, 417, 420, 423, 426, 429, - 432, 435, 438, 441, 444, 447, 450, 453, 456, 459, - 462, 465, 468, 471, 474, 477, 480, 483, 486, 489, - 492, 495, 498, 501, 504, 507, 510, 513, 516, 519, - 522, 525, 528, 531, 534, 538, 541, 544, 547, 550, - 553, 556, 559, 562, 565, 568, 571, 574, 577, 580, - 583, 586, 589, 592, 595, 599, 602, 605, 608, 611, - 614, 617, 620, 623, 626, 629, 633, 637, 640, 643, - 646, 649, 652, 655, 658, 661, 664, 667, 669, 672, - 673, 675, 677, 679, 681, 683, 685, 687, 689, 692, - 695, 698, 701, 704, 707, 710, 713, 715, 718, 719, - 721, 723, 725, 727, 729, 731, 733, 735, 737, 739, - 741, 743, 746, 749, 752, 755, 758, 761, 764, 767, - 770, 773, 776, 779, 781, 784, 785, 787 + 265, 268, 269, 271, 273, 275, 277, 279, 281, 284, + 285, 287, 289, 291, 293, 296, 299, 302, 305, 308, + 311, 314, 317, 320, 323, 326, 329, 332, 335, 338, + 341, 344, 347, 350, 353, 356, 359, 362, 365, 368, + 371, 374, 377, 380, 383, 386, 389, 392, 395, 398, + 401, 404, 407, 410, 413, 416, 419, 422, 425, 428, + 431, 434, 437, 440, 443, 446, 449, 452, 455, 458, + 461, 464, 467, 470, 473, 476, 479, 482, 485, 488, + 491, 494, 497, 500, 503, 506, 509, 512, 515, 518, + 521, 524, 527, 530, 533, 536, 540, 543, 546, 549, + 552, 555, 558, 561, 564, 567, 570, 573, 576, 579, + 582, 585, 588, 591, 594, 597, 600, 604, 607, 610, + 613, 616, 619, 622, 625, 628, 631, 634, 638, 642, + 645, 648, 651, 654, 657, 660, 663, 666, 669, 672, + 674, 677, 678, 680, 682, 684, 686, 688, 690, 692, + 694, 697, 700, 703, 706, 709, 712, 715, 718, 720, + 723, 724, 726, 728, 730, 732, 734, 736, 738, 740, + 742, 744, 746, 748, 751, 754, 757, 760, 763, 766, + 769, 772, 775, 778, 781, 784, 786, 789, 790, 792 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int16 yyrhs[] = { - 162, 0, -1, -1, 162, 163, -1, 164, 165, -1, - 167, 168, -1, 170, 171, -1, 323, 324, -1, 297, - 298, -1, 308, 309, -1, 11, -1, 165, 166, -1, - -1, 173, -1, 174, -1, 178, -1, 181, -1, 187, - -1, 188, -1, 189, -1, 190, -1, 179, -1, 200, - -1, 201, -1, 202, -1, 203, -1, 204, -1, 223, - -1, 224, -1, 225, -1, 229, -1, 230, -1, 184, - -1, 231, -1, 232, -1, 235, -1, 233, -1, 234, - -1, 237, -1, 238, -1, 239, -1, 252, -1, 213, - -1, 214, -1, 215, -1, 216, -1, 240, -1, 255, - -1, 209, -1, 211, -1, 256, -1, 262, -1, 263, - -1, 264, -1, 185, -1, 222, -1, 271, -1, 272, - -1, 210, -1, 267, -1, 197, -1, 180, -1, 205, - -1, 253, -1, 259, -1, 241, -1, 254, -1, 274, - -1, 275, -1, 186, -1, 175, -1, 196, -1, 245, - -1, 176, -1, 182, -1, 183, -1, 206, -1, 207, - -1, 273, -1, 243, -1, 247, -1, 248, -1, 177, - -1, 276, -1, 226, -1, 251, -1, 198, -1, 212, - -1, 257, -1, 258, -1, 261, -1, 266, -1, 208, - -1, 268, -1, 269, -1, 270, -1, 217, -1, 221, - -1, 249, -1, 250, -1, 218, -1, 242, -1, 265, - -1, 199, -1, 191, -1, 192, -1, 193, -1, 194, - -1, 195, -1, 277, -1, 278, -1, 279, -1, 219, - -1, 227, -1, 228, -1, 280, -1, 281, -1, 236, - -1, 244, -1, 220, -1, 282, -1, 284, -1, 283, - -1, 285, -1, 286, -1, 287, -1, 246, -1, 260, - -1, 38, -1, 168, 169, -1, -1, 288, -1, 289, - -1, 290, -1, 292, -1, 291, -1, 44, -1, 171, - 172, -1, -1, 293, -1, 294, -1, 295, -1, 296, - -1, 13, 10, -1, 12, 10, -1, 76, 10, -1, - 79, 10, -1, 97, 10, -1, 14, 10, -1, 16, - 10, -1, 67, 10, -1, 15, 10, -1, 80, 10, - -1, 81, 10, -1, 31, 10, -1, 60, 10, -1, - 75, 10, -1, 17, 10, -1, 18, 10, -1, 19, - 10, -1, 20, 10, -1, 123, 10, -1, 124, 10, - -1, 125, 10, -1, 126, 10, -1, 127, 10, -1, - 77, 10, -1, 66, 10, -1, 102, 10, -1, 122, - 10, -1, 21, 10, -1, 22, 10, -1, 23, 10, - -1, 24, 10, -1, 25, 10, -1, 68, 10, -1, - 82, 10, -1, 83, 10, -1, 110, 10, -1, 54, - 10, -1, 64, 10, -1, 55, 10, -1, 103, 10, - -1, 48, 10, -1, 49, 10, -1, 50, 10, -1, - 51, 10, -1, 114, 10, -1, 118, 10, -1, 119, - 10, -1, 152, 10, -1, 115, 10, -1, 61, 10, - -1, 26, 10, -1, 27, 10, -1, 28, 10, -1, - 99, 10, -1, 133, 10, -1, 134, 10, -1, 29, - 10, -1, 30, 10, -1, 32, 10, -1, 33, 10, - -1, 35, 10, -1, 36, 10, -1, 34, 10, -1, - 135, 10, -1, 41, 10, -1, 42, 10, -1, 43, - 10, -1, 52, 10, -1, 71, 10, -1, 120, 10, - -1, 85, 10, -1, 151, 10, -1, 78, 10, -1, - 159, 10, -1, 86, 10, -1, 87, 10, -1, 116, - 10, -1, 117, 10, -1, 101, 10, -1, 47, 10, - -1, 69, 10, -1, 72, 10, 10, -1, 53, 10, - -1, 56, 10, -1, 106, 10, -1, 107, 10, -1, - 70, 10, -1, 160, 10, -1, 108, 10, -1, 57, - 10, -1, 58, 10, -1, 59, 10, -1, 121, 10, - -1, 109, 10, -1, 65, 10, -1, 112, 10, -1, - 113, 10, -1, 111, 10, -1, 62, 10, -1, 63, - 10, -1, 84, 10, -1, 73, 10, 10, -1, 74, - 10, -1, 98, 10, -1, 130, 10, -1, 131, 10, - -1, 132, 10, -1, 136, 10, -1, 137, 10, -1, - 153, 10, -1, 155, 10, -1, 154, 10, -1, 156, - 10, 10, -1, 157, 10, 10, -1, 158, 10, -1, - 37, 10, -1, 39, 10, -1, 40, 10, -1, 129, - 10, -1, 100, 10, -1, 37, 10, -1, 45, 10, - -1, 46, 10, -1, 128, 10, -1, 88, -1, 298, - 299, -1, -1, 300, -1, 302, -1, 301, -1, 304, - -1, 305, -1, 306, -1, 307, -1, 303, -1, 89, - 10, -1, 91, 10, -1, 90, 10, -1, 96, 10, - -1, 92, 10, -1, 93, 10, -1, 94, 10, -1, - 95, 10, -1, 138, -1, 309, 310, -1, -1, 311, - -1, 312, -1, 313, -1, 314, -1, 315, -1, 316, - -1, 317, -1, 318, -1, 319, -1, 320, -1, 321, - -1, 322, -1, 139, 10, -1, 140, 10, -1, 141, - 10, -1, 142, 10, -1, 143, 10, -1, 144, 10, - -1, 145, 10, -1, 146, 10, -1, 147, 10, -1, - 148, 10, -1, 149, 10, -1, 150, 10, -1, 104, - -1, 324, 325, -1, -1, 326, -1, 105, 10, -1 + 163, 0, -1, -1, 163, 164, -1, 165, 166, -1, + 168, 169, -1, 171, 172, -1, 325, 326, -1, 299, + 300, -1, 310, 311, -1, 11, -1, 166, 167, -1, + -1, 174, -1, 175, -1, 179, -1, 182, -1, 188, + -1, 189, -1, 190, -1, 191, -1, 180, -1, 201, + -1, 202, -1, 203, -1, 204, -1, 205, -1, 224, + -1, 225, -1, 226, -1, 230, -1, 231, -1, 185, + -1, 232, -1, 233, -1, 236, -1, 234, -1, 235, + -1, 238, -1, 239, -1, 240, -1, 253, -1, 214, + -1, 215, -1, 216, -1, 217, -1, 241, -1, 256, + -1, 210, -1, 212, -1, 257, -1, 263, -1, 264, + -1, 265, -1, 186, -1, 223, -1, 273, -1, 274, + -1, 211, -1, 268, -1, 198, -1, 181, -1, 206, + -1, 254, -1, 260, -1, 242, -1, 255, -1, 276, + -1, 277, -1, 187, -1, 176, -1, 197, -1, 246, + -1, 177, -1, 183, -1, 184, -1, 207, -1, 208, + -1, 275, -1, 244, -1, 248, -1, 249, -1, 178, + -1, 278, -1, 227, -1, 252, -1, 199, -1, 213, + -1, 258, -1, 259, -1, 262, -1, 267, -1, 209, + -1, 269, -1, 270, -1, 271, -1, 218, -1, 222, + -1, 250, -1, 251, -1, 219, -1, 243, -1, 266, + -1, 200, -1, 192, -1, 193, -1, 194, -1, 195, + -1, 196, -1, 279, -1, 280, -1, 281, -1, 220, + -1, 228, -1, 229, -1, 282, -1, 283, -1, 237, + -1, 245, -1, 221, -1, 284, -1, 286, -1, 285, + -1, 287, -1, 288, -1, 289, -1, 247, -1, 261, + -1, 272, -1, 38, -1, 169, 170, -1, -1, 290, + -1, 291, -1, 292, -1, 294, -1, 293, -1, 44, + -1, 172, 173, -1, -1, 295, -1, 296, -1, 297, + -1, 298, -1, 13, 10, -1, 12, 10, -1, 76, + 10, -1, 79, 10, -1, 97, 10, -1, 14, 10, + -1, 16, 10, -1, 67, 10, -1, 15, 10, -1, + 80, 10, -1, 81, 10, -1, 31, 10, -1, 60, + 10, -1, 75, 10, -1, 17, 10, -1, 18, 10, + -1, 19, 10, -1, 20, 10, -1, 123, 10, -1, + 124, 10, -1, 125, 10, -1, 126, 10, -1, 127, + 10, -1, 77, 10, -1, 66, 10, -1, 102, 10, + -1, 122, 10, -1, 21, 10, -1, 22, 10, -1, + 23, 10, -1, 24, 10, -1, 25, 10, -1, 68, + 10, -1, 82, 10, -1, 83, 10, -1, 110, 10, + -1, 54, 10, -1, 64, 10, -1, 55, 10, -1, + 103, 10, -1, 48, 10, -1, 49, 10, -1, 50, + 10, -1, 51, 10, -1, 114, 10, -1, 118, 10, + -1, 119, 10, -1, 152, 10, -1, 115, 10, -1, + 61, 10, -1, 26, 10, -1, 27, 10, -1, 28, + 10, -1, 99, 10, -1, 133, 10, -1, 134, 10, + -1, 29, 10, -1, 30, 10, -1, 32, 10, -1, + 33, 10, -1, 35, 10, -1, 36, 10, -1, 34, + 10, -1, 135, 10, -1, 41, 10, -1, 42, 10, + -1, 43, 10, -1, 52, 10, -1, 71, 10, -1, + 120, 10, -1, 85, 10, -1, 151, 10, -1, 78, + 10, -1, 159, 10, -1, 86, 10, -1, 87, 10, + -1, 116, 10, -1, 117, 10, -1, 101, 10, -1, + 47, 10, -1, 69, 10, -1, 72, 10, 10, -1, + 53, 10, -1, 56, 10, -1, 106, 10, -1, 107, + 10, -1, 70, 10, -1, 160, 10, -1, 108, 10, + -1, 57, 10, -1, 58, 10, -1, 59, 10, -1, + 121, 10, -1, 109, 10, -1, 65, 10, -1, 112, + 10, -1, 113, 10, -1, 111, 10, -1, 161, 10, + -1, 62, 10, -1, 63, 10, -1, 84, 10, -1, + 73, 10, 10, -1, 74, 10, -1, 98, 10, -1, + 130, 10, -1, 131, 10, -1, 132, 10, -1, 136, + 10, -1, 137, 10, -1, 153, 10, -1, 155, 10, + -1, 154, 10, -1, 156, 10, 10, -1, 157, 10, + 10, -1, 158, 10, -1, 37, 10, -1, 39, 10, + -1, 40, 10, -1, 129, 10, -1, 100, 10, -1, + 37, 10, -1, 45, 10, -1, 46, 10, -1, 128, + 10, -1, 88, -1, 300, 301, -1, -1, 302, -1, + 304, -1, 303, -1, 306, -1, 307, -1, 308, -1, + 309, -1, 305, -1, 89, 10, -1, 91, 10, -1, + 90, 10, -1, 96, 10, -1, 92, 10, -1, 93, + 10, -1, 94, 10, -1, 95, 10, -1, 138, -1, + 311, 312, -1, -1, 313, -1, 314, -1, 315, -1, + 316, -1, 317, -1, 318, -1, 319, -1, 320, -1, + 321, -1, 322, -1, 323, -1, 324, -1, 139, 10, + -1, 140, 10, -1, 141, 10, -1, 142, 10, -1, + 143, 10, -1, 144, 10, -1, 145, 10, -1, 146, + 10, -1, 147, 10, -1, 148, 10, -1, 149, 10, + -1, 150, 10, -1, 104, -1, 326, 327, -1, -1, + 328, -1, 105, 10, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ @@ -910,26 +913,26 @@ static const yytype_uint16 yyrline[] = 174, 174, 175, 175, 176, 176, 176, 177, 177, 177, 178, 178, 178, 179, 179, 179, 180, 180, 180, 181, 181, 181, 182, 182, 182, 183, 183, 184, 184, 185, - 185, 185, 186, 186, 187, 187, 188, 188, 190, 202, - 203, 204, 204, 204, 204, 204, 206, 218, 219, 220, - 220, 220, 220, 222, 231, 240, 251, 260, 269, 278, - 291, 306, 315, 324, 333, 342, 351, 360, 369, 378, - 387, 396, 405, 414, 421, 428, 437, 446, 460, 469, - 478, 485, 492, 499, 507, 514, 521, 528, 535, 543, - 551, 559, 566, 573, 582, 591, 598, 605, 613, 621, - 631, 641, 654, 665, 673, 686, 695, 704, 713, 723, - 731, 744, 753, 761, 770, 778, 791, 800, 807, 817, - 827, 837, 847, 857, 867, 877, 887, 894, 901, 908, - 917, 926, 935, 942, 952, 969, 976, 994, 1007, 1020, - 1029, 1038, 1047, 1056, 1066, 1076, 1085, 1094, 1101, 1110, - 1119, 1128, 1136, 1149, 1157, 1181, 1188, 1203, 1213, 1223, - 1230, 1237, 1246, 1255, 1263, 1276, 1289, 1302, 1311, 1321, - 1328, 1335, 1344, 1354, 1364, 1371, 1378, 1387, 1392, 1393, - 1394, 1394, 1394, 1395, 1395, 1395, 1396, 1396, 1398, 1408, - 1417, 1424, 1434, 1441, 1448, 1455, 1462, 1467, 1468, 1469, - 1469, 1470, 1470, 1471, 1471, 1472, 1473, 1474, 1475, 1476, - 1477, 1479, 1487, 1494, 1502, 1510, 1517, 1524, 1533, 1542, - 1551, 1560, 1569, 1578, 1583, 1584, 1585, 1587 + 185, 185, 186, 186, 187, 187, 188, 188, 189, 191, + 203, 204, 205, 205, 205, 205, 205, 207, 219, 220, + 221, 221, 221, 221, 223, 232, 241, 252, 261, 270, + 279, 292, 307, 316, 325, 334, 343, 352, 361, 370, + 379, 388, 397, 406, 415, 422, 429, 438, 447, 461, + 470, 479, 486, 493, 500, 508, 515, 522, 529, 536, + 544, 552, 560, 567, 574, 583, 592, 599, 606, 614, + 622, 632, 642, 655, 666, 674, 687, 696, 705, 714, + 724, 732, 745, 754, 762, 771, 779, 792, 801, 808, + 818, 828, 838, 848, 858, 868, 878, 888, 895, 902, + 909, 918, 927, 936, 943, 953, 970, 977, 995, 1008, + 1021, 1030, 1039, 1048, 1057, 1067, 1077, 1086, 1095, 1102, + 1111, 1120, 1129, 1138, 1146, 1159, 1167, 1191, 1198, 1213, + 1223, 1233, 1240, 1247, 1256, 1265, 1273, 1286, 1299, 1312, + 1321, 1331, 1338, 1345, 1354, 1364, 1374, 1381, 1388, 1397, + 1402, 1403, 1404, 1404, 1404, 1405, 1405, 1405, 1406, 1406, + 1408, 1418, 1427, 1434, 1444, 1451, 1458, 1465, 1472, 1477, + 1478, 1479, 1479, 1480, 1480, 1481, 1481, 1482, 1483, 1484, + 1485, 1486, 1487, 1489, 1497, 1504, 1512, 1520, 1527, 1534, + 1543, 1552, 1561, 1570, 1579, 1588, 1593, 1594, 1595, 1597 }; #endif @@ -994,17 +997,18 @@ static const char *const yytname[] = "VAR_HARDEN_ALGO_DOWNGRADE", "VAR_IP_TRANSPARENT", "VAR_RATELIMIT", "VAR_RATELIMIT_SLABS", "VAR_RATELIMIT_SIZE", "VAR_RATELIMIT_FOR_DOMAIN", "VAR_RATELIMIT_BELOW_DOMAIN", "VAR_RATELIMIT_FACTOR", - "VAR_CAPS_WHITELIST", "VAR_CACHE_MAX_NEGATIVE_TTL", "$accept", - "toplevelvars", "toplevelvar", "serverstart", "contents_server", - "content_server", "stubstart", "contents_stub", "content_stub", - "forwardstart", "contents_forward", "content_forward", - "server_num_threads", "server_verbosity", "server_statistics_interval", - "server_statistics_cumulative", "server_extended_statistics", - "server_port", "server_interface", "server_outgoing_interface", - "server_outgoing_range", "server_outgoing_port_permit", - "server_outgoing_port_avoid", "server_outgoing_num_tcp", - "server_incoming_num_tcp", "server_interface_automatic", "server_do_ip4", - "server_do_ip6", "server_do_udp", "server_do_tcp", "server_tcp_upstream", + "VAR_CAPS_WHITELIST", "VAR_CACHE_MAX_NEGATIVE_TTL", + "VAR_PERMIT_SMALL_HOLDDOWN", "$accept", "toplevelvars", "toplevelvar", + "serverstart", "contents_server", "content_server", "stubstart", + "contents_stub", "content_stub", "forwardstart", "contents_forward", + "content_forward", "server_num_threads", "server_verbosity", + "server_statistics_interval", "server_statistics_cumulative", + "server_extended_statistics", "server_port", "server_interface", + "server_outgoing_interface", "server_outgoing_range", + "server_outgoing_port_permit", "server_outgoing_port_avoid", + "server_outgoing_num_tcp", "server_incoming_num_tcp", + "server_interface_automatic", "server_do_ip4", "server_do_ip6", + "server_do_udp", "server_do_tcp", "server_tcp_upstream", "server_ssl_upstream", "server_ssl_service_key", "server_ssl_service_pem", "server_ssl_port", "server_do_daemonize", "server_use_syslog", "server_log_time_ascii", "server_log_queries", @@ -1039,7 +1043,8 @@ static const char *const yytname[] = "server_val_clean_additional", "server_val_permissive_mode", "server_ignore_cd_flag", "server_val_log_level", "server_val_nsec3_keysize_iterations", "server_add_holddown", - "server_del_holddown", "server_keep_missing", "server_key_cache_size", + "server_del_holddown", "server_keep_missing", + "server_permit_small_holddown", "server_key_cache_size", "server_key_cache_slabs", "server_neg_cache_size", "server_local_zone", "server_local_data", "server_local_data_ptr", "server_minimal_responses", "server_rrset_roundrobin", "server_max_udp_size", "server_dns64_prefix", @@ -1085,28 +1090,28 @@ static const yytype_uint16 yytoknum[] = 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415 + 415, 416 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint16 yyr1[] = { - 0, 161, 162, 162, 163, 163, 163, 163, 163, 163, - 164, 165, 165, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 166, 166, - 166, 166, 166, 166, 166, 166, 166, 166, 167, 168, - 168, 169, 169, 169, 169, 169, 170, 171, 171, 172, - 172, 172, 172, 173, 174, 175, 176, 177, 178, 179, + 0, 162, 163, 163, 164, 164, 164, 164, 164, 164, + 165, 166, 166, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, + 167, 167, 167, 167, 167, 167, 167, 167, 167, 168, + 169, 169, 170, 170, 170, 170, 170, 171, 172, 172, + 173, 173, 173, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, @@ -1118,12 +1123,12 @@ static const yytype_uint16 yyr1[] = 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, - 290, 291, 292, 293, 294, 295, 296, 297, 298, 298, - 299, 299, 299, 299, 299, 299, 299, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 309, 310, - 310, 310, 310, 310, 310, 310, 310, 310, 310, 310, - 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 322, 323, 324, 324, 325, 326 + 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, + 300, 300, 301, 301, 301, 301, 301, 301, 301, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, + 311, 312, 312, 312, 312, 312, 312, 312, 312, 312, + 312, 312, 312, 313, 314, 315, 316, 317, 318, 319, + 320, 321, 322, 323, 324, 325, 326, 326, 327, 328 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -1141,26 +1146,26 @@ static const yytype_uint8 yyr2[] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 0, 1, 1, 1, 1, 1, 1, 2, 0, 1, - 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 3, 3, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 1, 2, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 1, 2, 0, 1, 2 + 2, 0, 1, 1, 1, 1, 1, 1, 2, 0, + 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 3, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, + 2, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 2, 0, 1, 2 }; /* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. @@ -1168,8 +1173,8 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint16 yydefact[] = { - 2, 0, 1, 10, 128, 136, 267, 313, 286, 3, - 12, 130, 138, 269, 288, 315, 4, 5, 6, 8, + 2, 0, 1, 10, 129, 137, 269, 315, 288, 3, + 12, 131, 139, 271, 290, 317, 4, 5, 6, 8, 9, 7, 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, @@ -1181,62 +1186,62 @@ static const yytype_uint16 yydefact[] = 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, 0, 0, 0, 0, 0, 0, 11, 13, 14, - 70, 73, 82, 15, 21, 61, 16, 74, 75, 32, - 54, 69, 17, 18, 19, 20, 104, 105, 106, 107, - 108, 71, 60, 86, 103, 22, 23, 24, 25, 26, - 62, 76, 77, 92, 48, 58, 49, 87, 42, 43, - 44, 45, 96, 100, 112, 119, 97, 55, 27, 28, - 29, 84, 113, 114, 30, 31, 33, 34, 36, 37, - 35, 117, 38, 39, 40, 46, 65, 101, 79, 118, - 72, 126, 80, 81, 98, 99, 85, 41, 63, 66, - 47, 50, 88, 89, 64, 127, 90, 51, 52, 53, - 102, 91, 59, 93, 94, 95, 56, 57, 78, 67, - 68, 83, 109, 110, 111, 115, 116, 120, 122, 121, - 123, 124, 125, 0, 0, 0, 0, 0, 129, 131, - 132, 133, 135, 134, 0, 0, 0, 0, 137, 139, - 140, 141, 142, 0, 0, 0, 0, 0, 0, 0, - 0, 268, 270, 272, 271, 277, 273, 274, 275, 276, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 287, 289, 290, 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, 0, 314, 316, 144, 143, - 148, 151, 149, 157, 158, 159, 160, 170, 171, 172, - 173, 174, 193, 194, 195, 199, 200, 154, 201, 202, - 205, 203, 204, 207, 208, 209, 222, 183, 184, 185, - 186, 210, 225, 179, 181, 226, 232, 233, 234, 155, - 192, 241, 242, 180, 237, 167, 150, 175, 223, 229, - 211, 0, 0, 245, 156, 145, 166, 215, 146, 152, - 153, 176, 177, 243, 213, 217, 218, 147, 246, 196, - 221, 168, 182, 227, 228, 231, 236, 178, 240, 238, - 239, 187, 191, 219, 220, 188, 189, 212, 235, 169, - 161, 162, 163, 164, 165, 247, 248, 249, 197, 198, - 206, 250, 251, 214, 190, 252, 254, 253, 0, 0, - 257, 216, 230, 258, 259, 260, 262, 261, 263, 264, - 265, 266, 278, 280, 279, 282, 283, 284, 285, 281, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 317, 224, 244, 255, 256 + 0, 0, 0, 0, 0, 0, 0, 0, 11, 13, + 14, 70, 73, 82, 15, 21, 61, 16, 74, 75, + 32, 54, 69, 17, 18, 19, 20, 104, 105, 106, + 107, 108, 71, 60, 86, 103, 22, 23, 24, 25, + 26, 62, 76, 77, 92, 48, 58, 49, 87, 42, + 43, 44, 45, 96, 100, 112, 119, 97, 55, 27, + 28, 29, 84, 113, 114, 30, 31, 33, 34, 36, + 37, 35, 117, 38, 39, 40, 46, 65, 101, 79, + 118, 72, 126, 80, 81, 98, 99, 85, 41, 63, + 66, 47, 50, 88, 89, 64, 127, 90, 51, 52, + 53, 102, 91, 59, 93, 94, 95, 128, 56, 57, + 78, 67, 68, 83, 109, 110, 111, 115, 116, 120, + 122, 121, 123, 124, 125, 0, 0, 0, 0, 0, + 130, 132, 133, 134, 136, 135, 0, 0, 0, 0, + 138, 140, 141, 142, 143, 0, 0, 0, 0, 0, + 0, 0, 0, 270, 272, 274, 273, 279, 275, 276, + 277, 278, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 289, 291, 292, 293, 294, 295, + 296, 297, 298, 299, 300, 301, 302, 0, 316, 318, + 145, 144, 149, 152, 150, 158, 159, 160, 161, 171, + 172, 173, 174, 175, 194, 195, 196, 200, 201, 155, + 202, 203, 206, 204, 205, 208, 209, 210, 223, 184, + 185, 186, 187, 211, 226, 180, 182, 227, 233, 234, + 235, 156, 193, 243, 244, 181, 238, 168, 151, 176, + 224, 230, 212, 0, 0, 247, 157, 146, 167, 216, + 147, 153, 154, 177, 178, 245, 214, 218, 219, 148, + 248, 197, 222, 169, 183, 228, 229, 232, 237, 179, + 241, 239, 240, 188, 192, 220, 221, 189, 190, 213, + 236, 170, 162, 163, 164, 165, 166, 249, 250, 251, + 198, 199, 207, 252, 253, 215, 191, 254, 256, 255, + 0, 0, 259, 217, 231, 242, 260, 261, 262, 264, + 263, 265, 266, 267, 268, 280, 282, 281, 284, 285, + 286, 287, 283, 303, 304, 305, 306, 307, 308, 309, + 310, 311, 312, 313, 314, 319, 225, 246, 257, 258 }; /* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 1, 9, 10, 16, 137, 11, 17, 258, 12, - 18, 268, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, 251, 252, 259, 260, 261, - 262, 263, 269, 270, 271, 272, 13, 19, 281, 282, - 283, 284, 285, 286, 287, 288, 289, 14, 20, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 15, 21, 316, 317 + -1, 1, 9, 10, 16, 138, 11, 17, 260, 12, + 18, 270, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 261, 262, + 263, 264, 265, 271, 272, 273, 274, 13, 19, 283, + 284, 285, 286, 287, 288, 289, 290, 291, 14, 20, + 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 15, 21, 318, 319 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing @@ -1247,17 +1252,17 @@ static const yytype_int16 yypact[] = -81, 116, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -12, 89, 47, -13, 22, -80, 16, 17, 18, 23, 24, 78, 107, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 139, 140, - 141, 142, 143, 145, 146, 147, 148, 149, 163, 164, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 195, 196, 197, - 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 209, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 245, 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, -81, -81, -81, + 121, 122, 123, 124, 125, 126, 127, 128, 140, 141, + 142, 143, 145, 146, 147, 148, 149, 163, 164, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 195, 196, 197, 198, + 199, 200, 201, 202, 203, 204, 205, 206, 207, 209, + 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, + 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, + 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, + 241, 242, 243, 245, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, @@ -1269,28 +1274,28 @@ static const yytype_int16 yypact[] = -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, 258, 259, 260, 261, 262, -81, -81, - -81, -81, -81, -81, 263, 264, 265, 266, -81, -81, - -81, -81, -81, 267, 268, 269, 270, 271, 272, 273, - 274, -81, -81, -81, -81, -81, -81, -81, -81, -81, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, 287, -81, -81, -81, -81, + -81, -81, -81, -81, -81, 260, 261, 262, 263, 264, + -81, -81, -81, -81, -81, -81, 265, 266, 267, 268, + -81, -81, -81, -81, -81, 269, 270, 271, 272, 273, + 274, 275, 276, -81, -81, -81, -81, -81, -81, -81, + -81, -81, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, -81, -81, -81, -81, -81, -81, + -81, -81, -81, -81, -81, -81, -81, 289, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, 288, 289, -81, -81, -81, -81, -81, -81, -81, + -81, -81, -81, 290, 291, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, 290, 291, + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, + 292, 293, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81 + -81, -81, -81, -81, -81, -81, -81, -81, -81, -81 }; /* YYPGOTO[NTERM-NUM]. */ @@ -1312,7 +1317,7 @@ static const yytype_int8 yypgoto[] = -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81 + -81, -81, -81, -81, -81, -81, -81 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If @@ -1323,35 +1328,35 @@ static const yytype_uint16 yytable[] = { 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 315, 318, 319, 320, 47, - 48, 49, 0, 321, 322, 50, 51, 52, 53, 54, + 42, 43, 44, 45, 46, 317, 320, 321, 322, 47, + 48, 49, 0, 323, 324, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 273, 274, 275, 276, - 277, 278, 279, 280, 264, 91, 92, 93, 323, 94, - 95, 96, 265, 266, 97, 98, 99, 100, 101, 102, + 85, 86, 87, 88, 89, 90, 275, 276, 277, 278, + 279, 280, 281, 282, 266, 91, 92, 93, 325, 94, + 95, 96, 267, 268, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 2, 324, 119, 120, - 121, 122, 123, 124, 125, 126, 253, 3, 254, 255, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 334, - 335, 336, 337, 338, 4, 339, 340, 341, 342, 343, - 5, 290, 291, 292, 293, 294, 295, 296, 297, 298, - 299, 300, 301, 344, 345, 267, 346, 347, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 256, - 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, - 369, 370, 371, 372, 6, 373, 374, 375, 376, 377, - 378, 379, 380, 381, 382, 383, 384, 385, 257, 386, - 7, 387, 388, 389, 390, 391, 392, 393, 394, 395, - 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, - 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 8, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, - 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, - 465, 466 + 113, 114, 115, 116, 117, 118, 2, 326, 119, 120, + 121, 122, 123, 124, 125, 126, 255, 3, 256, 257, + 327, 328, 329, 330, 331, 332, 333, 334, 335, 127, + 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 336, 337, 338, 339, 4, 340, 341, 342, 343, 344, + 5, 292, 293, 294, 295, 296, 297, 298, 299, 300, + 301, 302, 303, 345, 346, 269, 347, 348, 349, 350, + 351, 352, 353, 354, 355, 356, 357, 358, 359, 258, + 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 6, 374, 375, 376, 377, 378, + 379, 380, 381, 382, 383, 384, 385, 386, 259, 387, + 7, 388, 389, 390, 391, 392, 393, 394, 395, 396, + 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, + 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, + 417, 418, 419, 420, 8, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, + 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, + 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, + 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, + 466, 467, 468, 469 }; #define yypact_value_is_default(Yystate) \ @@ -1376,7 +1381,7 @@ static const yytype_int16 yycheck[] = 122, 123, 124, 125, 126, 127, 0, 10, 130, 131, 132, 133, 134, 135, 136, 137, 37, 11, 39, 40, 10, 10, 10, 10, 10, 10, 10, 10, 10, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 10, + 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 10, 10, 10, 10, 38, 10, 10, 10, 10, 10, 44, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 10, 10, 128, 10, 10, 10, 10, @@ -1392,16 +1397,16 @@ static const yytype_int16 yycheck[] = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10 + 10, 10, 10, 10 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint16 yystos[] = { - 0, 162, 0, 11, 38, 44, 88, 104, 138, 163, - 164, 167, 170, 297, 308, 323, 165, 168, 171, 298, - 309, 324, 12, 13, 14, 15, 16, 17, 18, 19, + 0, 163, 0, 11, 38, 44, 88, 104, 138, 164, + 165, 168, 171, 299, 310, 325, 166, 169, 172, 300, + 311, 326, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 41, 42, 43, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, @@ -1412,7 +1417,7 @@ static const yytype_uint16 yystos[] = 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 130, 131, 132, 133, 134, 135, 136, 137, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 166, 173, 174, + 154, 155, 156, 157, 158, 159, 160, 161, 167, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, @@ -1424,13 +1429,13 @@ static const yytype_uint16 yystos[] = 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 37, 39, 40, 100, 129, 169, 288, - 289, 290, 291, 292, 37, 45, 46, 128, 172, 293, - 294, 295, 296, 89, 90, 91, 92, 93, 94, 95, - 96, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 105, 325, 326, 10, 10, + 285, 286, 287, 288, 289, 37, 39, 40, 100, 129, + 170, 290, 291, 292, 293, 294, 37, 45, 46, 128, + 173, 295, 296, 297, 298, 89, 90, 91, 92, 93, + 94, 95, 96, 301, 302, 303, 304, 305, 306, 307, + 308, 309, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 312, 313, 314, 315, 316, 317, + 318, 319, 320, 321, 322, 323, 324, 105, 327, 328, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, @@ -1445,7 +1450,7 @@ static const yytype_uint16 yystos[] = 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10 + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 }; #define yyerrok (yyerrstatus = 0) @@ -2253,9 +2258,9 @@ yyreduce: } break; - case 128: + case 129: /* Line 1792 of yacc.c */ -#line 191 "./util/configparser.y" +#line 192 "./util/configparser.y" { struct config_stub* s; OUTYY(("\nP(stub_zone:)\n")); @@ -2268,9 +2273,9 @@ yyreduce: } break; - case 136: + case 137: /* Line 1792 of yacc.c */ -#line 207 "./util/configparser.y" +#line 208 "./util/configparser.y" { struct config_stub* s; OUTYY(("\nP(forward_zone:)\n")); @@ -2283,9 +2288,9 @@ yyreduce: } break; - case 143: + case 144: /* Line 1792 of yacc.c */ -#line 223 "./util/configparser.y" +#line 224 "./util/configparser.y" { OUTYY(("P(server_num_threads:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -2295,9 +2300,9 @@ yyreduce: } break; - case 144: + case 145: /* Line 1792 of yacc.c */ -#line 232 "./util/configparser.y" +#line 233 "./util/configparser.y" { OUTYY(("P(server_verbosity:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -2307,9 +2312,9 @@ yyreduce: } break; - case 145: + case 146: /* Line 1792 of yacc.c */ -#line 241 "./util/configparser.y" +#line 242 "./util/configparser.y" { OUTYY(("P(server_statistics_interval:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "") == 0 || strcmp((yyvsp[(2) - (2)].str), "0") == 0) @@ -2321,9 +2326,9 @@ yyreduce: } break; - case 146: + case 147: /* Line 1792 of yacc.c */ -#line 252 "./util/configparser.y" +#line 253 "./util/configparser.y" { OUTYY(("P(server_statistics_cumulative:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2333,9 +2338,9 @@ yyreduce: } break; - case 147: + case 148: /* Line 1792 of yacc.c */ -#line 261 "./util/configparser.y" +#line 262 "./util/configparser.y" { OUTYY(("P(server_extended_statistics:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2345,9 +2350,9 @@ yyreduce: } break; - case 148: + case 149: /* Line 1792 of yacc.c */ -#line 270 "./util/configparser.y" +#line 271 "./util/configparser.y" { OUTYY(("P(server_port:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -2357,9 +2362,9 @@ yyreduce: } break; - case 149: + case 150: /* Line 1792 of yacc.c */ -#line 279 "./util/configparser.y" +#line 280 "./util/configparser.y" { OUTYY(("P(server_interface:%s)\n", (yyvsp[(2) - (2)].str))); if(cfg_parser->cfg->num_ifs == 0) @@ -2373,9 +2378,9 @@ yyreduce: } break; - case 150: + case 151: /* Line 1792 of yacc.c */ -#line 292 "./util/configparser.y" +#line 293 "./util/configparser.y" { OUTYY(("P(server_outgoing_interface:%s)\n", (yyvsp[(2) - (2)].str))); if(cfg_parser->cfg->num_out_ifs == 0) @@ -2391,9 +2396,9 @@ yyreduce: } break; - case 151: + case 152: /* Line 1792 of yacc.c */ -#line 307 "./util/configparser.y" +#line 308 "./util/configparser.y" { OUTYY(("P(server_outgoing_range:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -2403,9 +2408,9 @@ yyreduce: } break; - case 152: + case 153: /* Line 1792 of yacc.c */ -#line 316 "./util/configparser.y" +#line 317 "./util/configparser.y" { OUTYY(("P(server_outgoing_port_permit:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_mark_ports((yyvsp[(2) - (2)].str), 1, @@ -2415,9 +2420,9 @@ yyreduce: } break; - case 153: + case 154: /* Line 1792 of yacc.c */ -#line 325 "./util/configparser.y" +#line 326 "./util/configparser.y" { OUTYY(("P(server_outgoing_port_avoid:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_mark_ports((yyvsp[(2) - (2)].str), 0, @@ -2427,9 +2432,9 @@ yyreduce: } break; - case 154: + case 155: /* Line 1792 of yacc.c */ -#line 334 "./util/configparser.y" +#line 335 "./util/configparser.y" { OUTYY(("P(server_outgoing_num_tcp:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -2439,9 +2444,9 @@ yyreduce: } break; - case 155: + case 156: /* Line 1792 of yacc.c */ -#line 343 "./util/configparser.y" +#line 344 "./util/configparser.y" { OUTYY(("P(server_incoming_num_tcp:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -2451,9 +2456,9 @@ yyreduce: } break; - case 156: + case 157: /* Line 1792 of yacc.c */ -#line 352 "./util/configparser.y" +#line 353 "./util/configparser.y" { OUTYY(("P(server_interface_automatic:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2463,9 +2468,9 @@ yyreduce: } break; - case 157: + case 158: /* Line 1792 of yacc.c */ -#line 361 "./util/configparser.y" +#line 362 "./util/configparser.y" { OUTYY(("P(server_do_ip4:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2475,9 +2480,9 @@ yyreduce: } break; - case 158: + case 159: /* Line 1792 of yacc.c */ -#line 370 "./util/configparser.y" +#line 371 "./util/configparser.y" { OUTYY(("P(server_do_ip6:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2487,9 +2492,9 @@ yyreduce: } break; - case 159: + case 160: /* Line 1792 of yacc.c */ -#line 379 "./util/configparser.y" +#line 380 "./util/configparser.y" { OUTYY(("P(server_do_udp:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2499,9 +2504,9 @@ yyreduce: } break; - case 160: + case 161: /* Line 1792 of yacc.c */ -#line 388 "./util/configparser.y" +#line 389 "./util/configparser.y" { OUTYY(("P(server_do_tcp:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2511,9 +2516,9 @@ yyreduce: } break; - case 161: + case 162: /* Line 1792 of yacc.c */ -#line 397 "./util/configparser.y" +#line 398 "./util/configparser.y" { OUTYY(("P(server_tcp_upstream:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2523,9 +2528,9 @@ yyreduce: } break; - case 162: + case 163: /* Line 1792 of yacc.c */ -#line 406 "./util/configparser.y" +#line 407 "./util/configparser.y" { OUTYY(("P(server_ssl_upstream:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2535,9 +2540,9 @@ yyreduce: } break; - case 163: + case 164: /* Line 1792 of yacc.c */ -#line 415 "./util/configparser.y" +#line 416 "./util/configparser.y" { OUTYY(("P(server_ssl_service_key:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->ssl_service_key); @@ -2545,9 +2550,9 @@ yyreduce: } break; - case 164: + case 165: /* Line 1792 of yacc.c */ -#line 422 "./util/configparser.y" +#line 423 "./util/configparser.y" { OUTYY(("P(server_ssl_service_pem:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->ssl_service_pem); @@ -2555,9 +2560,9 @@ yyreduce: } break; - case 165: + case 166: /* Line 1792 of yacc.c */ -#line 429 "./util/configparser.y" +#line 430 "./util/configparser.y" { OUTYY(("P(server_ssl_port:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -2567,9 +2572,9 @@ yyreduce: } break; - case 166: + case 167: /* Line 1792 of yacc.c */ -#line 438 "./util/configparser.y" +#line 439 "./util/configparser.y" { OUTYY(("P(server_do_daemonize:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2579,9 +2584,9 @@ yyreduce: } break; - case 167: + case 168: /* Line 1792 of yacc.c */ -#line 447 "./util/configparser.y" +#line 448 "./util/configparser.y" { OUTYY(("P(server_use_syslog:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2596,9 +2601,9 @@ yyreduce: } break; - case 168: + case 169: /* Line 1792 of yacc.c */ -#line 461 "./util/configparser.y" +#line 462 "./util/configparser.y" { OUTYY(("P(server_log_time_ascii:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2608,9 +2613,9 @@ yyreduce: } break; - case 169: + case 170: /* Line 1792 of yacc.c */ -#line 470 "./util/configparser.y" +#line 471 "./util/configparser.y" { OUTYY(("P(server_log_queries:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2620,9 +2625,9 @@ yyreduce: } break; - case 170: + case 171: /* Line 1792 of yacc.c */ -#line 479 "./util/configparser.y" +#line 480 "./util/configparser.y" { OUTYY(("P(server_chroot:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->chrootdir); @@ -2630,9 +2635,9 @@ yyreduce: } break; - case 171: + case 172: /* Line 1792 of yacc.c */ -#line 486 "./util/configparser.y" +#line 487 "./util/configparser.y" { OUTYY(("P(server_username:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->username); @@ -2640,9 +2645,9 @@ yyreduce: } break; - case 172: + case 173: /* Line 1792 of yacc.c */ -#line 493 "./util/configparser.y" +#line 494 "./util/configparser.y" { OUTYY(("P(server_directory:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->directory); @@ -2650,9 +2655,9 @@ yyreduce: } break; - case 173: + case 174: /* Line 1792 of yacc.c */ -#line 500 "./util/configparser.y" +#line 501 "./util/configparser.y" { OUTYY(("P(server_logfile:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->logfile); @@ -2661,9 +2666,9 @@ yyreduce: } break; - case 174: + case 175: /* Line 1792 of yacc.c */ -#line 508 "./util/configparser.y" +#line 509 "./util/configparser.y" { OUTYY(("P(server_pidfile:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->pidfile); @@ -2671,9 +2676,9 @@ yyreduce: } break; - case 175: + case 176: /* Line 1792 of yacc.c */ -#line 515 "./util/configparser.y" +#line 516 "./util/configparser.y" { OUTYY(("P(server_root_hints:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->root_hints, (yyvsp[(2) - (2)].str))) @@ -2681,9 +2686,9 @@ yyreduce: } break; - case 176: + case 177: /* Line 1792 of yacc.c */ -#line 522 "./util/configparser.y" +#line 523 "./util/configparser.y" { OUTYY(("P(server_dlv_anchor_file:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->dlv_anchor_file); @@ -2691,9 +2696,9 @@ yyreduce: } break; - case 177: + case 178: /* Line 1792 of yacc.c */ -#line 529 "./util/configparser.y" +#line 530 "./util/configparser.y" { OUTYY(("P(server_dlv_anchor:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->dlv_anchor_list, (yyvsp[(2) - (2)].str))) @@ -2701,9 +2706,9 @@ yyreduce: } break; - case 178: + case 179: /* Line 1792 of yacc.c */ -#line 536 "./util/configparser.y" +#line 537 "./util/configparser.y" { OUTYY(("P(server_auto_trust_anchor_file:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg-> @@ -2712,9 +2717,9 @@ yyreduce: } break; - case 179: + case 180: /* Line 1792 of yacc.c */ -#line 544 "./util/configparser.y" +#line 545 "./util/configparser.y" { OUTYY(("P(server_trust_anchor_file:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg-> @@ -2723,9 +2728,9 @@ yyreduce: } break; - case 180: + case 181: /* Line 1792 of yacc.c */ -#line 552 "./util/configparser.y" +#line 553 "./util/configparser.y" { OUTYY(("P(server_trusted_keys_file:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg-> @@ -2734,9 +2739,9 @@ yyreduce: } break; - case 181: + case 182: /* Line 1792 of yacc.c */ -#line 560 "./util/configparser.y" +#line 561 "./util/configparser.y" { OUTYY(("P(server_trust_anchor:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->trust_anchor_list, (yyvsp[(2) - (2)].str))) @@ -2744,9 +2749,9 @@ yyreduce: } break; - case 182: + case 183: /* Line 1792 of yacc.c */ -#line 567 "./util/configparser.y" +#line 568 "./util/configparser.y" { OUTYY(("P(server_domain_insecure:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->domain_insecure, (yyvsp[(2) - (2)].str))) @@ -2754,9 +2759,9 @@ yyreduce: } break; - case 183: + case 184: /* Line 1792 of yacc.c */ -#line 574 "./util/configparser.y" +#line 575 "./util/configparser.y" { OUTYY(("P(server_hide_identity:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2766,9 +2771,9 @@ yyreduce: } break; - case 184: + case 185: /* Line 1792 of yacc.c */ -#line 583 "./util/configparser.y" +#line 584 "./util/configparser.y" { OUTYY(("P(server_hide_version:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2778,9 +2783,9 @@ yyreduce: } break; - case 185: + case 186: /* Line 1792 of yacc.c */ -#line 592 "./util/configparser.y" +#line 593 "./util/configparser.y" { OUTYY(("P(server_identity:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->identity); @@ -2788,9 +2793,9 @@ yyreduce: } break; - case 186: + case 187: /* Line 1792 of yacc.c */ -#line 599 "./util/configparser.y" +#line 600 "./util/configparser.y" { OUTYY(("P(server_version:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->version); @@ -2798,9 +2803,9 @@ yyreduce: } break; - case 187: + case 188: /* Line 1792 of yacc.c */ -#line 606 "./util/configparser.y" +#line 607 "./util/configparser.y" { OUTYY(("P(server_so_rcvbuf:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->so_rcvbuf)) @@ -2809,9 +2814,9 @@ yyreduce: } break; - case 188: + case 189: /* Line 1792 of yacc.c */ -#line 614 "./util/configparser.y" +#line 615 "./util/configparser.y" { OUTYY(("P(server_so_sndbuf:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->so_sndbuf)) @@ -2820,9 +2825,9 @@ yyreduce: } break; - case 189: + case 190: /* Line 1792 of yacc.c */ -#line 622 "./util/configparser.y" +#line 623 "./util/configparser.y" { OUTYY(("P(server_so_reuseport:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2833,9 +2838,9 @@ yyreduce: } break; - case 190: + case 191: /* Line 1792 of yacc.c */ -#line 632 "./util/configparser.y" +#line 633 "./util/configparser.y" { OUTYY(("P(server_ip_transparent:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2846,9 +2851,9 @@ yyreduce: } break; - case 191: + case 192: /* Line 1792 of yacc.c */ -#line 642 "./util/configparser.y" +#line 643 "./util/configparser.y" { OUTYY(("P(server_edns_buffer_size:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -2862,9 +2867,9 @@ yyreduce: } break; - case 192: + case 193: /* Line 1792 of yacc.c */ -#line 655 "./util/configparser.y" +#line 656 "./util/configparser.y" { OUTYY(("P(server_msg_buffer_size:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -2876,9 +2881,9 @@ yyreduce: } break; - case 193: + case 194: /* Line 1792 of yacc.c */ -#line 666 "./util/configparser.y" +#line 667 "./util/configparser.y" { OUTYY(("P(server_msg_cache_size:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->msg_cache_size)) @@ -2887,9 +2892,9 @@ yyreduce: } break; - case 194: + case 195: /* Line 1792 of yacc.c */ -#line 674 "./util/configparser.y" +#line 675 "./util/configparser.y" { OUTYY(("P(server_msg_cache_slabs:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -2903,9 +2908,9 @@ yyreduce: } break; - case 195: + case 196: /* Line 1792 of yacc.c */ -#line 687 "./util/configparser.y" +#line 688 "./util/configparser.y" { OUTYY(("P(server_num_queries_per_thread:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -2915,9 +2920,9 @@ yyreduce: } break; - case 196: + case 197: /* Line 1792 of yacc.c */ -#line 696 "./util/configparser.y" +#line 697 "./util/configparser.y" { OUTYY(("P(server_jostle_timeout:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -2927,9 +2932,9 @@ yyreduce: } break; - case 197: + case 198: /* Line 1792 of yacc.c */ -#line 705 "./util/configparser.y" +#line 706 "./util/configparser.y" { OUTYY(("P(server_delay_close:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -2939,9 +2944,9 @@ yyreduce: } break; - case 198: + case 199: /* Line 1792 of yacc.c */ -#line 714 "./util/configparser.y" +#line 715 "./util/configparser.y" { OUTYY(("P(server_unblock_lan_zones:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -2952,9 +2957,9 @@ yyreduce: } break; - case 199: + case 200: /* Line 1792 of yacc.c */ -#line 724 "./util/configparser.y" +#line 725 "./util/configparser.y" { OUTYY(("P(server_rrset_cache_size:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->rrset_cache_size)) @@ -2963,9 +2968,9 @@ yyreduce: } break; - case 200: + case 201: /* Line 1792 of yacc.c */ -#line 732 "./util/configparser.y" +#line 733 "./util/configparser.y" { OUTYY(("P(server_rrset_cache_slabs:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -2979,9 +2984,9 @@ yyreduce: } break; - case 201: + case 202: /* Line 1792 of yacc.c */ -#line 745 "./util/configparser.y" +#line 746 "./util/configparser.y" { OUTYY(("P(server_infra_host_ttl:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -2991,9 +2996,9 @@ yyreduce: } break; - case 202: + case 203: /* Line 1792 of yacc.c */ -#line 754 "./util/configparser.y" +#line 755 "./util/configparser.y" { OUTYY(("P(server_infra_lame_ttl:%s)\n", (yyvsp[(2) - (2)].str))); verbose(VERB_DETAIL, "ignored infra-lame-ttl: %s (option " @@ -3002,9 +3007,9 @@ yyreduce: } break; - case 203: + case 204: /* Line 1792 of yacc.c */ -#line 762 "./util/configparser.y" +#line 763 "./util/configparser.y" { OUTYY(("P(server_infra_cache_numhosts:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -3014,9 +3019,9 @@ yyreduce: } break; - case 204: + case 205: /* Line 1792 of yacc.c */ -#line 771 "./util/configparser.y" +#line 772 "./util/configparser.y" { OUTYY(("P(server_infra_cache_lame_size:%s)\n", (yyvsp[(2) - (2)].str))); verbose(VERB_DETAIL, "ignored infra-cache-lame-size: %s " @@ -3025,9 +3030,9 @@ yyreduce: } break; - case 205: + case 206: /* Line 1792 of yacc.c */ -#line 779 "./util/configparser.y" +#line 780 "./util/configparser.y" { OUTYY(("P(server_infra_cache_slabs:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -3041,9 +3046,9 @@ yyreduce: } break; - case 206: + case 207: /* Line 1792 of yacc.c */ -#line 792 "./util/configparser.y" +#line 793 "./util/configparser.y" { OUTYY(("P(server_infra_cache_min_rtt:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3053,9 +3058,9 @@ yyreduce: } break; - case 207: + case 208: /* Line 1792 of yacc.c */ -#line 801 "./util/configparser.y" +#line 802 "./util/configparser.y" { OUTYY(("P(server_target_fetch_policy:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->target_fetch_policy); @@ -3063,9 +3068,9 @@ yyreduce: } break; - case 208: + case 209: /* Line 1792 of yacc.c */ -#line 808 "./util/configparser.y" +#line 809 "./util/configparser.y" { OUTYY(("P(server_harden_short_bufsize:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3076,9 +3081,9 @@ yyreduce: } break; - case 209: + case 210: /* Line 1792 of yacc.c */ -#line 818 "./util/configparser.y" +#line 819 "./util/configparser.y" { OUTYY(("P(server_harden_large_queries:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3089,9 +3094,9 @@ yyreduce: } break; - case 210: + case 211: /* Line 1792 of yacc.c */ -#line 828 "./util/configparser.y" +#line 829 "./util/configparser.y" { OUTYY(("P(server_harden_glue:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3102,9 +3107,9 @@ yyreduce: } break; - case 211: + case 212: /* Line 1792 of yacc.c */ -#line 838 "./util/configparser.y" +#line 839 "./util/configparser.y" { OUTYY(("P(server_harden_dnssec_stripped:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3115,9 +3120,9 @@ yyreduce: } break; - case 212: + case 213: /* Line 1792 of yacc.c */ -#line 848 "./util/configparser.y" +#line 849 "./util/configparser.y" { OUTYY(("P(server_harden_below_nxdomain:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3128,9 +3133,9 @@ yyreduce: } break; - case 213: + case 214: /* Line 1792 of yacc.c */ -#line 858 "./util/configparser.y" +#line 859 "./util/configparser.y" { OUTYY(("P(server_harden_referral_path:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3141,9 +3146,9 @@ yyreduce: } break; - case 214: + case 215: /* Line 1792 of yacc.c */ -#line 868 "./util/configparser.y" +#line 869 "./util/configparser.y" { OUTYY(("P(server_harden_algo_downgrade:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3154,9 +3159,9 @@ yyreduce: } break; - case 215: + case 216: /* Line 1792 of yacc.c */ -#line 878 "./util/configparser.y" +#line 879 "./util/configparser.y" { OUTYY(("P(server_use_caps_for_id:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3167,9 +3172,9 @@ yyreduce: } break; - case 216: + case 217: /* Line 1792 of yacc.c */ -#line 888 "./util/configparser.y" +#line 889 "./util/configparser.y" { OUTYY(("P(server_caps_whitelist:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->caps_whitelist, (yyvsp[(2) - (2)].str))) @@ -3177,9 +3182,9 @@ yyreduce: } break; - case 217: + case 218: /* Line 1792 of yacc.c */ -#line 895 "./util/configparser.y" +#line 896 "./util/configparser.y" { OUTYY(("P(server_private_address:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->private_address, (yyvsp[(2) - (2)].str))) @@ -3187,9 +3192,9 @@ yyreduce: } break; - case 218: + case 219: /* Line 1792 of yacc.c */ -#line 902 "./util/configparser.y" +#line 903 "./util/configparser.y" { OUTYY(("P(server_private_domain:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->private_domain, (yyvsp[(2) - (2)].str))) @@ -3197,9 +3202,9 @@ yyreduce: } break; - case 219: + case 220: /* Line 1792 of yacc.c */ -#line 909 "./util/configparser.y" +#line 910 "./util/configparser.y" { OUTYY(("P(server_prefetch:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3209,9 +3214,9 @@ yyreduce: } break; - case 220: + case 221: /* Line 1792 of yacc.c */ -#line 918 "./util/configparser.y" +#line 919 "./util/configparser.y" { OUTYY(("P(server_prefetch_key:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3221,9 +3226,9 @@ yyreduce: } break; - case 221: + case 222: /* Line 1792 of yacc.c */ -#line 927 "./util/configparser.y" +#line 928 "./util/configparser.y" { OUTYY(("P(server_unwanted_reply_threshold:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3233,9 +3238,9 @@ yyreduce: } break; - case 222: + case 223: /* Line 1792 of yacc.c */ -#line 936 "./util/configparser.y" +#line 937 "./util/configparser.y" { OUTYY(("P(server_do_not_query_address:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->donotqueryaddrs, (yyvsp[(2) - (2)].str))) @@ -3243,9 +3248,9 @@ yyreduce: } break; - case 223: + case 224: /* Line 1792 of yacc.c */ -#line 943 "./util/configparser.y" +#line 944 "./util/configparser.y" { OUTYY(("P(server_do_not_query_localhost:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3256,9 +3261,9 @@ yyreduce: } break; - case 224: + case 225: /* Line 1792 of yacc.c */ -#line 953 "./util/configparser.y" +#line 954 "./util/configparser.y" { OUTYY(("P(server_access_control:%s %s)\n", (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str))); if(strcmp((yyvsp[(3) - (3)].str), "deny")!=0 && strcmp((yyvsp[(3) - (3)].str), "refuse")!=0 && @@ -3276,9 +3281,9 @@ yyreduce: } break; - case 225: + case 226: /* Line 1792 of yacc.c */ -#line 970 "./util/configparser.y" +#line 971 "./util/configparser.y" { OUTYY(("P(server_module_conf:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->module_conf); @@ -3286,9 +3291,9 @@ yyreduce: } break; - case 226: + case 227: /* Line 1792 of yacc.c */ -#line 977 "./util/configparser.y" +#line 978 "./util/configparser.y" { OUTYY(("P(server_val_override_date:%s)\n", (yyvsp[(2) - (2)].str))); if(strlen((yyvsp[(2) - (2)].str)) == 0 || strcmp((yyvsp[(2) - (2)].str), "0") == 0) { @@ -3307,9 +3312,9 @@ yyreduce: } break; - case 227: + case 228: /* Line 1792 of yacc.c */ -#line 995 "./util/configparser.y" +#line 996 "./util/configparser.y" { OUTYY(("P(server_val_sig_skew_min:%s)\n", (yyvsp[(2) - (2)].str))); if(strlen((yyvsp[(2) - (2)].str)) == 0 || strcmp((yyvsp[(2) - (2)].str), "0") == 0) { @@ -3323,9 +3328,9 @@ yyreduce: } break; - case 228: + case 229: /* Line 1792 of yacc.c */ -#line 1008 "./util/configparser.y" +#line 1009 "./util/configparser.y" { OUTYY(("P(server_val_sig_skew_max:%s)\n", (yyvsp[(2) - (2)].str))); if(strlen((yyvsp[(2) - (2)].str)) == 0 || strcmp((yyvsp[(2) - (2)].str), "0") == 0) { @@ -3339,9 +3344,9 @@ yyreduce: } break; - case 229: + case 230: /* Line 1792 of yacc.c */ -#line 1021 "./util/configparser.y" +#line 1022 "./util/configparser.y" { OUTYY(("P(server_cache_max_ttl:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3351,9 +3356,9 @@ yyreduce: } break; - case 230: + case 231: /* Line 1792 of yacc.c */ -#line 1030 "./util/configparser.y" +#line 1031 "./util/configparser.y" { OUTYY(("P(server_cache_max_negative_ttl:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3363,9 +3368,9 @@ yyreduce: } break; - case 231: + case 232: /* Line 1792 of yacc.c */ -#line 1039 "./util/configparser.y" +#line 1040 "./util/configparser.y" { OUTYY(("P(server_cache_min_ttl:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3375,9 +3380,9 @@ yyreduce: } break; - case 232: + case 233: /* Line 1792 of yacc.c */ -#line 1048 "./util/configparser.y" +#line 1049 "./util/configparser.y" { OUTYY(("P(server_bogus_ttl:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3387,9 +3392,9 @@ yyreduce: } break; - case 233: + case 234: /* Line 1792 of yacc.c */ -#line 1057 "./util/configparser.y" +#line 1058 "./util/configparser.y" { OUTYY(("P(server_val_clean_additional:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3400,9 +3405,9 @@ yyreduce: } break; - case 234: + case 235: /* Line 1792 of yacc.c */ -#line 1067 "./util/configparser.y" +#line 1068 "./util/configparser.y" { OUTYY(("P(server_val_permissive_mode:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3413,9 +3418,9 @@ yyreduce: } break; - case 235: + case 236: /* Line 1792 of yacc.c */ -#line 1077 "./util/configparser.y" +#line 1078 "./util/configparser.y" { OUTYY(("P(server_ignore_cd_flag:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3425,9 +3430,9 @@ yyreduce: } break; - case 236: + case 237: /* Line 1792 of yacc.c */ -#line 1086 "./util/configparser.y" +#line 1087 "./util/configparser.y" { OUTYY(("P(server_val_log_level:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3437,9 +3442,9 @@ yyreduce: } break; - case 237: + case 238: /* Line 1792 of yacc.c */ -#line 1095 "./util/configparser.y" +#line 1096 "./util/configparser.y" { OUTYY(("P(server_val_nsec3_keysize_iterations:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->val_nsec3_key_iterations); @@ -3447,9 +3452,9 @@ yyreduce: } break; - case 238: + case 239: /* Line 1792 of yacc.c */ -#line 1102 "./util/configparser.y" +#line 1103 "./util/configparser.y" { OUTYY(("P(server_add_holddown:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3459,9 +3464,9 @@ yyreduce: } break; - case 239: + case 240: /* Line 1792 of yacc.c */ -#line 1111 "./util/configparser.y" +#line 1112 "./util/configparser.y" { OUTYY(("P(server_del_holddown:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3471,9 +3476,9 @@ yyreduce: } break; - case 240: + case 241: /* Line 1792 of yacc.c */ -#line 1120 "./util/configparser.y" +#line 1121 "./util/configparser.y" { OUTYY(("P(server_keep_missing:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3483,9 +3488,22 @@ yyreduce: } break; - case 241: + case 242: /* Line 1792 of yacc.c */ -#line 1129 "./util/configparser.y" +#line 1130 "./util/configparser.y" + { + OUTYY(("P(server_permit_small_holddown:%s)\n", (yyvsp[(2) - (2)].str))); + if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->permit_small_holddown = + (strcmp((yyvsp[(2) - (2)].str), "yes")==0); + free((yyvsp[(2) - (2)].str)); + } + break; + + case 243: +/* Line 1792 of yacc.c */ +#line 1139 "./util/configparser.y" { OUTYY(("P(server_key_cache_size:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->key_cache_size)) @@ -3494,9 +3512,9 @@ yyreduce: } break; - case 242: + case 244: /* Line 1792 of yacc.c */ -#line 1137 "./util/configparser.y" +#line 1147 "./util/configparser.y" { OUTYY(("P(server_key_cache_slabs:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -3510,9 +3528,9 @@ yyreduce: } break; - case 243: + case 245: /* Line 1792 of yacc.c */ -#line 1150 "./util/configparser.y" +#line 1160 "./util/configparser.y" { OUTYY(("P(server_neg_cache_size:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->neg_cache_size)) @@ -3521,9 +3539,9 @@ yyreduce: } break; - case 244: + case 246: /* Line 1792 of yacc.c */ -#line 1158 "./util/configparser.y" +#line 1168 "./util/configparser.y" { OUTYY(("P(server_local_zone:%s %s)\n", (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str))); if(strcmp((yyvsp[(3) - (3)].str), "static")!=0 && strcmp((yyvsp[(3) - (3)].str), "deny")!=0 && @@ -3548,9 +3566,9 @@ yyreduce: } break; - case 245: + case 247: /* Line 1792 of yacc.c */ -#line 1182 "./util/configparser.y" +#line 1192 "./util/configparser.y" { OUTYY(("P(server_local_data:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->local_data, (yyvsp[(2) - (2)].str))) @@ -3558,9 +3576,9 @@ yyreduce: } break; - case 246: + case 248: /* Line 1792 of yacc.c */ -#line 1189 "./util/configparser.y" +#line 1199 "./util/configparser.y" { char* ptr; OUTYY(("P(server_local_data_ptr:%s)\n", (yyvsp[(2) - (2)].str))); @@ -3576,9 +3594,9 @@ yyreduce: } break; - case 247: + case 249: /* Line 1792 of yacc.c */ -#line 1204 "./util/configparser.y" +#line 1214 "./util/configparser.y" { OUTYY(("P(server_minimal_responses:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3589,9 +3607,9 @@ yyreduce: } break; - case 248: + case 250: /* Line 1792 of yacc.c */ -#line 1214 "./util/configparser.y" +#line 1224 "./util/configparser.y" { OUTYY(("P(server_rrset_roundrobin:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3602,9 +3620,9 @@ yyreduce: } break; - case 249: + case 251: /* Line 1792 of yacc.c */ -#line 1224 "./util/configparser.y" +#line 1234 "./util/configparser.y" { OUTYY(("P(server_max_udp_size:%s)\n", (yyvsp[(2) - (2)].str))); cfg_parser->cfg->max_udp_size = atoi((yyvsp[(2) - (2)].str)); @@ -3612,9 +3630,9 @@ yyreduce: } break; - case 250: + case 252: /* Line 1792 of yacc.c */ -#line 1231 "./util/configparser.y" +#line 1241 "./util/configparser.y" { OUTYY(("P(dns64_prefix:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->dns64_prefix); @@ -3622,9 +3640,9 @@ yyreduce: } break; - case 251: + case 253: /* Line 1792 of yacc.c */ -#line 1238 "./util/configparser.y" +#line 1248 "./util/configparser.y" { OUTYY(("P(server_dns64_synthall:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3634,9 +3652,9 @@ yyreduce: } break; - case 252: + case 254: /* Line 1792 of yacc.c */ -#line 1247 "./util/configparser.y" +#line 1257 "./util/configparser.y" { OUTYY(("P(server_ratelimit:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3646,9 +3664,9 @@ yyreduce: } break; - case 253: + case 255: /* Line 1792 of yacc.c */ -#line 1256 "./util/configparser.y" +#line 1266 "./util/configparser.y" { OUTYY(("P(server_ratelimit_size:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->ratelimit_size)) @@ -3657,9 +3675,9 @@ yyreduce: } break; - case 254: + case 256: /* Line 1792 of yacc.c */ -#line 1264 "./util/configparser.y" +#line 1274 "./util/configparser.y" { OUTYY(("P(server_ratelimit_slabs:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -3673,9 +3691,9 @@ yyreduce: } break; - case 255: + case 257: /* Line 1792 of yacc.c */ -#line 1277 "./util/configparser.y" +#line 1287 "./util/configparser.y" { OUTYY(("P(server_ratelimit_for_domain:%s %s)\n", (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str))); if(atoi((yyvsp[(3) - (3)].str)) == 0 && strcmp((yyvsp[(3) - (3)].str), "0") != 0) { @@ -3689,9 +3707,9 @@ yyreduce: } break; - case 256: + case 258: /* Line 1792 of yacc.c */ -#line 1290 "./util/configparser.y" +#line 1300 "./util/configparser.y" { OUTYY(("P(server_ratelimit_below_domain:%s %s)\n", (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str))); if(atoi((yyvsp[(3) - (3)].str)) == 0 && strcmp((yyvsp[(3) - (3)].str), "0") != 0) { @@ -3705,9 +3723,9 @@ yyreduce: } break; - case 257: + case 259: /* Line 1792 of yacc.c */ -#line 1303 "./util/configparser.y" +#line 1313 "./util/configparser.y" { OUTYY(("P(server_ratelimit_factor:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0) @@ -3717,9 +3735,9 @@ yyreduce: } break; - case 258: + case 260: /* Line 1792 of yacc.c */ -#line 1312 "./util/configparser.y" +#line 1322 "./util/configparser.y" { OUTYY(("P(name:%s)\n", (yyvsp[(2) - (2)].str))); if(cfg_parser->cfg->stubs->name) @@ -3730,9 +3748,9 @@ yyreduce: } break; - case 259: + case 261: /* Line 1792 of yacc.c */ -#line 1322 "./util/configparser.y" +#line 1332 "./util/configparser.y" { OUTYY(("P(stub-host:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->stubs->hosts, (yyvsp[(2) - (2)].str))) @@ -3740,9 +3758,9 @@ yyreduce: } break; - case 260: + case 262: /* Line 1792 of yacc.c */ -#line 1329 "./util/configparser.y" +#line 1339 "./util/configparser.y" { OUTYY(("P(stub-addr:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->stubs->addrs, (yyvsp[(2) - (2)].str))) @@ -3750,9 +3768,9 @@ yyreduce: } break; - case 261: + case 263: /* Line 1792 of yacc.c */ -#line 1336 "./util/configparser.y" +#line 1346 "./util/configparser.y" { OUTYY(("P(stub-first:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3762,9 +3780,9 @@ yyreduce: } break; - case 262: + case 264: /* Line 1792 of yacc.c */ -#line 1345 "./util/configparser.y" +#line 1355 "./util/configparser.y" { OUTYY(("P(stub-prime:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3775,9 +3793,9 @@ yyreduce: } break; - case 263: + case 265: /* Line 1792 of yacc.c */ -#line 1355 "./util/configparser.y" +#line 1365 "./util/configparser.y" { OUTYY(("P(name:%s)\n", (yyvsp[(2) - (2)].str))); if(cfg_parser->cfg->forwards->name) @@ -3788,9 +3806,9 @@ yyreduce: } break; - case 264: + case 266: /* Line 1792 of yacc.c */ -#line 1365 "./util/configparser.y" +#line 1375 "./util/configparser.y" { OUTYY(("P(forward-host:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->forwards->hosts, (yyvsp[(2) - (2)].str))) @@ -3798,9 +3816,9 @@ yyreduce: } break; - case 265: + case 267: /* Line 1792 of yacc.c */ -#line 1372 "./util/configparser.y" +#line 1382 "./util/configparser.y" { OUTYY(("P(forward-addr:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->forwards->addrs, (yyvsp[(2) - (2)].str))) @@ -3808,9 +3826,9 @@ yyreduce: } break; - case 266: + case 268: /* Line 1792 of yacc.c */ -#line 1379 "./util/configparser.y" +#line 1389 "./util/configparser.y" { OUTYY(("P(forward-first:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3820,17 +3838,17 @@ yyreduce: } break; - case 267: + case 269: /* Line 1792 of yacc.c */ -#line 1388 "./util/configparser.y" +#line 1398 "./util/configparser.y" { OUTYY(("\nP(remote-control:)\n")); } break; - case 278: + case 280: /* Line 1792 of yacc.c */ -#line 1399 "./util/configparser.y" +#line 1409 "./util/configparser.y" { OUTYY(("P(control_enable:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3841,9 +3859,9 @@ yyreduce: } break; - case 279: + case 281: /* Line 1792 of yacc.c */ -#line 1409 "./util/configparser.y" +#line 1419 "./util/configparser.y" { OUTYY(("P(control_port:%s)\n", (yyvsp[(2) - (2)].str))); if(atoi((yyvsp[(2) - (2)].str)) == 0) @@ -3853,9 +3871,9 @@ yyreduce: } break; - case 280: + case 282: /* Line 1792 of yacc.c */ -#line 1418 "./util/configparser.y" +#line 1428 "./util/configparser.y" { OUTYY(("P(control_interface:%s)\n", (yyvsp[(2) - (2)].str))); if(!cfg_strlist_insert(&cfg_parser->cfg->control_ifs, (yyvsp[(2) - (2)].str))) @@ -3863,9 +3881,9 @@ yyreduce: } break; - case 281: + case 283: /* Line 1792 of yacc.c */ -#line 1425 "./util/configparser.y" +#line 1435 "./util/configparser.y" { OUTYY(("P(control_use_cert:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3876,9 +3894,9 @@ yyreduce: } break; - case 282: + case 284: /* Line 1792 of yacc.c */ -#line 1435 "./util/configparser.y" +#line 1445 "./util/configparser.y" { OUTYY(("P(rc_server_key_file:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->server_key_file); @@ -3886,9 +3904,9 @@ yyreduce: } break; - case 283: + case 285: /* Line 1792 of yacc.c */ -#line 1442 "./util/configparser.y" +#line 1452 "./util/configparser.y" { OUTYY(("P(rc_server_cert_file:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->server_cert_file); @@ -3896,9 +3914,9 @@ yyreduce: } break; - case 284: + case 286: /* Line 1792 of yacc.c */ -#line 1449 "./util/configparser.y" +#line 1459 "./util/configparser.y" { OUTYY(("P(rc_control_key_file:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->control_key_file); @@ -3906,9 +3924,9 @@ yyreduce: } break; - case 285: + case 287: /* Line 1792 of yacc.c */ -#line 1456 "./util/configparser.y" +#line 1466 "./util/configparser.y" { OUTYY(("P(rc_control_cert_file:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->control_cert_file); @@ -3916,17 +3934,17 @@ yyreduce: } break; - case 286: + case 288: /* Line 1792 of yacc.c */ -#line 1463 "./util/configparser.y" +#line 1473 "./util/configparser.y" { OUTYY(("\nP(dnstap:)\n")); } break; - case 301: + case 303: /* Line 1792 of yacc.c */ -#line 1480 "./util/configparser.y" +#line 1490 "./util/configparser.y" { OUTYY(("P(dt_dnstap_enable:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3935,9 +3953,9 @@ yyreduce: } break; - case 302: + case 304: /* Line 1792 of yacc.c */ -#line 1488 "./util/configparser.y" +#line 1498 "./util/configparser.y" { OUTYY(("P(dt_dnstap_socket_path:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->dnstap_socket_path); @@ -3945,9 +3963,9 @@ yyreduce: } break; - case 303: + case 305: /* Line 1792 of yacc.c */ -#line 1495 "./util/configparser.y" +#line 1505 "./util/configparser.y" { OUTYY(("P(dt_dnstap_send_identity:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3956,9 +3974,9 @@ yyreduce: } break; - case 304: + case 306: /* Line 1792 of yacc.c */ -#line 1503 "./util/configparser.y" +#line 1513 "./util/configparser.y" { OUTYY(("P(dt_dnstap_send_version:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3967,9 +3985,9 @@ yyreduce: } break; - case 305: + case 307: /* Line 1792 of yacc.c */ -#line 1511 "./util/configparser.y" +#line 1521 "./util/configparser.y" { OUTYY(("P(dt_dnstap_identity:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->dnstap_identity); @@ -3977,9 +3995,9 @@ yyreduce: } break; - case 306: + case 308: /* Line 1792 of yacc.c */ -#line 1518 "./util/configparser.y" +#line 1528 "./util/configparser.y" { OUTYY(("P(dt_dnstap_version:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->dnstap_version); @@ -3987,9 +4005,9 @@ yyreduce: } break; - case 307: + case 309: /* Line 1792 of yacc.c */ -#line 1525 "./util/configparser.y" +#line 1535 "./util/configparser.y" { OUTYY(("P(dt_dnstap_log_resolver_query_messages:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -3999,9 +4017,9 @@ yyreduce: } break; - case 308: + case 310: /* Line 1792 of yacc.c */ -#line 1534 "./util/configparser.y" +#line 1544 "./util/configparser.y" { OUTYY(("P(dt_dnstap_log_resolver_response_messages:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -4011,9 +4029,9 @@ yyreduce: } break; - case 309: + case 311: /* Line 1792 of yacc.c */ -#line 1543 "./util/configparser.y" +#line 1553 "./util/configparser.y" { OUTYY(("P(dt_dnstap_log_client_query_messages:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -4023,9 +4041,9 @@ yyreduce: } break; - case 310: + case 312: /* Line 1792 of yacc.c */ -#line 1552 "./util/configparser.y" +#line 1562 "./util/configparser.y" { OUTYY(("P(dt_dnstap_log_client_response_messages:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -4035,9 +4053,9 @@ yyreduce: } break; - case 311: + case 313: /* Line 1792 of yacc.c */ -#line 1561 "./util/configparser.y" +#line 1571 "./util/configparser.y" { OUTYY(("P(dt_dnstap_log_forwarder_query_messages:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -4047,9 +4065,9 @@ yyreduce: } break; - case 312: + case 314: /* Line 1792 of yacc.c */ -#line 1570 "./util/configparser.y" +#line 1580 "./util/configparser.y" { OUTYY(("P(dt_dnstap_log_forwarder_response_messages:%s)\n", (yyvsp[(2) - (2)].str))); if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0) @@ -4059,17 +4077,17 @@ yyreduce: } break; - case 313: + case 315: /* Line 1792 of yacc.c */ -#line 1579 "./util/configparser.y" +#line 1589 "./util/configparser.y" { OUTYY(("\nP(python:)\n")); } break; - case 317: + case 319: /* Line 1792 of yacc.c */ -#line 1588 "./util/configparser.y" +#line 1598 "./util/configparser.y" { OUTYY(("P(python-script:%s)\n", (yyvsp[(2) - (2)].str))); free(cfg_parser->cfg->python_script); @@ -4079,7 +4097,7 @@ yyreduce: /* Line 1792 of yacc.c */ -#line 4083 "util/configparser.c" +#line 4101 "util/configparser.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -4311,7 +4329,7 @@ yyreturn: /* Line 2055 of yacc.c */ -#line 1593 "./util/configparser.y" +#line 1603 "./util/configparser.y" /* parse helper routines could be here */ diff --git a/external/unbound/util/configparser.h b/external/unbound/util/configparser.h index 52ec99221..ca2daeefd 100644 --- a/external/unbound/util/configparser.h +++ b/external/unbound/util/configparser.h @@ -203,7 +203,8 @@ extern int yydebug; VAR_RATELIMIT_BELOW_DOMAIN = 412, VAR_RATELIMIT_FACTOR = 413, VAR_CAPS_WHITELIST = 414, - VAR_CACHE_MAX_NEGATIVE_TTL = 415 + VAR_CACHE_MAX_NEGATIVE_TTL = 415, + VAR_PERMIT_SMALL_HOLDDOWN = 416 }; #endif /* Tokens. */ @@ -365,6 +366,7 @@ extern int yydebug; #define VAR_RATELIMIT_FACTOR 413 #define VAR_CAPS_WHITELIST 414 #define VAR_CACHE_MAX_NEGATIVE_TTL 415 +#define VAR_PERMIT_SMALL_HOLDDOWN 416 @@ -378,7 +380,7 @@ typedef union YYSTYPE /* Line 2058 of yacc.c */ -#line 382 "util/configparser.h" +#line 384 "util/configparser.h" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ diff --git a/external/unbound/util/configparser.y b/external/unbound/util/configparser.y index ad7f3d292..d6db3c86f 100644 --- a/external/unbound/util/configparser.y +++ b/external/unbound/util/configparser.y @@ -121,7 +121,7 @@ extern struct config_parser_state* cfg_parser; %token VAR_HARDEN_ALGO_DOWNGRADE VAR_IP_TRANSPARENT %token VAR_RATELIMIT VAR_RATELIMIT_SLABS VAR_RATELIMIT_SIZE %token VAR_RATELIMIT_FOR_DOMAIN VAR_RATELIMIT_BELOW_DOMAIN VAR_RATELIMIT_FACTOR -%token VAR_CAPS_WHITELIST VAR_CACHE_MAX_NEGATIVE_TTL +%token VAR_CAPS_WHITELIST VAR_CACHE_MAX_NEGATIVE_TTL VAR_PERMIT_SMALL_HOLDDOWN %% toplevelvars: /* empty */ | toplevelvars toplevelvar ; @@ -185,7 +185,8 @@ content_server: server_num_threads | server_verbosity | server_port | server_ip_transparent | server_ratelimit | server_ratelimit_slabs | server_ratelimit_size | server_ratelimit_for_domain | server_ratelimit_below_domain | server_ratelimit_factor | - server_caps_whitelist | server_cache_max_negative_ttl + server_caps_whitelist | server_cache_max_negative_ttl | + server_permit_small_holddown ; stubstart: VAR_STUB_ZONE { @@ -1125,6 +1126,15 @@ server_keep_missing: VAR_KEEP_MISSING STRING_ARG free($2); } ; +server_permit_small_holddown: VAR_PERMIT_SMALL_HOLDDOWN STRING_ARG + { + OUTYY(("P(server_permit_small_holddown:%s)\n", $2)); + if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0) + yyerror("expected yes or no."); + else cfg_parser->cfg->permit_small_holddown = + (strcmp($2, "yes")==0); + free($2); + } server_key_cache_size: VAR_KEY_CACHE_SIZE STRING_ARG { OUTYY(("P(server_key_cache_size:%s)\n", $2)); diff --git a/external/unbound/util/data/msgencode.c b/external/unbound/util/data/msgencode.c index f9a8c5f67..43464e9bb 100644 --- a/external/unbound/util/data/msgencode.c +++ b/external/unbound/util/data/msgencode.c @@ -283,7 +283,7 @@ compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt, size_t owner_pos, uint16_t* owner_ptr, int owner_labs) { struct compress_tree_node* p; - struct compress_tree_node** insertpt; + struct compress_tree_node** insertpt = NULL; if(!*owner_ptr) { /* compress first time dname */ if((p = compress_tree_lookup(tree, key->rk.dname, diff --git a/external/unbound/util/data/msgreply.c b/external/unbound/util/data/msgreply.c index b1d3df639..06593ffe1 100644 --- a/external/unbound/util/data/msgreply.c +++ b/external/unbound/util/data/msgreply.c @@ -822,13 +822,13 @@ log_query_info(enum verbosity_value v, const char* str, } int -reply_check_cname_chain(struct reply_info* rep) +reply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep) { /* check only answer section rrs for matching cname chain. * the cache may return changed rdata, but owner names are untouched.*/ size_t i; - uint8_t* sname = rep->rrsets[0]->rk.dname; - size_t snamelen = rep->rrsets[0]->rk.dname_len; + uint8_t* sname = qinfo->qname; + size_t snamelen = qinfo->qname_len; for(i=0; ian_numrrsets; i++) { uint16_t t = ntohs(rep->rrsets[i]->rk.type); if(t == LDNS_RR_TYPE_DNAME) diff --git a/external/unbound/util/data/msgreply.h b/external/unbound/util/data/msgreply.h index e8d6d762e..708897950 100644 --- a/external/unbound/util/data/msgreply.h +++ b/external/unbound/util/data/msgreply.h @@ -359,10 +359,11 @@ uint8_t* reply_find_final_cname_target(struct query_info* qinfo, /** * Check if cname chain in cached reply is still valid. + * @param qinfo: query info with query name. * @param rep: reply to check. * @return: true if valid, false if invalid. */ -int reply_check_cname_chain(struct reply_info* rep); +int reply_check_cname_chain(struct query_info* qinfo, struct reply_info* rep); /** * Check security status of all RRs in the message. diff --git a/external/unbound/util/iana_ports.inc b/external/unbound/util/iana_ports.inc index 03ad2baaf..91dd39abe 100644 --- a/external/unbound/util/iana_ports.inc +++ b/external/unbound/util/iana_ports.inc @@ -1066,7 +1066,6 @@ 1404, 1405, 1406, -1407, 1408, 1409, 1410, @@ -4667,6 +4666,7 @@ 7725, 7726, 7727, +7728, 7734, 7738, 7741, @@ -4781,6 +4781,7 @@ 8301, 8320, 8321, +8322, 8351, 8376, 8377, @@ -4788,6 +4789,7 @@ 8379, 8380, 8383, +8384, 8400, 8401, 8402, @@ -4804,6 +4806,7 @@ 8474, 8500, 8501, +8503, 8554, 8555, 8567, @@ -5034,6 +5037,7 @@ 10200, 10201, 10252, +10253, 10260, 10288, 10439, @@ -5168,6 +5172,8 @@ 17220, 17221, 17222, +17224, +17225, 17234, 17235, 17500, @@ -5380,6 +5386,7 @@ 40843, 40853, 41111, +41230, 41794, 41795, 42508, diff --git a/external/unbound/util/net_help.c b/external/unbound/util/net_help.c index 8b39af6b3..07605b19f 100644 --- a/external/unbound/util/net_help.c +++ b/external/unbound/util/net_help.c @@ -629,9 +629,9 @@ void* listen_sslctx_create(char* key, char* pem, char* verifypem) SSL_CTX_free(ctx); return NULL; } - if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) { + if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) { log_err("error for cert file: %s", pem); - log_crypto_err("error in SSL_CTX use_certificate_file"); + log_crypto_err("error in SSL_CTX use_certificate_chain_file"); SSL_CTX_free(ctx); return NULL; } @@ -647,6 +647,23 @@ void* listen_sslctx_create(char* key, char* pem, char* verifypem) SSL_CTX_free(ctx); return NULL; } +#if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO + if(!SSL_CTX_set_ecdh_auto(ctx,1)) { + log_crypto_err("Error in SSL_CTX_ecdh_auto, not enabling ECDHE"); + } +#elif defined(USE_ECDSA) + if(1) { + EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1); + if (!ecdh) { + log_crypto_err("could not find p256, not enabling ECDHE"); + } else { + if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) { + log_crypto_err("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE"); + } + EC_KEY_free (ecdh); + } + } +#endif if(verifypem && verifypem[0]) { if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) { @@ -684,7 +701,7 @@ void* connect_sslctx_create(char* key, char* pem, char* verifypem) return NULL; } if(key && key[0]) { - if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) { + if(!SSL_CTX_use_certificate_chain_file(ctx, pem)) { log_err("error in client certificate %s", pem); log_crypto_err("error in certificate file"); SSL_CTX_free(ctx); diff --git a/external/unbound/validator/autotrust.c b/external/unbound/validator/autotrust.c index d90eec9eb..e63b086e6 100644 --- a/external/unbound/validator/autotrust.c +++ b/external/unbound/validator/autotrust.c @@ -1225,7 +1225,7 @@ verify_dnskey(struct module_env* env, struct val_env* ve, { char* reason = NULL; uint8_t sigalg[ALGO_NEEDS_MAX+1]; - int downprot = 1; + int downprot = env->cfg->harden_algo_downgrade; enum sec_status sec = val_verify_DNSKEY_with_TA(env, ve, rrset, tp->ds_rrset, tp->dnskey_rrset, downprot?sigalg:NULL, &reason); /* sigalg is ignored, it returns algorithms signalled to exist, but @@ -1447,9 +1447,11 @@ set_tp_times(struct trust_anchor* tp, time_t rrsig_exp_interval, if(rrsig_exp_interval/2 < x) x = rrsig_exp_interval/2; /* MAX(1hr, x) */ - if(x < 3600) - tp->autr->query_interval = 3600; - else tp->autr->query_interval = x; + if(!autr_permit_small_holddown) { + if(x < 3600) + tp->autr->query_interval = 3600; + else tp->autr->query_interval = x; + } else tp->autr->query_interval = x; /* x= MIN(1day, ttl/10, expire/10) */ x = 24 * 3600; @@ -1458,9 +1460,11 @@ set_tp_times(struct trust_anchor* tp, time_t rrsig_exp_interval, if(rrsig_exp_interval/10 < x) x = rrsig_exp_interval/10; /* MAX(1hr, x) */ - if(x < 3600) - tp->autr->retry_time = 3600; - else tp->autr->retry_time = x; + if(!autr_permit_small_holddown) { + if(x < 3600) + tp->autr->retry_time = 3600; + else tp->autr->retry_time = x; + } else tp->autr->retry_time = x; if(qi != tp->autr->query_interval || rt != tp->autr->retry_time) { *changed = 1; @@ -1959,8 +1963,12 @@ calc_next_probe(struct module_env* env, time_t wait) { /* make it random, 90-100% */ time_t rnd, rest; - if(wait < 3600) - wait = 3600; + if(!autr_permit_small_holddown) { + if(wait < 3600) + wait = 3600; + } else { + if(wait == 0) wait = 1; + } rnd = wait/10; rest = wait-rnd; rnd = (time_t)ub_random_max(env->rnd, (long int)rnd); @@ -2349,6 +2357,8 @@ todo_probe(struct module_env* env, time_t* next) if( (el=rbtree_first(&env->anchors->autr->probe)) == RBTREE_NULL) { /* in case of revoked anchors */ lock_basic_unlock(&env->anchors->lock); + /* signal that there are no anchors to probe */ + *next = 0; return NULL; } tp = (struct trust_anchor*)el->key; @@ -2378,6 +2388,7 @@ autr_probe_timer(struct module_env* env) struct trust_anchor* tp; time_t next_probe = 3600; int num = 0; + if(autr_permit_small_holddown) next_probe = 1; verbose(VERB_ALGO, "autotrust probe timer callback"); /* while there are still anchors to probe */ while( (tp = todo_probe(env, &next_probe)) ) { @@ -2386,7 +2397,7 @@ autr_probe_timer(struct module_env* env) num++; } regional_free_all(env->scratch); - if(num == 0) + if(next_probe == 0) return 0; /* no trust points to probe */ verbose(VERB_ALGO, "autotrust probe timer %d callbacks done", num); return next_probe; diff --git a/external/unbound/validator/validator.c b/external/unbound/validator/validator.c index 74068659f..f8b429e52 100644 --- a/external/unbound/validator/validator.c +++ b/external/unbound/validator/validator.c @@ -2769,7 +2769,7 @@ process_dnskey_response(struct module_qstate* qstate, struct val_qstate* vq, vq->state = VAL_VALIDATE_STATE; return; } - downprot = 1; + downprot = qstate->env->cfg->harden_algo_downgrade; vq->key_entry = val_verify_new_DNSKEYs(qstate->region, qstate->env, ve, dnskey, vq->ds_rrset, downprot, &reason); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0b04af334..9b094a358 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -106,3 +106,7 @@ add_subdirectory(daemonizer) add_subdirectory(daemon) add_subdirectory(blockchain_utilities) + +if(PER_BLOCK_CHECKPOINT) + add_subdirectory(blocks) +endif() diff --git a/src/blockchain_db/CMakeLists.txt b/src/blockchain_db/CMakeLists.txt index adbe804aa..7301cab85 100644 --- a/src/blockchain_db/CMakeLists.txt +++ b/src/blockchain_db/CMakeLists.txt @@ -31,7 +31,7 @@ set(blockchain_db_sources lmdb/db_lmdb.cpp ) -if (NOT STATIC) +if (BERKELEY_DB) set(blockchain_db_sources ${blockchain_db_sources} berkeleydb/db_bdb.cpp @@ -46,7 +46,7 @@ set(blockchain_db_private_headers lmdb/db_lmdb.h ) -if (NOT STATIC) +if (BERKELEY_DB) set(blockchain_db_private_headers ${blockchain_db_private_headers} berkeleydb/db_bdb.h diff --git a/src/blockchain_db/berkeleydb/db_bdb.cpp b/src/blockchain_db/berkeleydb/db_bdb.cpp index 221c0cf2e..a990d7aaf 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.cpp +++ b/src/blockchain_db/berkeleydb/db_bdb.cpp @@ -1,20 +1,20 @@ // Copyright (c) 2014, The Monero Project // All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: -// +// // 1. Redistributions of source code must retain the above copyright notice, this list of // conditions and the following disclaimer. -// +// // 2. Redistributions in binary form must reproduce the above copyright notice, this list // of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. -// +// // 3. Neither the name of the copyright holder nor the names of its contributors may be // used to endorse or promote products derived from this software without specific // prior written permission. -// +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL @@ -36,6 +36,7 @@ #include "profile_tools.h" using epee::string_tools::pod_to_hex; +#define DB_DEFAULT_TX (m_write_txn != nullptr ? *m_write_txn : (DbTxn*) nullptr) namespace { @@ -43,46 +44,58 @@ namespace template inline void throw0(const T &e) { - LOG_PRINT_L0(e.what()); - throw e; + LOG_PRINT_L0(e.what()); + throw e; } template inline void throw1(const T &e) { - LOG_PRINT_L1(e.what()); - throw 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) + bdb_cur(DbTxn* txn, Db* dbi) { - m_cur->close(); - done = true; + 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; + Dbc* m_cur; + bool done; }; const char* const BDB_BLOCKS = "blocks"; @@ -105,65 +118,80 @@ const char* const BDB_OUTPUT_KEYS = "output_keys"; const char* const BDB_SPENT_KEYS = "spent_keys"; +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 = std::thread::hardware_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(const T &t) : + t_copy(t) + { + init(); + } - Dbt_copy() - { - init(); - } + Dbt_copy() + { + init(); + } - void init() - { - set_data(&t_copy); - set_size(sizeof(T)); - set_ulen(sizeof(T)); - set_flags(DB_DBT_USERMEM); - } + void init() + { + set_data(&t_copy); + set_size(sizeof(T)); + set_ulen(sizeof(T)); + set_flags(DB_DBT_USERMEM); + } - operator T() - { - return t_copy; - } + operator T() + { + return t_copy; + } private: - T t_copy; + 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); - } + 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; + 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) + Dbt_safe() { - free(buf); + set_data(NULL); + set_flags(DB_DBT_MALLOC); + } + ~Dbt_safe() + { + void* buf = get_data(); + if (buf != NULL) + { + free(buf); + } } - } }; } // anonymous namespace @@ -171,1519 +199,1666 @@ struct Dbt_safe : public Dbt 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 - ) +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(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); - Dbt_copy val_h(blk_hash); - if (m_block_heights->exists(*m_write_txn, &val_h, 0) == 0) - throw1(BLOCK_EXISTS("Attempting to add block that's already in the db")); + 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(*m_write_txn, &parent_key, &parent_h, 0)) + if (m_height > 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")); + 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")); } - 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 key(m_height + 1); - Dbt_copy blob(block_to_blob(blk)); - auto res = m_blocks->put(*m_write_txn, &key, &blob, 0); - if (res) - throw0(DB_ERROR("Failed to add block blob to db transaction.")); + 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(*m_write_txn, &key, &sz, 0)) - throw0(DB_ERROR("Failed to add block size 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(*m_write_txn, &key, &ts, 0)) - throw0(DB_ERROR("Failed to add block timestamp 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(*m_write_txn, &key, &diff, 0)) - throw0(DB_ERROR("Failed to add block cumulative difficulty 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(*m_write_txn, &key, &coinsgen, 0)) - throw0(DB_ERROR("Failed to add block total generated coins 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(*m_write_txn, &val_h, &key, 0)) - throw0(DB_ERROR("Failed to add block height by hash 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(*m_write_txn, &key, &val_h, 0)) - throw0(DB_ERROR("Failed to add block 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(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); - if (m_height == 0) - throw0(BLOCK_DNE ("Attempting to remove block from an empty blockchain")); + 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(*m_write_txn, &k, &h, 0)) - throw1(BLOCK_DNE("Attempting to remove block that's not in the db")); + 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(*m_write_txn, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block to db transaction")); + 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(*m_write_txn, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block size 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(*m_write_txn, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block cumulative difficulty 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(*m_write_txn, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block total generated coins 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(*m_write_txn, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block timestamp 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(*m_write_txn, &h, 0)) - throw1(DB_ERROR("Failed to add removal of block height by hash 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(*m_write_txn, &k, 0)) - throw1(DB_ERROR("Failed to add removal of block 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(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); - Dbt_copy val_h(tx_hash); + Dbt_copy val_h(tx_hash); - if (m_txs->exists(*m_write_txn, &val_h, 0) == 0) - throw1(TX_EXISTS("Attempting to add transaction that's already in the db")); + 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(*m_write_txn, &val_h, &blob, 0)) - throw0(DB_ERROR("Failed to add tx blob to db transaction")); + 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(*m_write_txn, &val_h, &height, 0)) - throw0(DB_ERROR("Failed to add tx block height 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(*m_write_txn, &val_h, &unlock_time, 0)) - throw0(DB_ERROR("Failed to add tx unlock time 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(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); - Dbt_copy val_h(tx_hash); - if (m_txs->exists(*m_write_txn, &val_h, 0)) - throw1(TX_DNE("Attempting to remove transaction that isn't in the db")); + 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(*m_write_txn, &val_h, 0)) - throw1(DB_ERROR("Failed to add removal of tx to db transaction")); - if (m_tx_unlocks->del(*m_write_txn, &val_h, 0)) - throw1(DB_ERROR("Failed to add removal of tx unlock time to db transaction")); - if (m_tx_heights->del(*m_write_txn, &val_h, 0)) - throw1(DB_ERROR("Failed to add removal of tx block height to db transaction")); + 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); + remove_tx_outputs(tx_hash, tx); - if (m_tx_outputs->del(*m_write_txn, &val_h, 0)) - throw1(DB_ERROR("Failed to add removal of tx outputs to db transaction")); + if (m_tx_outputs->del(DB_DEFAULT_TX, &val_h, 0)) + 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) +void BlockchainBDB::add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time) { - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); - Dbt_copy k(m_num_outputs + 1); - Dbt_copy v(tx_hash); + Dbt_copy k(m_num_outputs + 1); + Dbt_copy v(tx_hash); - if (m_output_txs->put(*m_write_txn, &k, &v, 0)) - throw0(DB_ERROR("Failed to add output tx hash to db transaction")); - if (m_tx_outputs->put(*m_write_txn, &v, &k, 0)) - throw0(DB_ERROR("Failed to add tx output index to db transaction")); + 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(*m_write_txn, &k, &val_local_index, 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(*m_write_txn, &val_amount, &k, 0)) - throw0(DB_ERROR("Failed to add output amount 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)) - { - Dbt_copy val_pubkey(boost::get(tx_output.target).key); - if (m_output_keys->put(*m_write_txn, &k, &val_pubkey, 0)) - throw0(DB_ERROR("Failed to add output pubkey 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; - m_num_outputs++; + 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")); + } + + m_num_outputs++; } void BlockchainBDB::remove_tx_outputs(const crypto::hash& tx_hash, const transaction& tx) { - LOG_PRINT_L3("BlockchainBDB::" << __func__); + LOG_PRINT_L3("BlockchainBDB::" << __func__); - bdb_cur cur(*m_write_txn, m_tx_outputs); + bdb_cur cur(DB_DEFAULT_TX, m_tx_outputs); - Dbt_copy k(tx_hash); - Dbt_copy v; + Dbt_copy k(tx_hash); + Dbt_copy v; - auto result = cur->get(&k, &v, DB_SET); - if (result == DB_NOTFOUND) - { - throw0(DB_ERROR("Attempting to remove a tx's outputs, but none found.")); - } - else if (result) - { - throw0(DB_ERROR("DB error attempting to get an output")); - } - else - { - db_recno_t num_elems = 0; - cur->count(&num_elems, 0); - - for (uint64_t i = 0; i < num_elems; ++i) + auto result = cur->get(&k, &v, DB_SET); + if (result == DB_NOTFOUND) { - const tx_out tx_output = tx.vout[i]; - remove_output(v, tx_output.amount); - if (i < num_elems - 1) - { - cur->get(&k, &v, DB_NEXT_DUP); - } + throw0(DB_ERROR("Attempting to remove a tx's outputs, but none found.")); } - } + else if (result) + { + throw0(DB_ERROR("DB error attempting to get an output")); + } + else + { + db_recno_t num_elems = 0; + cur->count(&num_elems, 0); - cur.close(); + for (uint64_t i = 0; i < num_elems; ++i) + { + const tx_out tx_output = tx.vout[i]; + remove_output(v, tx_output.amount); + if (i < num_elems - 1) + { + cur->get(&k, &v, DB_NEXT_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; + 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(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); - Dbt_copy k(out_index); + Dbt_copy k(out_index); - auto result = m_output_indices->del(*m_write_txn, &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")); - } + 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(*m_write_txn, &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_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(*m_write_txn, &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")); + 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); + remove_amount_output_index(amount, out_index); - m_num_outputs--; + 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(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); - bdb_cur cur(*m_write_txn, m_output_amounts); + bdb_cur cur(DB_DEFAULT_TX, m_output_amounts); - Dbt_copy k(amount); - Dbt_copy v; + 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")); + 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); + db_recno_t num_elems = 0; + cur->count(&num_elems, 0); - uint64_t amount_output_index = 0; - uint64_t goi = 0; - bool found_index = false; - for (uint64_t i = 0; i < num_elems; ++i) - { - goi = v; - if (goi == global_output_index) + uint64_t amount_output_index = 0; + uint64_t goi = 0; + bool found_index = false; + for (uint64_t i = 0; i < num_elems; ++i) { - amount_output_index = i; - found_index = true; - break; + goi = v; + if (goi == global_output_index) + { + amount_output_index = i; + found_index = true; + break; + } + cur->get(&k, &v, DB_NEXT_DUP); } - cur->get(&k, &v, DB_NEXT_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(); + 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(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); - Dbt_copy val_key(k_image); - if (m_spent_keys->exists(*m_write_txn, &val_key, 0) == 0) - throw1(KEY_IMAGE_EXISTS("Attempting to add spent key image that's already in the db")); + 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(*m_write_txn, &val_key, &val, 0)) - throw1(DB_ERROR("Error adding spent key image to db transaction.")); + 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(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); - Dbt_copy k(k_image); - auto result = m_spent_keys->del(*m_write_txn, &k, 0); - if (result != 0 && result != DB_NOTFOUND) - throw1(DB_ERROR("Error adding removal of key image to db transaction")); + 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")); } 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; + 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; + 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")); + if (!(::serialization::serialize(ba, o))) + throw1(DB_ERROR("Error deserializing tx output blob")); - return o; + return o; } -uint64_t BlockchainBDB::get_output_global_index(const uint64_t& amount, const uint64_t& index) const +uint64_t BlockchainBDB::get_output_global_index(const uint64_t& amount, const uint64_t& index) { - LOG_PRINT_L3("BlockchainLMDB::" << __func__); - check_open(); + 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")); + 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")); - bdb_cur cur(txn, 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; - cur->count(&num_elems, 0); - - if (num_elems <= index) - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but output not found")); - - for (uint64_t i = 0; i < index; ++i) - { - cur->get(&k, &v, DB_NEXT_DUP); - } - - uint64_t glob_index = v; - - cur.close(); - - txn.commit(); - - return glob_index; + 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")); + 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__); + LOG_PRINT_L3("BlockchainBDB::" << __func__); - if (m_open) - { - close(); - } + if (m_open) + { + close(); + } } -BlockchainBDB::BlockchainBDB(bool batch_transactions) +BlockchainBDB::BlockchainBDB(bool batch_transactions) : + 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_open = false; - - m_batch_transactions = batch_transactions; - m_write_txn = nullptr; - m_height = 0; + LOG_PRINT_L3("BlockchainBDB::" << __func__); + // initialize folder to something "safe" just in case + // someone accidentally misuses this class... + m_folder = "thishsouldnotexistbecauseitisgibberish"; + m_open = false; + m_run_checkpoint = 0; + m_batch_transactions = batch_transactions; + m_write_txn = nullptr; + m_height = 0; } void BlockchainBDB::open(const std::string& filename, const int db_flags) { - LOG_PRINT_L3("BlockchainBDB::" << __func__); + LOG_PRINT_L3("BlockchainBDB::" << __func__); - if (m_open) - throw0(DB_OPEN_FAILURE("Attempted to open db, but it's already open")); + 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_directory(direc)) - throw0(DB_OPEN_FAILURE(std::string("Failed to create directory ").append(filename).c_str())); - } + 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_directory(direc)) + throw0(DB_OPEN_FAILURE(std::string("Failed to create directory ").append(filename).c_str())); + } - m_folder = filename; + m_folder = filename; - try - { + try + { - //Create BerkeleyDB environment - m_env = new DbEnv(0); // no flags needed for DbEnv + //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; + uint32_t db_env_open_flags = DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN | DB_RECOVER | DB_THREAD; - // last parameter left 0, files will be created with default rw access - m_env->open(filename.c_str(), db_env_open_flags, 0); + // 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); + + // 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); + if(m_auto_remove_logs) + m_env->log_set_config(DB_LOG_AUTO_REMOVE, 1); - // 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); + // begin transaction to init dbs + bdb_txn_safe txn; + m_env->txn_begin(NULL, txn, 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); + // 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_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_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_spent_keys = 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); - // 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); + m_spent_keys = new Db(m_env, 0); - // 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)); + // 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); - 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(crypto::public_key)); + // 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)); - //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. + 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)); - // 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); + //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. - 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); + // 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_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_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_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_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_spent_keys->open(txn, BDB_SPENT_KEYS, 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); + + 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; + delete stats; + + // see above comment about DB_FAST_STAT + m_output_indices->stat(NULL, &stats, 0); + m_num_outputs = stats->bt_nkeys; + delete stats; + + // 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; + m_env->close(DB_FORCESYNC); +} + +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); + } + 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__); + // TODO: this +} + +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); + + 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) 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")); + + 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(DB_ERROR(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(DB_ERROR(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(DB_ERROR(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(DB_ERROR(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(DB_ERROR(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_blocks->stat(txn, &stats, DB_FAST_STAT); - m_height = stats->bt_nkeys; + m_txs->stat(DB_DEFAULT_TX, &stats, DB_FAST_STAT); + auto num_txs = stats->bt_nkeys; delete stats; - // see above comment about DB_FAST_STAT - m_output_indices->stat(txn, &stats, DB_FAST_STAT); - m_num_outputs = stats->bt_nkeys; - delete stats; - - txn.commit(); - } - catch (const std::exception& e) - { - throw0(DB_OPEN_FAILURE(e.what())); - } - - m_open = true; -} - -void BlockchainBDB::close() -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - this->sync(); - - // FIXME: not yet thread safe!!! Use with care. - m_open = false; - m_env->close(DB_FORCESYNC); -} - -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); - } - 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("BlockchainLMDB::" << __func__); - // TODO: this -} - -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); - - 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) const -{ - 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")); - - Dbt_copy key(h); - - auto get_result = m_block_heights->exists(txn, &key, 0); - if (get_result == DB_NOTFOUND) - { - txn.commit(); - 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")); - - txn.commit(); - 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(); - - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - - Dbt_copy key(h); - Dbt_copy result; - - auto get_result = m_block_heights->get(txn, &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")); - - txn.commit(); - - return (uint64_t)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(); - - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - - Dbt_copy key(height + 1); - Dbt_safe result; - auto get_result = m_blocks->get(txn, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw0(DB_ERROR(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")); - - txn.commit(); - - 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(); - - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - - Dbt_copy key(height + 1); - Dbt_copy result; - auto get_result = m_block_timestamps->get(txn, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw0(DB_ERROR(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")); - - txn.commit(); - 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(); - - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - - Dbt_copy key(height + 1); - Dbt_copy result; - auto get_result = m_block_sizes->get(txn, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw0(DB_ERROR(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")); - - txn.commit(); - return result; -} - -difficulty_type BlockchainBDB::get_block_cumulative_difficulty(const uint64_t& height) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__ << " height: " << height); - 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")); - - Dbt_copy key(height + 1); - Dbt_copy result; - auto get_result = m_block_diffs->get(txn, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw0(DB_ERROR(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")); - - txn.commit(); - 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(); - - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - - Dbt_copy key(height + 1); - Dbt_copy result; - auto get_result = m_block_coins->get(txn, &key, &result, 0); - if (get_result == DB_NOTFOUND) - { - throw0(DB_ERROR(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")); - - txn.commit(); - return result; -} - -crypto::hash BlockchainBDB::get_block_hash_from_height(const uint64_t& height) const -{ - 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")); - - Dbt_copy key(height + 1); - Dbt_copy result; - auto get_result = m_block_hashes->get(txn, &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.")); - - txn.commit(); - 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(); - - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - - Dbt_copy key(h); - - TIME_MEASURE_START(time1); - auto get_result = m_txs->exists(txn, &key, 0); - TIME_MEASURE_FINISH(time1); - time_tx_exists += time1; - if (get_result == DB_NOTFOUND) - { - txn.commit(); - 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("BlockchainLMDB::" << __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")); - - Dbt_copy key(h); - Dbt_copy result; - auto get_result = m_tx_unlocks->get(txn, &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(); - - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - - Dbt_copy key(h); - Dbt_safe result; - auto get_result = m_txs->get(txn, &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")); - - txn.commit(); - - return tx; -} - -uint64_t BlockchainBDB::get_tx_count() const -{ - 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")); - - 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(txn, &stats, DB_FAST_STAT); - auto num_txs = stats->bt_nkeys; - delete stats; - - txn.commit(); - - return num_txs; + return num_txs; } std::vector BlockchainBDB::get_tx_list(const std::vector& hlist) const { - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - std::vector v; + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); + std::vector v; - for (auto& h : hlist) - { - v.push_back(get_tx(h)); - } +for (auto& h : hlist) + { + v.push_back(get_tx(h)); + } - return v; + return v; } uint64_t BlockchainBDB::get_tx_block_height(const crypto::hash& h) const { - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); + 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")); + 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")); - Dbt_copy key(h); - Dbt_copy result; - auto get_result = m_tx_heights->get(txn, &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")); - - txn.commit(); - - return (uint64_t)result - 1; -} - -//FIXME: make sure the random method used here is appropriate -uint64_t BlockchainBDB::get_random_output(const uint64_t& amount) const -{ - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); - - uint64_t num_outputs = get_num_outputs(amount); - if (num_outputs == 0) - throw1(OUTPUT_DNE("Attempting to get a random output for an amount, but none exist")); - - return crypto::rand() % num_outputs; + return (uint64_t)result - 1; } uint64_t BlockchainBDB::get_num_outputs(const uint64_t& amount) const { - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); + 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")); + bdb_cur cur(DB_DEFAULT_TX, m_output_amounts); - bdb_cur cur(txn, 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")); - 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); - db_recno_t num_elems = 0; - cur->count(&num_elems, 0); + cur.close(); - txn.commit(); - - return num_elems; + return num_elems; } -crypto::public_key BlockchainBDB::get_output_key(const uint64_t& amount, const uint64_t& index) const +output_data_t BlockchainBDB::get_output_key(const uint64_t& global_index) const { - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); - uint64_t glob_index = get_output_global_index(amount, index); + 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) + throw0(DB_ERROR("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")); - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); + return v; +} - Dbt_copy k(glob_index); - Dbt_copy v; - auto get_result = m_output_keys->get(txn, &k, &v, 0); - if (get_result == DB_NOTFOUND) - throw0(DB_ERROR("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")); +output_data_t BlockchainBDB::get_output_key(const uint64_t& amount, const uint64_t& index) +{ + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); - return v; + uint64_t glob_index = get_output_global_index(amount, index); + return get_output_key(glob_index); } // As this is not used, its return is now a blank output. // This will save on space in the db. tx_out BlockchainBDB::get_output(const crypto::hash& h, const uint64_t& index) const { - LOG_PRINT_L3("BlockchainBDB::" << __func__); - return tx_out(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + return tx_out(); } // As this is not used, its return is now a blank output. // This will save on space in the db. tx_out BlockchainBDB::get_output(const uint64_t& index) const { - LOG_PRINT_L3("BlockchainBDB::" << __func__); - return tx_out(); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + return tx_out(); } -tx_out_index BlockchainBDB::get_output_tx_and_index_from_global(const uint64_t& index) const +tx_out_index BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) { - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); + 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")); - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - - Dbt_copy k(index); - Dbt_copy v; - - auto get_result = m_output_txs->get(txn, &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(txn, &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")); - - txn.commit(); - - return tx_out_index(tx_hash, result); -} - -tx_out_index BlockchainBDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const -{ - 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")); - - bdb_cur cur(txn, 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); - - if (num_elems <= index) - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but output not found")); - - for (uint64_t i = 0; i < index; ++i) - { - cur->get(&k, &v, DB_NEXT_DUP); - } - - uint64_t glob_index = v; - - cur.close(); - - txn.commit(); - - return get_output_tx_and_index_from_global(glob_index); + 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; + LOG_PRINT_L3("BlockchainBDB::" << __func__); + check_open(); + std::vector index_vec; - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - - bdb_cur cur(txn, 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(); - txn.commit(); - - 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); - - bdb_txn_safe txn; - if (m_env->txn_begin(NULL, txn, 0)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - - 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(txn, m_output_amounts); - - Dbt_copy k(amount); - Dbt_copy v; + 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 index by amount and amount index, but amount not found")); + 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")); + 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) + for (uint64_t i = 0; i < num_elems; ++i) { - 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(); - txn.commit(); - throw1(OUTPUT_DNE("specified output not found in db")); + index_vec.push_back(v); + cur->get(&k, &v, DB_NEXT_DUP); } cur.close(); - ++i; - } - txn.commit(); + return index_vec; +} - return index_vec2; +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(); + 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")); + Dbt_copy val_key(img); + if (m_spent_keys->exists(DB_DEFAULT_TX, &val_key, 0) == 0) + { + return true; + } - Dbt_copy val_key(img); - if (m_spent_keys->exists(txn, &val_key, 0) == 0) - { - txn.commit(); - return true; - } - - txn.commit(); - return false; + return false; } // Ostensibly BerkeleyDB has batch transaction support built-in, // so the following few functions will be NOP. -void BlockchainBDB::batch_start() +void BlockchainBDB::batch_start(uint64_t batch_num_blocks) { - LOG_PRINT_L3("BlockchainBDB::" << __func__); + LOG_PRINT_L3("BlockchainBDB::" << __func__); } void BlockchainBDB::batch_commit() { - LOG_PRINT_L3("BlockchainBDB::" << __func__); + LOG_PRINT_L3("BlockchainBDB::" << __func__); } void BlockchainBDB::batch_stop() { - LOG_PRINT_L3("BlockchainBDB::" << __func__); + LOG_PRINT_L3("BlockchainBDB::" << __func__); } void BlockchainBDB::batch_abort() { - LOG_PRINT_L3("BlockchainBDB::" << __func__); + LOG_PRINT_L3("BlockchainBDB::" << __func__); } void BlockchainBDB::set_batch_transactions(bool batch_transactions) { - LOG_PRINT_L3("BlockchainLMDB::" << __func__); - m_batch_transactions = batch_transactions; - LOG_PRINT_L3("batch transactions " << (m_batch_transactions ? "enabled" : "disabled")); + LOG_PRINT_L3("BlockchainBDB::" << __func__); + m_batch_transactions = batch_transactions; + LOG_PRINT_L3("batch transactions " << (m_batch_transactions ? "enabled" : "disabled")); } -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 - ) +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(); + 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; + 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; + 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; - } + 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; + return ++m_height; } void BlockchainBDB::pop_block(block& blk, std::vector& txs) { - LOG_PRINT_L3("BlockchainBDB::" << __func__); - check_open(); + 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; + 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); + 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_write_txn = NULL; + txn.commit(); + } + catch (...) + { + m_num_outputs = num_outputs; + m_write_txn = NULL; + throw; + } - --m_height; + --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); +} + +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.") } } // namespace cryptonote diff --git a/src/blockchain_db/berkeleydb/db_bdb.h b/src/blockchain_db/berkeleydb/db_bdb.h index 83588b031..f92bbef68 100644 --- a/src/blockchain_db/berkeleydb/db_bdb.h +++ b/src/blockchain_db/berkeleydb/db_bdb.h @@ -30,6 +30,11 @@ #include "blockchain_db/blockchain_db.h" #include "cryptonote_protocol/blobdatatype.h" // for type blobdata +#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 { @@ -83,10 +88,145 @@ struct bdb_txn_safe { 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() + { + std::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) + { + std::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; + + std::condition_variable m_cv; + std::vector m_open_slot; + size_t m_count; + std::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: @@ -155,12 +295,11 @@ public: virtual uint64_t get_tx_block_height(const crypto::hash& h) const; - virtual uint64_t get_random_output(const uint64_t& amount) const; - virtual uint64_t get_num_outputs(const uint64_t& amount) const; - virtual crypto::public_key get_output_key(const uint64_t& amount, const uint64_t& index) const; - + 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 get_output(const crypto::hash& h, const uint64_t& index) const; /** @@ -175,8 +314,11 @@ public: tx_out get_output(const uint64_t& index) const; 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) 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; @@ -191,13 +333,19 @@ public: ); virtual void set_batch_transactions(bool batch_transactions); - virtual void batch_start(); + virtual void batch_start(uint64_t batch_num_blocks=0); virtual void batch_commit(); virtual void batch_stop(); virtual void batch_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 + private: virtual void add_block( const block& blk , const size_t& block_size @@ -212,7 +360,7 @@ private: 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); + virtual void add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time); virtual void remove_output(const tx_out& tx_output); @@ -225,6 +373,7 @@ private: 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); /** * @brief convert a tx output to a blob for storage * @@ -251,9 +400,13 @@ private: * * @return the global index of the desired output */ - uint64_t get_output_global_index(const uint64_t& amount, const uint64_t& index) const; - + uint64_t get_output_global_index(const uint64_t& amount, const uint64_t& index); + void checkpoint_worker() const; void check_open() const; + 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; diff --git a/src/blockchain_db/blockchain_db.cpp b/src/blockchain_db/blockchain_db.cpp index bfe93948a..9d865d4de 100644 --- a/src/blockchain_db/blockchain_db.cpp +++ b/src/blockchain_db/blockchain_db.cpp @@ -56,24 +56,37 @@ 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_key)) + { + add_spent_key(boost::get(tx_input).k_image); + } + else if (tx_input.type() == typeid(txin_gen)) + { + /* nothing to do here */ + } + else + { + LOG_PRINT_L1("Unsupported input type, removing key images and aborting transaction addition"); + for (const txin_v& tx_input : tx.vin) + { + if (tx_input.type() == typeid(txin_to_key)) + { + remove_spent_key(boost::get(tx_input).k_image); + } + } + return; + } + } + add_transaction_data(blk_hash, tx, tx_hash); // iterate tx.vout using indices instead of C++11 foreach syntax because // we need the index - if (tx.vout.size() != 0) // it may be technically possible for a tx to have no outputs + for (uint64_t i = 0; i < tx.vout.size(); ++i) { - for (uint64_t i = 0; i < tx.vout.size(); ++i) - { - add_output(tx_hash, tx.vout[i], i); - } - - 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); - } - } + add_output(tx_hash, tx.vout[i], i, tx.unlock_time); } } diff --git a/src/blockchain_db/blockchain_db.h b/src/blockchain_db/blockchain_db.h index 46c860122..25a34fc09 100644 --- a/src/blockchain_db/blockchain_db.h +++ b/src/blockchain_db/blockchain_db.h @@ -104,7 +104,6 @@ * height get_tx_block_height(hash) * * Outputs: - * index get_random_output(amount) * uint64_t get_num_outputs(amount) * pub_key get_output_key(amount, index) * tx_out get_output(tx_hash, index) @@ -138,6 +137,15 @@ namespace cryptonote // typedef for convenience typedef std::pair tx_out_index; +#pragma pack(push, 1) +struct output_data_t +{ + crypto::public_key pubkey; + uint64_t unlock_time; + uint64_t height; +}; +#pragma pack(pop) + /*********************************** * Exception Definitions ***********************************/ @@ -279,7 +287,7 @@ private: virtual void remove_transaction_data(const crypto::hash& tx_hash, const transaction& tx) = 0; // tells the subclass to store an output - virtual void add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index) = 0; + virtual void add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time) = 0; // tells the subclass to remove an output virtual void remove_output(const tx_out& tx_output) = 0; @@ -313,7 +321,7 @@ protected: mutable uint64_t time_tx_exists = 0; uint64_t time_commit1 = 0; - + bool m_auto_remove_logs = true; public: @@ -357,7 +365,7 @@ public: // release db lock virtual void unlock() = 0; - virtual void batch_start() = 0; + virtual void batch_start(uint64_t batch_num_blocks=0) = 0; virtual void batch_stop() = 0; virtual void set_batch_transactions(bool) = 0; @@ -454,14 +462,12 @@ public: // returns height of block that contains transaction with hash virtual uint64_t get_tx_block_height(const crypto::hash& h) const = 0; - // return global output index of a random output of amount - virtual uint64_t get_random_output(const uint64_t& amount) const = 0; - // returns the total number of outputs of amount virtual uint64_t get_num_outputs(const uint64_t& amount) const = 0; // return public key for output with global output amount and index - virtual crypto::public_key get_output_key(const uint64_t& amount, const uint64_t& index) const = 0; + virtual output_data_t get_output_key(const uint64_t& amount, const uint64_t& index) = 0; + virtual output_data_t get_output_key(const uint64_t& global_index) const = 0; // returns the output indexed by in the transaction with hash virtual tx_out get_output(const crypto::hash& h, const uint64_t& index) const = 0; @@ -471,7 +477,11 @@ public: // returns the transaction-local reference for the output with at // return type is pair of tx hash and index - virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const = 0; + virtual tx_out_index get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) = 0; + virtual void get_output_tx_and_index(const uint64_t& amount, const std::vector &offsets, std::vector &indices) = 0; + virtual void get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs) = 0; + + virtual bool can_thread_bulk_indices() const = 0; // return a vector of indices corresponding to the global output index for // each output in the transaction with hash @@ -483,7 +493,10 @@ public: // returns true if key image is present in spent key images storage virtual bool has_key_image(const crypto::key_image& img) const = 0; + void set_auto_remove_logs(bool auto_remove) { m_auto_remove_logs = auto_remove; } + bool m_open; + mutable epee::critical_section m_synchronization_lock; }; // class BlockchainDB diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 0ed044954..1583a0c06 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -28,8 +28,10 @@ #include "db_lmdb.h" #include +#include #include // std::unique_ptr #include // memcpy +#include #include "cryptonote_core/cryptonote_format_utils.h" #include "crypto/crypto.h" @@ -65,10 +67,19 @@ struct lmdb_cur done = false; } - ~lmdb_cur() { close(); } + ~lmdb_cur() + { + close(); + } - operator MDB_cursor*() { return m_cur; } - operator MDB_cursor**() { return &m_cur; } + operator MDB_cursor*() + { + return m_cur; + } + operator MDB_cursor**() + { + return &m_cur; + } void close() { @@ -87,7 +98,8 @@ private: template struct MDB_val_copy: public MDB_val { - MDB_val_copy(const T &t): t_copy(t) + MDB_val_copy(const T &t) : + t_copy(t) { mv_size = sizeof (T); mv_data = &t_copy; @@ -99,7 +111,8 @@ private: template<> struct MDB_val_copy: public MDB_val { - MDB_val_copy(const cryptonote::blobdata &bd): data(new char[bd.size()]) + MDB_val_copy(const cryptonote::blobdata &bd) : + data(new char[bd.size()]) { memcpy(data.get(), bd.data(), bd.size()); mv_size = bd.size(); @@ -109,7 +122,8 @@ private: std::unique_ptr data; }; -auto compare_uint64 = [](const MDB_val *a, const MDB_val *b) { +auto compare_uint64 = [](const MDB_val *a, const MDB_val *b) +{ const uint64_t va = *(const uint64_t*)a->mv_data; const uint64_t vb = *(const uint64_t*)b->mv_data; if (va < vb) return -1; @@ -117,6 +131,20 @@ auto compare_uint64 = [](const MDB_val *a, const MDB_val *b) { else return 1; }; +int compare_hash32(const MDB_val *a, const MDB_val *b) +{ + uint32_t *va = (uint32_t*) a->mv_data; + uint32_t *vb = (uint32_t*) b->mv_data; + for (int n = 7; n >= 0; n--) + { + if (va[n] == vb[n]) + continue; + return va[n] < vb[n] ? -1 : 1; + } + + return 0; +} + const char* const LMDB_BLOCKS = "blocks"; const char* const LMDB_BLOCK_TIMESTAMPS = "block_timestamps"; const char* const LMDB_BLOCK_HEIGHTS = "block_heights"; @@ -233,8 +261,29 @@ void mdb_txn_safe::allow_new_txns() -void BlockchainLMDB::do_resize() +void BlockchainLMDB::do_resize(uint64_t increase_size) { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + CRITICAL_REGION_LOCAL(m_synchronization_lock); + const uint64_t add_size = 1LL << 30; + + // check disk capacity + try + { + boost::filesystem::path path(m_folder); + boost::filesystem::space_info si = boost::filesystem::space(path); + if(si.available < add_size) + { + LOG_PRINT_RED_L0("!! WARNING: Insufficient free space to extend database !!: " << si.available / 1LL << 20L); + return; + } + } + catch(...) + { + // print something but proceed. + LOG_PRINT_YELLOW("Unable to query free disk space.", LOG_LEVEL_0); + } + MDB_envinfo mei; mdb_env_info(m_env, &mei); @@ -243,7 +292,14 @@ void BlockchainLMDB::do_resize() mdb_env_stat(m_env, &mst); - uint64_t new_mapsize = (double)mei.me_mapsize * RESIZE_FACTOR; + // add 1Gb per resize, instead of doing a percentage increase + uint64_t new_mapsize = (double) mei.me_mapsize + add_size; + + // If given, use increase_size intead of above way of resizing. + // This is currently used for increasing by an estimated size at start of new + // batch txn. + if (increase_size > 0) + new_mapsize = mei.me_mapsize + increase_size; new_mapsize += (new_mapsize % mst.ms_psize); @@ -265,15 +321,16 @@ void BlockchainLMDB::do_resize() mdb_env_set_mapsize(m_env, new_mapsize); - LOG_PRINT_L0("LMDB Mapsize increased." - << " Old: " << mei.me_mapsize / (1024 * 1024) << "MiB" - << ", New: " << new_mapsize / (1024 * 1024) << "MiB"); + LOG_PRINT_GREEN("LMDB Mapsize increased." << " Old: " << mei.me_mapsize / (1024 * 1024) << "MiB" << ", New: " << new_mapsize / (1024 * 1024) << "MiB", LOG_LEVEL_0); mdb_txn_safe::allow_new_txns(); } -bool BlockchainLMDB::need_resize() const +// threshold_size is used for batch transactions +bool BlockchainLMDB::need_resize(uint64_t threshold_size) const { + LOG_PRINT_L3("BlockchainLMDB::" << __func__); +#if defined(ENABLE_AUTO_RESIZE) MDB_envinfo mei; mdb_env_info(m_env, &mei); @@ -282,21 +339,130 @@ bool BlockchainLMDB::need_resize() const mdb_env_stat(m_env, &mst); + // size_used doesn't include data yet to be committed, which can be + // significant size during batch transactions. For that, we estimate the size + // needed at the beginning of the batch transaction and pass in the + // additional size needed. uint64_t size_used = mst.ms_psize * mei.me_last_pgno; - if ((double)size_used / mei.me_mapsize > RESIZE_PERCENT) + LOG_PRINT_L1("DB map size: " << mei.me_mapsize); + LOG_PRINT_L1("Space used: " << size_used); + LOG_PRINT_L1("Space remaining: " << mei.me_mapsize - size_used); + LOG_PRINT_L1("Size threshold: " << threshold_size); + float resize_percent_old = RESIZE_PERCENT; + LOG_PRINT_L1(boost::format("Percent used: %.04f Percent threshold: %.04f") % ((double)size_used/mei.me_mapsize) % resize_percent_old); + + if (threshold_size > 0) { + if (mei.me_mapsize - size_used < threshold_size) + { + LOG_PRINT_L1("Threshold met (size-based)"); + return true; + } + else + return false; + } + + std::mt19937 engine(std::random_device{}()); + std::uniform_real_distribution fdis(0.6, 0.9); + double resize_percent = fdis(engine); + + if ((double)size_used / mei.me_mapsize > resize_percent) + { + LOG_PRINT_L1("Threshold met (percent-based)"); return true; } return false; +#else + return false; +#endif } -void BlockchainLMDB::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 - ) +void BlockchainLMDB::check_and_resize_for_batch(uint64_t batch_num_blocks) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + LOG_PRINT_L1("[" << __func__ << "] " << "checking DB size"); + const uint64_t min_increase_size = 128 * (1 << 20); + uint64_t threshold_size = 0; + uint64_t increase_size = 0; + if (batch_num_blocks > 0) + { + threshold_size = get_estimated_batch_size(batch_num_blocks); + LOG_PRINT_L1("calculated batch size: " << threshold_size); + + // The increased DB size could be a multiple of threshold_size, a fixed + // size increase (> threshold_size), or other variations. + // + // Currently we use the greater of threshold size and a minimum size. The + // minimum size increase is used to avoid frequent resizes when the batch + // size is set to a very small numbers of blocks. + increase_size = (threshold_size > min_increase_size) ? threshold_size : min_increase_size; + LOG_PRINT_L1("increase size: " << increase_size); + } + + // if threshold_size is 0 (i.e. number of blocks for batch not passed in), it + // will fall back to the percent-based threshold check instead of the + // size-based check + if (need_resize(threshold_size)) + { + LOG_PRINT_L0("[batch] DB resize needed"); + do_resize(increase_size); + } +} + +uint64_t BlockchainLMDB::get_estimated_batch_size(uint64_t batch_num_blocks) const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + uint64_t threshold_size = 0; + + // batch size estimate * batch safety factor = final size estimate + // Takes into account "reasonable" block size increases in batch. + float batch_safety_factor = 1.7f; + // estimate of stored block expanded from raw block, including denormalization and db overhead. + // Note that this probably doesn't grow linearly with block size. + float db_expand_factor = 4.5f; + uint64_t num_prev_blocks = 500; + // For resizing purposes, allow for at least 4k average block size. + uint64_t min_block_size = 4 * 1024; + + uint64_t block_stop = 0; + if (m_height > 1) + block_stop = m_height - 1; + uint64_t block_start = 0; + if (block_stop >= num_prev_blocks) + block_start = block_stop - num_prev_blocks + 1; + uint32_t num_blocks_used = 0; + uint64_t total_block_size = 0; + LOG_PRINT_L1("[" << __func__ << "] " << "m_height: " << m_height << " block_start: " << block_start << " block_stop: " << block_stop); + size_t avg_block_size = 0; + if (m_height == 0) + { + LOG_PRINT_L1("No existing blocks to check for average block size"); + } + else + { + for (uint64_t block_num = block_start; block_num <= block_stop; ++block_num) + { + uint32_t block_size = get_block_size(block_num); + total_block_size += block_size; + // Track number of blocks being totalled here instead of assuming, in case + // some blocks were to be skipped for being outliers. + ++num_blocks_used; + } + avg_block_size = total_block_size / num_blocks_used; + LOG_PRINT_L1("average block size across recent " << num_blocks_used << " blocks: " << avg_block_size); + } + if (avg_block_size < min_block_size) + avg_block_size = min_block_size; + LOG_PRINT_L1("estimated average block size for batch: " << avg_block_size); + + threshold_size = avg_block_size * db_expand_factor * batch_num_blocks; + threshold_size = threshold_size * batch_safety_factor; + return threshold_size; +} + +void BlockchainLMDB::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("BlockchainLMDB::" << __func__); check_open(); @@ -447,7 +613,7 @@ void BlockchainLMDB::remove_transaction_data(const crypto::hash& tx_hash, const } -void BlockchainLMDB::add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index) +void BlockchainLMDB::add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); @@ -476,10 +642,15 @@ void BlockchainLMDB::add_output(const crypto::hash& tx_hash, const tx_out& tx_ou if (tx_output.target.type() == typeid(txout_to_key)) { - MDB_val_copy val_pubkey(boost::get(tx_output.target).key); - result = mdb_put(*m_write_txn, m_output_keys, &k, &val_pubkey, 0); - if (result) - throw0(DB_ERROR(std::string("Failed to add output pubkey to db transaction: ").append(mdb_strerror(result)).c_str())); + output_data_t od; + od.pubkey = boost::get < txout_to_key > (tx_output.target).key; + od.unlock_time = unlock_time; + od.height = m_height; + + MDB_val_copy data(od); + //MDB_val_copy val_pubkey(boost::get(tx_output.target).key); + if (mdb_put(*m_write_txn, m_output_keys, &k, &data, 0)) + throw0(DB_ERROR("Failed to add output pubkey to db transaction")); } @@ -710,47 +881,17 @@ tx_out BlockchainLMDB::output_from_blob(const blobdata& blob) const return o; } -uint64_t BlockchainLMDB::get_output_global_index(const uint64_t& amount, const uint64_t& index) const +uint64_t BlockchainLMDB::get_output_global_index(const uint64_t& amount, const uint64_t& index) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); - check_open(); - - mdb_txn_safe txn; - if (mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - - lmdb_cur cur(txn, m_output_amounts); - - MDB_val_copy k(amount); - MDB_val v; - - auto result = mdb_cursor_get(cur, &k, &v, MDB_SET); - if (result == MDB_NOTFOUND) + std::vector offsets; + std::vector 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")); - else if (result) - throw0(DB_ERROR("DB error attempting to get an output")); - size_t num_elems = 0; - mdb_cursor_count(cur, &num_elems); - if (num_elems <= index) - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but output not found")); - - mdb_cursor_get(cur, &k, &v, MDB_FIRST_DUP); - - for (uint64_t i = 0; i < index; ++i) - { - mdb_cursor_get(cur, &k, &v, MDB_NEXT_DUP); - } - - mdb_cursor_get(cur, &k, &v, MDB_GET_CURRENT); - - uint64_t glob_index = *(const uint64_t*)v.mv_data; - - cur.close(); - - txn.commit(); - - return glob_index; + return global_indices[0]; } void BlockchainLMDB::check_open() const @@ -805,8 +946,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) // check for existing LMDB files in base directory boost::filesystem::path old_files = direc.parent_path(); - if (boost::filesystem::exists(old_files / "data.mdb") || - boost::filesystem::exists(old_files / "lock.mdb")) + if (boost::filesystem::exists(old_files / "data.mdb") || boost::filesystem::exists(old_files / "lock.mdb")) { LOG_PRINT_L0("Found existing LMDB files in " << old_files.string()); LOG_PRINT_L0("Move data.mdb and/or lock.mdb to " << filename << ", or delete them, and then restart"); @@ -872,7 +1012,7 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) lmdb_db_open(txn, LMDB_OUTPUT_TXS, MDB_INTEGERKEY | MDB_CREATE, m_output_txs, "Failed to open db handle for m_output_txs"); lmdb_db_open(txn, LMDB_OUTPUT_INDICES, MDB_INTEGERKEY | MDB_CREATE, m_output_indices, "Failed to open db handle for m_output_indices"); - lmdb_db_open(txn, LMDB_OUTPUT_AMOUNTS, MDB_INTEGERKEY | MDB_DUPSORT | MDB_CREATE, m_output_amounts, "Failed to open db handle for m_output_amounts"); + 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"); lmdb_db_open(txn, LMDB_OUTPUT_KEYS, MDB_INTEGERKEY | MDB_CREATE, m_output_keys, "Failed to open db handle for m_output_keys"); /*************** not used, but kept for posterity @@ -884,6 +1024,11 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) mdb_set_dupsort(txn, m_output_amounts, compare_uint64); mdb_set_dupsort(txn, m_tx_outputs, compare_uint64); + mdb_set_compare(txn, m_spent_keys, compare_hash32); + mdb_set_compare(txn, m_block_heights, compare_hash32); + mdb_set_compare(txn, m_txs, compare_hash32); + mdb_set_compare(txn, m_tx_unlocks, compare_hash32); + mdb_set_compare(txn, m_tx_heights, compare_hash32); // get and keep current height MDB_stat db_stats; @@ -897,6 +1042,34 @@ void BlockchainLMDB::open(const std::string& filename, const int mdb_flags) throw0(DB_ERROR("Failed to query m_output_indices")); m_num_outputs = db_stats.ms_entries; + // ND: This "new" version of the lmdb database is incompatible with + // the previous version. Ensure that the output_keys database is + // sizeof(output_data_t) in length. Otherwise, inform user and + // terminate. + if(m_height > 0) + { + MDB_val_copy k(0); + MDB_val v; + auto get_result = mdb_get(txn, m_output_keys, &k, &v); + if(get_result != MDB_SUCCESS) + { + txn.abort(); + m_open = false; + return; + } + + // LOG_PRINT_L0("Output keys size: " << v.mv_size); + if(v.mv_size != sizeof(output_data_t)) + { + txn.abort(); + mdb_env_close(m_env); + m_open = false; + LOG_PRINT_RED_L0("Existing lmdb database is incompatible with this version."); + LOG_PRINT_RED_L0("Please delete the existing database and resync."); + return; + } + } + // commit the transaction txn.commit(); @@ -1464,19 +1637,6 @@ uint64_t BlockchainLMDB::get_tx_block_height(const crypto::hash& h) const return *(const uint64_t*)result.mv_data; } -//FIXME: make sure the random method used here is appropriate -uint64_t BlockchainLMDB::get_random_output(const uint64_t& amount) const -{ - LOG_PRINT_L3("BlockchainLMDB::" << __func__); - check_open(); - - uint64_t num_outputs = get_num_outputs(amount); - if (num_outputs == 0) - throw1(OUTPUT_DNE("Attempting to get a random output for an amount, but none exist")); - - return crypto::rand() % num_outputs; -} - uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); @@ -1506,26 +1666,33 @@ uint64_t BlockchainLMDB::get_num_outputs(const uint64_t& amount) const return num_elems; } -crypto::public_key BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index) const +output_data_t BlockchainLMDB::get_output_key(const uint64_t &global_index) const { LOG_PRINT_L3("BlockchainLMDB::" << __func__); check_open(); - uint64_t glob_index = get_output_global_index(amount, index); - mdb_txn_safe txn; if (mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn)) throw0(DB_ERROR("Failed to create a transaction for the db")); - MDB_val_copy k(glob_index); + MDB_val_copy k(global_index); MDB_val v; auto get_result = mdb_get(txn, m_output_keys, &k, &v); if (get_result == MDB_NOTFOUND) throw0(DB_ERROR("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")); + txn.commit(); + return *(output_data_t *) v.mv_data; +} - return *(crypto::public_key*)v.mv_data; +output_data_t BlockchainLMDB::get_output_key(const uint64_t& amount, const uint64_t& index) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + + uint64_t glob_index = get_output_global_index(amount, index); + return get_output_key(glob_index); } tx_out BlockchainLMDB::get_output(const crypto::hash& h, const uint64_t& index) const @@ -1633,53 +1800,17 @@ tx_out_index BlockchainLMDB::get_output_tx_and_index_from_global(const uint64_t& return tx_out_index(tx_hash, *(const uint64_t *)v.mv_data); } -tx_out_index BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) const +tx_out_index BlockchainLMDB::get_output_tx_and_index(const uint64_t& amount, const uint64_t& index) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); - check_open(); - - mdb_txn_safe txn; - mdb_txn_safe* txn_ptr = &txn; - if (m_batch_active) - txn_ptr = m_write_txn; - else - { - if (mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn)) - throw0(DB_ERROR("Failed to create a transaction for the db")); - } - lmdb_cur cur(*txn_ptr, m_output_amounts); - - MDB_val_copy k(amount); - MDB_val v; - - auto result = mdb_cursor_get(cur, &k, &v, MDB_SET); - if (result == MDB_NOTFOUND) + 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")); - else if (result) - throw0(DB_ERROR("DB error attempting to get an output")); - size_t num_elems = 0; - mdb_cursor_count(cur, &num_elems); - if (num_elems <= index) - throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but output not found")); - - mdb_cursor_get(cur, &k, &v, MDB_FIRST_DUP); - - for (uint64_t i = 0; i < index; ++i) - { - mdb_cursor_get(cur, &k, &v, MDB_NEXT_DUP); - } - - mdb_cursor_get(cur, &k, &v, MDB_GET_CURRENT); - - uint64_t glob_index = *(const uint64_t*)v.mv_data; - - cur.close(); - - if (! m_batch_active) - txn.commit(); - - return get_output_tx_and_index_from_global(glob_index); + return indices[0]; } std::vector BlockchainLMDB::get_tx_output_indices(const crypto::hash& h) const @@ -1820,7 +1951,8 @@ bool BlockchainLMDB::has_key_image(const crypto::key_image& img) const return false; } -void BlockchainLMDB::batch_start() +// batch_num_blocks: (optional) Used to check if resize needed before batch transaction starts. +void BlockchainLMDB::batch_start(uint64_t batch_num_blocks) { LOG_PRINT_L3("BlockchainLMDB::" << __func__); if (! m_batch_transactions) @@ -1833,6 +1965,8 @@ void BlockchainLMDB::batch_start() throw0(DB_ERROR("batch transaction attempted, but m_write_txn already in use")); check_open(); + check_and_resize_for_batch(batch_num_blocks); + m_write_batch_txn = new mdb_txn_safe(); // NOTE: need to make sure it's destroyed properly when done @@ -1915,19 +2049,16 @@ void BlockchainLMDB::set_batch_transactions(bool batch_transactions) LOG_PRINT_L3("batch transactions " << (m_batch_transactions ? "enabled" : "disabled")); } -uint64_t BlockchainLMDB::add_block( const block& blk - , const size_t& block_size - , const difficulty_type& cumulative_difficulty - , const uint64_t& coins_generated - , const std::vector& txs - ) +uint64_t BlockchainLMDB::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("BlockchainLMDB::" << __func__); check_open(); if (m_height % 1000 == 0) { - if (need_resize()) + // for batch mode, DB resize check is done at start of batch transaction + if (! m_batch_active && need_resize()) { LOG_PRINT_L0("LMDB memory map needs resized, doing that now."); do_resize(); @@ -2001,4 +2132,219 @@ void BlockchainLMDB::pop_block(block& blk, std::vector& txs) --m_height; } +void BlockchainLMDB::get_output_tx_and_index_from_global(const std::vector &global_indices, + std::vector &tx_out_indices) const +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + tx_out_indices.clear(); + + mdb_txn_safe txn; + mdb_txn_safe* txn_ptr = &txn; + if (m_batch_active) + txn_ptr = m_write_txn; + else + { + if (mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn)) + throw0(DB_ERROR("Failed to create a transaction for the db")); + } + + for (const uint64_t &index : global_indices) + { + MDB_val_copy k(index); + MDB_val v; + + auto get_result = mdb_get(*txn_ptr, m_output_txs, &k, &v); + 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")); + + crypto::hash tx_hash = *(crypto::hash*) v.mv_data; + + get_result = mdb_get(*txn_ptr, m_output_indices, &k, &v); + 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 index")); + + auto result = tx_out_index(tx_hash, *(const uint64_t *) v.mv_data); + tx_out_indices.push_back(result); + } + + if (!m_batch_active) + txn.commit(); +} + +void BlockchainLMDB::get_output_global_indices(const uint64_t& amount, const std::vector &offsets, + std::vector &global_indices) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + TIME_MEASURE_START(txx); + check_open(); + global_indices.clear(); + + uint64_t max = 0; + for (const uint64_t &index : offsets) + { + if (index > max) + max = index; + } + + mdb_txn_safe txn; + mdb_txn_safe* txn_ptr = &txn; + if(m_batch_active) + txn_ptr = m_write_txn; + else + { + if (mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn)) + throw0(DB_ERROR("Failed to create a transaction for the db")); + } + + lmdb_cur cur(*txn_ptr, m_output_amounts); + + MDB_val_copy k(amount); + MDB_val v; + auto result = mdb_cursor_get(cur, &k, &v, MDB_SET); + if (result == MDB_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")); + + size_t num_elems = 0; + mdb_cursor_count(cur, &num_elems); + if (max <= 1 && num_elems <= max) + throw1(OUTPUT_DNE("Attempting to get an output index by amount and amount index, but output not found")); + + uint64_t t_dbmul = 0; + uint64_t t_dbscan = 0; + if (max <= 1) + { + for (const uint64_t& index : offsets) + { + mdb_cursor_get(cur, &k, &v, MDB_FIRST_DUP); + for (uint64_t i = 0; i < index; ++i) + { + mdb_cursor_get(cur, &k, &v, MDB_NEXT_DUP); + } + + mdb_cursor_get(cur, &k, &v, MDB_GET_CURRENT); + uint64_t glob_index = *(const uint64_t*) v.mv_data; + LOG_PRINT_L3("Amount: " << amount << " M0->v: " << glob_index); + global_indices.push_back(glob_index); + } + } + else + { + 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; + } + while (index >= curcount) + { + TIME_MEASURE_START(db1); + if (mdb_cursor_get(cur, &k, &v, curcount == 0 ? MDB_GET_MULTIPLE : MDB_NEXT_MULTIPLE) != 0) + { + // allow partial results + result = false; + break; + } + + int count = v.mv_size / sizeof(uint64_t); + + blockstart = curcount; + curcount += count; + TIME_MEASURE_FINISH(db1); + t_dbmul += db1; + } + + LOG_PRINT_L3("Records returned: " << curcount << " Index: " << index); + TIME_MEASURE_START(db2); + uint64_t actual_index = index - blockstart; + uint64_t glob_index = ((const uint64_t*) v.mv_data)[actual_index]; + + LOG_PRINT_L3("Amount: " << amount << " M1->v: " << glob_index); + global_indices.push_back(glob_index); + + TIME_MEASURE_FINISH(db2); + t_dbscan += db2; + + } + } + + cur.close(); + if(!m_batch_active) + txn.commit(); + + TIME_MEASURE_FINISH(txx); + LOG_PRINT_L3("txx: " << txx << " db1: " << t_dbmul << " db2: " << t_dbscan); +} + +void BlockchainLMDB::get_output_key(const uint64_t &amount, const std::vector &offsets, std::vector &outputs) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + TIME_MEASURE_START(db3); + check_open(); + outputs.clear(); + + std::vector global_indices; + get_output_global_indices(amount, offsets, global_indices); + + if (global_indices.size() > 0) + { + mdb_txn_safe txn; + mdb_txn_safe* txn_ptr = &txn; + if (m_batch_active) + txn_ptr = m_write_txn; + else + { + if (mdb_txn_begin(m_env, NULL, MDB_RDONLY, txn)) + throw0(DB_ERROR("Failed to create a transaction for the db")); + } + for (const uint64_t &index : global_indices) + { + MDB_val_copy k(index); + MDB_val v; + + auto get_result = mdb_get(*txn_ptr, m_output_keys, &k, &v); + if (get_result != 0) + throw0(DB_ERROR("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")); + + output_data_t data = *(output_data_t *) v.mv_data; + outputs.push_back(data); + } + + if (!m_batch_active) + txn.commit(); + } + + 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) +{ + LOG_PRINT_L3("BlockchainLMDB::" << __func__); + check_open(); + indices.clear(); + + std::vector 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); +} + } // namespace cryptonote diff --git a/src/blockchain_db/lmdb/db_lmdb.h b/src/blockchain_db/lmdb/db_lmdb.h index 6a2646816..b4c197803 100644 --- a/src/blockchain_db/lmdb/db_lmdb.h +++ b/src/blockchain_db/lmdb/db_lmdb.h @@ -33,6 +33,8 @@ #include +#define ENABLE_AUTO_RESIZE + namespace cryptonote { @@ -155,11 +157,11 @@ public: virtual uint64_t get_tx_block_height(const crypto::hash& h) const; - virtual uint64_t get_random_output(const uint64_t& amount) const; - virtual uint64_t get_num_outputs(const uint64_t& amount) const; - virtual crypto::public_key get_output_key(const uint64_t& amount, const uint64_t& index) const; + 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 get_output(const crypto::hash& h, const uint64_t& index) const; @@ -175,8 +177,12 @@ public: tx_out get_output(const uint64_t& index) const; 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) 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 void get_output_global_indices(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; @@ -191,17 +197,20 @@ public: ); virtual void set_batch_transactions(bool batch_transactions); - virtual void batch_start(); + virtual void batch_start(uint64_t batch_num_blocks=0); virtual void batch_commit(); virtual void batch_stop(); virtual void batch_abort(); virtual void pop_block(block& blk, std::vector& txs); + virtual bool can_thread_bulk_indices() const { return true; } private: - void do_resize(); + void do_resize(uint64_t size_increase=0); - bool need_resize() const; + bool need_resize(uint64_t threshold_size=0) const; + void check_and_resize_for_batch(uint64_t batch_num_blocks); + uint64_t get_estimated_batch_size(uint64_t batch_num_blocks) const; virtual void add_block( const block& blk , const size_t& block_size @@ -216,7 +225,7 @@ private: 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); + virtual void add_output(const crypto::hash& tx_hash, const tx_out& tx_output, const uint64_t& local_index, const uint64_t unlock_time); virtual void remove_output(const tx_out& tx_output); @@ -255,7 +264,7 @@ private: * * @return the global index of the desired output */ - uint64_t get_output_global_index(const uint64_t& amount, const uint64_t& index) const; + uint64_t get_output_global_index(const uint64_t& amount, const uint64_t& index); void check_open() const; @@ -292,9 +301,18 @@ private: bool m_batch_transactions; // support for batch transactions bool m_batch_active; // whether batch transaction is in progress - constexpr static uint64_t DEFAULT_MAPSIZE = 1 << 30; +#if defined(__arm__) + // force a value so it can compile with 32-bit ARM + constexpr static uint64_t DEFAULT_MAPSIZE = 1LL << 31; +#else +#if defined(ENABLE_AUTO_RESIZE) + constexpr static uint64_t DEFAULT_MAPSIZE = 1LL << 30; +#else + constexpr static uint64_t DEFAULT_MAPSIZE = 1LL << 33; +#endif +#endif + constexpr static float RESIZE_PERCENT = 0.8f; - constexpr static float RESIZE_FACTOR = 1.5f; }; } // namespace cryptonote diff --git a/src/blockchain_utilities/README.md b/src/blockchain_utilities/README.md index 9ac8c5dd8..9fba77194 100644 --- a/src/blockchain_utilities/README.md +++ b/src/blockchain_utilities/README.md @@ -4,13 +4,19 @@ Copyright (c) 2014-2015, The Monero Project ## Introduction +The blockchain utilities allow one to convert an old style blockchain.bin file +to a new style database. There are two ways to upgrade an old style blockchain: +The recommended way is to run a `blockchain_export`, then `blockchain_import`. +The other way is to run `blockchain_converter`. In both cases, you will be left +with a new style blockchain. + For importing into the LMDB database, compile with `DATABASE=lmdb` e.g. `DATABASE=lmdb make release` -This is also the default compile setting on the blockchain branch. +This is also the default compile setting on the master branch. By default, the exporter will use the original in-memory database (blockchain.bin) as its source. This default is to make migrating to an LMDB database easy, without having to recompile anything. @@ -30,7 +36,8 @@ This loads the existing blockchain, for whichever database type it was compiled `$ blockchain_import` -This imports blocks from `$MONERO_DATA_DIR/export/blockchain.raw` into the current database. +This imports blocks from `$MONERO_DATA_DIR/export/blockchain.raw` (exported using the `blockchain_export` tool as described above) +into the current database. Defaults: `--batch on`, `--batch size 20000`, `--verify on` @@ -38,6 +45,9 @@ Batch size refers to number of blocks and can be adjusted for performance based Verification should only be turned off if importing from a trusted blockchain. +If you encounter an error like "resizing not supported in batch mode", you can just re-run +the `blockchain_import` command again, and it will restart from where it left off. + ```bash ## use default settings to import blockchain.raw into database $ blockchain_import diff --git a/src/blockchain_utilities/blockchain_converter.cpp b/src/blockchain_utilities/blockchain_converter.cpp index 855dde644..d18ce8789 100644 --- a/src/blockchain_utilities/blockchain_converter.cpp +++ b/src/blockchain_utilities/blockchain_converter.cpp @@ -236,7 +236,7 @@ int main(int argc, char* argv[]) } if (opt_batch) - blockchain->batch_start(); + blockchain->batch_start(db_batch_size); uint64_t i = 0; for (i = start_block; i < end_block + 1; ++i) { @@ -277,7 +277,7 @@ int main(int argc, char* argv[]) std::cout << "\r \r"; std::cout << "[- batch commit at height " << i + 1 << " -]" << ENDL; blockchain->batch_stop(); - blockchain->batch_start(); + blockchain->batch_start(db_batch_size); std::cout << ENDL; blockchain->show_stats(); } diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp index ec885ea98..8db8b7cdb 100644 --- a/src/blockchain_utilities/blockchain_export.cpp +++ b/src/blockchain_utilities/blockchain_export.cpp @@ -39,13 +39,14 @@ int main(int argc, char* argv[]) { uint32_t log_level = 0; uint64_t block_stop = 0; - std::string import_filename = BLOCKCHAIN_RAW; boost::filesystem::path default_data_path {tools::get_default_data_dir()}; boost::filesystem::path default_testnet_data_path {default_data_path / "testnet"}; + boost::filesystem::path output_file_path; po::options_description desc_cmd_only("Command line options"); po::options_description desc_cmd_sett("Command line options and settings options"); + const command_line::arg_descriptor arg_output_file = {"output-file", "Specify output file", "", true}; const command_line::arg_descriptor arg_log_level = {"log-level", "", log_level}; const command_line::arg_descriptor arg_block_stop = {"block-stop", "Stop at block number", block_stop}; const command_line::arg_descriptor arg_testnet_on = { @@ -57,6 +58,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_cmd_sett, command_line::arg_data_dir, default_data_path.string()); command_line::add_arg(desc_cmd_sett, command_line::arg_testnet_data_dir, default_testnet_data_path.string()); + command_line::add_arg(desc_cmd_sett, arg_output_file); command_line::add_arg(desc_cmd_sett, arg_testnet_on); command_line::add_arg(desc_cmd_sett, arg_log_level); command_line::add_arg(desc_cmd_sett, arg_block_stop); @@ -97,9 +99,12 @@ int main(int argc, char* argv[]) auto data_dir_arg = opt_testnet ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; m_config_folder = command_line::get_arg(vm, data_dir_arg); - boost::filesystem::path output_dir {m_config_folder}; - output_dir /= "export"; - LOG_PRINT_L0("Export directory: " << output_dir.string()); + + if (command_line::has_arg(vm, arg_output_file)) + output_file_path = boost::filesystem::path(command_line::get_arg(vm, arg_output_file)); + else + output_file_path = boost::filesystem::path(m_config_folder) / "export" / BLOCKCHAIN_RAW; + LOG_PRINT_L0("Export output file: " << output_file_path.string()); // If we wanted to use the memory pool, we would set up a fake_core. @@ -151,7 +156,7 @@ int main(int argc, char* argv[]) LOG_PRINT_L0("Exporting blockchain raw data..."); BootstrapFile bootstrap; - r = bootstrap.store_blockchain_raw(core_storage, NULL, output_dir, block_stop); + r = bootstrap.store_blockchain_raw(core_storage, NULL, output_file_path, block_stop); CHECK_AND_ASSERT_MES(r, false, "Failed to export blockchain raw data"); LOG_PRINT_L0("Blockchain raw data exported OK"); } diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp index aeed2b335..88d748411 100644 --- a/src/blockchain_utilities/blockchain_import.cpp +++ b/src/blockchain_utilities/blockchain_import.cpp @@ -173,7 +173,7 @@ int pop_blocks(FakeCore& simple_core, int num_blocks) } template -int import_from_file(FakeCore& simple_core, std::string& import_file_path, uint64_t block_stop=0) +int import_from_file(FakeCore& simple_core, const std::string& import_file_path, uint64_t block_stop=0) { #if !defined(BLOCKCHAIN_DB) static_assert(std::is_same::value || std::is_same::value, @@ -188,11 +188,11 @@ int import_from_file(FakeCore& simple_core, std::string& import_file_path, uint6 simple_core.m_storage.get_db().reset_stats(); } #endif - boost::filesystem::path raw_file_path(import_file_path); + boost::filesystem::path fs_import_file_path(import_file_path); boost::system::error_code ec; - if (!boost::filesystem::exists(raw_file_path, ec)) + if (!boost::filesystem::exists(fs_import_file_path, ec)) { - LOG_PRINT_L0("bootstrap file not found: " << raw_file_path); + LOG_PRINT_L0("bootstrap file not found: " << fs_import_file_path); return false; } @@ -254,7 +254,7 @@ int import_from_file(FakeCore& simple_core, std::string& import_file_path, uint6 } if (use_batch) - simple_core.batch_start(); + simple_core.batch_start(db_batch_size); LOG_PRINT_L0("Reading blockchain from bootstrap file..."); std::cout << ENDL; @@ -482,7 +482,7 @@ int import_from_file(FakeCore& simple_core, std::string& import_file_path, uint6 // zero-based height std::cout << ENDL << "[- batch commit at height " << h-1 << " -]" << ENDL; simple_core.batch_stop(); - simple_core.batch_start(); + simple_core.batch_start(db_batch_size); std::cout << ENDL; #if !defined(BLOCKCHAIN_DB) || (BLOCKCHAIN_DB == DB_LMDB) simple_core.m_storage.get_db().show_stats(); @@ -526,7 +526,6 @@ int import_from_file(FakeCore& simple_core, std::string& import_file_path, uint6 int main(int argc, char* argv[]) { - std::string import_filename = BLOCKCHAIN_RAW; #if defined(BLOCKCHAIN_DB) && (BLOCKCHAIN_DB == DB_MEMORY) std::string default_db_engine = "memory"; #else @@ -536,14 +535,16 @@ int main(int argc, char* argv[]) uint32_t log_level = LOG_LEVEL_0; uint64_t num_blocks = 0; uint64_t block_stop = 0; - std::string dirname; + std::string m_config_folder; std::string db_arg_str; boost::filesystem::path default_data_path {tools::get_default_data_dir()}; boost::filesystem::path default_testnet_data_path {default_data_path / "testnet"}; + std::string import_file_path; po::options_description desc_cmd_only("Command line options"); po::options_description desc_cmd_sett("Command line options and settings options"); + const command_line::arg_descriptor arg_input_file = {"input-file", "Specify input file", "", true}; const command_line::arg_descriptor arg_log_level = {"log-level", "", log_level}; const command_line::arg_descriptor arg_block_stop = {"block-stop", "Stop at block number", block_stop}; const command_line::arg_descriptor arg_batch_size = {"batch-size", "", db_batch_size}; @@ -571,6 +572,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_cmd_sett, command_line::arg_data_dir, default_data_path.string()); command_line::add_arg(desc_cmd_sett, command_line::arg_testnet_data_dir, default_testnet_data_path.string()); + command_line::add_arg(desc_cmd_sett, arg_input_file); command_line::add_arg(desc_cmd_sett, arg_testnet_on); command_line::add_arg(desc_cmd_sett, arg_log_level); command_line::add_arg(desc_cmd_sett, arg_database); @@ -643,7 +645,7 @@ int main(int argc, char* argv[]) opt_testnet = command_line::get_arg(vm, arg_testnet_on); auto data_dir_arg = opt_testnet ? command_line::arg_testnet_data_dir : command_line::arg_data_dir; - dirname = command_line::get_arg(vm, data_dir_arg); + m_config_folder = command_line::get_arg(vm, data_dir_arg); db_arg_str = command_line::get_arg(vm, arg_database); log_space::get_set_log_detalisation_level(true, log_level); @@ -651,10 +653,15 @@ int main(int argc, char* argv[]) LOG_PRINT_L0("Starting..."); LOG_PRINT_L0("Setting log level = " << log_level); - boost::filesystem::path file_path {dirname}; - std::string import_file_path; + boost::filesystem::path fs_import_file_path; + + if (command_line::has_arg(vm, arg_input_file)) + fs_import_file_path = boost::filesystem::path(command_line::get_arg(vm, arg_input_file)); + else + fs_import_file_path = boost::filesystem::path(m_config_folder) / "export" / BLOCKCHAIN_RAW; + + import_file_path = fs_import_file_path.string(); - import_file_path = (file_path / "export" / import_filename).string(); if (command_line::has_arg(vm, arg_count_blocks)) { BootstrapFile bootstrap; @@ -694,7 +701,7 @@ int main(int argc, char* argv[]) LOG_PRINT_L0("testnet: " << std::boolalpha << opt_testnet << std::noboolalpha); LOG_PRINT_L0("bootstrap file path: " << import_file_path); - LOG_PRINT_L0("database path: " << file_path.string()); + LOG_PRINT_L0("database path: " << m_config_folder); try { @@ -710,12 +717,12 @@ int main(int argc, char* argv[]) #if !defined(BLOCKCHAIN_DB) if (db_engine == "lmdb") { - fake_core_lmdb simple_core(dirname, opt_testnet, opt_batch, mdb_flags); + fake_core_lmdb simple_core(m_config_folder, opt_testnet, opt_batch, mdb_flags); import_from_file(simple_core, import_file_path, block_stop); } else if (db_engine == "memory") { - fake_core_memory simple_core(dirname, opt_testnet); + fake_core_memory simple_core(m_config_folder, opt_testnet); import_from_file(simple_core, import_file_path, block_stop); } else @@ -732,9 +739,9 @@ int main(int argc, char* argv[]) return 1; } #if BLOCKCHAIN_DB == DB_LMDB - fake_core_lmdb simple_core(dirname, opt_testnet, opt_batch, mdb_flags); + fake_core_lmdb simple_core(m_config_folder, opt_testnet, opt_batch, mdb_flags); #else - fake_core_memory simple_core(dirname, opt_testnet); + fake_core_memory simple_core(m_config_folder, opt_testnet); #endif if (! vm["pop-blocks"].defaulted()) diff --git a/src/blockchain_utilities/bootstrap_file.cpp b/src/blockchain_utilities/bootstrap_file.cpp index 70f0b1fec..ab841c8c6 100644 --- a/src/blockchain_utilities/bootstrap_file.cpp +++ b/src/blockchain_utilities/bootstrap_file.cpp @@ -50,8 +50,9 @@ namespace -bool BootstrapFile::open_writer(const boost::filesystem::path& dir_path) +bool BootstrapFile::open_writer(const boost::filesystem::path& file_path) { + const boost::filesystem::path dir_path = file_path.parent_path(); if (boost::filesystem::exists(dir_path)) { if (!boost::filesystem::is_directory(dir_path)) @@ -69,7 +70,6 @@ bool BootstrapFile::open_writer(const boost::filesystem::path& dir_path) } } - std::string file_path = (dir_path / BLOCKCHAIN_RAW).string(); m_raw_data_file = new std::ofstream(); bool do_initialize_file = false; @@ -83,15 +83,15 @@ bool BootstrapFile::open_writer(const boost::filesystem::path& dir_path) } else { - num_blocks = count_blocks(file_path); + num_blocks = count_blocks(file_path.string()); LOG_PRINT_L0("appending to existing file with height: " << num_blocks-1 << " total blocks: " << num_blocks); } m_height = num_blocks; if (do_initialize_file) - m_raw_data_file->open(file_path, std::ios_base::binary | std::ios_base::out | std::ios::trunc); + m_raw_data_file->open(file_path.string(), std::ios_base::binary | std::ios_base::out | std::ios::trunc); else - m_raw_data_file->open(file_path, std::ios_base::binary | std::ios_base::out | std::ios::app | std::ios::ate); + m_raw_data_file->open(file_path.string(), std::ios_base::binary | std::ios_base::out | std::ios::app | std::ios::ate); if (m_raw_data_file->fail()) return false; @@ -286,9 +286,9 @@ bool BootstrapFile::close() #if SOURCE_DB == DB_MEMORY -bool BootstrapFile::store_blockchain_raw(blockchain_storage* _blockchain_storage, tx_memory_pool* _tx_pool, boost::filesystem::path& output_dir, uint64_t requested_block_stop) +bool BootstrapFile::store_blockchain_raw(blockchain_storage* _blockchain_storage, tx_memory_pool* _tx_pool, boost::filesystem::path& output_file, uint64_t requested_block_stop) #else -bool BootstrapFile::store_blockchain_raw(Blockchain* _blockchain_storage, tx_memory_pool* _tx_pool, boost::filesystem::path& output_dir, uint64_t requested_block_stop) +bool BootstrapFile::store_blockchain_raw(Blockchain* _blockchain_storage, tx_memory_pool* _tx_pool, boost::filesystem::path& output_file, uint64_t requested_block_stop) #endif { uint64_t num_blocks_written = 0; @@ -297,7 +297,7 @@ bool BootstrapFile::store_blockchain_raw(Blockchain* _blockchain_storage, tx_mem m_tx_pool = _tx_pool; uint64_t progress_interval = 100; LOG_PRINT_L0("Storing blocks raw data..."); - if (!BootstrapFile::open_writer(output_dir)) + if (!BootstrapFile::open_writer(output_file)) { LOG_PRINT_RED_L0("failed to open raw file for write"); return false; @@ -454,7 +454,7 @@ uint64_t BootstrapFile::count_blocks(const std::string& import_file_path) str1.assign(buf1, sizeof(chunk_size)); if (! ::serialization::parse_binary(str1, chunk_size)) throw std::runtime_error("Error in deserialization of chunk_size"); - LOG_PRINT_L1("chunk_size: " << chunk_size); + LOG_PRINT_L3("chunk_size: " << chunk_size); if (chunk_size > BUFFER_SIZE) { diff --git a/src/blockchain_utilities/bootstrap_file.h b/src/blockchain_utilities/bootstrap_file.h index 5fb8a1d4a..fcf89d1ac 100644 --- a/src/blockchain_utilities/bootstrap_file.h +++ b/src/blockchain_utilities/bootstrap_file.h @@ -81,10 +81,10 @@ public: #if SOURCE_DB == DB_MEMORY bool store_blockchain_raw(cryptonote::blockchain_storage* cs, cryptonote::tx_memory_pool* txp, - boost::filesystem::path& output_dir, uint64_t use_block_height=0); + boost::filesystem::path& output_file, uint64_t use_block_height=0); #else bool store_blockchain_raw(cryptonote::Blockchain* cs, cryptonote::tx_memory_pool* txp, - boost::filesystem::path& output_dir, uint64_t use_block_height=0); + boost::filesystem::path& output_file, uint64_t use_block_height=0); #endif protected: @@ -102,7 +102,7 @@ protected: boost::iostreams::stream>* m_output_stream; // open export file for write - bool open_writer(const boost::filesystem::path& dir_path); + bool open_writer(const boost::filesystem::path& file_path); bool initialize_file(); bool close(); void write_block(block& block); diff --git a/src/blockchain_utilities/fake_core.h b/src/blockchain_utilities/fake_core.h index 79fb51842..5eda504fe 100644 --- a/src/blockchain_utilities/fake_core.h +++ b/src/blockchain_utilities/fake_core.h @@ -96,9 +96,9 @@ struct fake_core_lmdb return m_storage.get_db().add_block(blk, block_size, cumulative_difficulty, coins_generated, txs); } - void batch_start() + void batch_start(uint64_t batch_num_blocks = 0) { - m_storage.get_db().batch_start(); + m_storage.get_db().batch_start(batch_num_blocks); } void batch_stop() @@ -150,7 +150,7 @@ struct fake_core_memory return 2; } - void batch_start() + void batch_start(uint64_t batch_num_blocks = 0) { LOG_PRINT_L0("WARNING: [batch_start] opt_batch set, but this database doesn't support/need transactions - ignoring"); } diff --git a/src/blocks/CMakeLists.txt b/src/blocks/CMakeLists.txt new file mode 100644 index 000000000..4020132a9 --- /dev/null +++ b/src/blocks/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (c) 2014-2015, The Monero Project +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without modification, are +# permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, this list of +# conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, this list +# of conditions and the following disclaimer in the documentation and/or other +# materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its contributors may be +# used to endorse or promote products derived from this software without specific +# prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if(APPLE) + add_library(blocks STATIC blockexports.c) + set_target_properties(blocks PROPERTIES LINKER_LANGUAGE C) +else() + add_custom_command(OUTPUT blocks.o COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ld -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocks.o blocks.dat) + add_library(blocks STATIC blocks.o blockexports.c) + set_target_properties(blocks PROPERTIES LINKER_LANGUAGE C) +endif() + + diff --git a/src/blocks/blockexports.c b/src/blocks/blockexports.c new file mode 100644 index 000000000..cea72b299 --- /dev/null +++ b/src/blocks/blockexports.c @@ -0,0 +1,48 @@ +#include + +#if defined(__APPLE__) +#include + +#if !defined(__LP64__) +extern const struct mach_header _mh_execute_header; +#else +extern const struct mach_header_64 _mh_execute_header; +#endif + +const unsigned char *get_blocks_dat_start() +{ + size_t size; + return getsectiondata(&_mh_execute_header, "__DATA", "__blocks_dat", &size); +} + +size_t get_blocks_dat_size() +{ + size_t size; + getsectiondata(&_mh_execute_header, "__DATA", "__blocks_dat", &size); + return size; +} + +#else + +#if defined(_WIN32) && !defined(_WIN64) +#define _binary_blocks_start binary_blocks_dat_start +#define _binary_blocks_end binary_blocks_dat_end +#else +#define _binary_blocks_start _binary_blocks_dat_start +#define _binary_blocks_end _binary_blocks_dat_end +#endif + +extern const unsigned char _binary_blocks_start[]; +extern const unsigned char _binary_blocks_end[]; + +const unsigned char *get_blocks_dat_start(void) +{ + return _binary_blocks_start; +} + +size_t get_blocks_dat_size(void) +{ + return (size_t) (_binary_blocks_end - _binary_blocks_start); +} + +#endif diff --git a/src/blocks/blocks.dat b/src/blocks/blocks.dat new file mode 100644 index 000000000..e69de29bb diff --git a/src/blocks/blocks.h b/src/blocks/blocks.h new file mode 100644 index 000000000..76a08c89d --- /dev/null +++ b/src/blocks/blocks.h @@ -0,0 +1,16 @@ +#ifndef SRC_BLOCKS_BLOCKS_H_ +#define SRC_BLOCKS_BLOCKS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +const unsigned char *get_blocks_dat_start(); +size_t get_blocks_dat_size(); + +#ifdef __cplusplus +} +#endif + + +#endif /* SRC_BLOCKS_BLOCKS_H_ */ diff --git a/src/blocks/checkpoints.dat b/src/blocks/checkpoints.dat new file mode 100644 index 000000000..249956e75 Binary files /dev/null and b/src/blocks/checkpoints.dat differ diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 620e1add9..b1db006d9 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -30,7 +30,8 @@ set(common_sources base58.cpp command_line.cpp dns_utils.cpp - util.cpp) + util.cpp + i18n.cpp) set(common_headers) @@ -46,7 +47,8 @@ set(common_private_headers scoped_message_writer.h unordered_containers_boost_serialization.h util.h - varint.h) + varint.h + i18n.h) bitmonero_private_headers(common ${common_private_headers}) diff --git a/src/common/i18n.cpp b/src/common/i18n.cpp new file mode 100644 index 000000000..9add06cb9 --- /dev/null +++ b/src/common/i18n.cpp @@ -0,0 +1,297 @@ +// Copyright (c) 2014-2015, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include +#include +#include +#include +#include "include_base_utils.h" +#include "file_io_utils.h" +#include "common/util.h" +#include "common/i18n.h" + +static const unsigned char qm_magic[16] = {0x3c, 0xb8, 0x64, 0x18, 0xca, 0xef, 0x9c, 0x95, 0xcd, 0x21, 0x1c, 0xbf, 0x60, 0xa1, 0xbd, 0xdd}; + +static std::map i18n_entries; + +/* Logging isn't initialized yet when this is run */ +/* add std::flush, because std::endl doesn't seem to flush, contrary to expected */ +// #define i18n_log(x) do { std::cout << __FILE__ << ":" << __LINE__ << ": " << x << std::endl; std::cout << std::flush; } while(0) +#define i18n_log(x) ((void)0) + +static std::string get_language() +{ + const char *e; + + e = getenv("LANG"); + i18n_log("LANG=" << e); + if (!e || !*e) { + e = getenv("LC_ALL"); + i18n_log("LC_ALL=" << e); + } + if (!e || !*e) + e = "en"; + + std::string language = e; + std::transform(language.begin(), language.end(), language.begin(), tolower); + return language; +} + +static uint32_t be32(const unsigned char *data) +{ + return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; +} + +static std::string utf16(const unsigned char *data, uint32_t len) +{ + std::string s; + while (len >= 2) { + uint32_t code = (data[0] << 8) | data[1]; + data += 2; + len -= 2; + if (code >= 0xd800 && code <= 0xdbfff && len >= 2) { + uint32_t next = (data[0] << 8) | data[1]; + if (next >= 0xdc00 && next <= 0xdfff) { + code = (code << 10) + next - 0x35dfc00; + data += 2; + len -= 2; + } + } + if (code <= 0x7f) { + s += (char)code; + } + else if (code <= 0x7ff) { + s += 0xc0 | (code >> 6); + s += 0x80 | (code & 0x3f); + } + else if (code <= 0xffff) { + s += 0xe0 | (code >> 12); + s += 0x80 | ((code >> 6) & 0x3f); + s += 0x80 | (code & 0x3f); + } + else { + s += 0xf0 | (code >> 18); + s += 0x80 | ((code >> 12) & 0x3f); + s += 0x80 | ((code >> 6) & 0x3f); + s += 0x80 | (code & 0x3f); + } + } + return s; +} + +static std::string utf8(const unsigned char *data, uint32_t len) +{ + /* assume well formedness */ + return std::string((const char *)data,len); +} + +int i18n_set_language(const char *directory, const char *base) +{ + std::string language, filename, contents; + const unsigned char *data; + size_t datalen; + size_t idx; + unsigned char chunk_type; + uint32_t chunk_size; + uint32_t num_messages = (uint32_t)-1; + uint32_t messages_idx = (uint32_t)-1; + uint32_t offsets_idx = (uint32_t)-1; + std::string translation, source, context; + + i18n_log("i18n_set_language(" << directory << "," << base << ")"); + if (!directory || !base) + return -1; + + language = get_language(); + filename = std::string(directory) + "/" + base + "_" + language + ".qm"; + i18n_log("Loading translations for language " << language); + + boost::system::error_code ignored_ec; + if (!boost::filesystem::exists(filename, ignored_ec)) { + i18n_log("Translations file not found: " << filename); + const char *underscore = strchr(language.c_str(), '_'); + if (underscore) { + std::string fallback_language = std::string(language, 0, underscore - language.c_str()); + filename = std::string(directory) + "/" + base + "_" + fallback_language + ".qm"; + i18n_log("Not found, loading translations for language " << fallback_language); + if (!boost::filesystem::exists(filename, ignored_ec)) { + i18n_log("Translations file not found: " << filename); + return -1; + } + } + } + + if (!epee::file_io_utils::load_file_to_string(filename, contents)) { + i18n_log("Failed to load translations file: " << filename); + return -1; + } + + data = (const unsigned char*)contents.c_str(); + datalen = contents.size(); + idx = 0; + i18n_log("Translations file size: " << datalen); + + /* Format of the QM file (AFAICT): + * 16 bytes magic + * chunk list: N instances of chunks: + * 1 byte: chunk type (0x42: offsets, 0x69: messages) + * 4 bytes: chunk length, big endian + * D bytes: "chunk length" bytes of data + * + * 0x42 chunk: N instances of subchunks: + * 1 byte: subchunk type + * 0x01: end, no data + * 0x02: unsupported + * 0x03: translation + * 4 bytes: string length, big endian + * N bytes: string data, UTF-16 (or UCS2-BE ?) + * 0x04: unsupported + * 0x05: obsolete, unsupported + * 0x06: source text + * 0x07: context + * 0x08: obsolete, unsupported + * other: unsupported + * 4 bytes: subchunk length, big endian - except for 0x01, which has none + * S bytes: "chunk length" bytes of data + * 0x69 chunk: + * string data indexed by the 0x42 chunk data + */ + if (datalen < sizeof(qm_magic) || memcmp(data, qm_magic, sizeof(qm_magic))) { + i18n_log("Bad translations file format: " << filename); + return -1; + } + idx += sizeof(qm_magic); + + while (idx < datalen) { + if (idx + 5 > datalen) { + i18n_log("Bad translations file format: " << filename); + return -1; + } + chunk_type = data[idx++]; + chunk_size = be32(data+idx); + idx += 4; + + i18n_log("Found " << chunk_type << " of " << chunk_size << " bytes"); + if (chunk_size >= datalen || idx > datalen - chunk_size) { + i18n_log("Bad translations file format: " << filename); + return -1; + } + + switch (chunk_type) { + case 0x42: + i18n_log("Found offsets at " << idx); + /* two 32 bit integers, and possible padding */ + offsets_idx = idx; + num_messages = chunk_size / 8; + break; + case 0x69: + i18n_log("Found messages at " << idx); + messages_idx = idx; + break; + default: + i18n_log("Found unsupported chunk type: " << chunk_type); + break; + } + + idx += chunk_size; + } + + if (offsets_idx == (uint32_t)-1) { + i18n_log("No offsets chunk found"); + return -1; + } + if (messages_idx == (uint32_t)-1) { + i18n_log("No messages chunk found"); + return -1; + } + + for (uint32_t m = 0; m < num_messages; ++m) { + be32(data+offsets_idx+m*8); // unused + idx = be32(data+offsets_idx+m*8+4); + idx += messages_idx; + + if (idx > datalen || idx + 1 > datalen) { + i18n_log("Bad translations file format: " << filename); + return -1; + } + + while (1) { + if (idx + 5 > datalen) { + i18n_log("Bad translations file format: " << filename); + return -1; + } + chunk_type = data[idx++]; + chunk_size = 0; + if (chunk_type == 0x01) { + i18n_entries[context + std::string("",1) + source] = translation; + context = std::string(); + source = std::string(); + translation = std::string(); + break; + } + + chunk_size = be32(data+idx); + idx += 4; + i18n_log("Found " << chunk_type << " of " << chunk_size << " bytes"); + if (chunk_size >= datalen || idx > datalen - chunk_size) { + i18n_log("Bad translations file format: " << filename); + return -1; + } + switch (chunk_type) { + case 0x03: // translation, UTF-16 + translation = utf16(data+idx, chunk_size); + i18n_log("Found translation: " << translation); + break; + case 0x06: // source, UTF-8 + source = utf8(data+idx, chunk_size); + i18n_log("Found source: " << source); + break; + case 0x07: // context, UTF-8 + context = utf8(data+idx, chunk_size); + i18n_log("Found context: " << context); + break; + } + idx += chunk_size; + } + } + + return 0; +} + +/* The entries is constant by that time */ +const char *i18n_translate(const char *s, const std::string &context) +{ + const std::string key = context + std::string("", 1) + s; + std::map::const_iterator i = i18n_entries.find(key); + if (i == i18n_entries.end()) + return s; + return (*i).second.c_str(); +} + + diff --git a/src/common/i18n.h b/src/common/i18n.h new file mode 100644 index 000000000..2aeac2287 --- /dev/null +++ b/src/common/i18n.h @@ -0,0 +1,36 @@ +// Copyright (c) 2014-2015, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#pragma once + +#define QT_TRANSLATE_NOOP(context,str) i18n_translate(str,context) + +int i18n_set_language(const char *directory, const char *base); +const char *i18n_translate(const char *str, const std::string &context); +static inline std::string get_default_i18n_context() { return std::string(); } +static inline const char *tr(const char *str) { return i18n_translate(str,get_default_i18n_context()); } diff --git a/src/crypto/aesb.c b/src/crypto/aesb.c index ba48313da..128c523ea 100644 --- a/src/crypto/aesb.c +++ b/src/crypto/aesb.c @@ -140,7 +140,15 @@ extern "C" d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3); -void aesb_single_round(const uint8_t *in, uint8_t *out, uint8_t *expandedKey) +#if !defined(STATIC) +#define STATIC +#endif + +#if !defined(INLINE) +#define INLINE +#endif + +STATIC INLINE void aesb_single_round(const uint8_t *in, uint8_t *out, uint8_t *expandedKey) { uint32_t b0[4], b1[4]; const uint32_t *kp = (uint32_t *) expandedKey; @@ -151,7 +159,7 @@ void aesb_single_round(const uint8_t *in, uint8_t *out, uint8_t *expandedKey) state_out(out, b1); } -void aesb_pseudo_round(const uint8_t *in, uint8_t *out, uint8_t *expandedKey) +STATIC INLINE void aesb_pseudo_round(const uint8_t *in, uint8_t *out, uint8_t *expandedKey) { uint32_t b0[4], b1[4]; const uint32_t *kp = (uint32_t *) expandedKey; diff --git a/src/crypto/hash.h b/src/crypto/hash.h index 2f91a5358..1ce2f9816 100644 --- a/src/crypto/hash.h +++ b/src/crypto/hash.h @@ -45,9 +45,13 @@ namespace crypto { POD_CLASS hash { char data[HASH_SIZE]; }; + POD_CLASS hash8 { + char data[8]; + }; #pragma pack(pop) static_assert(sizeof(hash) == HASH_SIZE, "Invalid structure size"); + static_assert(sizeof(hash8) == 8, "Invalid structure size"); /* Cryptonight hash functions @@ -74,3 +78,4 @@ namespace crypto { } CRYPTO_MAKE_HASHABLE(hash) +CRYPTO_MAKE_COMPARABLE(hash8) diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index 425737984..60699d4e6 100644 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -624,6 +624,196 @@ void cn_slow_hash(const void *data, size_t length, char *hash) extra_hashes[state.hs.b[0] & 3](&state, 200, hash); } +#elif defined(__arm__) +// ND: Some minor optimizations for ARM7 (raspberrry pi 2), effect seems to be ~40-50% faster. +// Needs more work. +void slow_hash_allocate_state(void) +{ + // Do nothing, this is just to maintain compatibility with the upgraded slow-hash.c + return; +} + +void slow_hash_free_state(void) +{ + // As above + return; +} + +static void (*const extra_hashes[4])(const void *, size_t, char *) = { + hash_extra_blake, hash_extra_groestl, hash_extra_jh, hash_extra_skein +}; + +#define MEMORY (1 << 21) /* 2 MiB */ +#define ITER (1 << 20) +#define AES_BLOCK_SIZE 16 +#define AES_KEY_SIZE 32 /*16*/ +#define INIT_SIZE_BLK 8 +#define INIT_SIZE_BYTE (INIT_SIZE_BLK * AES_BLOCK_SIZE) + +#if defined(__GNUC__) +#define RDATA_ALIGN16 __attribute__ ((aligned(16))) +#define STATIC static +#define INLINE inline +#else +#define RDATA_ALIGN16 +#define STATIC static +#define INLINE +#endif + +#define U64(x) ((uint64_t *) (x)) + +#include "aesb.c" + +STATIC INLINE void ___mul128(uint32_t *a, uint32_t *b, uint32_t *h, uint32_t *l) +{ + // ND: 64x64 multiplication for ARM7 + __asm__ __volatile__ + ( + // lo hi + "umull %[r0], %[r1], %[b], %[d]\n\t" // bd [r0 = bd.lo] + "umull %[r2], %[r3], %[b], %[c]\n\t" // bc + "umull %[b], %[c], %[a], %[c]\n\t" // ac + "adds %[r1], %[r1], %[r2]\n\t" // r1 = bd.hi + bc.lo + "adcs %[r2], %[r3], %[b]\n\t" // r2 = ac.lo + bc.hi + carry + "adc %[r3], %[c], #0\n\t" // r3 = ac.hi + carry + "umull %[b], %[a], %[a], %[d]\n\t" // ad + "adds %[r1], %[r1], %[b]\n\t" // r1 = bd.hi + bc.lo + ad.lo + "adcs %[r2], %[r2], %[a]\n\t" // r2 = ac.lo + bc.hi + ad.hi + carry + "adc %[r3], %[r3], #0\n\t" // r3 = ac.hi + carry + : [r0]"=&r"(l[0]), [r1]"=&r"(l[1]), [r2]"=&r"(h[0]), [r3]"=&r"(h[1]) + : [a]"r"(a[1]), [b]"r"(a[0]), [c]"r"(b[1]), [d]"r"(b[0]) + : "cc" + ); +} + +STATIC INLINE void mul(const uint8_t* a, const uint8_t* b, uint8_t* res) +{ + ___mul128((uint32_t *) a, (uint32_t *) b, (uint32_t *) (res + 0), (uint32_t *) (res + 8)); +} + +STATIC INLINE void sum_half_blocks(uint8_t* a, const uint8_t* b) +{ + uint64_t a0, a1, b0, b1; + a0 = U64(a)[0]; + a1 = U64(a)[1]; + b0 = U64(b)[0]; + b1 = U64(b)[1]; + a0 += b0; + a1 += b1; + U64(a)[0] = a0; + U64(a)[1] = a1; +} + +STATIC INLINE void swap_blocks(uint8_t *a, uint8_t *b) +{ + uint64_t t[2]; + U64(t)[0] = U64(a)[0]; + U64(t)[1] = U64(a)[1]; + U64(a)[0] = U64(b)[0]; + U64(a)[1] = U64(b)[1]; + U64(b)[0] = U64(t)[0]; + U64(b)[1] = U64(t)[1]; +} + +STATIC INLINE void xor_blocks(uint8_t* a, const uint8_t* b) +{ + U64(a)[0] ^= U64(b)[0]; + U64(a)[1] ^= U64(b)[1]; +} + +#pragma pack(push, 1) +union cn_slow_hash_state +{ + union hash_state hs; + struct + { + uint8_t k[64]; + uint8_t init[INIT_SIZE_BYTE]; + }; +}; +#pragma pack(pop) + +void cn_slow_hash(const void *data, size_t length, char *hash) +{ + uint8_t long_state[MEMORY]; + uint8_t text[INIT_SIZE_BYTE]; + uint8_t a[AES_BLOCK_SIZE]; + uint8_t b[AES_BLOCK_SIZE]; + uint8_t d[AES_BLOCK_SIZE]; + uint8_t aes_key[AES_KEY_SIZE]; + RDATA_ALIGN16 uint8_t expandedKey[256]; + + union cn_slow_hash_state state; + + size_t i, j; + uint8_t *p = NULL; + oaes_ctx *aes_ctx; + static void (*const extra_hashes[4])(const void *, size_t, char *) = + { + hash_extra_blake, hash_extra_groestl, hash_extra_jh, hash_extra_skein + }; + + hash_process(&state.hs, data, length); + memcpy(text, state.init, INIT_SIZE_BYTE); + + aes_ctx = (oaes_ctx *) oaes_alloc(); + oaes_key_import_data(aes_ctx, state.hs.b, AES_KEY_SIZE); + + // use aligned data + memcpy(expandedKey, aes_ctx->key->exp_data, aes_ctx->key->exp_data_len); + for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) + { + for(j = 0; j < INIT_SIZE_BLK; j++) + aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], expandedKey); + memcpy(&long_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE); + } + + U64(a)[0] = U64(&state.k[0])[0] ^ U64(&state.k[32])[0]; + U64(a)[1] = U64(&state.k[0])[1] ^ U64(&state.k[32])[1]; + U64(b)[0] = U64(&state.k[16])[0] ^ U64(&state.k[48])[0]; + U64(b)[1] = U64(&state.k[16])[1] ^ U64(&state.k[48])[1]; + + for(i = 0; i < ITER / 2; i++) + { + #define MASK ((uint32_t)(((MEMORY / AES_BLOCK_SIZE) - 1) << 4)) + #define state_index(x) ((*(uint32_t *) x) & MASK) + + // Iteration 1 + p = &long_state[state_index(a)]; + aesb_single_round(p, p, a); + + xor_blocks(b, p); + swap_blocks(b, p); + swap_blocks(a, b); + + // Iteration 2 + p = &long_state[state_index(a)]; + + mul(a, p, d); + sum_half_blocks(b, d); + swap_blocks(b, p); + xor_blocks(b, p); + swap_blocks(a, b); + } + + memcpy(text, state.init, INIT_SIZE_BYTE); + oaes_key_import_data(aes_ctx, &state.hs.b[32], AES_KEY_SIZE); + memcpy(expandedKey, aes_ctx->key->exp_data, aes_ctx->key->exp_data_len); + for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) + { + for(j = 0; j < INIT_SIZE_BLK; j++) + { + xor_blocks(&text[j * AES_BLOCK_SIZE], &long_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]); + aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], expandedKey); + } + } + + oaes_free((OAES_CTX **) &aes_ctx); + memcpy(state.init, text, INIT_SIZE_BYTE); + hash_permutation(&state.hs); + extra_hashes[state.hs.b[0] & 3](&state, 200, hash); +} + #else // Portable implementation as a fallback diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index e144a93a2..6315fc4f0 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -62,6 +62,12 @@ set(cryptonote_core_private_headers tx_pool.h verification_context.h) +if(PER_BLOCK_CHECKPOINT) + set(Blocks "blocks") +else() + set(Blocks "") +endif() + bitmonero_private_headers(cryptonote_core ${crypto_private_headers}) bitmonero_add_library(cryptonote_core @@ -78,6 +84,7 @@ target_link_libraries(cryptonote_core ${Boost_PROGRAM_OPTIONS_LIBRARY} ${Boost_SERIALIZATION_LIBRARY} LINK_PRIVATE + ${Blocks} ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY} ${Boost_THREAD_LIBRARY} diff --git a/src/cryptonote_core/account.cpp b/src/cryptonote_core/account.cpp index eb79f5949..fe8dbd1e8 100644 --- a/src/cryptonote_core/account.cpp +++ b/src/cryptonote_core/account.cpp @@ -120,7 +120,7 @@ DISABLE_VS_WARNINGS(4244 4345) return get_account_address_as_str(testnet, m_keys.m_account_address); } //----------------------------------------------------------------- - std::string account_base::get_public_integrated_address_str(const crypto::hash &payment_id, bool testnet) const + std::string account_base::get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const { //TODO: change this code into base 58 return get_account_integrated_address_as_str(testnet, m_keys.m_account_address, payment_id); diff --git a/src/cryptonote_core/account.h b/src/cryptonote_core/account.h index 088363bf1..732645ee4 100644 --- a/src/cryptonote_core/account.h +++ b/src/cryptonote_core/account.h @@ -61,7 +61,7 @@ namespace cryptonote void create_from_viewkey(const cryptonote::account_public_address& address, const crypto::secret_key& viewkey); const account_keys& get_keys() const; std::string get_public_address_str(bool testnet) const; - std::string get_public_integrated_address_str(const crypto::hash &payment_id, bool testnet) const; + std::string get_public_integrated_address_str(const crypto::hash8 &payment_id, bool testnet) const; uint64_t get_createtime() const { return m_creation_timestamp; } void set_createtime(uint64_t val) { m_creation_timestamp = val; } diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp index d9d8ef6b9..be0a4a6d7 100644 --- a/src/cryptonote_core/blockchain.cpp +++ b/src/cryptonote_core/blockchain.cpp @@ -50,6 +50,10 @@ #include "warnings.h" #include "crypto/hash.h" #include "cryptonote_core/checkpoints_create.h" +#if defined(PER_BLOCK_CHECKPOINT) +#include "blocks/blocks.h" +#endif + //#include "serialization/json_archive.h" /* TODO: @@ -60,275 +64,360 @@ using namespace cryptonote; using epee::string_tools::pod_to_hex; +extern "C" void slow_hash_allocate_state(); +extern "C" void slow_hash_free_state(); DISABLE_VS_WARNINGS(4267) //------------------------------------------------------------------ -Blockchain::Blockchain(tx_memory_pool& tx_pool):m_db(), m_tx_pool(tx_pool), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), m_is_blockchain_storing(false), m_enforce_dns_checkpoints(false) +Blockchain::Blockchain(tx_memory_pool& tx_pool) : +m_db(), m_tx_pool(tx_pool), m_timestamps_and_difficulties_height(0), m_current_block_cumul_sz_limit(0), m_is_in_checkpoint_zone(false), +m_is_blockchain_storing(false), m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_blocks_per_sync(1), m_db_sync_mode(db_async), m_fast_sync(true) { - LOG_PRINT_L3("Blockchain::" << __func__); + LOG_PRINT_L3("Blockchain::" << __func__); } //------------------------------------------------------------------ //TODO: is this still needed? I don't think so - tewinget template void Blockchain::serialize(archive_t & ar, const unsigned int version) { - LOG_PRINT_L3("Blockchain::" << __func__); - if(version < 11) - return; - CRITICAL_REGION_LOCAL(m_blockchain_lock); - ar & m_blocks; - ar & m_blocks_index; - ar & m_transactions; - ar & m_spent_keys; - ar & m_alternative_chains; - ar & m_outputs; - ar & m_invalid_blocks; - ar & m_current_block_cumul_sz_limit; - /*serialization bug workaround*/ - if(version > 11) - { - uint64_t total_check_count = m_db->height() + m_blocks_index.size() + m_transactions.size() + m_spent_keys.size() + m_alternative_chains.size() + m_outputs.size() + m_invalid_blocks.size() + m_current_block_cumul_sz_limit; - if(archive_t::is_saving::value) - { - ar & total_check_count; - }else + key_images_container dummy_key_images_container; + + LOG_PRINT_L3("Blockchain::" << __func__); + if(version < 11) + return; + CRITICAL_REGION_LOCAL(m_blockchain_lock); + ar & m_blocks; + ar & m_blocks_index; + ar & m_transactions; + ar & dummy_key_images_container; + ar & m_alternative_chains; + ar & m_outputs; + ar & m_invalid_blocks; + ar & m_current_block_cumul_sz_limit; + /*serialization bug workaround*/ + if(version > 11) { - uint64_t total_check_count_loaded = 0; - ar & total_check_count_loaded; - if(total_check_count != total_check_count_loaded) - { - LOG_ERROR("Blockchain storage data corruption detected. total_count loaded from file = " << total_check_count_loaded << ", expected = " << total_check_count); + uint64_t total_check_count = m_db->height() + m_blocks_index.size() + m_transactions.size() + dummy_key_images_container.size() + m_alternative_chains.size() + m_outputs.size() + m_invalid_blocks.size() + m_current_block_cumul_sz_limit; + if(archive_t::is_saving::value) + { + ar & total_check_count; + } + else + { + uint64_t total_check_count_loaded = 0; + ar & total_check_count_loaded; + if(total_check_count != total_check_count_loaded) + { + LOG_ERROR("Blockchain storage data corruption detected. total_count loaded from file = " << total_check_count_loaded << ", expected = " << total_check_count); - LOG_PRINT_L0("Blockchain storage:" << std::endl << - "m_blocks: " << m_db->height() << std::endl << - "m_blocks_index: " << m_blocks_index.size() << std::endl << - "m_transactions: " << m_transactions.size() << std::endl << - "m_spent_keys: " << m_spent_keys.size() << std::endl << - "m_alternative_chains: " << m_alternative_chains.size() << std::endl << - "m_outputs: " << m_outputs.size() << std::endl << - "m_invalid_blocks: " << m_invalid_blocks.size() << std::endl << - "m_current_block_cumul_sz_limit: " << m_current_block_cumul_sz_limit); + LOG_PRINT_L0("Blockchain storage:" << std::endl << "m_blocks: " << m_db->height() << std::endl << "m_blocks_index: " << m_blocks_index.size() << std::endl << "m_transactions: " << m_transactions.size() << std::endl << "dummy_key_images_container: " << dummy_key_images_container.size() << std::endl << "m_alternative_chains: " << m_alternative_chains.size() << std::endl << "m_outputs: " << m_outputs.size() << std::endl << "m_invalid_blocks: " << m_invalid_blocks.size() << std::endl << "m_current_block_cumul_sz_limit: " << m_current_block_cumul_sz_limit); - throw std::runtime_error("Blockchain data corruption"); - } + throw std::runtime_error("Blockchain data corruption"); + } + } } - } - - LOG_PRINT_L3("Blockchain storage:" << std::endl << - "m_blocks: " << m_db->height() << std::endl << - "m_blocks_index: " << m_blocks_index.size() << std::endl << - "m_transactions: " << m_transactions.size() << std::endl << - "m_spent_keys: " << m_spent_keys.size() << std::endl << - "m_alternative_chains: " << m_alternative_chains.size() << std::endl << - "m_outputs: " << m_outputs.size() << std::endl << - "m_invalid_blocks: " << m_invalid_blocks.size() << std::endl << - "m_current_block_cumul_sz_limit: " << m_current_block_cumul_sz_limit); + LOG_PRINT_L3("Blockchain storage:" << std::endl << "m_blocks: " << m_db->height() << std::endl << "m_blocks_index: " << m_blocks_index.size() << std::endl << "m_transactions: " << m_transactions.size() << std::endl << "dummy_key_images_container: " << dummy_key_images_container.size() << std::endl << "m_alternative_chains: " << m_alternative_chains.size() << std::endl << "m_outputs: " << m_outputs.size() << std::endl << "m_invalid_blocks: " << m_invalid_blocks.size() << std::endl << "m_current_block_cumul_sz_limit: " << m_current_block_cumul_sz_limit); } //------------------------------------------------------------------ bool Blockchain::have_tx(const crypto::hash &id) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - return m_db->tx_exists(id); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + return m_db->tx_exists(id); } //------------------------------------------------------------------ bool Blockchain::have_tx_keyimg_as_spent(const crypto::key_image &key_im) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - return m_db->has_key_image(key_im); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + return m_db->has_key_image(key_im); } //------------------------------------------------------------------ // This function makes sure that each "input" in an input (mixins) exists // 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(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height) const +template +bool Blockchain::scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t &vis, const crypto::hash &tx_prefix_hash, uint64_t* pmax_related_block_height) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); - // verify that the input has key offsets (that it exists properly, really) - if(!tx_in_to_key.key_offsets.size()) - return false; + // ND: Disable locking and make method private. + //CRITICAL_REGION_LOCAL(m_blockchain_lock); - // cryptonote_format_utils uses relative offsets for indexing to the global - // outputs list. that is to say that absolute offset #2 is absolute offset - // #1 plus relative offset #2. - // TODO: Investigate if this is necessary / why this is done. - std::vector absolute_offsets = relative_output_offsets_to_absolute(tx_in_to_key.key_offsets); + // verify that the input has key offsets (that it exists properly, really) + if(!tx_in_to_key.key_offsets.size()) + return false; + // cryptonote_format_utils uses relative offsets for indexing to the global + // outputs list. that is to say that absolute offset #2 is absolute offset + // #1 plus relative offset #2. + // TODO: Investigate if this is necessary / why this is done. + std::vector absolute_offsets = relative_output_offsets_to_absolute(tx_in_to_key.key_offsets); + std::vector outputs; - //std::vector >& amount_outs_vec = it->second; - size_t count = 0; - for (const uint64_t& i : absolute_offsets) - { - try + bool found = false; + auto it = m_scan_table.find(tx_prefix_hash); + if (it != m_scan_table.end()) { - // get tx hash and output index for output - auto output_index = m_db->get_output_tx_and_index(tx_in_to_key.amount, i); - - // get tx that output is from - auto tx = m_db->get_tx(output_index.first); - - // make sure output index is within range for the given transaction - if (output_index.second >= tx.vout.size()) - { - LOG_PRINT_L0("Output does not exist. tx = " << output_index.first << ", index = " << output_index.second); - return false; - } - - // call to the passed boost visitor to grab the public key for the output - if(!vis.handle_output(tx, tx.vout[output_index.second])) - { - LOG_PRINT_L0("Failed to handle_output for output no = " << count << ", with 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 = m_db->get_tx_block_height(output_index.first); - if(*pmax_related_block_height < h) + auto its = it->second.find(tx_in_to_key.k_image); + if (its != it->second.end()) { - *pmax_related_block_height = h; + outputs = its->second; + found = true; } - } - } - catch (const OUTPUT_DNE& e) + + if (!found) { - LOG_PRINT_L0("Output does not exist: " << e.what()); - return false; + m_db->get_output_key(tx_in_to_key.amount, absolute_offsets, outputs); } - catch (const TX_DNE& e) + else { - LOG_PRINT_L0("Transaction does not exist: " << e.what()); - return false; + // check for partial results and add the rest if needed; + if (outputs.size() < absolute_offsets.size() && outputs.size() > 0) + { + LOG_PRINT_L1("Additional outputs needed: " << absolute_offsets.size() - outputs.size()); + std::vector < uint64_t > add_offsets; + std::vector add_outputs; + for (size_t i = outputs.size(); i < absolute_offsets.size(); i++) + add_offsets.push_back(absolute_offsets[i]); + m_db->get_output_key(tx_in_to_key.amount, add_offsets, add_outputs); + 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(tx_in_to_key.amount, i); - return true; + // 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)) + { + LOG_PRINT_L0("Failed to handle_output for output no = " << count << ", with absolute offset " << i); + return false; + } + } + catch (...) + { + LOG_PRINT_L0("Output does not exist! amount = " << tx_in_to_key.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) + { + LOG_PRINT_L0("Output does not exist: " << e.what()); + return false; + } + catch (const TX_DNE& e) + { + LOG_PRINT_L0("Transaction does not exist: " << e.what()); + return false; + } + + } + + return true; } //------------------------------------------------------------------ uint64_t Blockchain::get_current_blockchain_height() const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - return m_db->height(); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + return m_db->height(); } //------------------------------------------------------------------ //FIXME: possibly move this into the constructor, to avoid accidentally // dereferencing a null BlockchainDB pointer bool Blockchain::init(BlockchainDB* db, const bool testnet) { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - if (db == nullptr) - { - LOG_ERROR("Attempted to init Blockchain with null DB"); - return false; - } - if (!db->is_open()) - { - LOG_ERROR("Attempted to init Blockchain with unopened DB"); - return false; - } - - m_db = db; - - // if the blockchain is new, add the genesis block - // this feels kinda kludgy to do it this way, but can be looked at later. - // TODO: add function to create and store genesis block, - // taking testnet into account - if(!m_db->height()) - { - LOG_PRINT_L0("Blockchain not loaded, generating genesis block."); - block bl = boost::value_initialized(); - block_verification_context bvc = boost::value_initialized(); - if (testnet) + if (db == nullptr) { - generate_genesis_block(bl, config::testnet::GENESIS_TX, config::testnet::GENESIS_NONCE); + LOG_ERROR("Attempted to init Blockchain with null DB"); + return false; } + if (!db->is_open()) + { + LOG_ERROR("Attempted to init Blockchain with unopened DB"); + return false; + } + + m_db = db; + + // if the blockchain is new, add the genesis block + // this feels kinda kludgy to do it this way, but can be looked at later. + // TODO: add function to create and store genesis block, + // taking testnet into account + if(!m_db->height()) + { + LOG_PRINT_L0("Blockchain not loaded, generating genesis block."); + block bl = boost::value_initialized(); + block_verification_context bvc = boost::value_initialized(); + if (testnet) + { + generate_genesis_block(bl, config::testnet::GENESIS_TX, config::testnet::GENESIS_NONCE); + } + else + { + generate_genesis_block(bl, config::GENESIS_TX, config::GENESIS_NONCE); + } + add_new_block(bl, bvc); + CHECK_AND_ASSERT_MES(!bvc.m_verifivation_failed, false, "Failed to add genesis block to blockchain"); + } + // TODO: if blockchain load successful, verify blockchain against both + // hard-coded and runtime-loaded (and enforced) checkpoints. else { - generate_genesis_block(bl, config::GENESIS_TX, config::GENESIS_NONCE); } - add_new_block(bl, bvc); - CHECK_AND_ASSERT_MES(!bvc.m_verifivation_failed, false, "Failed to add genesis block to blockchain"); - } - // TODO: if blockchain load successful, verify blockchain against both - // hard-coded and runtime-loaded (and enforced) checkpoints. - else - { - } - // check how far behind we are - uint64_t top_block_timestamp = m_db->get_top_block_timestamp(); - uint64_t timestamp_diff = time(NULL) - top_block_timestamp; + // check how far behind we are + uint64_t top_block_timestamp = m_db->get_top_block_timestamp(); + uint64_t timestamp_diff = time(NULL) - top_block_timestamp; - // genesis block has no timestamp, could probably change it to have timestamp of 1341378000... - if(!top_block_timestamp) - timestamp_diff = time(NULL) - 1341378000; - LOG_PRINT_GREEN("Blockchain initialized. last block: " << m_db->height() - 1 << ", " << epee::misc_utils::get_time_interval_string(timestamp_diff) << " time ago, current difficulty: " << get_difficulty_for_next_block(), LOG_LEVEL_0); + // genesis block has no timestamp, could probably change it to have timestamp of 1341378000... + if(!top_block_timestamp) + timestamp_diff = time(NULL) - 1341378000; - return true; + // create general purpose async service queue + + m_async_work_idle = std::unique_ptr < boost::asio::io_service::work > (new boost::asio::io_service::work(m_async_service)); + // we only need 1 + m_async_pool.create_thread(boost::bind(&boost::asio::io_service::run, &m_async_service)); + +#if defined(PER_BLOCK_CHECKPOINT) + if (m_fast_sync && !testnet && get_blocks_dat_start() != nullptr) + { + if (get_blocks_dat_size() > 4) + { + const unsigned char *p = get_blocks_dat_start(); + uint32_t nblocks = *(uint32_t *) p; + if(nblocks > 0 && nblocks > m_db->height()) + { + LOG_PRINT_L0("Loading precomputed blocks: " << nblocks); + p += sizeof(uint32_t); + for (uint32_t i = 0; i < nblocks; i++) + { + crypto::hash hash; + memcpy(hash.data, p, sizeof(hash.data)); + p += sizeof(hash.data); + m_blocks_hash_check.push_back(hash); + } + + // FIXME: clear tx_pool because the process might have been + // terminated and caused it to store txs kept by blocks. + // The core will not call check_tx_inputs(..) for these + // transactions in this case. Consequently, the sanity check + // for tx hashes will fail in handle_block_to_main_chain(..) + std::list txs; + m_tx_pool.get_transactions(txs); + + size_t blob_size; + uint64_t fee; + transaction pool_tx; + for(const transaction &tx : txs) + { + crypto::hash tx_hash = get_transaction_hash(tx); + m_tx_pool.take_tx(tx_hash, pool_tx, blob_size, fee); + } + } + } + } +#endif + + LOG_PRINT_GREEN("Blockchain initialized. last block: " << m_db->height() - 1 << ", " << epee::misc_utils::get_time_interval_string(timestamp_diff) << " time ago, current difficulty: " << get_difficulty_for_next_block(), LOG_LEVEL_0); + + return true; } //------------------------------------------------------------------ bool Blockchain::store_blockchain() { - LOG_PRINT_L3("Blockchain::" << __func__); - // TODO: make sure if this throws that it is not simply ignored higher - // up the call stack - try - { - m_db->sync(); - } - catch (const std::exception& e) - { - LOG_PRINT_L0(std::string("Error syncing blockchain db: ") + e.what() + "-- shutting down now to prevent issues!"); - throw; - } - catch (...) - { - LOG_PRINT_L0("There was an issue storing the blockchain, shutting down now to prevent issues!"); - throw; - } - LOG_PRINT_L0("Blockchain stored OK."); - return true; + LOG_PRINT_YELLOW("Blockchain::" << __func__, LOG_LEVEL_3); + // lock because the rpc_thread command handler also calls this + CRITICAL_REGION_LOCAL(m_db->m_synchronization_lock); + + TIME_MEASURE_START(save); + // TODO: make sure sync(if this throws that it is not simply ignored higher + // up the call stack + try + { + m_db->sync(); + } + catch (const std::exception& e) + { + LOG_PRINT_L0(std::string("Error syncing blockchain db: ") + e.what() + "-- shutting down now to prevent issues!"); + throw; + } + catch (...) + { + LOG_PRINT_L0("There was an issue storing the blockchain, shutting down now to prevent issues!"); + throw; + } + + TIME_MEASURE_FINISH(save); + if(m_show_time_stats) + LOG_PRINT_L0("Blockchain stored OK, took: " << save << " ms"); + return true; } //------------------------------------------------------------------ bool Blockchain::deinit() { - LOG_PRINT_L3("Blockchain::" << __func__); - // as this should be called if handling a SIGSEGV, need to check - // if m_db is a NULL pointer (and thus may have caused the illegal - // memory operation), otherwise we may cause a loop. - if (m_db == NULL) - { - throw new DB_ERROR("The db pointer is null in Blockchain, the blockchain may be corrupt!"); - } + LOG_PRINT_L3("Blockchain::" << __func__); - try - { - m_db->close(); - } - catch (const std::exception& e) - { - LOG_PRINT_L0(std::string("Error closing blockchain db: ") + e.what()); - } - catch (...) - { - LOG_PRINT_L0("There was an issue closing/storing the blockchain, shutting down now to prevent issues!"); - } + LOG_PRINT_L0("Closing IO Service.") + // stop async service + m_async_work_idle.reset(); + m_async_pool.join_all(); + m_async_service.stop(); - delete m_db; - return true; + // as this should be called if handling a SIGSEGV, need to check + // if m_db is a NULL pointer (and thus may have caused the illegal + // memory operation), otherwise we may cause a loop. + if (m_db == NULL) + { + throw new DB_ERROR("The db pointer is null in Blockchain, the blockchain may be corrupt!"); + } + + try + { + m_db->close(); + } + catch (const std::exception& e) + { + LOG_PRINT_L0(std::string("Error closing blockchain db: ") + e.what()); + } + catch (...) + { + LOG_PRINT_L0("There was an issue closing/storing the blockchain, shutting down now to prevent issues!"); + } + + delete m_db; + return true; } //------------------------------------------------------------------ // This function tells BlockchainDB to remove the top block from the @@ -336,123 +425,77 @@ bool Blockchain::deinit() // from it to the tx_pool block Blockchain::pop_block_from_blockchain() { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - block popped_block; - std::vector popped_txs; + m_timestamps_and_difficulties_height = 0; - try - { - m_db->pop_block(popped_block, popped_txs); - } - // anything that could cause this to throw is likely catastrophic, - // so we re-throw - catch (const std::exception& e) - { - LOG_ERROR("Error popping block from blockchain: " << e.what()); - throw; - } - catch (...) - { - LOG_ERROR("Error popping block from blockchain, throwing!"); - throw; - } + block popped_block; + std::vector popped_txs; - // return transactions from popped block to the tx_pool - for (transaction& tx : popped_txs) - { - if (!is_coinbase(tx)) + try { - cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc); - bool r = m_tx_pool.add_tx(tx, tvc, true); - if (!r) - { - LOG_ERROR("Error returning transaction to tx_pool"); - } + m_db->pop_block(popped_block, popped_txs); + } + // anything that could cause this to throw is likely catastrophic, + // so we re-throw + catch (const std::exception& e) + { + LOG_ERROR("Error popping block from blockchain: " << e.what()); + throw; + } + catch (...) + { + LOG_ERROR("Error popping block from blockchain, throwing!"); + throw; } - } - return popped_block; + // return transactions from popped block to the tx_pool + for (transaction& tx : popped_txs) + { + if (!is_coinbase(tx)) + { + cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc); + bool r = m_tx_pool.add_tx(tx, tvc, true); + if (!r) + { + LOG_ERROR("Error returning transaction to tx_pool"); + } + } + } + + return popped_block; } //------------------------------------------------------------------ bool Blockchain::reset_and_set_genesis_block(const block& b) { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - m_transactions.clear(); - m_spent_keys.clear(); - m_blocks.clear(); - m_blocks_index.clear(); - m_alternative_chains.clear(); - m_outputs.clear(); - m_db->reset(); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + m_transactions.clear(); + m_blocks.clear(); + m_blocks_index.clear(); + m_alternative_chains.clear(); + m_outputs.clear(); + m_db->reset(); - block_verification_context bvc = boost::value_initialized(); - add_new_block(b, bvc); - return bvc.m_added_to_main_chain && !bvc.m_verifivation_failed; -} -//------------------------------------------------------------------ -//TODO: move to BlockchainDB subclass -bool Blockchain::purge_transaction_keyimages_from_blockchain(const transaction& tx, bool strict_check) -{ - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - struct purge_transaction_visitor: public boost::static_visitor - { - key_images_container& m_spent_keys; - bool m_strict_check; - purge_transaction_visitor(key_images_container& spent_keys, bool strict_check):m_spent_keys(spent_keys), m_strict_check(strict_check){} - - bool operator()(const txin_to_key& inp) const - { - //const crypto::key_image& ki = inp.k_image; - auto r = m_spent_keys.find(inp.k_image); - if(r != m_spent_keys.end()) - { - m_spent_keys.erase(r); - }else - { - CHECK_AND_ASSERT_MES(!m_strict_check, false, "purge_block_data_from_blockchain: key image in transaction not found"); - } - return true; - } - bool operator()(const txin_gen& inp) const - { - return true; - } - bool operator()(const txin_to_script& tx) const - { - return false; - } - - bool operator()(const txin_to_scripthash& tx) const - { - return false; - } - }; - - BOOST_FOREACH(const txin_v& in, tx.vin) - { - bool r = boost::apply_visitor(purge_transaction_visitor(m_spent_keys, strict_check), in); - CHECK_AND_ASSERT_MES(!strict_check || r, false, "failed to process purge_transaction_visitor"); - } - return true; + block_verification_context bvc = boost::value_initialized(); + add_new_block(b, bvc); + return bvc.m_added_to_main_chain && !bvc.m_verifivation_failed; } //------------------------------------------------------------------ crypto::hash Blockchain::get_tail_id(uint64_t& height) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - height = m_db->height() - 1; - return get_tail_id(); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + height = m_db->height() - 1; + return get_tail_id(); } //------------------------------------------------------------------ crypto::hash Blockchain::get_tail_id() const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - return m_db->top_block_hash(); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + return m_db->top_block_hash(); } //------------------------------------------------------------------ /*TODO: this function was...poorly written. As such, I'm not entirely @@ -469,119 +512,120 @@ crypto::hash Blockchain::get_tail_id() const */ bool Blockchain::get_short_chain_history(std::list& ids) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - uint64_t i = 0; - uint64_t current_multiplier = 1; - uint64_t sz = m_db->height(); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + uint64_t i = 0; + uint64_t current_multiplier = 1; + uint64_t sz = m_db->height(); + + if(!sz) + return true; + + bool genesis_included = false; + uint64_t current_back_offset = 1; + while(current_back_offset < sz) + { + ids.push_back(m_db->get_block_hash_from_height(sz - current_back_offset)); + + if(sz-current_back_offset == 0) + { + genesis_included = true; + } + if(i < 10) + { + ++current_back_offset; + } + else + { + current_multiplier *= 2; + current_back_offset += current_multiplier; + } + ++i; + } + + if (!genesis_included) + { + ids.push_back(m_db->get_block_hash_from_height(0)); + } - if(!sz) return true; - - bool genesis_included = false; - uint64_t current_back_offset = 1; - while(current_back_offset < sz) - { - ids.push_back(m_db->get_block_hash_from_height(sz - current_back_offset)); - - if(sz-current_back_offset == 0) - { - genesis_included = true; - } - if(i < 10) - { - ++current_back_offset; - } - else - { - current_multiplier *= 2; - current_back_offset += current_multiplier; - } - ++i; - } - - if (!genesis_included) - { - ids.push_back(m_db->get_block_hash_from_height(0)); - } - - return true; } //------------------------------------------------------------------ crypto::hash Blockchain::get_block_id_by_height(uint64_t height) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - try - { - return m_db->get_block_hash_from_height(height); - } - catch (const BLOCK_DNE& e) - { - } - catch (const std::exception& e) - { - LOG_PRINT_L0(std::string("Something went wrong fetching block hash by height: ") + e.what()); - throw; - } - catch (...) - { - LOG_PRINT_L0(std::string("Something went wrong fetching block hash by height")); - throw; - } - return null_hash; + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + try + { + return m_db->get_block_hash_from_height(height); + } + catch (const BLOCK_DNE& e) + { + } + catch (const std::exception& e) + { + LOG_PRINT_L0(std::string("Something went wrong fetching block hash by height: ") + e.what()); + throw; + } + catch (...) + { + LOG_PRINT_L0(std::string("Something went wrong fetching block hash by height")); + throw; + } + return null_hash; } //------------------------------------------------------------------ bool Blockchain::get_block_by_hash(const crypto::hash &h, block &blk) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - // try to find block in main chain - try - { - blk = m_db->get_block(h); - return true; - } - // try to find block in alternative chain - catch (const BLOCK_DNE& e) - { - blocks_ext_by_hash::const_iterator it_alt = m_alternative_chains.find(h); - if (m_alternative_chains.end() != it_alt) { - blk = it_alt->second.bl; - return true; + // try to find block in main chain + try + { + blk = m_db->get_block(h); + return true; + } + // try to find block in alternative chain + catch (const BLOCK_DNE& e) + { + blocks_ext_by_hash::const_iterator it_alt = m_alternative_chains.find(h); + if (m_alternative_chains.end() != it_alt) + { + blk = it_alt->second.bl; + return true; + } + } + catch (const std::exception& e) + { + LOG_PRINT_L0(std::string("Something went wrong fetching block by hash: ") + e.what()); + throw; + } + catch (...) + { + LOG_PRINT_L0(std::string("Something went wrong fetching block hash by hash")); + throw; } - } - catch (const std::exception& e) - { - LOG_PRINT_L0(std::string("Something went wrong fetching block by hash: ") + e.what()); - throw; - } - catch (...) - { - LOG_PRINT_L0(std::string("Something went wrong fetching block hash by hash")); - throw; - } - return false; + return false; } //------------------------------------------------------------------ //FIXME: this function does not seem to be called from anywhere, but // if it ever is, should probably change std::list for std::vector void Blockchain::get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - for (auto& a : m_db->get_hashes_range(0, m_db->height() - 1)) - { - main.push_back(a); - } + for (auto& a : m_db->get_hashes_range(0, m_db->height() - 1)) + { + main.push_back(a); + } - BOOST_FOREACH(const blocks_ext_by_hash::value_type &v, m_alternative_chains) + BOOST_FOREACH(const blocks_ext_by_hash::value_type &v, m_alternative_chains) alt.push_back(v.first); - BOOST_FOREACH(const blocks_ext_by_hash::value_type &v, m_invalid_blocks) + BOOST_FOREACH(const blocks_ext_by_hash::value_type &v, m_invalid_blocks) invalid.push_back(v.first); } //------------------------------------------------------------------ @@ -589,27 +633,53 @@ void Blockchain::get_all_known_block_ids(std::list &main, std::lis // last DIFFICULTY_BLOCKS_COUNT blocks and passes them to next_difficulty, // returning the result of that call. Ignores the genesis block, and can use // less blocks than desired if there aren't enough. -difficulty_type Blockchain::get_difficulty_for_next_block() const +difficulty_type Blockchain::get_difficulty_for_next_block() { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - std::vector timestamps; - std::vector cumulative_difficulties; - auto h = m_db->height(); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + std::vector timestamps; + std::vector difficulties; + auto height = m_db->height(); + // ND: Speedup + // 1. Keep a list of the last 735 (or less) blocks that is used to compute difficulty, + // then when the next block difficulty is queried, push the latest height data and + // pop the oldest one from the list. This only requires 1x read per height instead + // of doing 735 (DIFFICULTY_BLOCKS_COUNT). + if (m_timestamps_and_difficulties_height != 0 && ((height - m_timestamps_and_difficulties_height) == 1)) + { + uint64_t index = height - 1; + m_timestamps.push_back(m_db->get_block_timestamp(index)); + m_difficulties.push_back(m_db->get_block_cumulative_difficulty(index)); - size_t offset = h - std::min(h, static_cast(DIFFICULTY_BLOCKS_COUNT)); + while (m_timestamps.size() > DIFFICULTY_BLOCKS_COUNT) + m_timestamps.erase(m_timestamps.begin()); + while (m_difficulties.size() > DIFFICULTY_BLOCKS_COUNT) + m_difficulties.erase(m_difficulties.begin()); - if (offset == 0) - { - ++offset; - } + m_timestamps_and_difficulties_height = height; + timestamps = m_timestamps; + difficulties = m_difficulties; + } + else + { + size_t offset = height - std::min < size_t > (height, static_cast(DIFFICULTY_BLOCKS_COUNT)); + if (offset == 0) + ++offset; - for(; offset < h; offset++) - { - timestamps.push_back(m_db->get_block_timestamp(offset)); - cumulative_difficulties.push_back(m_db->get_block_cumulative_difficulty(offset)); - } - return next_difficulty(timestamps, cumulative_difficulties); + timestamps.clear(); + difficulties.clear(); + for (; offset < height; offset++) + { + timestamps.push_back(m_db->get_block_timestamp(offset)); + difficulties.push_back(m_db->get_block_cumulative_difficulty(offset)); + } + + m_timestamps_and_difficulties_height = height; + m_timestamps = timestamps; + m_difficulties = difficulties; + } + + return next_difficulty(timestamps, difficulties); } //------------------------------------------------------------------ // This function removes blocks from the blockchain until it gets to the @@ -617,186 +687,186 @@ difficulty_type Blockchain::get_difficulty_for_next_block() const // that had been removed. bool Blockchain::rollback_blockchain_switching(std::list& original_chain, uint64_t rollback_height) { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - // remove blocks from blockchain until we get back to where we should be. - while (m_db->height() != rollback_height) - { - pop_block_from_blockchain(); - } + m_timestamps_and_difficulties_height = 0; - //return back original chain - for (auto& bl : original_chain) - { - block_verification_context bvc = boost::value_initialized(); - bool r = handle_block_to_main_chain(bl, bvc); - CHECK_AND_ASSERT_MES(r && bvc.m_added_to_main_chain, false, "PANIC! failed to add (again) block while chain switching during the rollback!"); - } + // remove blocks from blockchain until we get back to where we should be. + while (m_db->height() != rollback_height) + { + pop_block_from_blockchain(); + } - LOG_PRINT_L1("Rollback to height " << rollback_height << " was successful."); - if (original_chain.size()) - { - LOG_PRINT_L1("Restoration to previous blockchain successful as well."); - } - return true; + //return back original chain + for (auto& bl : original_chain) + { + block_verification_context bvc = boost::value_initialized(); + bool r = handle_block_to_main_chain(bl, bvc); + CHECK_AND_ASSERT_MES(r && bvc.m_added_to_main_chain, false, "PANIC! failed to add (again) block while chain switching during the rollback!"); + } + + LOG_PRINT_L1("Rollback to height " << rollback_height << " was successful."); + if (original_chain.size()) + { + LOG_PRINT_L1("Restoration to previous blockchain successful as well."); + } + return true; } //------------------------------------------------------------------ // This function attempts to switch to an alternate chain, returning // boolean based on success therein. bool Blockchain::switch_to_alternative_blockchain(std::list& alt_chain, bool discard_disconnected_chain) { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - // if empty alt chain passed (not sure how that could happen), return false - CHECK_AND_ASSERT_MES(alt_chain.size(), false, "switch_to_alternative_blockchain: empty chain passed"); + m_timestamps_and_difficulties_height = 0; - // verify that main chain has front of alt chain's parent block - if (!m_db->block_exists(alt_chain.front()->second.bl.prev_id)) - { - LOG_ERROR("Attempting to move to an alternate chain, but it doesn't appear to connect to the main chain!"); - return false; - } + // if empty alt chain passed (not sure how that could happen), return false + CHECK_AND_ASSERT_MES(alt_chain.size(), false, "switch_to_alternative_blockchain: empty chain passed"); - // pop blocks from the blockchain until the top block is the parent - // of the front block of the alt chain. - std::list disconnected_chain; - while (m_db->top_block_hash() != alt_chain.front()->second.bl.prev_id) - { - block b = pop_block_from_blockchain(); - disconnected_chain.push_front(b); - } - - auto split_height = m_db->height(); - - //connecting new alternative chain - for(auto alt_ch_iter = alt_chain.begin(); alt_ch_iter != alt_chain.end(); alt_ch_iter++) - { - auto ch_ent = *alt_ch_iter; - block_verification_context bvc = boost::value_initialized(); - - // add block to main chain - bool r = handle_block_to_main_chain(ch_ent->second.bl, bvc); - - // if adding block to main chain failed, rollback to previous state and - // return false - if(!r || !bvc.m_added_to_main_chain) + // verify that main chain has front of alt chain's parent block + if (!m_db->block_exists(alt_chain.front()->second.bl.prev_id)) { - LOG_PRINT_L1("Failed to switch to alternative blockchain"); - - // rollback_blockchain_switching should be moved to two different - // functions: rollback and apply_chain, but for now we pretend it is - // just the latter (because the rollback was done above). - rollback_blockchain_switching(disconnected_chain, m_db->height()); - - // FIXME: Why do we keep invalid blocks around? Possibly in case we hear - // about them again so we can immediately dismiss them, but needs some - // looking into. - add_block_as_invalid(ch_ent->second, get_block_hash(ch_ent->second.bl)); - LOG_PRINT_L1("The block was inserted as invalid while connecting new alternative chain, block_id: " << get_block_hash(ch_ent->second.bl)); - m_alternative_chains.erase(ch_ent); - - for(auto alt_ch_to_orph_iter = ++alt_ch_iter; alt_ch_to_orph_iter != alt_chain.end(); alt_ch_to_orph_iter++) - { - add_block_as_invalid((*alt_ch_iter)->second, (*alt_ch_iter)->first); - m_alternative_chains.erase(*alt_ch_to_orph_iter); - } - return false; + LOG_ERROR("Attempting to move to an alternate chain, but it doesn't appear to connect to the main chain!"); + return false; } - } - // if we're to keep the disconnected blocks, add them as alternates - if(!discard_disconnected_chain) - { - //pushing old chain as alternative chain - for (auto& old_ch_ent : disconnected_chain) + // pop blocks from the blockchain until the top block is the parent + // of the front block of the alt chain. + std::list disconnected_chain; + while (m_db->top_block_hash() != alt_chain.front()->second.bl.prev_id) { - block_verification_context bvc = boost::value_initialized(); - bool r = handle_alternative_block(old_ch_ent, get_block_hash(old_ch_ent), bvc); - if(!r) - { - LOG_PRINT_L1("Failed to push ex-main chain blocks to alternative chain "); - // previously this would fail the blockchain switching, but I don't - // think this is bad enough to warrant that. - } + block b = pop_block_from_blockchain(); + disconnected_chain.push_front(b); } - } - //removing alt_chain entries from alternative chain - BOOST_FOREACH(auto ch_ent, alt_chain) - { - m_alternative_chains.erase(ch_ent); - } + auto split_height = m_db->height(); - LOG_PRINT_GREEN("REORGANIZE SUCCESS! on height: " << split_height << ", new blockchain size: " << m_db->height(), LOG_LEVEL_0); - return true; + //connecting new alternative chain + for(auto alt_ch_iter = alt_chain.begin(); alt_ch_iter != alt_chain.end(); alt_ch_iter++) + { + auto ch_ent = *alt_ch_iter; + block_verification_context bvc = boost::value_initialized(); + + // add block to main chain + bool r = handle_block_to_main_chain(ch_ent->second.bl, bvc); + + // if adding block to main chain failed, rollback to previous state and + // return false + if(!r || !bvc.m_added_to_main_chain) + { + LOG_PRINT_L1("Failed to switch to alternative blockchain"); + + // rollback_blockchain_switching should be moved to two different + // functions: rollback and apply_chain, but for now we pretend it is + // just the latter (because the rollback was done above). + rollback_blockchain_switching(disconnected_chain, m_db->height()); + + // FIXME: Why do we keep invalid blocks around? Possibly in case we hear + // about them again so we can immediately dismiss them, but needs some + // looking into. + add_block_as_invalid(ch_ent->second, get_block_hash(ch_ent->second.bl)); + LOG_PRINT_L1("The block was inserted as invalid while connecting new alternative chain, block_id: " << get_block_hash(ch_ent->second.bl)); + m_alternative_chains.erase(ch_ent); + + for(auto alt_ch_to_orph_iter = ++alt_ch_iter; alt_ch_to_orph_iter != alt_chain.end(); alt_ch_to_orph_iter++) + { + add_block_as_invalid((*alt_ch_iter)->second, (*alt_ch_iter)->first); + m_alternative_chains.erase(*alt_ch_to_orph_iter); + } + return false; + } + } + + // if we're to keep the disconnected blocks, add them as alternates + if(!discard_disconnected_chain) + { + //pushing old chain as alternative chain + for (auto& old_ch_ent : disconnected_chain) + { + block_verification_context bvc = boost::value_initialized(); + bool r = handle_alternative_block(old_ch_ent, get_block_hash(old_ch_ent), bvc); + if(!r) + { + LOG_PRINT_L1("Failed to push ex-main chain blocks to alternative chain "); + // previously this would fail the blockchain switching, but I don't + // think this is bad enough to warrant that. + } + } + } + + //removing alt_chain entries from alternative chain + BOOST_FOREACH(auto ch_ent, alt_chain) + { + m_alternative_chains.erase(ch_ent); + } + + LOG_PRINT_GREEN("REORGANIZE SUCCESS! on height: " << split_height << ", new blockchain size: " << m_db->height(), LOG_LEVEL_0); + return true; } //------------------------------------------------------------------ // This function calculates the difficulty target for the block being added to // an alternate chain. difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std::list& alt_chain, block_extended_info& bei) const { - LOG_PRINT_L3("Blockchain::" << __func__); - std::vector timestamps; - std::vector cumulative_difficulties; + LOG_PRINT_L3("Blockchain::" << __func__); + std::vector timestamps; + std::vector cumulative_difficulties; - // if the alt chain isn't long enough to calculate the difficulty target - // based on its blocks alone, need to get more blocks from the main chain - if(alt_chain.size()< DIFFICULTY_BLOCKS_COUNT) - { - CRITICAL_REGION_LOCAL(m_blockchain_lock); - - // Figure out start and stop offsets for main chain blocks - size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front()->second.height : bei.height; - size_t main_chain_count = DIFFICULTY_BLOCKS_COUNT - std::min(static_cast(DIFFICULTY_BLOCKS_COUNT), alt_chain.size()); - main_chain_count = std::min(main_chain_count, main_chain_stop_offset); - size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count; - - if(!main_chain_start_offset) - ++main_chain_start_offset; //skip genesis block - - // get difficulties and timestamps from relevant main chain blocks - for(; main_chain_start_offset < main_chain_stop_offset; ++main_chain_start_offset) + // if the alt chain isn't long enough to calculate the difficulty target + // based on its blocks alone, need to get more blocks from the main chain + if(alt_chain.size()< DIFFICULTY_BLOCKS_COUNT) { - timestamps.push_back(m_db->get_block_timestamp(main_chain_start_offset)); - cumulative_difficulties.push_back(m_db->get_block_cumulative_difficulty(main_chain_start_offset)); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + + // Figure out start and stop offsets for main chain blocks + size_t main_chain_stop_offset = alt_chain.size() ? alt_chain.front()->second.height : bei.height; + size_t main_chain_count = DIFFICULTY_BLOCKS_COUNT - std::min(static_cast(DIFFICULTY_BLOCKS_COUNT), alt_chain.size()); + main_chain_count = std::min(main_chain_count, main_chain_stop_offset); + size_t main_chain_start_offset = main_chain_stop_offset - main_chain_count; + + if(!main_chain_start_offset) + ++main_chain_start_offset; //skip genesis block + + // get difficulties and timestamps from relevant main chain blocks + for(; main_chain_start_offset < main_chain_stop_offset; ++main_chain_start_offset) + { + timestamps.push_back(m_db->get_block_timestamp(main_chain_start_offset)); + cumulative_difficulties.push_back(m_db->get_block_cumulative_difficulty(main_chain_start_offset)); + } + + // make sure we haven't accidentally grabbed too many blocks...maybe don't need this check? + CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= DIFFICULTY_BLOCKS_COUNT, false, "Internal error, alt_chain.size()[" << alt_chain.size() << "] + vtimestampsec.size()[" << timestamps.size() << "] NOT <= DIFFICULTY_WINDOW[]" << DIFFICULTY_BLOCKS_COUNT); + + for (auto it : alt_chain) + { + timestamps.push_back(it->second.bl.timestamp); + cumulative_difficulties.push_back(it->second.cumulative_difficulty); + } + } + // if the alt chain is long enough for the difficulty calc, grab difficulties + // and timestamps from it alone + else + { + timestamps.resize(static_cast(DIFFICULTY_BLOCKS_COUNT)); + cumulative_difficulties.resize(static_cast(DIFFICULTY_BLOCKS_COUNT)); + size_t count = 0; + size_t max_i = timestamps.size()-1; + // get difficulties and timestamps from most recent blocks in alt chain + BOOST_REVERSE_FOREACH(auto it, alt_chain) + { + timestamps[max_i - count] = it->second.bl.timestamp; + cumulative_difficulties[max_i - count] = it->second.cumulative_difficulty; + count++; + if(count >= DIFFICULTY_BLOCKS_COUNT) + break; + } } - // make sure we haven't accidentally grabbed too many blocks...maybe don't need this check? - CHECK_AND_ASSERT_MES((alt_chain.size() + timestamps.size()) <= DIFFICULTY_BLOCKS_COUNT, false, - "Internal error, alt_chain.size()[" << alt_chain.size() - << "] + vtimestampsec.size()[" << timestamps.size() - << "] NOT <= DIFFICULTY_WINDOW[]" << DIFFICULTY_BLOCKS_COUNT - ); - - for (auto it : alt_chain) - { - timestamps.push_back(it->second.bl.timestamp); - cumulative_difficulties.push_back(it->second.cumulative_difficulty); - } - } - // if the alt chain is long enough for the difficulty calc, grab difficulties - // and timestamps from it alone - else - { - timestamps.resize(static_cast(DIFFICULTY_BLOCKS_COUNT)); - cumulative_difficulties.resize(static_cast(DIFFICULTY_BLOCKS_COUNT)); - size_t count = 0; - size_t max_i = timestamps.size()-1; - // get difficulties and timestamps from most recent blocks in alt chain - BOOST_REVERSE_FOREACH(auto it, alt_chain) - { - timestamps[max_i - count] = it->second.bl.timestamp; - cumulative_difficulties[max_i - count] = it->second.cumulative_difficulty; - count++; - if(count >= DIFFICULTY_BLOCKS_COUNT) - break; - } - } - - // calculate the difficulty target for the block and return it - return next_difficulty(timestamps, cumulative_difficulties); + // calculate the difficulty target for the block and return it + return next_difficulty(timestamps, cumulative_difficulties); } //------------------------------------------------------------------ // This function does a sanity check on basic things that all miner @@ -806,85 +876,82 @@ difficulty_type Blockchain::get_next_difficulty_for_alternative_chain(const std: // a non-overflowing tx amount (dubious necessity on this check) bool Blockchain::prevalidate_miner_transaction(const block& b, uint64_t height) { - LOG_PRINT_L3("Blockchain::" << __func__); - CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, false, "coinbase transaction in the block has no inputs"); - CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(txin_gen), false, "coinbase transaction in the block has the wrong type"); - if(boost::get(b.miner_tx.vin[0]).height != height) - { - LOG_PRINT_RED_L1("The miner transaction in block has invalid height: " << boost::get(b.miner_tx.vin[0]).height << ", expected: " << height); - return false; - } - CHECK_AND_ASSERT_MES(b.miner_tx.unlock_time == height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, - false, - "coinbase transaction transaction has the wrong unlock time=" << b.miner_tx.unlock_time << ", expected " << height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW); + LOG_PRINT_L3("Blockchain::" << __func__); + CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 1, false, "coinbase transaction in the block has no inputs"); + CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(txin_gen), false, "coinbase transaction in the block has the wrong type"); + if(boost::get(b.miner_tx.vin[0]).height != height) + { + LOG_PRINT_RED_L1("The miner transaction in block has invalid height: " << boost::get(b.miner_tx.vin[0]).height << ", expected: " << height); + return false; + } + CHECK_AND_ASSERT_MES(b.miner_tx.unlock_time == height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW, false, "coinbase transaction transaction has the wrong unlock time=" << b.miner_tx.unlock_time << ", expected " << height + CRYPTONOTE_MINED_MONEY_UNLOCK_WINDOW); + //check outs overflow + //NOTE: not entirely sure this is necessary, given that this function is + // designed simply to make sure the total amount for a transaction + // does not overflow a uint64_t, and this transaction *is* a uint64_t... + if(!check_outs_overflow(b.miner_tx)) + { + LOG_PRINT_RED_L1("miner transaction has money overflow in block " << get_block_hash(b)); + return false; + } - //check outs overflow - //NOTE: not entirely sure this is necessary, given that this function is - // designed simply to make sure the total amount for a transaction - // does not overflow a uint64_t, and this transaction *is* a uint64_t... - if(!check_outs_overflow(b.miner_tx)) - { - LOG_PRINT_RED_L1("miner transaction has money overflow in block " << get_block_hash(b)); - return false; - } - - return true; + return true; } //------------------------------------------------------------------ // 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) { - LOG_PRINT_L3("Blockchain::" << __func__); - //validate reward - uint64_t money_in_use = 0; - BOOST_FOREACH(auto& o, b.miner_tx.vout) + LOG_PRINT_L3("Blockchain::" << __func__); + //validate reward + uint64_t money_in_use = 0; + BOOST_FOREACH(auto& o, b.miner_tx.vout) money_in_use += o.amount; - 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)) { - LOG_PRINT_L1("block size " << cumulative_block_size << " is bigger than allowed for this blockchain"); - return false; - } - if(base_reward + fee < money_in_use) - { - LOG_PRINT_L1("coinbase transaction spend too much money (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + fee) << "(" << print_money(base_reward) << "+" << print_money(fee) << ")"); - return false; - } - if(base_reward + fee != money_in_use) - { - LOG_PRINT_L1("coinbase transaction doesn't use full amount of block reward: spent: " - << money_in_use << ", block reward " << base_reward + fee << "(" << base_reward << "+" << fee << ")"); - return false; - } - return true; + 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)) + { + LOG_PRINT_L1("block size " << cumulative_block_size << " is bigger than allowed for this blockchain"); + return false; + } + if(base_reward + fee < money_in_use) + { + LOG_PRINT_L1("coinbase transaction spend too much money (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + fee) << "(" << print_money(base_reward) << "+" << print_money(fee) << ")"); + return false; + } + if(base_reward + fee != money_in_use) + { + LOG_PRINT_L1("coinbase transaction doesn't use full amount of block reward: spent: " << money_in_use << ", block reward " << base_reward + fee << "(" << base_reward << "+" << fee << ")"); + return false; + } + return true; } //------------------------------------------------------------------ // get the block sizes of the last blocks, starting at // and return by reference . void Blockchain::get_last_n_blocks_sizes(std::vector& sz, size_t count) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - auto h = m_db->height(); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + auto h = m_db->height(); - // this function is meaningless for an empty blockchain...granted it should never be empty - if(h == 0) - return; + // this function is meaningless for an empty blockchain...granted it should never be empty + if(h == 0) + return; - // add size of last blocks to vector (or less, if blockchain size < count) - size_t start_offset = h - std::min(h, count); - for(size_t i = start_offset; i < h; i++) - { - sz.push_back(m_db->get_block_size(i)); - } + // add size of last blocks to vector (or less, if blockchain size < count) + size_t start_offset = h - std::min(h, count); + for(size_t i = start_offset; i < h; i++) + { + sz.push_back(m_db->get_block_size(i)); + } } //------------------------------------------------------------------ uint64_t Blockchain::get_current_cumulative_blocksize_limit() const { - LOG_PRINT_L3("Blockchain::" << __func__); - return m_current_block_cumul_sz_limit; + LOG_PRINT_L3("Blockchain::" << __func__); + return m_current_block_cumul_sz_limit; } //------------------------------------------------------------------ //TODO: This function only needed minor modification to work with BlockchainDB, @@ -898,146 +965,160 @@ uint64_t Blockchain::get_current_cumulative_blocksize_limit() const // in a lot of places. That flag is not referenced in any of the code // nor any of the makefiles, howeve. Need to look into whether or not it's // necessary at all. -bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce) const +bool Blockchain::create_block_template(block& b, const account_public_address& miner_address, difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce) { - LOG_PRINT_L3("Blockchain::" << __func__); - size_t median_size; - uint64_t already_generated_coins; + LOG_PRINT_L3("Blockchain::" << __func__); + size_t median_size; + uint64_t already_generated_coins; - CRITICAL_REGION_BEGIN(m_blockchain_lock); - b.major_version = CURRENT_BLOCK_MAJOR_VERSION; - b.minor_version = CURRENT_BLOCK_MINOR_VERSION; - b.prev_id = get_tail_id(); - b.timestamp = time(NULL); + CRITICAL_REGION_BEGIN(m_blockchain_lock); + b.major_version = CURRENT_BLOCK_MAJOR_VERSION; + b.minor_version = CURRENT_BLOCK_MINOR_VERSION; + b.prev_id = get_tail_id(); + b.timestamp = time(NULL); - height = m_db->height(); - diffic = get_difficulty_for_next_block(); - CHECK_AND_ASSERT_MES(diffic, false, "difficulty owverhead."); + height = m_db->height(); + diffic = get_difficulty_for_next_block(); + CHECK_AND_ASSERT_MES(diffic, false, "difficulty owverhead."); - median_size = m_current_block_cumul_sz_limit / 2; - already_generated_coins = m_db->get_block_already_generated_coins(height - 1); + median_size = m_current_block_cumul_sz_limit / 2; + already_generated_coins = m_db->get_block_already_generated_coins(height - 1); - CRITICAL_REGION_END(); + CRITICAL_REGION_END(); - size_t txs_size; - uint64_t fee; - if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee)) { - return false; - } + size_t txs_size; + uint64_t fee; + if (!m_tx_pool.fill_block_template(b, median_size, already_generated_coins, txs_size, fee)) + { + return false; + } #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) - size_t real_txs_size = 0; - uint64_t real_fee = 0; - CRITICAL_REGION_BEGIN(m_tx_pool.m_transactions_lock); - BOOST_FOREACH(crypto::hash &cur_hash, b.tx_hashes) { - auto cur_res = m_tx_pool.m_transactions.find(cur_hash); - if (cur_res == m_tx_pool.m_transactions.end()) { - LOG_ERROR("Creating block template: error: transaction not found"); - continue; + size_t real_txs_size = 0; + uint64_t real_fee = 0; + CRITICAL_REGION_BEGIN(m_tx_pool.m_transactions_lock); + BOOST_FOREACH(crypto::hash &cur_hash, b.tx_hashes) + { + auto cur_res = m_tx_pool.m_transactions.find(cur_hash); + if (cur_res == m_tx_pool.m_transactions.end()) + { + LOG_ERROR("Creating block template: error: transaction not found"); + continue; + } + tx_memory_pool::tx_details &cur_tx = cur_res->second; + real_txs_size += cur_tx.blob_size; + real_fee += cur_tx.fee; + if (cur_tx.blob_size != get_object_blobsize(cur_tx.tx)) + { + LOG_ERROR("Creating block template: error: invalid transaction size"); + } + uint64_t inputs_amount; + if (!get_inputs_money_amount(cur_tx.tx, inputs_amount)) + { + LOG_ERROR("Creating block template: error: cannot get inputs amount"); + } + else if (cur_tx.fee != inputs_amount - get_outs_money_amount(cur_tx.tx)) + { + LOG_ERROR("Creating block template: error: invalid fee"); + } } - tx_memory_pool::tx_details &cur_tx = cur_res->second; - real_txs_size += cur_tx.blob_size; - real_fee += cur_tx.fee; - if (cur_tx.blob_size != get_object_blobsize(cur_tx.tx)) { - LOG_ERROR("Creating block template: error: invalid transaction size"); + if (txs_size != real_txs_size) + { + LOG_ERROR("Creating block template: error: wrongly calculated transaction size"); } - uint64_t inputs_amount; - if (!get_inputs_money_amount(cur_tx.tx, inputs_amount)) { - LOG_ERROR("Creating block template: error: cannot get inputs amount"); - } else if (cur_tx.fee != inputs_amount - get_outs_money_amount(cur_tx.tx)) { - LOG_ERROR("Creating block template: error: invalid fee"); + if (fee != real_fee) + { + LOG_ERROR("Creating block template: error: wrongly calculated fee"); } - } - if (txs_size != real_txs_size) { - LOG_ERROR("Creating block template: error: wrongly calculated transaction size"); - } - if (fee != real_fee) { - LOG_ERROR("Creating block template: error: wrongly calculated fee"); - } - CRITICAL_REGION_END(); - LOG_PRINT_L1("Creating block template: height " << height << - ", median size " << median_size << - ", already generated coins " << already_generated_coins << - ", transaction size " << txs_size << - ", fee " << fee); + CRITICAL_REGION_END(); + LOG_PRINT_L1("Creating block template: height " << height << + ", median size " << median_size << + ", already generated coins " << already_generated_coins << + ", transaction size " << txs_size << + ", fee " << fee); #endif - /* + /* two-phase miner transaction generation: we don't know exact block size until we prepare block, but we don't know reward until we know block size, so first miner transaction generated with fake amount of money, and with phase we know think we know expected block size - */ - //make blocks coin-base tx looks close to real coinbase tx to get truthful blob size - bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, 11); - CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance"); - size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx); + */ + //make blocks coin-base tx looks close to real coinbase tx to get truthful blob size + bool r = construct_miner_tx(height, median_size, already_generated_coins, txs_size, fee, miner_address, b.miner_tx, ex_nonce, 11); + CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance"); + size_t cumulative_size = txs_size + get_object_blobsize(b.miner_tx); #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) - LOG_PRINT_L1("Creating block template: miner tx size " << get_object_blobsize(b.miner_tx) << - ", cumulative size " << cumulative_size); + LOG_PRINT_L1("Creating block template: miner tx size " << get_object_blobsize(b.miner_tx) << + ", cumulative size " << cumulative_size); #endif - for (size_t try_count = 0; try_count != 10; ++try_count) { - r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, 11); + for (size_t try_count = 0; try_count != 10; ++try_count) + { + r = construct_miner_tx(height, median_size, already_generated_coins, cumulative_size, fee, miner_address, b.miner_tx, ex_nonce, 11); - CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance"); - size_t coinbase_blob_size = get_object_blobsize(b.miner_tx); - if (coinbase_blob_size > cumulative_size - txs_size) { - cumulative_size = txs_size + coinbase_blob_size; + CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, second chance"); + size_t coinbase_blob_size = get_object_blobsize(b.miner_tx); + if (coinbase_blob_size > cumulative_size - txs_size) + { + cumulative_size = txs_size + coinbase_blob_size; #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) - LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size << - ", cumulative size " << cumulative_size << " is greater then before"); + LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size << + ", cumulative size " << cumulative_size << " is greater then before"); #endif - continue; - } - - if (coinbase_blob_size < cumulative_size - txs_size) { - size_t delta = cumulative_size - txs_size - coinbase_blob_size; -#if defined(DEBUG_CREATE_BLOCK_TEMPLATE) - LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size << - ", cumulative size " << txs_size + coinbase_blob_size << - " is less then before, adding " << delta << " zero bytes"); -#endif - b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0); - //here could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len. - if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx)) { - CHECK_AND_ASSERT_MES(cumulative_size + 1 == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " + 1 is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx)); - b.miner_tx.extra.resize(b.miner_tx.extra.size() - 1); - if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx)) { - //fuck, not lucky, -1 makes varint-counter size smaller, in that case we continue to grow with cumulative_size - LOG_PRINT_RED("Miner tx creation has no luck with delta_extra size = " << delta << " and " << delta - 1 , LOG_LEVEL_2); - cumulative_size += delta - 1; - continue; + continue; } - LOG_PRINT_GREEN("Setting extra for block: " << b.miner_tx.extra.size() << ", try_count=" << try_count, LOG_LEVEL_1); - } - } - CHECK_AND_ASSERT_MES(cumulative_size == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx)); + + if (coinbase_blob_size < cumulative_size - txs_size) + { + size_t delta = cumulative_size - txs_size - coinbase_blob_size; #if defined(DEBUG_CREATE_BLOCK_TEMPLATE) - LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size << - ", cumulative size " << cumulative_size << " is now good"); + LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size << + ", cumulative size " << txs_size + coinbase_blob_size << + " is less then before, adding " << delta << " zero bytes"); #endif - return true; - } - LOG_ERROR("Failed to create_block_template with " << 10 << " tries"); - return false; + b.miner_tx.extra.insert(b.miner_tx.extra.end(), delta, 0); + //here could be 1 byte difference, because of extra field counter is varint, and it can become from 1-byte len to 2-bytes len. + if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx)) + { + CHECK_AND_ASSERT_MES(cumulative_size + 1 == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " + 1 is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx)); + b.miner_tx.extra.resize(b.miner_tx.extra.size() - 1); + if (cumulative_size != txs_size + get_object_blobsize(b.miner_tx)) + { + //fuck, not lucky, -1 makes varint-counter size smaller, in that case we continue to grow with cumulative_size + LOG_PRINT_RED("Miner tx creation has no luck with delta_extra size = " << delta << " and " << delta - 1 , LOG_LEVEL_2); + cumulative_size += delta - 1; + continue; + } + LOG_PRINT_GREEN("Setting extra for block: " << b.miner_tx.extra.size() << ", try_count=" << try_count, LOG_LEVEL_1); + } + } + CHECK_AND_ASSERT_MES(cumulative_size == txs_size + get_object_blobsize(b.miner_tx), false, "unexpected case: cumulative_size=" << cumulative_size << " is not equal txs_cumulative_size=" << txs_size << " + get_object_blobsize(b.miner_tx)=" << get_object_blobsize(b.miner_tx)); +#if defined(DEBUG_CREATE_BLOCK_TEMPLATE) + LOG_PRINT_L1("Creating block template: miner tx size " << coinbase_blob_size << + ", cumulative size " << cumulative_size << " is now good"); +#endif + return true; + } + LOG_ERROR("Failed to create_block_template with " << 10 << " tries"); + return false; } //------------------------------------------------------------------ // for an alternate chain, get the timestamps from the main chain to complete // the needed number of timestamps for the BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW. bool Blockchain::complete_timestamps_vector(uint64_t start_top_height, std::vector& timestamps) { - LOG_PRINT_L3("Blockchain::" << __func__); + LOG_PRINT_L3("Blockchain::" << __func__); - if(timestamps.size() >= BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW) + if(timestamps.size() >= BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW) + return true; + + CRITICAL_REGION_LOCAL(m_blockchain_lock); + size_t need_elements = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW - timestamps.size(); + CHECK_AND_ASSERT_MES(start_top_height < m_db->height(), false, "internal error: passed start_height not < " << " m_db->height() -- " << start_top_height << " >= " << m_db->height()); + size_t stop_offset = start_top_height > need_elements ? start_top_height - need_elements : 0; + while (start_top_height != stop_offset) + { + timestamps.push_back(m_db->get_block_timestamp(start_top_height)); + --start_top_height; + } return true; - - CRITICAL_REGION_LOCAL(m_blockchain_lock); - size_t need_elements = BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW - timestamps.size(); - CHECK_AND_ASSERT_MES(start_top_height < m_db->height(), false, "internal error: passed start_height not < " << " m_db->height() -- " << start_top_height << " >= " << m_db->height()); - size_t stop_offset = start_top_height > need_elements ? start_top_height - need_elements : 0; - while (start_top_height != stop_offset) - { - timestamps.push_back(m_db->get_block_timestamp(start_top_height)); - --start_top_height; - } - return true; } //------------------------------------------------------------------ // If a block is to be added and its parent block is not the current @@ -1048,228 +1129,215 @@ bool Blockchain::complete_timestamps_vector(uint64_t start_top_height, std::vect // a long forked chain eventually. bool Blockchain::handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc) { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - - uint64_t block_height = get_block_height(b); - if(0 == block_height) - { - LOG_PRINT_L1("Block with id: " << epee::string_tools::pod_to_hex(id) << " (as alternative), but miner tx says height is 0."); - bvc.m_verifivation_failed = true; - return false; - } - // this basically says if the blockchain is smaller than the first - // checkpoint then alternate blocks are allowed. Alternatively, if the - // last checkpoint *before* the end of the current chain is also before - // the block to be added, then this is fine. - if (!m_checkpoints.is_alternative_block_allowed(get_current_blockchain_height(), block_height)) - { - LOG_PRINT_RED_L1("Block with id: " << id - << std::endl << " can't be accepted for alternative chain, block height: " << block_height - << std::endl << " blockchain height: " << get_current_blockchain_height()); - bvc.m_verifivation_failed = true; - return false; - } - - //block is not related with head of main chain - //first of all - look in alternative chains container - auto it_prev = m_alternative_chains.find(b.prev_id); - bool parent_in_main = m_db->block_exists(b.prev_id); - if(it_prev != m_alternative_chains.end() || parent_in_main) - { - //we have new block in alternative chain - - //build alternative subchain, front -> mainchain, back -> alternative head - blocks_ext_by_hash::iterator alt_it = it_prev; //m_alternative_chains.find() - std::list alt_chain; - std::vector timestamps; - while(alt_it != m_alternative_chains.end()) + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + m_timestamps_and_difficulties_height = 0; + uint64_t block_height = get_block_height(b); + if(0 == block_height) { - alt_chain.push_front(alt_it); - timestamps.push_back(alt_it->second.bl.timestamp); - alt_it = m_alternative_chains.find(alt_it->second.bl.prev_id); - } - - // if block to be added connects to known blocks that aren't part of the - // main chain -- that is, if we're adding on to an alternate chain - if(alt_chain.size()) - { - // make sure alt chain doesn't somehow start past the end of the main chain - CHECK_AND_ASSERT_MES(m_db->height() > alt_chain.front()->second.height, false, "main blockchain wrong height"); - - // make sure that the blockchain contains the block that should connect - // this alternate chain with it. - if (!m_db->block_exists(alt_chain.front()->second.bl.prev_id)) - { - LOG_PRINT_L1("alternate chain does not appear to connect to main chain..."); + LOG_PRINT_L1("Block with id: " << epee::string_tools::pod_to_hex(id) << " (as alternative), but miner tx says height is 0."); + bvc.m_verifivation_failed = true; return false; - } - - // make sure block connects correctly to the main chain - auto h = m_db->get_block_hash_from_height(alt_chain.front()->second.height - 1); - CHECK_AND_ASSERT_MES(h == alt_chain.front()->second.bl.prev_id, false, "alternative chain has wrong connection to main chain"); - complete_timestamps_vector(m_db->get_block_height(alt_chain.front()->second.bl.prev_id), timestamps); } - // if block not associated with known alternate chain - else + // this basically says if the blockchain is smaller than the first + // checkpoint then alternate blocks are allowed. Alternatively, if the + // last checkpoint *before* the end of the current chain is also before + // the block to be added, then this is fine. + if (!m_checkpoints.is_alternative_block_allowed(get_current_blockchain_height(), block_height)) { - // if block parent is not part of main chain or an alternate chain, - // we ignore it - CHECK_AND_ASSERT_MES(parent_in_main, false, "internal error: broken imperative condition it_main_prev != m_blocks_index.end()"); - - complete_timestamps_vector(m_db->get_block_height(b.prev_id), timestamps); + LOG_PRINT_RED_L1("Block with id: " << id << std::endl << " can't be accepted for alternative chain, block height: " << block_height << std::endl << " blockchain height: " << get_current_blockchain_height()); + bvc.m_verifivation_failed = true; + return false; } - // verify that the block's timestamp is within the acceptable range - // (not earlier than the median of the last X blocks) - if(!check_block_timestamp(timestamps, b)) + //block is not related with head of main chain + //first of all - look in alternative chains container + auto it_prev = m_alternative_chains.find(b.prev_id); + bool parent_in_main = m_db->block_exists(b.prev_id); + if(it_prev != m_alternative_chains.end() || parent_in_main) { - LOG_PRINT_RED_L1("Block with id: " << id - << std::endl << " for alternative chain, has invalid timestamp: " << b.timestamp); - bvc.m_verifivation_failed = true; - return false; - } + //we have new block in alternative chain - // FIXME: consider moving away from block_extended_info at some point - block_extended_info bei = boost::value_initialized(); - bei.bl = b; - bei.height = alt_chain.size() ? it_prev->second.height + 1 : m_db->get_block_height(b.prev_id) + 1; + //build alternative subchain, front -> mainchain, back -> alternative head + blocks_ext_by_hash::iterator alt_it = it_prev; //m_alternative_chains.find() + std::list alt_chain; + std::vector timestamps; + while(alt_it != m_alternative_chains.end()) + { + alt_chain.push_front(alt_it); + timestamps.push_back(alt_it->second.bl.timestamp); + alt_it = m_alternative_chains.find(alt_it->second.bl.prev_id); + } - bool is_a_checkpoint; - if(!m_checkpoints.check_block(bei.height, id, is_a_checkpoint)) - { - LOG_ERROR("CHECKPOINT VALIDATION FAILED"); - bvc.m_verifivation_failed = true; - return false; - } + // if block to be added connects to known blocks that aren't part of the + // main chain -- that is, if we're adding on to an alternate chain + if(alt_chain.size()) + { + // make sure alt chain doesn't somehow start past the end of the main chain + CHECK_AND_ASSERT_MES(m_db->height() > alt_chain.front()->second.height, false, "main blockchain wrong height"); - // Check the block's hash against the difficulty target for its alt chain - m_is_in_checkpoint_zone = false; - difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei); - CHECK_AND_ASSERT_MES(current_diff, false, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!"); - crypto::hash proof_of_work = null_hash; - get_block_longhash(bei.bl, proof_of_work, bei.height); - if(!check_hash(proof_of_work, current_diff)) - { - LOG_PRINT_RED_L1("Block with id: " << id - << std::endl << " for alternative chain, does not have enough proof of work: " << proof_of_work - << std::endl << " expected difficulty: " << current_diff); - bvc.m_verifivation_failed = true; - return false; - } + // make sure that the blockchain contains the block that should connect + // this alternate chain with it. + if (!m_db->block_exists(alt_chain.front()->second.bl.prev_id)) + { + LOG_PRINT_L1("alternate chain does not appear to connect to main chain..."); + return false; + } - if(!prevalidate_miner_transaction(b, bei.height)) - { - LOG_PRINT_RED_L1("Block with id: " << epee::string_tools::pod_to_hex(id) - << " (as alternative) has incorrect miner transaction."); - bvc.m_verifivation_failed = true; - return false; + // make sure block connects correctly to the main chain + auto h = m_db->get_block_hash_from_height(alt_chain.front()->second.height - 1); + CHECK_AND_ASSERT_MES(h == alt_chain.front()->second.bl.prev_id, false, "alternative chain has wrong connection to main chain"); + complete_timestamps_vector(m_db->get_block_height(alt_chain.front()->second.bl.prev_id), timestamps); + } + // if block not associated with known alternate chain + else + { + // if block parent is not part of main chain or an alternate chain, + // we ignore it + CHECK_AND_ASSERT_MES(parent_in_main, false, "internal error: broken imperative condition it_main_prev != m_blocks_index.end()"); - } + complete_timestamps_vector(m_db->get_block_height(b.prev_id), timestamps); + } - // FIXME: - // this brings up an interesting point: consider allowing to get block - // difficulty both by height OR by hash, not just height. - difficulty_type main_chain_cumulative_difficulty = m_db->get_block_cumulative_difficulty(m_db->height() - 1); - if (alt_chain.size()) - { - bei.cumulative_difficulty = it_prev->second.cumulative_difficulty; + // verify that the block's timestamp is within the acceptable range + // (not earlier than the median of the last X blocks) + if(!check_block_timestamp(timestamps, b)) + { + LOG_PRINT_RED_L1("Block with id: " << id << std::endl << " for alternative chain, has invalid timestamp: " << b.timestamp); + bvc.m_verifivation_failed = true; + return false; + } + + // FIXME: consider moving away from block_extended_info at some point + block_extended_info bei = boost::value_initialized(); + bei.bl = b; + bei.height = alt_chain.size() ? it_prev->second.height + 1 : m_db->get_block_height(b.prev_id) + 1; + + bool is_a_checkpoint; + if(!m_checkpoints.check_block(bei.height, id, is_a_checkpoint)) + { + LOG_ERROR("CHECKPOINT VALIDATION FAILED"); + bvc.m_verifivation_failed = true; + return false; + } + + // Check the block's hash against the difficulty target for its alt chain + m_is_in_checkpoint_zone = false; + difficulty_type current_diff = get_next_difficulty_for_alternative_chain(alt_chain, bei); + CHECK_AND_ASSERT_MES(current_diff, false, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!"); + crypto::hash proof_of_work = null_hash; + get_block_longhash(bei.bl, proof_of_work, bei.height); + if(!check_hash(proof_of_work, current_diff)) + { + LOG_PRINT_RED_L1("Block with id: " << id << std::endl << " for alternative chain, does not have enough proof of work: " << proof_of_work << std::endl << " expected difficulty: " << current_diff); + bvc.m_verifivation_failed = true; + return false; + } + + if(!prevalidate_miner_transaction(b, bei.height)) + { + LOG_PRINT_RED_L1("Block with id: " << epee::string_tools::pod_to_hex(id) << " (as alternative) has incorrect miner transaction."); + bvc.m_verifivation_failed = true; + return false; + + } + + // FIXME: + // this brings up an interesting point: consider allowing to get block + // difficulty both by height OR by hash, not just height. + difficulty_type main_chain_cumulative_difficulty = m_db->get_block_cumulative_difficulty(m_db->height() - 1); + if (alt_chain.size()) + { + bei.cumulative_difficulty = it_prev->second.cumulative_difficulty; + } + else + { + // passed-in block's previous block's cumulative difficulty, found on the main chain + bei.cumulative_difficulty = m_db->get_block_cumulative_difficulty(m_db->get_block_height(b.prev_id)); + } + bei.cumulative_difficulty += current_diff; + + // add block to alternate blocks storage, + // as well as the current "alt chain" container + auto i_res = m_alternative_chains.insert(blocks_ext_by_hash::value_type(id, bei)); + CHECK_AND_ASSERT_MES(i_res.second, false, "insertion of new alternative block returned as it already exist"); + alt_chain.push_back(i_res.first); + + // FIXME: is it even possible for a checkpoint to show up not on the main chain? + if(is_a_checkpoint) + { + //do reorganize! + LOG_PRINT_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_db->height() - 1 << ", checkpoint is found in alternative chain on height " << bei.height, LOG_LEVEL_0); + + bool r = switch_to_alternative_blockchain(alt_chain, true); + + bvc.m_added_to_main_chain = r; + bvc.m_verifivation_failed = !r; + + return r; + } + else if(main_chain_cumulative_difficulty < bei.cumulative_difficulty) //check if difficulty bigger then in main chain + { + //do reorganize! + LOG_PRINT_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_db->height() - 1 << " with cum_difficulty " << m_db->get_block_cumulative_difficulty(m_db->height() - 1) << std::endl << " alternative blockchain size: " << alt_chain.size() << " with cum_difficulty " << bei.cumulative_difficulty, LOG_LEVEL_0); + + bool r = switch_to_alternative_blockchain(alt_chain, false); + if (r) + bvc.m_added_to_main_chain = true; + else + bvc.m_verifivation_failed = true; + return r; + } + else + { + LOG_PRINT_BLUE("----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT " << bei.height << std::endl << "id:\t" << id << std::endl << "PoW:\t" << proof_of_work << std::endl << "difficulty:\t" << current_diff, LOG_LEVEL_0); + return true; + } } else { - // passed-in block's previous block's cumulative difficulty, found on the main chain - bei.cumulative_difficulty = m_db->get_block_cumulative_difficulty(m_db->get_block_height(b.prev_id)); + //block orphaned + bvc.m_marked_as_orphaned = true; + LOG_PRINT_RED_L1("Block recognized as orphaned and rejected, id = " << id); } - bei.cumulative_difficulty += current_diff; - // add block to alternate blocks storage, - // as well as the current "alt chain" container - auto i_res = m_alternative_chains.insert(blocks_ext_by_hash::value_type(id, bei)); - CHECK_AND_ASSERT_MES(i_res.second, false, "insertion of new alternative block returned as it already exist"); - alt_chain.push_back(i_res.first); - - // FIXME: is it even possible for a checkpoint to show up not on the main chain? - if(is_a_checkpoint) - { - //do reorganize! - LOG_PRINT_GREEN("###### REORGANIZE on height: " << alt_chain.front()->second.height << " of " << m_db->height() - 1 << - ", checkpoint is found in alternative chain on height " << bei.height, LOG_LEVEL_0); - - bool r = switch_to_alternative_blockchain(alt_chain, true); - - bvc.m_added_to_main_chain = r; - bvc.m_verifivation_failed = !r; - - return r; - } - else if(main_chain_cumulative_difficulty < bei.cumulative_difficulty) //check if difficulty bigger then in main chain - { - //do reorganize! - LOG_PRINT_GREEN("###### REORGANIZE on height: " - << alt_chain.front()->second.height << " of " << m_db->height() - 1 - << " with cum_difficulty " << m_db->get_block_cumulative_difficulty(m_db->height() - 1) - << std::endl << " alternative blockchain size: " << alt_chain.size() - << " with cum_difficulty " << bei.cumulative_difficulty, LOG_LEVEL_0 - ); - - bool r = switch_to_alternative_blockchain(alt_chain, false); - if(r) bvc.m_added_to_main_chain = true; - else bvc.m_verifivation_failed = true; - return r; - } - else - { - LOG_PRINT_BLUE("----- BLOCK ADDED AS ALTERNATIVE ON HEIGHT " << bei.height - << std::endl << "id:\t" << id - << std::endl << "PoW:\t" << proof_of_work - << std::endl << "difficulty:\t" << current_diff, LOG_LEVEL_0); - return true; - } - } - else - { - //block orphaned - bvc.m_marked_as_orphaned = true; - LOG_PRINT_RED_L1("Block recognized as orphaned and rejected, id = " << id); - } - - return true; + return true; } //------------------------------------------------------------------ bool Blockchain::get_blocks(uint64_t start_offset, size_t count, std::list& blocks, std::list& txs) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - if(start_offset > m_db->height()) - return false; + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + if(start_offset > m_db->height()) + return false; - if (!get_blocks(start_offset, count, blocks)) - { - return false; - } + if (!get_blocks(start_offset, count, blocks)) + { + return false; + } - for(const block& blk : blocks) - { - std::list missed_ids; - get_transactions(blk.tx_hashes, txs, missed_ids); - CHECK_AND_ASSERT_MES(!missed_ids.size(), false, "has missed transactions in own block in main blockchain"); - } + for(const block& blk : blocks) + { + std::list missed_ids; + get_transactions(blk.tx_hashes, txs, missed_ids); + CHECK_AND_ASSERT_MES(!missed_ids.size(), false, "has missed transactions in own block in main blockchain"); + } - return true; + return true; } //------------------------------------------------------------------ bool Blockchain::get_blocks(uint64_t start_offset, size_t count, std::list& blocks) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - if(start_offset > m_db->height()) - return false; + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + if(start_offset > m_db->height()) + return false; - for(size_t i = start_offset; i < start_offset + count && i <= m_db->height();i++) - { - blocks.push_back(m_db->get_block_from_height(i)); - } - return true; + for(size_t i = start_offset; i < start_offset + count && i <= m_db->height();i++) + { + blocks.push_back(m_db->get_block_from_height(i)); + } + return true; } //------------------------------------------------------------------ //TODO: This function *looks* like it won't need to be rewritten @@ -1277,67 +1345,68 @@ bool Blockchain::get_blocks(uint64_t start_offset, size_t count, std::list blocks; - get_blocks(arg.blocks, blocks, rsp.missed_ids); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + rsp.current_blockchain_height = get_current_blockchain_height(); + std::list blocks; + get_blocks(arg.blocks, blocks, rsp.missed_ids); - BOOST_FOREACH(const auto& bl, blocks) - { - std::list missed_tx_id; + BOOST_FOREACH(const auto& bl, blocks) + { + std::list missed_tx_id; + std::list txs; + get_transactions(bl.tx_hashes, txs, rsp.missed_ids); + CHECK_AND_ASSERT_MES(!missed_tx_id.size(), false, "Internal error: has missed missed_tx_id.size()=" << missed_tx_id.size() + << std::endl << "for block id = " << get_block_hash(bl)); + rsp.blocks.push_back(block_complete_entry()); + block_complete_entry& e = rsp.blocks.back(); + //pack block + e.block = t_serializable_object_to_blob(bl); + //pack transactions + BOOST_FOREACH(transaction& tx, txs) + e.txs.push_back(t_serializable_object_to_blob(tx)); + + } + //get another transactions, if need std::list txs; - get_transactions(bl.tx_hashes, txs, rsp.missed_ids); - CHECK_AND_ASSERT_MES(!missed_tx_id.size(), false, "Internal error: has missed missed_tx_id.size()=" << missed_tx_id.size() - << std::endl << "for block id = " << get_block_hash(bl)); - rsp.blocks.push_back(block_complete_entry()); - block_complete_entry& e = rsp.blocks.back(); - //pack block - e.block = t_serializable_object_to_blob(bl); - //pack transactions - BOOST_FOREACH(transaction& tx, txs) - e.txs.push_back(t_serializable_object_to_blob(tx)); - - } - //get another transactions, if need - std::list txs; - get_transactions(arg.txs, txs, rsp.missed_ids); - //pack aside transactions - BOOST_FOREACH(const auto& tx, txs) + get_transactions(arg.txs, txs, rsp.missed_ids); + //pack aside transactions + BOOST_FOREACH(const auto& tx, txs) rsp.txs.push_back(t_serializable_object_to_blob(tx)); - return true; + return true; } //------------------------------------------------------------------ bool Blockchain::get_alternative_blocks(std::list& blocks) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - BOOST_FOREACH(const auto& alt_bl, m_alternative_chains) - { - blocks.push_back(alt_bl.second.bl); - } - return true; + BOOST_FOREACH(const auto& alt_bl, m_alternative_chains) + { + blocks.push_back(alt_bl.second.bl); + } + return true; } //------------------------------------------------------------------ size_t Blockchain::get_alternative_blocks_count() const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - return m_alternative_chains.size(); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + return m_alternative_chains.size(); } //------------------------------------------------------------------ // This function adds the output specified by to the result_outs container // unlocked and other such checks should be done by here. void Blockchain::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry& oen = *result_outs.outs.insert(result_outs.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry()); - oen.global_amount_index = i; - oen.out_key = m_db->get_output_key(amount, i); + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry& oen = *result_outs.outs.insert(result_outs.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry()); + oen.global_amount_index = i; + output_data_t data = m_db->get_output_key(amount, i); + oen.out_key = data.pubkey; } //------------------------------------------------------------------ // This function takes an RPC request for mixins and creates an RPC response @@ -1346,72 +1415,80 @@ void Blockchain::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_A // in some cases bool Blockchain::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) const { - LOG_PRINT_L3("Blockchain::" << __func__); - srand(static_cast(time(NULL))); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + srand(static_cast(time(NULL))); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - // for each amount that we need to get mixins for, get random outputs - // from BlockchainDB where is req.outs_count (number of mixins). - for (uint64_t amount : req.amounts) - { - // create outs_for_amount struct and populate amount field - COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs = *res.outs.insert(res.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount()); - result_outs.amount = amount; - - std::unordered_set seen_indices; - - // if there aren't enough outputs to mix with (or just enough), - // use all of them. Eventually this should become impossible. - if (m_db->get_num_outputs(amount) <= req.outs_count) + // for each amount that we need to get mixins for, get random outputs + // from BlockchainDB where is req.outs_count (number of mixins). + for (uint64_t amount : req.amounts) { - for (uint64_t i = 0; i < m_db->get_num_outputs(amount); i++) - { - // get tx_hash, tx_out_index from DB - tx_out_index toi = m_db->get_output_tx_and_index(amount, i); + auto num_outs = m_db->get_num_outputs(amount); + // create outs_for_amount struct and populate amount field + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs = *res.outs.insert(res.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount()); + result_outs.amount = amount; - // if tx is unlocked, add output to result_outs - if (is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first))) + std::unordered_set seen_indices; + + // if there aren't enough outputs to mix with (or just enough), + // use all of them. Eventually this should become impossible. + if (num_outs <= req.outs_count) { - add_out_to_get_random_outs(result_outs, amount, i); - } + for (uint64_t i = 0; i < num_outs; i++) + { + // get tx_hash, tx_out_index from DB + tx_out_index toi = m_db->get_output_tx_and_index(amount, i); - } + // if tx is unlocked, add output to result_outs + if (is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first))) + { + add_out_to_get_random_outs(result_outs, amount, i); + } + + } + } + else + { + // while we still need more mixins + while (result_outs.outs.size() < req.outs_count) + { + // if we've gone through every possible output, we've gotten all we can + if (seen_indices.size() == num_outs) + { + break; + } + + // get a random output index from the DB. If we've already seen it, + // return to the top of the loop and try again, otherwise add it to the + // list of output indices we've seen. + + // triangular distribution over [a,b) with a=0, mode c=b=up_index_limit + uint64_t r = crypto::rand() % ((uint64_t)1 << 53); + double frac = std::sqrt((double)r / ((uint64_t)1 << 53)); + uint64_t i = (uint64_t)(frac*num_outs); + // just in case rounding up to 1 occurs after sqrt + if (i == num_outs) + --i; + + if (seen_indices.count(i)) + { + continue; + } + seen_indices.emplace(i); + + // get tx_hash, tx_out_index from DB + tx_out_index toi = m_db->get_output_tx_and_index(amount, i); + + // if the output's transaction is unlocked, add the output's index to + // our list. + if (is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first))) + { + add_out_to_get_random_outs(result_outs, amount, i); + } + } + } } - else - { - // while we still need more mixins - auto num_outs = m_db->get_num_outputs(amount); - while (result_outs.outs.size() < req.outs_count) - { - // if we've gone through every possible output, we've gotten all we can - if (seen_indices.size() == num_outs) - { - break; - } - - // get a random output index from the DB. If we've already seen it, - // return to the top of the loop and try again, otherwise add it to the - // list of output indices we've seen. - uint64_t i = m_db->get_random_output(amount); - if (seen_indices.count(i)) - { - continue; - } - seen_indices.emplace(i); - - // get tx_hash, tx_out_index from DB - tx_out_index toi = m_db->get_output_tx_and_index(amount, i); - - // if the output's transaction is unlocked, add the output's index to - // our list. - if (is_tx_spendtime_unlocked(m_db->get_tx_unlock_time(toi.first))) - { - add_out_to_get_random_outs(result_outs, amount, i); - } - } - } - } - return true; + return true; } //------------------------------------------------------------------ // This function takes a list of block hashes from another node @@ -1419,187 +1496,175 @@ bool Blockchain::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUT // This is used to see what to send another node that needs to sync. bool Blockchain::find_blockchain_supplement(const std::list& qblock_ids, uint64_t& starter_offset) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - // make sure the request includes at least the genesis block, otherwise - // how can we expect to sync from the client that the block list came from? - if(!qblock_ids.size() /*|| !req.m_total_height*/) - { - LOG_PRINT_L1("Client sent wrong NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << qblock_ids.size() << /*", m_height=" << req.m_total_height <<*/ ", dropping connection"); - return false; - } - - // make sure that the last block in the request's block list matches - // the genesis block - auto gen_hash = m_db->get_block_hash_from_height(0); - if(qblock_ids.back() != gen_hash) - { - LOG_PRINT_L1("Client sent wrong NOTIFY_REQUEST_CHAIN: genesis block missmatch: " << std::endl << "id: " - << qblock_ids.back() << ", " << std::endl << "expected: " << gen_hash - << "," << std::endl << " dropping connection"); - return false; - } - - // Find the first block the foreign chain has that we also have. - // Assume qblock_ids is in reverse-chronological order. - auto bl_it = qblock_ids.begin(); - uint64_t split_height = 0; - for(; bl_it != qblock_ids.end(); bl_it++) - { - try + // make sure the request includes at least the genesis block, otherwise + // how can we expect to sync from the client that the block list came from? + if(!qblock_ids.size() /*|| !req.m_total_height*/) { - split_height = m_db->get_block_height(*bl_it); - break; + LOG_PRINT_L1("Client sent wrong NOTIFY_REQUEST_CHAIN: m_block_ids.size()=" << qblock_ids.size() << /*", m_height=" << req.m_total_height <<*/ ", dropping connection"); + return false; } - catch (const BLOCK_DNE& e) + + // make sure that the last block in the request's block list matches + // the genesis block + auto gen_hash = m_db->get_block_hash_from_height(0); + if(qblock_ids.back() != gen_hash) { - continue; + LOG_PRINT_L1("Client sent wrong NOTIFY_REQUEST_CHAIN: genesis block missmatch: " << std::endl << "id: " << qblock_ids.back() << ", " << std::endl << "expected: " << gen_hash << "," << std::endl << " dropping connection"); + return false; } - catch (const std::exception& e) + + // Find the first block the foreign chain has that we also have. + // Assume qblock_ids is in reverse-chronological order. + auto bl_it = qblock_ids.begin(); + uint64_t split_height = 0; + for(; bl_it != qblock_ids.end(); bl_it++) { - LOG_PRINT_L1("Non-critical error trying to find block by hash in BlockchainDB, hash: " << *bl_it); - return false; + try + { + split_height = m_db->get_block_height(*bl_it); + break; + } + catch (const BLOCK_DNE& e) + { + continue; + } + catch (const std::exception& e) + { + LOG_PRINT_L1("Non-critical error trying to find block by hash in BlockchainDB, hash: " << *bl_it); + return false; + } } - } - // this should be impossible, as we checked that we share the genesis block, - // but just in case... - if(bl_it == qblock_ids.end()) - { - LOG_PRINT_L1("Internal error handling connection, can't find split point"); - return false; - } + // this should be impossible, as we checked that we share the genesis block, + // but just in case... + if(bl_it == qblock_ids.end()) + { + LOG_PRINT_L1("Internal error handling connection, can't find split point"); + return false; + } - // if split_height remains 0, we didn't have any but the genesis block in common - // which is only fine if the blocks just have the genesis block - if(split_height == 0 && qblock_ids.size() > 1) - { - LOG_ERROR("Ours and foreign blockchain have only genesis block in common... o.O"); - return false; - } + // if split_height remains 0, we didn't have any but the genesis block in common + // which is only fine if the blocks just have the genesis block + if(split_height == 0 && qblock_ids.size() > 1) + { + LOG_ERROR("Ours and foreign blockchain have only genesis block in common... o.O"); + return false; + } - //we start to put block ids INCLUDING last known id, just to make other side be sure - starter_offset = split_height; - return true; + //we start to put block ids INCLUDING last known id, just to make other side be sure + starter_offset = split_height; + return true; } //------------------------------------------------------------------ uint64_t Blockchain::block_difficulty(uint64_t i) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - try - { - return m_db->get_block_difficulty(i); - } - catch (const BLOCK_DNE& e) - { - LOG_PRINT_L0("Attempted to get block difficulty for height above blockchain height"); - } - return 0; + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + try + { + return m_db->get_block_difficulty(i); + } + catch (const BLOCK_DNE& e) + { + LOG_PRINT_L0("Attempted to get block difficulty for height above blockchain height"); + } + return 0; } //------------------------------------------------------------------ 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); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - for (const auto& block_hash : block_ids) - { - try + for (const auto& block_hash : block_ids) { - blocks.push_back(m_db->get_block(block_hash)); + try + { + blocks.push_back(m_db->get_block(block_hash)); + } + catch (const BLOCK_DNE& e) + { + missed_bs.push_back(block_hash); + } + catch (const std::exception& e) + { + return false; + } } - catch (const BLOCK_DNE& e) - { - missed_bs.push_back(block_hash); - } - catch (const std::exception& e) - { - return false; - } - } - return true; + 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); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - for (const auto& tx_hash : txs_ids) - { - try + for (const auto& tx_hash : txs_ids) { - txs.push_back(m_db->get_tx(tx_hash)); + try + { + txs.push_back(m_db->get_tx(tx_hash)); + } + catch (const TX_DNE& e) + { + missed_txs.push_back(tx_hash); + } + //FIXME: is this the correct way to handle this? + catch (const std::exception& e) + { + return false; + } } - catch (const TX_DNE& e) - { - missed_txs.push_back(tx_hash); - } - //FIXME: is this the correct way to handle this? - catch (const std::exception& e) - { - return false; - } - } - return true; + return true; } //------------------------------------------------------------------ void Blockchain::print_blockchain(uint64_t start_index, uint64_t end_index) { - LOG_PRINT_L3("Blockchain::" << __func__); - std::stringstream ss; - CRITICAL_REGION_LOCAL(m_blockchain_lock); - auto h = m_db->height(); - if(start_index > h) - { - LOG_PRINT_L1("Wrong starter index set: " << start_index << ", expected max index " << h); - return; - } + LOG_PRINT_L3("Blockchain::" << __func__); + std::stringstream ss; + CRITICAL_REGION_LOCAL(m_blockchain_lock); + auto h = m_db->height(); + if(start_index > h) + { + LOG_PRINT_L1("Wrong starter index set: " << start_index << ", expected max index " << h); + return; + } - for(size_t i = start_index; i <= h && i != end_index; i++) - { - ss << "height " << i - << ", timestamp " << m_db->get_block_timestamp(i) - << ", cumul_dif " << m_db->get_block_cumulative_difficulty(i) - << ", size " << m_db->get_block_size(i) - << "\nid\t\t" << m_db->get_block_hash_from_height(i) - << "\ndifficulty\t\t" << m_db->get_block_difficulty(i) - << ", nonce " << m_db->get_block_from_height(i).nonce - << ", tx_count " << m_db->get_block_from_height(i).tx_hashes.size() - << std::endl; - } - LOG_PRINT_L1("Current blockchain:" << std::endl << ss.str()); - LOG_PRINT_L0("Blockchain printed with log level 1"); + for(size_t i = start_index; i <= h && i != end_index; i++) + { + ss << "height " << i << ", timestamp " << m_db->get_block_timestamp(i) << ", cumul_dif " << m_db->get_block_cumulative_difficulty(i) << ", size " << m_db->get_block_size(i) << "\nid\t\t" << m_db->get_block_hash_from_height(i) << "\ndifficulty\t\t" << m_db->get_block_difficulty(i) << ", nonce " << m_db->get_block_from_height(i).nonce << ", tx_count " << m_db->get_block_from_height(i).tx_hashes.size() << std::endl; + } + LOG_PRINT_L1("Current blockchain:" << std::endl << ss.str()); + LOG_PRINT_L0("Blockchain printed with log level 1"); } //------------------------------------------------------------------ void Blockchain::print_blockchain_index() { - LOG_PRINT_L3("Blockchain::" << __func__); - std::stringstream ss; - CRITICAL_REGION_LOCAL(m_blockchain_lock); - auto height = m_db->height(); - if (height != 0) - { - for(uint64_t i = 0; i <= height; i++) + LOG_PRINT_L3("Blockchain::" << __func__); + std::stringstream ss; + CRITICAL_REGION_LOCAL(m_blockchain_lock); + auto height = m_db->height(); + if (height != 0) { - ss << "height: " << i << ", hash: " << m_db->get_block_hash_from_height(i); + for(uint64_t i = 0; i <= height; i++) + { + ss << "height: " << i << ", hash: " << m_db->get_block_hash_from_height(i); + } } - } - LOG_PRINT_L0("Current blockchain index:" << std::endl - << ss.str() - ); + LOG_PRINT_L0("Current blockchain index:" << std::endl << ss.str()); } //------------------------------------------------------------------ //TODO: remove this function and references to it void Blockchain::print_blockchain_outs(const std::string& file) { - LOG_PRINT_L3("Blockchain::" << __func__); - return; + LOG_PRINT_L3("Blockchain::" << __func__); + return; } //------------------------------------------------------------------ // Find the split point between us and foreign blockchain and return @@ -1607,22 +1672,22 @@ void Blockchain::print_blockchain_outs(const std::string& file) // BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT additional (more recent) hashes. bool Blockchain::find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - // if we can't find the split point, return false - if(!find_blockchain_supplement(qblock_ids, resp.start_height)) - { - return false; - } + // if we can't find the split point, return false + if(!find_blockchain_supplement(qblock_ids, resp.start_height)) + { + return false; + } - resp.total_height = get_current_blockchain_height(); - size_t count = 0; - for(size_t i = resp.start_height; i < resp.total_height && count < BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT; i++, count++) - { - resp.m_block_ids.push_back(m_db->get_block_hash_from_height(i)); - } - return true; + resp.total_height = get_current_blockchain_height(); + size_t count = 0; + for(size_t i = resp.start_height; i < resp.total_height && count < BLOCKS_IDS_SYNCHRONIZING_DEFAULT_COUNT; i++, count++) + { + resp.m_block_ids.push_back(m_db->get_block_hash_from_height(i)); + } + return true; } //------------------------------------------------------------------ //FIXME: change argument to std::vector, low priority @@ -1631,96 +1696,96 @@ bool Blockchain::find_blockchain_supplement(const std::list& qbloc // blocks by reference. bool Blockchain::find_blockchain_supplement(const uint64_t req_start_block, const std::list& qblock_ids, std::list > >& blocks, uint64_t& total_height, uint64_t& start_height, size_t max_count) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - // if a specific start height has been requested - if(req_start_block > 0) - { - // if requested height is higher than our chain, return false -- we can't help - if (req_start_block >= m_db->height()) + // if a specific start height has been requested + if(req_start_block > 0) { - return false; + // if requested height is higher than our chain, return false -- we can't help + if (req_start_block >= m_db->height()) + { + return false; + } + start_height = req_start_block; } - start_height = req_start_block; - } - else - { - if(!find_blockchain_supplement(qblock_ids, start_height)) + else { - return false; + if(!find_blockchain_supplement(qblock_ids, start_height)) + { + return false; + } } - } - total_height = get_current_blockchain_height(); - size_t count = 0; - for(size_t i = start_height; i < total_height && count < max_count; i++, count++) - { - blocks.resize(blocks.size()+1); - blocks.back().first = m_db->get_block_from_height(i); - std::list mis; - get_transactions(blocks.back().first.tx_hashes, blocks.back().second, mis); - CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, transaction from block not found"); - } - return true; + total_height = get_current_blockchain_height(); + size_t count = 0; + for(size_t i = start_height; i < total_height && count < max_count; i++, count++) + { + blocks.resize(blocks.size()+1); + blocks.back().first = m_db->get_block_from_height(i); + std::list mis; + get_transactions(blocks.back().first.tx_hashes, blocks.back().second, mis); + CHECK_AND_ASSERT_MES(!mis.size(), false, "internal error, transaction from block not found"); + } + return true; } //------------------------------------------------------------------ bool Blockchain::add_block_as_invalid(const block& bl, const crypto::hash& h) { - LOG_PRINT_L3("Blockchain::" << __func__); - block_extended_info bei = AUTO_VAL_INIT(bei); - bei.bl = bl; - return add_block_as_invalid(bei, h); + LOG_PRINT_L3("Blockchain::" << __func__); + block_extended_info bei = AUTO_VAL_INIT(bei); + bei.bl = bl; + return add_block_as_invalid(bei, h); } //------------------------------------------------------------------ bool Blockchain::add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h) { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - auto i_res = m_invalid_blocks.insert(std::map::value_type(h, bei)); - CHECK_AND_ASSERT_MES(i_res.second, false, "at insertion invalid by tx returned status existed"); - LOG_PRINT_L1("BLOCK ADDED AS INVALID: " << h << std::endl << ", prev_id=" << bei.bl.prev_id << ", m_invalid_blocks count=" << m_invalid_blocks.size()); - return true; + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + auto i_res = m_invalid_blocks.insert(std::map::value_type(h, bei)); + CHECK_AND_ASSERT_MES(i_res.second, false, "at insertion invalid by tx returned status existed"); + LOG_PRINT_L1("BLOCK ADDED AS INVALID: " << h << std::endl << ", prev_id=" << bei.bl.prev_id << ", m_invalid_blocks count=" << m_invalid_blocks.size()); + return true; } //------------------------------------------------------------------ bool Blockchain::have_block(const crypto::hash& id) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); - if(m_db->block_exists(id)) - { - LOG_PRINT_L3("block exists in main chain"); - return true; - } + if(m_db->block_exists(id)) + { + LOG_PRINT_L3("block exists in main chain"); + return true; + } - if(m_alternative_chains.count(id)) - { - LOG_PRINT_L3("block found in m_alternative_chains"); - return true; - } + if(m_alternative_chains.count(id)) + { + LOG_PRINT_L3("block found in m_alternative_chains"); + return true; + } - if(m_invalid_blocks.count(id)) - { - LOG_PRINT_L3("block found in m_invalid_blocks"); - return true; - } + if(m_invalid_blocks.count(id)) + { + LOG_PRINT_L3("block found in m_invalid_blocks"); + return true; + } - return false; + return false; } //------------------------------------------------------------------ bool Blockchain::handle_block_to_main_chain(const block& bl, block_verification_context& bvc) { - LOG_PRINT_L3("Blockchain::" << __func__); - crypto::hash id = get_block_hash(bl); - return handle_block_to_main_chain(bl, id, bvc); + LOG_PRINT_L3("Blockchain::" << __func__); + crypto::hash id = get_block_hash(bl); + return handle_block_to_main_chain(bl, id, bvc); } //------------------------------------------------------------------ size_t Blockchain::get_total_transactions() const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - return m_db->get_tx_count(); + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + return m_db->get_tx_count(); } //------------------------------------------------------------------ // This function checks each input in the transaction to make sure it @@ -1731,245 +1796,409 @@ size_t Blockchain::get_total_transactions() const // remove them later if the block fails validation. bool Blockchain::check_for_double_spend(const transaction& tx, key_images_container& keys_this_block) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - struct add_transaction_input_visitor: public boost::static_visitor - { - key_images_container& m_spent_keys; - BlockchainDB* m_db; - add_transaction_input_visitor(key_images_container& spent_keys, BlockchainDB* db):m_spent_keys(spent_keys), m_db(db) - {} - bool operator()(const txin_to_key& in) const + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + struct add_transaction_input_visitor: public boost::static_visitor { - const crypto::key_image& ki = in.k_image; + key_images_container& m_spent_keys; + BlockchainDB* m_db; + add_transaction_input_visitor(key_images_container& spent_keys, BlockchainDB* db) : + m_spent_keys(spent_keys), m_db(db) + { + } + bool operator()(const txin_to_key& in) const + { + const crypto::key_image& ki = in.k_image; - // attempt to insert the newly-spent key into the container of - // keys spent this block. If this fails, the key was spent already - // in this block, return false to flag that a double spend was detected. - // - // if the insert into the block-wide spent keys container succeeds, - // check the blockchain-wide spent keys container and make sure the - // key wasn't used in another block already. - auto r = m_spent_keys.insert(ki); - if(!r.second || m_db->has_key_image(ki)) - { - //double spend detected - return false; - } + // attempt to insert the newly-spent key into the container of + // keys spent this block. If this fails, the key was spent already + // in this block, return false to flag that a double spend was detected. + // + // if the insert into the block-wide spent keys container succeeds, + // check the blockchain-wide spent keys container and make sure the + // key wasn't used in another block already. + auto r = m_spent_keys.insert(ki); + if(!r.second || m_db->has_key_image(ki)) + { + //double spend detected + return false; + } - // if no double-spend detected, return true - return true; + // if no double-spend detected, return true + return true; + } + + bool operator()(const txin_gen& tx) const + { + return true; + } + bool operator()(const txin_to_script& tx) const + { + return false; + } + bool operator()(const txin_to_scripthash& tx) const + { + return false; + } + }; + + for (const txin_v& in : tx.vin) + { + if(!boost::apply_visitor(add_transaction_input_visitor(keys_this_block, m_db), in)) + { + LOG_ERROR("Double spend detected!"); + return false; + } } - bool operator()(const txin_gen& tx) const{return true;} - bool operator()(const txin_to_script& tx) const{return false;} - bool operator()(const txin_to_scripthash& tx) const{return false;} - }; - - for (const txin_v& in : tx.vin) - { - if(!boost::apply_visitor(add_transaction_input_visitor(keys_this_block, m_db), in)) - { - LOG_ERROR("Double spend detected!"); - return false; - } - } - - return true; + return true; } //------------------------------------------------------------------ bool Blockchain::get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs) const { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - if (!m_db->tx_exists(tx_id)) - { - LOG_PRINT_RED_L1("warning: get_tx_outputs_gindexs failed to find transaction with id = " << tx_id); - return false; - } + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + if (!m_db->tx_exists(tx_id)) + { + LOG_PRINT_RED_L1("warning: get_tx_outputs_gindexs failed to find transaction with id = " << tx_id); + return false; + } - // get amount output indexes, currently referred to in parts as "output global indices", but they are actually specific to amounts - indexs = m_db->get_tx_amount_output_indices(tx_id); - CHECK_AND_ASSERT_MES(indexs.size(), false, "internal error: global indexes for transaction " << tx_id << " is empty"); + // get amount output indexes, currently referred to in parts as "output global indices", but they are actually specific to amounts + indexs = m_db->get_tx_amount_output_indices(tx_id); + CHECK_AND_ASSERT_MES(indexs.size(), false, "internal error: global indexes for transaction " << tx_id << " is empty"); - return true; + return true; } //------------------------------------------------------------------ // This function overloads its sister function with // an extra value (hash of highest block that holds an output used as input) // as a return-by-reference. -bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t& max_used_block_height, crypto::hash& max_used_block_id) const +bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t& max_used_block_height, crypto::hash& max_used_block_id, bool kept_by_block) { - LOG_PRINT_L3("Blockchain::" << __func__); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - bool res = check_tx_inputs(tx, &max_used_block_height); - if(!res) return false; - CHECK_AND_ASSERT_MES(max_used_block_height < m_db->height(), false, "internal error: max used block index=" << max_used_block_height << " is not less then blockchain size = " << m_db->height()); - max_used_block_id = m_db->get_block_hash_from_height(max_used_block_height); - return true; + LOG_PRINT_L3("Blockchain::" << __func__); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + +#if defined(PER_BLOCK_CHECKPOINT) + // check if we're doing per-block checkpointing + if (m_db->height() < m_blocks_hash_check.size() && kept_by_block) + { + TIME_MEASURE_START(a); + m_blocks_txs_check.push_back(get_transaction_hash(tx)); + max_used_block_id = null_hash; + max_used_block_height = 0; + TIME_MEASURE_FINISH(a); + if(m_show_time_stats) + LOG_PRINT_L0("HASH: " << "-" << " VIN/VOUT: " << tx.vin.size() << "/" << tx.vout.size() << " H: " << 0 << " chcktx: " << a); + return true; + } +#endif + + TIME_MEASURE_START(a); + bool res = check_tx_inputs(tx, &max_used_block_height); + TIME_MEASURE_FINISH(a); + crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx); + if(m_show_time_stats) + LOG_PRINT_L0("HASH: " << "+" << " VIN/VOUT: " << tx.vin.size() << "/" << tx.vout.size() << " H: " << max_used_block_height << " chcktx: " << a + m_fake_scan_time); + + if (!res) + return false; + + // ND: Speedup: + // 1. keep a list of verified transactions, when the Blockchain tries to check a tx again, + // verify against list and skip if already verified to be correct. + m_check_tx_inputs_table.emplace(tx_prefix_hash, std::make_pair(res, max_used_block_height)); + + CHECK_AND_ASSERT_MES(max_used_block_height < m_db->height(), false, "internal error: max used block index=" << max_used_block_height << " is not less then blockchain size = " << m_db->height()); + max_used_block_id = m_db->get_block_hash_from_height(max_used_block_height); + return true; } //------------------------------------------------------------------ bool Blockchain::have_tx_keyimges_as_spent(const transaction &tx) const { - LOG_PRINT_L3("Blockchain::" << __func__); - BOOST_FOREACH(const txin_v& in, tx.vin) - { - CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, in_to_key, true); - if(have_tx_keyimg_as_spent(in_to_key.k_image)) - return true; - } - return false; + LOG_PRINT_L3("Blockchain::" << __func__); + BOOST_FOREACH(const txin_v& in, tx.vin) + { + CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, in_to_key, true); + if(have_tx_keyimg_as_spent(in_to_key.k_image)) + return true; + } + return false; } //------------------------------------------------------------------ // This function validates transaction inputs and their keys. Previously // it also performed double spend checking, but that has been moved to its // own function. -bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height) const +bool Blockchain::check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height) { - LOG_PRINT_L3("Blockchain::" << __func__); - size_t sig_index = 0; - if(pmax_used_block_height) - *pmax_used_block_height = 0; + LOG_PRINT_L3("Blockchain::" << __func__); + size_t sig_index = 0; + if(pmax_used_block_height) + *pmax_used_block_height = 0; - crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx); + crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx); - for (const auto& txin : tx.vin) - { - // make sure output being spent is of type txin_to_key, rather than - // e.g. txin_gen, which is only used for miner transactions - CHECK_AND_ASSERT_MES(txin.type() == typeid(txin_to_key), false, "wrong type id in tx input at Blockchain::check_tx_inputs"); - const txin_to_key& in_to_key = boost::get(txin); - - // make sure tx output has key offset(s) (is signed to be used) - CHECK_AND_ASSERT_MES(in_to_key.key_offsets.size(), false, "empty in_to_key.key_offsets in transaction with id " << get_transaction_hash(tx)); - - // 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); - - // make sure that output being spent matches up correctly with the - // signature spending it. - if(!check_tx_input(in_to_key, tx_prefix_hash, tx.signatures[sig_index], pmax_used_block_height)) + auto its = m_check_tx_inputs_table.find(tx_prefix_hash); + if (its != m_check_tx_inputs_table.end()) { - LOG_PRINT_L1("Failed to check ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index); - if (pmax_used_block_height) // a default value of NULL is used when called from Blockchain::handle_block_to_main_chain() - { - LOG_PRINT_L1(" *pmax_used_block_height: " << *pmax_used_block_height); - } - return false; + if (!its->second.first) + return false; + if (pmax_used_block_height) + *pmax_used_block_height = its->second.second; + return true; } - sig_index++; - } + auto it = m_check_txin_table.find(tx_prefix_hash); + if(it == m_check_txin_table.end()) + { + m_check_txin_table.emplace(tx_prefix_hash, std::unordered_map()); + it = m_check_txin_table.find(tx_prefix_hash); + assert(it != m_check_txin_table.end()); + } - return true; + uint64_t t_t1 = 0; + std::vector> pubkeys(tx.vin.size()); + std::vector < uint64_t > results; + results.resize(tx.vin.size(), 0); + + int threads = std::thread::hardware_concurrency(); + + boost::asio::io_service ioservice; + boost::thread_group threadpool; + + std::auto_ptr < boost::asio::io_service::work > work(new boost::asio::io_service::work(ioservice)); + if(threads > 1) + { + for (int i = 0; i < threads; i++) + { + threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioservice)); + } + } + +#define KILL_IOSERVICE() \ + if(threads > 1) \ + { \ + work.reset(); \ + threadpool.join_all(); \ + ioservice.stop(); \ + } \ + + for (const auto& txin : tx.vin) + { + // make sure output being spent is of type txin_to_key, rather than + // e.g. txin_gen, which is only used for miner transactions + CHECK_AND_ASSERT_MES(txin.type() == typeid(txin_to_key), false, "wrong type id in tx input at Blockchain::check_tx_inputs"); + const txin_to_key& in_to_key = boost::get(txin); + + // make sure tx output has key offset(s) (is signed to be used) + CHECK_AND_ASSERT_MES(in_to_key.key_offsets.size(), false, "empty in_to_key.key_offsets in transaction with id " << get_transaction_hash(tx)); + + // 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(in_to_key.k_image); + if(itk != it->second.end()) + { + if(!itk->second) + { + LOG_PRINT_L1("Failed ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index); + return false; + } + + // txin has been verified already, skip + sig_index++; + continue; + } +#endif + + // make sure that output being spent matches up correctly with the + // signature spending it. + TIME_MEASURE_START(aa); + if (!check_tx_input(in_to_key, tx_prefix_hash, tx.signatures[sig_index], pubkeys[sig_index], pmax_used_block_height)) + { + it->second[in_to_key.k_image] = false; + LOG_PRINT_L1("Failed to check ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index); + if (pmax_used_block_height) // a default value of NULL is used when called from Blockchain::handle_block_to_main_chain() + { + LOG_PRINT_L1(" *pmax_used_block_height: " << *pmax_used_block_height); + } + + KILL_IOSERVICE(); + return false; + } + + bool result; + if (threads > 1) + { + // ND: Speedup + // 1. Thread ring signature verification if possible. + ioservice.dispatch(boost::bind(&Blockchain::check_ring_signature, this, std::cref(tx_prefix_hash), std::cref(in_to_key.k_image), std::cref(pubkeys[sig_index]), std::cref(tx.signatures[sig_index]), std::ref(results[sig_index]))); + } + else + { + check_ring_signature(tx_prefix_hash, in_to_key.k_image, pubkeys[sig_index], tx.signatures[sig_index], results[sig_index]); + if (!results[sig_index]) + { + it->second[in_to_key.k_image] = false; + LOG_PRINT_L1("Failed to check ring signature for tx " << get_transaction_hash(tx) << " vin key with k_image: " << in_to_key.k_image << " sig_index: " << sig_index); + + if (pmax_used_block_height) // a default value of NULL is used when called from Blockchain::handle_block_to_main_chain() + { + LOG_PRINT_L1("*pmax_used_block_height: " << *pmax_used_block_height); + } + + KILL_IOSERVICE(); + return false; + } + it->second[in_to_key.k_image] = true; + } + + sig_index++; + } + + KILL_IOSERVICE(); + + if (threads > 1) + { + // save results to table, passed or otherwise + bool failed = false; + for (size_t i = 0; i < tx.vin.size(); i++) + { + const txin_to_key& in_to_key = boost::get(tx.vin[i]); + it->second[in_to_key.k_image] = results[i]; + if(!failed && !results[i]) + failed = true; + } + + if (failed) + { + LOG_PRINT_L1("Failed to check ring signatures!, t_loop: " << t_t1); + return false; + } + } + LOG_PRINT_L1("t_loop: " << t_t1); + return true; } + +//------------------------------------------------------------------ +void Blockchain::check_ring_signature(const crypto::hash &tx_prefix_hash, const crypto::key_image &key_image, const std::vector &pubkeys, const std::vector& sig, uint64_t &result) +{ + if (m_is_in_checkpoint_zone) + { + result = true; + return; + } + + std::vector p_output_keys; + for (auto &key : pubkeys) + { + p_output_keys.push_back(&key); + } + + result = crypto::check_ring_signature(tx_prefix_hash, key_image, p_output_keys, sig.data()) ? 1 : 0; +} + //------------------------------------------------------------------ // This function checks to see if a tx is unlocked. unlock_time is either // a block index or a unix time. bool Blockchain::is_tx_spendtime_unlocked(uint64_t unlock_time) const { - LOG_PRINT_L3("Blockchain::" << __func__); - if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER) - { - //interpret as block index - if(get_current_blockchain_height() + CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS >= unlock_time) - return true; + LOG_PRINT_L3("Blockchain::" << __func__); + if(unlock_time < CRYPTONOTE_MAX_BLOCK_NUMBER) + { + // ND: Instead of calling get_current_blockchain_height(), call m_db->height() + // directly as get_current_blockchain_height() locks the recursive mutex. + if(m_db->height() + CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_BLOCKS >= unlock_time) + return true; + else + return false; + } else - return false; - }else - { - //interpret as time - uint64_t current_time = static_cast(time(NULL)); - if(current_time + CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS >= unlock_time) - return true; - else - return false; - } - return false; + { + //interpret as time + uint64_t current_time = static_cast(time(NULL)); + if(current_time + CRYPTONOTE_LOCKED_TX_ALLOWED_DELTA_SECONDS >= unlock_time) + return true; + else + return false; + } + return false; } //------------------------------------------------------------------ // This function locates all outputs associated with a given input (mixins) // and validates that they exist and are usable. It also checks the ring // signature for each input. -bool Blockchain::check_tx_input(const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t* pmax_related_block_height) const +bool Blockchain::check_tx_input(const txin_to_key& 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); + LOG_PRINT_L3("Blockchain::" << __func__); - struct outputs_visitor - { - std::vector& m_p_output_keys; - std::vector& m_output_keys; - const Blockchain& m_bch; - outputs_visitor(std::vector& output_keys, std::vector& p_output_keys, const Blockchain& bch) : m_output_keys(output_keys), m_p_output_keys(p_output_keys), m_bch(bch) - {} - bool handle_output(const transaction& tx, const tx_out& out) + // ND: + // 1. Disable locking and make method private. + //CRITICAL_REGION_LOCAL(m_blockchain_lock); + + struct outputs_visitor { - //check tx unlock time - if(!m_bch.is_tx_spendtime_unlocked(tx.unlock_time)) - { - LOG_PRINT_L1("One of outputs for one of inputs has wrong tx.unlock_time = " << tx.unlock_time); - return false; - } + std::vector& m_output_keys; + const Blockchain& m_bch; + outputs_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) + { + //check tx unlock time + if (!m_bch.is_tx_spendtime_unlocked(unlock_time)) + { + LOG_PRINT_L1("One of outputs for one of inputs has wrong tx.unlock_time = " << unlock_time); + return false; + } - if(out.target.type() != typeid(txout_to_key)) - { - LOG_PRINT_L1("Output has wrong type id, which=" << out.target.which()); - return false; - } + m_output_keys.push_back(pubkey); + return true; + } + }; - m_output_keys.push_back(boost::get(out.target).key); - return true; + output_keys.clear(); + + //check ring signature + outputs_visitor vi(output_keys, *this); + if (!scan_outputkeys_for_indexes(txin, vi, tx_prefix_hash, pmax_related_block_height)) + { + LOG_PRINT_L1("Failed to get output keys for tx with amount = " << print_money(txin.amount) << " and count indexes " << txin.key_offsets.size()); + return false; } - }; - //check ring signature - std::vector output_keys; - std::vector p_output_keys; - outputs_visitor vi(output_keys, p_output_keys, *this); - if(!scan_outputkeys_for_indexes(txin, vi, pmax_related_block_height)) - { - LOG_PRINT_L1("Failed to get output keys for tx with amount = " << print_money(txin.amount) << " and count indexes " << txin.key_offsets.size()); - return false; - } - - for (auto& k : output_keys) - { - p_output_keys.push_back(&k); - } - - if(txin.key_offsets.size() != output_keys.size()) - { - LOG_PRINT_L1("Output keys for tx with amount = " << txin.amount << " and count indexes " << txin.key_offsets.size() << " returned wrong keys count " << output_keys.size()); - return false; - } - 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()); - if(m_is_in_checkpoint_zone) + if(txin.key_offsets.size() != output_keys.size()) + { + LOG_PRINT_L1("Output keys for tx with amount = " << txin.amount << " and count indexes " << txin.key_offsets.size() << " returned wrong keys count " << output_keys.size()); + return false; + } + 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; - return crypto::check_ring_signature(tx_prefix_hash, txin.k_image, p_output_keys, sig.data()); } //------------------------------------------------------------------ //TODO: Is this intended to do something else? Need to look into the todo there. uint64_t Blockchain::get_adjusted_time() const { - LOG_PRINT_L3("Blockchain::" << __func__); - //TODO: add collecting median time - return time(NULL); + LOG_PRINT_L3("Blockchain::" << __func__); + //TODO: add collecting median time + return time(NULL); } //------------------------------------------------------------------ //TODO: revisit, has changed a bit on upstream bool Blockchain::check_block_timestamp(std::vector& timestamps, const block& b) const { - LOG_PRINT_L3("Blockchain::" << __func__); - uint64_t median_ts = epee::misc_utils::median(timestamps); + LOG_PRINT_L3("Blockchain::" << __func__); + uint64_t median_ts = epee::misc_utils::median(timestamps); - if(b.timestamp < median_ts) - { - LOG_PRINT_L1("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", less than median of last " << BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW << " blocks, " << median_ts); - return false; - } + if(b.timestamp < median_ts) + { + LOG_PRINT_L1("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", less than median of last " << BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW << " blocks, " << median_ts); + return false; + } - return true; + return true; } //------------------------------------------------------------------ // This function grabs the timestamps from the most recent blocks, @@ -1981,32 +2210,30 @@ bool Blockchain::check_block_timestamp(std::vector& timestamps, const // false otherwise bool Blockchain::check_block_timestamp(const block& b) const { - LOG_PRINT_L3("Blockchain::" << __func__); - if(b.timestamp > get_adjusted_time() + CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT) - { - LOG_PRINT_L1("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + 2 hours"); - return false; - } + LOG_PRINT_L3("Blockchain::" << __func__); + if(b.timestamp > get_adjusted_time() + CRYPTONOTE_BLOCK_FUTURE_TIME_LIMIT) + { + LOG_PRINT_L1("Timestamp of block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + 2 hours"); + return false; + } - // if not enough blocks, no proper median yet, return true - if(m_db->height() < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW + 1) - { - return true; - } + // if not enough blocks, no proper median yet, return true + if(m_db->height() < BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW) + { + return true; + } - std::vector timestamps; - auto h = m_db->height(); + std::vector timestamps; + auto h = m_db->height(); - // need most recent 60 blocks, get index of first of those - // using +1 because BlockchainDB::height() returns the index of the top block, - // not the size of the blockchain (0-indexed) - size_t offset = h - BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW - 1; - for(;offset < h; ++offset) - { - timestamps.push_back(m_db->get_block_timestamp(offset)); - } + // need most recent 60 blocks, get index of first of those + size_t offset = h - BLOCKCHAIN_TIMESTAMP_CHECK_WINDOW; + for(;offset < h; ++offset) + { + timestamps.push_back(m_db->get_block_timestamp(offset)); + } - return check_block_timestamp(timestamps, b); + return check_block_timestamp(timestamps, b); } //------------------------------------------------------------------ // Needs to validate the block and acquire each transaction from the @@ -2014,288 +2241,376 @@ bool Blockchain::check_block_timestamp(const block& b) const // m_db->add_block() bool Blockchain::handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc) { - LOG_PRINT_L3("Blockchain::" << __func__); + LOG_PRINT_L3("Blockchain::" << __func__); - TIME_MEASURE_START(block_processing_time); - CRITICAL_REGION_LOCAL(m_blockchain_lock); - if(bl.prev_id != get_tail_id()) - { - LOG_PRINT_L1("Block with id: " << id << std::endl - << "has wrong prev_id: " << bl.prev_id << std::endl - << "expected: " << get_tail_id()); - return false; - } + TIME_MEASURE_START(block_processing_time); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + TIME_MEASURE_START(t1); - // make sure block timestamp is not less than the median timestamp - // of a set number of the most recent blocks. - if(!check_block_timestamp(bl)) - { - LOG_PRINT_L1("Block with id: " << id << std::endl - << "has invalid timestamp: " << bl.timestamp); - bvc.m_verifivation_failed = true; - return false; - } - - //check proof of work - TIME_MEASURE_START(target_calculating_time); - - // get the target difficulty for the block. - // the calculation can overflow, among other failure cases, - // so we need to check the return type. - // FIXME: get_difficulty_for_next_block can also assert, look into - // changing this to throwing exceptions instead so we can clean up. - difficulty_type current_diffic = get_difficulty_for_next_block(); - CHECK_AND_ASSERT_MES(current_diffic, false, "!!!!!!!!! difficulty overhead !!!!!!!!!"); - - TIME_MEASURE_FINISH(target_calculating_time); - - TIME_MEASURE_START(longhash_calculating_time); - - crypto::hash proof_of_work = null_hash; - - // Formerly the code below contained an if loop with the following condition - // !m_checkpoints.is_in_checkpoint_zone(get_current_blockchain_height()) - // however, this caused the daemon to not bother checking PoW for blocks - // before checkpoints, which is very dangerous behaviour. We moved the PoW - // validation out of the next chunk of code to make sure that we correctly - // check PoW now. - // FIXME: height parameter is not used...should it be used or should it not - // be a parameter? - proof_of_work = get_block_longhash(bl, m_db->height()); - - // validate proof_of_work versus difficulty target - if(!check_hash(proof_of_work, current_diffic)) - { - LOG_PRINT_L1("Block with id: " << id << std::endl - << "does not have enough proof of work: " << proof_of_work << std::endl - << "unexpected difficulty: " << current_diffic ); - bvc.m_verifivation_failed = true; - return false; - } - - // If we're at a checkpoint, ensure that our hardcoded checkpoint hash - // is correct. - if(m_checkpoints.is_in_checkpoint_zone(get_current_blockchain_height())) - { - if(!m_checkpoints.check_block(get_current_blockchain_height(), id)) + if(bl.prev_id != get_tail_id()) { - LOG_ERROR("CHECKPOINT VALIDATION FAILED"); - bvc.m_verifivation_failed = true; - return false; - } - } - - TIME_MEASURE_FINISH(longhash_calculating_time); - - // sanity check basic miner tx properties - if(!prevalidate_miner_transaction(bl, m_db->height())) - { - LOG_PRINT_L1("Block with id: " << id - << " failed to pass prevalidation"); - bvc.m_verifivation_failed = true; - return false; - } - - size_t coinbase_blob_size = get_object_blobsize(bl.miner_tx); - size_t cumulative_block_size = coinbase_blob_size; - - std::vector txs; - key_images_container keys; - - uint64_t fee_summary = 0; - - // Iterate over the block's transaction hashes, grabbing each - // from the tx_pool and validating them. Each is then added - // to txs. Keys spent in each are added to by the double spend check. - for (const crypto::hash& tx_id : bl.tx_hashes) - { - transaction tx; - size_t blob_size = 0; - uint64_t fee = 0; - - if (m_db->tx_exists(tx_id)) - { - LOG_PRINT_L1("Block with id: " << id << " attempting to add transaction already in blockchain with id: " << tx_id); - bvc.m_verifivation_failed = true; - break; + LOG_PRINT_L1("Block with id: " << id << std::endl << "has wrong prev_id: " << bl.prev_id << std::endl << "expected: " << get_tail_id()); + return false; } - // get transaction with hash from tx_pool - if(!m_tx_pool.take_tx(tx_id, tx, blob_size, fee)) + TIME_MEASURE_FINISH(t1); + TIME_MEASURE_START(t2); + + // make sure block timestamp is not less than the median timestamp + // of a set number of the most recent blocks. + if(!check_block_timestamp(bl)) { - LOG_PRINT_L1("Block with id: " << id << " has at least one unknown transaction with id: " << tx_id); - bvc.m_verifivation_failed = true; - break; + LOG_PRINT_L1("Block with id: " << id << std::endl << "has invalid timestamp: " << bl.timestamp); + bvc.m_verifivation_failed = true; + return false; } - // add the transaction to the temp list of transactions, so we can either - // store the list of transactions all at once or return the ones we've - // taken from the tx_pool back to it if the block fails verification. - txs.push_back(tx); + TIME_MEASURE_FINISH(t2); + //check proof of work + TIME_MEASURE_START(target_calculating_time); - // validate that transaction inputs and the keys spending them are correct. - if(!check_tx_inputs(tx)) + // get the target difficulty for the block. + // the calculation can overflow, among other failure cases, + // so we need to check the return type. + // FIXME: get_difficulty_for_next_block can also assert, look into + // changing this to throwing exceptions instead so we can clean up. + difficulty_type current_diffic = get_difficulty_for_next_block(); + CHECK_AND_ASSERT_MES(current_diffic, false, "!!!!!!!!! difficulty overhead !!!!!!!!!"); + + TIME_MEASURE_FINISH(target_calculating_time); + + TIME_MEASURE_START(longhash_calculating_time); + + crypto::hash proof_of_work = null_hash; + + // Formerly the code below contained an if loop with the following condition + // !m_checkpoints.is_in_checkpoint_zone(get_current_blockchain_height()) + // however, this caused the daemon to not bother checking PoW for blocks + // before checkpoints, which is very dangerous behaviour. We moved the PoW + // validation out of the next chunk of code to make sure that we correctly + // check PoW now. + // FIXME: height parameter is not used...should it be used or should it not + // be a parameter? + // validate proof_of_work versus difficulty target + bool precomputed = false; +#if defined(PER_BLOCK_CHECKPOINT) + bool fast_check = false; + if (m_db->height() < m_blocks_hash_check.size()) { - LOG_PRINT_L1("Block with id: " << id << " has at least one transaction (id: " << tx_id << ") with wrong inputs."); + auto hash = get_block_hash(bl); + if (memcmp(&hash, &m_blocks_hash_check[m_db->height()], sizeof(hash)) != 0) + { + LOG_PRINT_L1("Block with id is INVALID: " << id); + bvc.m_verifivation_failed = true; + return false; + } + fast_check = true; + } + else +#endif + { + auto it = m_blocks_longhash_table.find(id); + if (it != m_blocks_longhash_table.end()) + { + precomputed = true; + proof_of_work = it->second; + } + else + proof_of_work = get_block_longhash(bl, m_db->height()); - //TODO: why is this done? make sure that keeping invalid blocks makes sense. - add_block_as_invalid(bl, id); - LOG_PRINT_L1("Block with id " << id << " added as invalid becouse of wrong inputs in transactions"); - bvc.m_verifivation_failed = true; - break; + // validate proof_of_work versus difficulty target + if(!check_hash(proof_of_work, current_diffic)) + { + LOG_PRINT_L1("Block with id: " << id << std::endl << "does not have enough proof of work: " << proof_of_work << std::endl << "unexpected difficulty: " << current_diffic); + bvc.m_verifivation_failed = true; + return false; + } } - if (!check_for_double_spend(tx, keys)) + // If we're at a checkpoint, ensure that our hardcoded checkpoint hash + // is correct. + if(m_checkpoints.is_in_checkpoint_zone(get_current_blockchain_height())) { - LOG_PRINT_L0("Double spend detected in transaction (id: " << tx_id); - bvc.m_verifivation_failed = true; - break; + if(!m_checkpoints.check_block(get_current_blockchain_height(), id)) + { + LOG_ERROR("CHECKPOINT VALIDATION FAILED"); + bvc.m_verifivation_failed = true; + return false; + } } - fee_summary += fee; - cumulative_block_size += blob_size; - } + TIME_MEASURE_FINISH(longhash_calculating_time); + if (precomputed) + longhash_calculating_time += m_fake_pow_calc_time; - uint64_t base_reward = 0; - uint64_t already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0; - if(!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins)) - { - LOG_PRINT_L1("Block with id: " << id - << " has incorrect miner transaction"); - bvc.m_verifivation_failed = true; - } + TIME_MEASURE_START(t3); - - block_extended_info bei = boost::value_initialized(); - size_t block_size; - difficulty_type cumulative_difficulty; - - // populate various metadata about the block to be stored alongside it. - block_size = cumulative_block_size; - cumulative_difficulty = current_diffic; - already_generated_coins = already_generated_coins + base_reward; - if(m_db->height()) - cumulative_difficulty += m_db->get_block_cumulative_difficulty(m_db->height() - 1); - - update_next_cumulative_size_limit(); - - TIME_MEASURE_FINISH(block_processing_time); - - uint64_t new_height = 0; - bool add_success = true; - if (!bvc.m_verifivation_failed) - { - try + // sanity check basic miner tx properties; + if(!prevalidate_miner_transaction(bl, m_db->height())) { - new_height = m_db->add_block(bl, block_size, cumulative_difficulty, already_generated_coins, txs); + LOG_PRINT_L1("Block with id: " << id << " failed to pass prevalidation"); + bvc.m_verifivation_failed = true; + return false; } - catch (const std::exception& e) + + size_t coinbase_blob_size = get_object_blobsize(bl.miner_tx); + size_t cumulative_block_size = coinbase_blob_size; + + std::vector txs; + key_images_container keys; + + uint64_t fee_summary = 0; + uint64_t t_checktx = 0; + uint64_t t_exists = 0; + uint64_t t_pool = 0; + uint64_t t_dblspnd = 0; + uint64_t t_cc; + bool add_tx_to_pool = false; + TIME_MEASURE_FINISH(t3); + +// XXX old code adds miner tx here + + int tx_index = 0; + // Iterate over the block's transaction hashes, grabbing each + // from the tx_pool and validating them. Each is then added + // to txs. Keys spent in each are added to by the double spend check. + for (const crypto::hash& tx_id : bl.tx_hashes) { - //TODO: figure out the best way to deal with this failure - LOG_ERROR("Error adding block with hash: " << id << " to blockchain, what = " << e.what()); - add_success = false; - } - } + transaction tx; + size_t blob_size = 0; + uint64_t fee = 0; + TIME_MEASURE_START(aa); - // if we failed for any reason to verify the block, return taken - // transactions to the tx_pool. - if (bvc.m_verifivation_failed || !add_success) - { - // return taken transactions to transaction pool - for (auto& tx : txs) +// XXX old code does not check whether tx exists + if (m_db->tx_exists(tx_id)) + { + LOG_PRINT_L1("Block with id: " << id << " attempting to add transaction already in blockchain with id: " << tx_id); + bvc.m_verifivation_failed = true; + break; + } + + TIME_MEASURE_FINISH(aa); + t_exists += aa; + TIME_MEASURE_START(bb); + + // get transaction with hash from tx_pool + if(!m_tx_pool.take_tx(tx_id, tx, blob_size, fee)) + { + LOG_PRINT_L1("Block with id: " << id << " has at least one unknown transaction with id: " << tx_id); + bvc.m_verifivation_failed = true; + break; + } + + TIME_MEASURE_FINISH(bb); + t_pool += bb; + // add the transaction to the temp list of transactions, so we can either + // store the list of transactions all at once or return the ones we've + // taken from the tx_pool back to it if the block fails verification. + txs.push_back(tx); + TIME_MEASURE_START(dd); + + // ND: this is not needed, db->add_block() checks for duplicate k_images and fails accordingly. + // if (!check_for_double_spend(tx, keys)) + // { + // LOG_PRINT_L0("Double spend detected in transaction (id: " << tx_id); + // bvc.m_verifivation_failed = true; + // break; + // } + + TIME_MEASURE_FINISH(dd); + t_dblspnd += dd; + TIME_MEASURE_START(cc); + +#if defined(PER_BLOCK_CHECKPOINT) + if (!fast_check) +#endif + { + // validate that transaction inputs and the keys spending them are correct. + if(!check_tx_inputs(tx)) + { + LOG_PRINT_L1("Block with id: " << id << " has at least one transaction (id: " << tx_id << ") with wrong inputs."); + + //TODO: why is this done? make sure that keeping invalid blocks makes sense. + add_block_as_invalid(bl, id); + LOG_PRINT_L1("Block with id " << id << " added as invalid because of wrong inputs in transactions"); + bvc.m_verifivation_failed = true; + add_tx_to_pool = true; + break; + } + } +#if defined(PER_BLOCK_CHECKPOINT) + else + { + // ND: if fast_check is enabled for blocks, there is no need to check + // the transaction inputs, but do some sanity checks anyway. + if (memcmp(&m_blocks_txs_check[tx_index++], &tx_id, sizeof(tx_id)) != 0) + { + LOG_PRINT_L1("Block with id: " << id << " has at least one transaction (id: " << tx_id << ") with wrong inputs."); + //TODO: why is this done? make sure that keeping invalid blocks makes sense. + add_block_as_invalid(bl, id); + LOG_PRINT_L1("Block with id " << id << " added as invalid because of wrong inputs in transactions"); + bvc.m_verifivation_failed = true; + add_tx_to_pool = true; + break; + } + } +#endif + TIME_MEASURE_FINISH(cc); + t_checktx += cc; + fee_summary += fee; + cumulative_block_size += blob_size; + } + + m_blocks_txs_check.clear(); + + TIME_MEASURE_START(vmt); + uint64_t base_reward = 0; + uint64_t already_generated_coins = m_db->height() ? m_db->get_block_already_generated_coins(m_db->height() - 1) : 0; + if(!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins)) { - cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc); - if (!m_tx_pool.add_tx(tx, tvc, true)) - { - LOG_PRINT_L0("Failed to return taken transaction with hash: " << get_transaction_hash(tx) << " to tx_pool"); - } + LOG_PRINT_L1("Block with id: " << id << " has incorrect miner transaction"); + bvc.m_verifivation_failed = true; } - return false; - } - LOG_PRINT_L1("+++++ BLOCK SUCCESSFULLY ADDED" << std::endl << "id:\t" << id - << std::endl << "PoW:\t" << proof_of_work - << std::endl << "HEIGHT " << new_height << ", difficulty:\t" << current_diffic - << std::endl << "block reward: " << print_money(fee_summary + base_reward) << "(" << print_money(base_reward) << " + " << print_money(fee_summary) - << "), coinbase_blob_size: " << coinbase_blob_size << ", cumulative size: " << cumulative_block_size - << ", " << block_processing_time << "("<< target_calculating_time << "/" << longhash_calculating_time << ")ms"); + TIME_MEASURE_FINISH(vmt); + size_t block_size; + difficulty_type cumulative_difficulty; - bvc.m_added_to_main_chain = true; + // populate various metadata about the block to be stored alongside it. + block_size = cumulative_block_size; + cumulative_difficulty = current_diffic; + already_generated_coins = already_generated_coins + base_reward; + if(m_db->height()) + cumulative_difficulty += m_db->get_block_cumulative_difficulty(m_db->height() - 1); - // appears to be a NOP *and* is called elsewhere. wat? - m_tx_pool.on_blockchain_inc(new_height, id); + TIME_MEASURE_FINISH(block_processing_time); + if(precomputed) + block_processing_time += m_fake_pow_calc_time; - return true; + TIME_MEASURE_START(addblock); + uint64_t new_height = 0; + bool add_success = true; + if (!bvc.m_verifivation_failed) + { + try + { + new_height = m_db->add_block(bl, block_size, cumulative_difficulty, already_generated_coins, txs); + } + 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()); + add_success = false; + } + } + + // if we failed for any reason to verify the block, return taken + // transactions to the tx_pool. + if ((bvc.m_verifivation_failed && add_tx_to_pool) || !add_success) + { + // return taken transactions to transaction pool + for (auto& tx : txs) + { + cryptonote::tx_verification_context tvc = AUTO_VAL_INIT(tvc); + if (!m_tx_pool.add_tx(tx, tvc, true)) + { + LOG_PRINT_L0("Failed to return taken transaction with hash: " << get_transaction_hash(tx) << " to tx_pool"); + } + } + return false; + } + + TIME_MEASURE_FINISH(addblock); + + update_next_cumulative_size_limit(); + + LOG_PRINT_L1("+++++ BLOCK SUCCESSFULLY ADDED" << std::endl << "id:\t" << id << std::endl << "PoW:\t" << proof_of_work << std::endl << "HEIGHT " << new_height << ", difficulty:\t" << current_diffic << std::endl << "block reward: " << print_money(fee_summary + base_reward) << "(" << print_money(base_reward) << " + " << print_money(fee_summary) << "), coinbase_blob_size: " << coinbase_blob_size << ", cumulative size: " << cumulative_block_size << ", " << block_processing_time << "(" << target_calculating_time << "/" << longhash_calculating_time << ")ms"); + if(m_show_time_stats) + { + LOG_PRINT_L0("Height: " << new_height << " blob: " << coinbase_blob_size << " cumm: " + << cumulative_block_size << " p/t: " << block_processing_time << " (" + << target_calculating_time << "/" << longhash_calculating_time << "/" + << t1 << "/" << t2 << "/" << t3 << "/" << t_exists << "/" << t_pool + << "/" << t_checktx << "/" << t_dblspnd << "/" << vmt << "/" << addblock << ")ms"); + } + + bvc.m_added_to_main_chain = true; + ++m_sync_counter; + + // appears to be a NOP *and* is called elsewhere. wat? + m_tx_pool.on_blockchain_inc(new_height, id); + + return true; } //------------------------------------------------------------------ bool Blockchain::update_next_cumulative_size_limit() { - LOG_PRINT_L3("Blockchain::" << __func__); - std::vector sz; - get_last_n_blocks_sizes(sz, CRYPTONOTE_REWARD_BLOCKS_WINDOW); + LOG_PRINT_L3("Blockchain::" << __func__); + std::vector sz; + get_last_n_blocks_sizes(sz, CRYPTONOTE_REWARD_BLOCKS_WINDOW); - uint64_t median = epee::misc_utils::median(sz); - if(median <= CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE) - median = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE; + uint64_t median = epee::misc_utils::median(sz); + if(median <= CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE) + median = CRYPTONOTE_BLOCK_GRANTED_FULL_REWARD_ZONE; - m_current_block_cumul_sz_limit = median*2; - return true; + m_current_block_cumul_sz_limit = median*2; + return true; } //------------------------------------------------------------------ bool Blockchain::add_new_block(const block& bl_, block_verification_context& bvc) { - LOG_PRINT_L3("Blockchain::" << __func__); - //copy block here to let modify block.target - block bl = bl_; - crypto::hash id = get_block_hash(bl); - CRITICAL_REGION_LOCAL(m_tx_pool);//to avoid deadlock lets lock tx_pool for whole add/reorganize process - CRITICAL_REGION_LOCAL1(m_blockchain_lock); - if(have_block(id)) - { - LOG_PRINT_L3("block with id = " << id << " already exists"); - bvc.m_already_exists = true; - return false; - } + LOG_PRINT_L3("Blockchain::" << __func__); + //copy block here to let modify block.target + block bl = bl_; + crypto::hash id = get_block_hash(bl); + CRITICAL_REGION_LOCAL(m_tx_pool);//to avoid deadlock lets lock tx_pool for whole add/reorganize process + CRITICAL_REGION_LOCAL1(m_blockchain_lock); + if(have_block(id)) + { + LOG_PRINT_L3("block with id = " << id << " already exists"); + bvc.m_already_exists = true; + return false; + } - //check that block refers to chain tail - if(!(bl.prev_id == get_tail_id())) - { - //chain switching or wrong block - bvc.m_added_to_main_chain = false; - return handle_alternative_block(bl, id, bvc); - //never relay alternative blocks - } + //check that block refers to chain tail + if(!(bl.prev_id == get_tail_id())) + { + //chain switching or wrong block + bvc.m_added_to_main_chain = false; + return handle_alternative_block(bl, id, bvc); + //never relay alternative blocks + } - return handle_block_to_main_chain(bl, id, bvc); + return handle_block_to_main_chain(bl, id, bvc); } //------------------------------------------------------------------ void Blockchain::check_against_checkpoints(const checkpoints& points, bool enforce) { - const auto& pts = points.get_points(); + const auto& pts = points.get_points(); - for (const auto& pt : pts) - { - // if the checkpoint is for a block we don't have yet, move on - if (pt.first >= m_db->height()) + for (const auto& pt : pts) { - continue; - } + // if the checkpoint is for a block we don't have yet, move on + if (pt.first >= m_db->height()) + { + continue; + } - if (!points.check_block(pt.first, m_db->get_block_hash_from_height(pt.first))) - { - // if asked to enforce checkpoints, roll back to a couple of blocks before the checkpoint - if (enforce) - { - LOG_ERROR("Local blockchain failed to pass a checkpoint, rolling back!"); - std::list empty; - rollback_blockchain_switching(empty, pt.first - 2); - } - else - { - LOG_ERROR("WARNING: local blockchain failed to pass a MoneroPulse checkpoint, and you could be on a fork. You should either sync up from scratch, OR download a fresh blockchain bootstrap, OR enable checkpoint enforcing with the --enforce-dns-checkpointing command-line option"); - } + if (!points.check_block(pt.first, m_db->get_block_hash_from_height(pt.first))) + { + // if asked to enforce checkpoints, roll back to a couple of blocks before the checkpoint + if (enforce) + { + LOG_ERROR("Local blockchain failed to pass a checkpoint, rolling back!"); + std::list empty; + rollback_blockchain_switching(empty, pt.first - 2); + } + else + { + LOG_ERROR("WARNING: local blockchain failed to pass a MoneroPulse checkpoint, and you could be on a fork. You should either sync up from scratch, OR download a fresh blockchain bootstrap, OR enable checkpoint enforcing with the --enforce-dns-checkpointing command-line option"); + } + } } - } } //------------------------------------------------------------------ // returns false if any of the checkpoints loading returns false. @@ -2303,40 +2618,443 @@ void Blockchain::check_against_checkpoints(const checkpoints& points, bool enfor // with an existing checkpoint. bool Blockchain::update_checkpoints(const std::string& file_path, bool check_dns) { - if (!cryptonote::load_checkpoints_from_json(m_checkpoints, file_path)) - { - return false; - } - - // if we're checking both dns and json, load checkpoints from dns. - // if we're not hard-enforcing dns checkpoints, handle accordingly - if (m_enforce_dns_checkpoints && check_dns) - { - if (!cryptonote::load_checkpoints_from_dns(m_checkpoints)) + if (!cryptonote::load_checkpoints_from_json(m_checkpoints, file_path)) { - return false; + return false; } - } - else if (check_dns) - { - checkpoints dns_points; - cryptonote::load_checkpoints_from_dns(dns_points); - if (m_checkpoints.check_for_conflicts(dns_points)) - { - check_against_checkpoints(dns_points, false); - } - else - { - LOG_PRINT_L0("One or more checkpoints fetched from DNS conflicted with existing checkpoints!"); - } - } - check_against_checkpoints(m_checkpoints, true); + // if we're checking both dns and json, load checkpoints from dns. + // if we're not hard-enforcing dns checkpoints, handle accordingly + if (m_enforce_dns_checkpoints && check_dns) + { + if (!cryptonote::load_checkpoints_from_dns(m_checkpoints)) + { + return false; + } + } + else if (check_dns) + { + checkpoints dns_points; + cryptonote::load_checkpoints_from_dns(dns_points); + if (m_checkpoints.check_for_conflicts(dns_points)) + { + check_against_checkpoints(dns_points, false); + } + else + { + LOG_PRINT_L0("One or more checkpoints fetched from DNS conflicted with existing checkpoints!"); + } + } - return true; + check_against_checkpoints(m_checkpoints, true); + + return true; } //------------------------------------------------------------------ void Blockchain::set_enforce_dns_checkpoints(bool enforce_checkpoints) { - m_enforce_dns_checkpoints = enforce_checkpoints; + m_enforce_dns_checkpoints = enforce_checkpoints; +} + +//------------------------------------------------------------------ +void Blockchain::block_longhash_worker(const uint64_t height, const std::vector &blocks, std::unordered_map &map) const +{ + TIME_MEASURE_START(t); + slow_hash_allocate_state(); + + for (const auto & block : blocks) + { + crypto::hash id = get_block_hash(block); + crypto::hash pow = get_block_longhash(block, height); + map.emplace(id, pow); + } + + slow_hash_free_state(); + TIME_MEASURE_FINISH(t); +} + +//------------------------------------------------------------------ +bool Blockchain::cleanup_handle_incoming_blocks(bool force_sync) +{ + LOG_PRINT_YELLOW("Blockchain::" << __func__, LOG_LEVEL_3); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + TIME_MEASURE_START(t1); + auto height = m_db->height(); + + if (m_sync_counter > 0) + { + if (force_sync) + { + if(m_db_sync_mode != db_nosync) + store_blockchain(); + m_sync_counter = 0; + } + else if (m_sync_counter >= m_db_blocks_per_sync) + { + if(m_db_sync_mode == db_async) + { + m_sync_counter = 0; + m_async_service.dispatch(boost::bind(&Blockchain::store_blockchain, this)); + } + else if(m_db_sync_mode == db_sync) + { + store_blockchain(); + } + else // db_nosync + { + // DO NOTHING, not required to call sync. + } + } + } + + TIME_MEASURE_FINISH(t1); + m_blocks_longhash_table.clear(); + m_scan_table.clear(); + m_check_tx_inputs_table.clear(); + m_blocks_txs_check.clear(); + m_check_txin_table.clear(); + + return true; +} + +//------------------------------------------------------------------ +void Blockchain::output_scan_worker(const uint64_t amount, const std::vector &offsets, std::vector &outputs, std::unordered_map &txs) const +{ + try + { + m_db->get_output_key(amount, offsets, outputs); + } + catch (const std::exception& e) + { + LOG_PRINT_L1("EXCEPTION: " << e.what()); + } + catch (...) + { + + } +} + +//------------------------------------------------------------------ +// ND: Speedups: +// 1. Thread long_hash computations if possible (m_max_prepare_blocks_threads = nthreads, default = 4) +// 2. Group all amounts (from txs) and related absolute offsets and form a table of tx_prefix_hash +// vs [k_image, output_keys] (m_scan_table). This is faster because it takes advantage of bulk queries +// and is threaded if possible. The table (m_scan_table) will be used later when querying output +// keys. +bool Blockchain::prepare_handle_incoming_blocks(const std::list &blocks_entry) +{ + LOG_PRINT_YELLOW("Blockchain::" << __func__, LOG_LEVEL_3); + TIME_MEASURE_START(prepare); + CRITICAL_REGION_LOCAL(m_blockchain_lock); + + if(blocks_entry.size() == 0) + return false; + + if ((m_db->height() + blocks_entry.size()) < m_blocks_hash_check.size()) + return true; + + bool blocks_exist = false; + uint64_t threads = std::thread::hardware_concurrency(); + + if (blocks_entry.size() > 1 && threads > 1 && m_max_prepare_blocks_threads > 1) + { + // limit threads, default limit = 4 + if(threads > m_max_prepare_blocks_threads) + threads = m_max_prepare_blocks_threads; + + uint64_t height = m_db->height(); + std::vector thread_list; + int batches = blocks_entry.size() / threads; + int extra = blocks_entry.size() % threads; + LOG_PRINT_L1("block_batches: " << batches); + std::vector> maps(threads); + std::vector < std::vector < block >> blocks(threads); + auto it = blocks_entry.begin(); + + for (uint64_t i = 0; i < threads; i++) + { + for (int j = 0; j < batches; j++) + { + block block; + + if (!parse_and_validate_block_from_blob(it->block, block)) + { + std::advance(it, 1); + continue; + } + + // check first block and skip all blocks if its not chained properly + if (i == 0 && j == 0) + { + crypto::hash tophash = m_db->top_block_hash(); + if (block.prev_id != tophash) + { + LOG_PRINT_L0("Skipping prepare blocks. New blocks don't belong to chain.") + return true; + } + } + if (have_block(get_block_hash(block))) + { + blocks_exist = true; + break; + } + + blocks[i].push_back(block); + std::advance(it, 1); + } + } + + for (int i = 0; i < extra && !blocks_exist; i++) + { + block block; + + if (!parse_and_validate_block_from_blob(it->block, block)) + { + std::advance(it, 1); + continue; + } + + if (have_block(get_block_hash(block))) + { + blocks_exist = true; + break; + } + + blocks[i].push_back(block); + std::advance(it, 1); + } + + if (!blocks_exist) + { + m_blocks_longhash_table.clear(); + for (uint64_t i = 0; i < threads; i++) + { + thread_list.push_back(new boost::thread(&Blockchain::block_longhash_worker, this, height + (i * batches), std::cref(blocks[i]), std::ref(maps[i]))); + } + + for (size_t j = 0; j < thread_list.size(); j++) + { + thread_list[j]->join(); + delete thread_list[j]; + } + + thread_list.clear(); + + for (const auto & map : maps) + { + m_blocks_longhash_table.insert(map.begin(), map.end()); + } + } + } + + if (blocks_exist) + { + LOG_PRINT_L0("Skipping prepare blocks. Blocks exist.") + return true; + } + + m_fake_scan_time = 0; + m_fake_pow_calc_time = 0; + + m_scan_table.clear(); + m_check_tx_inputs_table.clear(); + m_check_txin_table.clear(); + + TIME_MEASURE_FINISH(prepare); + m_fake_pow_calc_time = prepare / blocks_entry.size(); + + if (blocks_entry.size() > 1 && threads > 1 && m_show_time_stats) + LOG_PRINT_L0("Prepare blocks took: " << prepare << " ms"); + + TIME_MEASURE_START(scantable); + + // [input] stores all unique amounts found + std::vector < uint64_t > amounts; + // [input] stores all absolute_offsets for each amount + std::map> offset_map; + // [output] stores all output_data_t for each absolute_offset + std::map> tx_map; + +#define SCAN_TABLE_QUIT(m) \ + do { \ + LOG_PRINT_L0(m) ;\ + m_scan_table.clear(); \ + return false; \ + } while(0); \ + + // generate sorted tables for all amounts and absolute offsets + for (const auto &entry : blocks_entry) + { + for (const auto &tx_blob : entry.txs) + { + crypto::hash tx_hash = null_hash; + crypto::hash tx_prefix_hash = null_hash; + transaction tx; + + if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_hash, tx_prefix_hash)) + SCAN_TABLE_QUIT("Could not parse tx from incoming blocks."); + + auto its = m_scan_table.find(tx_prefix_hash); + if (its != m_scan_table.end()) + SCAN_TABLE_QUIT("Duplicate tx found from incoming blocks."); + + m_scan_table.emplace(tx_prefix_hash, std::unordered_map>()); + its = m_scan_table.find(tx_prefix_hash); + assert(its != m_scan_table.end()); + + // get all amounts from tx.vin(s) + for (const auto &txin : tx.vin) + { + const txin_to_key &in_to_key = boost::get < txin_to_key > (txin); + + // check for duplicate + auto it = its->second.find(in_to_key.k_image); + if (it != its->second.end()) + SCAN_TABLE_QUIT("Duplicate key_image found from incoming blocks."); + + amounts.push_back(in_to_key.amount); + } + + // sort and remove duplicate amounts from amounts list + std::sort(amounts.begin(), amounts.end()); + auto last = std::unique(amounts.begin(), amounts.end()); + amounts.erase(last, amounts.end()); + + // add amount to the offset_map and tx_map + for (const uint64_t &amount : amounts) + { + if (offset_map.find(amount) == offset_map.end()) + offset_map.emplace(amount, std::vector()); + + if (tx_map.find(amount) == tx_map.end()) + tx_map.emplace(amount, std::vector()); + } + + // add new absolute_offsets to offset_map + for (const auto &txin : tx.vin) + { + const txin_to_key &in_to_key = boost::get < txin_to_key > (txin); + // no need to check for duplicate here. + auto absolute_offsets = relative_output_offsets_to_absolute(in_to_key.key_offsets); + for (const auto & offset : absolute_offsets) + offset_map[in_to_key.amount].push_back(offset); + + } + + // sort and remove duplicate absolute_offsets in offset_map + for (auto &offsets : offset_map) + { + std::sort(offsets.second.begin(), offsets.second.end()); + auto last = std::unique(offsets.second.begin(), offsets.second.end()); + offsets.second.erase(last, offsets.second.end()); + } + } + } + + // [output] stores all transactions for each tx_out_index::hash found + std::vector> transactions(amounts.size()); + + threads = std::thread::hardware_concurrency(); + if (!m_db->can_thread_bulk_indices()) + threads = 1; + + if (threads > 1) + { + boost::asio::io_service ioservice; + boost::thread_group threadpool; + std::unique_ptr < boost::asio::io_service::work > work(new boost::asio::io_service::work(ioservice)); + + for (uint64_t i = 0; i < threads; i++) + { + threadpool.create_thread(boost::bind(&boost::asio::io_service::run, &ioservice)); + } + + for (size_t i = 0; i < amounts.size(); i++) + { + uint64_t amount = amounts[i]; + ioservice.dispatch(boost::bind(&Blockchain::output_scan_worker, this, amount, std::cref(offset_map[amount]), std::ref(tx_map[amount]), std::ref(transactions[i]))); + } + + work.reset(); + threadpool.join_all(); + ioservice.stop(); + } + else + { + for (size_t i = 0; i < amounts.size(); i++) + { + uint64_t amount = amounts[i]; + output_scan_worker(amount, offset_map[amount], tx_map[amount], transactions[i]); + } + } + + int total_txs = 0; + + // now generate a table for each tx_prefix and k_image hashes + for (const auto &entry : blocks_entry) + { + for (const auto &tx_blob : entry.txs) + { + crypto::hash tx_hash = null_hash; + crypto::hash tx_prefix_hash = null_hash; + transaction tx; + + if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_hash, tx_prefix_hash)) + SCAN_TABLE_QUIT("Could not parse tx from incoming blocks."); + + ++total_txs; + auto its = m_scan_table.find(tx_prefix_hash); + if (its == m_scan_table.end()) + SCAN_TABLE_QUIT("Tx not found on scan table from incoming blocks."); + + for (const auto &txin : tx.vin) + { + const txin_to_key &in_to_key = boost::get < txin_to_key > (txin); + auto needed_offsets = relative_output_offsets_to_absolute(in_to_key.key_offsets); + + std::vector outputs; + for (const uint64_t & offset_needed : needed_offsets) + { + size_t pos = 0; + bool found = false; + + for (const uint64_t &offset_found : offset_map[in_to_key.amount]) + { + if (offset_needed == offset_found) + { + found = true; + break; + } + + ++pos; + } + + if (found && pos < tx_map[in_to_key.amount].size()) + outputs.push_back(tx_map[in_to_key.amount].at(pos)); + else + break; + } + + its->second.emplace(in_to_key.k_image, outputs); + } + } + } + + TIME_MEASURE_FINISH(scantable); + if (total_txs > 0) + { + m_fake_scan_time = scantable / total_txs; + if(m_show_time_stats) + LOG_PRINT_L0("Prepare scantable took: " << scantable << " ms"); + } + + return true; +} + +void Blockchain::set_user_options(uint64_t maxthreads, uint64_t blocks_per_sync, blockchain_db_sync_mode sync_mode, bool fast_sync) +{ + m_db_sync_mode = sync_mode; + m_fast_sync = fast_sync; + m_db_blocks_per_sync = blocks_per_sync; + m_max_prepare_blocks_threads = maxthreads; } diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h index 869b0b4b6..57763f6ca 100644 --- a/src/cryptonote_core/blockchain.h +++ b/src/cryptonote_core/blockchain.h @@ -56,6 +56,13 @@ namespace cryptonote { class tx_memory_pool; + enum blockchain_db_sync_mode + { + db_sync, + db_async, + db_nosync + }; + /************************************************************************/ /* */ /************************************************************************/ @@ -94,6 +101,8 @@ namespace cryptonote crypto::hash get_block_id_by_height(uint64_t height) const; bool get_block_by_hash(const crypto::hash &h, block &blk) const; void get_all_known_block_ids(std::list &main, std::list &alt, std::list &invalid) const; + bool prepare_handle_incoming_blocks(const std::list &blocks); + bool cleanup_handle_incoming_blocks(bool force_sync = false); template void serialize(archive_t & ar, const unsigned int version); @@ -102,16 +111,13 @@ namespace cryptonote bool have_tx_keyimges_as_spent(const transaction &tx) const; bool have_tx_keyimg_as_spent(const crypto::key_image &key_im) const; - template - bool scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height = NULL) const; - uint64_t get_current_blockchain_height() const; crypto::hash get_tail_id() const; crypto::hash get_tail_id(uint64_t& height) const; - difficulty_type get_difficulty_for_next_block() const; + difficulty_type get_difficulty_for_next_block(); bool add_new_block(const block& bl_, block_verification_context& bvc); bool reset_and_set_genesis_block(const block& b); - bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, const blobdata& ex_nonce) const; + bool create_block_template(block& b, const account_public_address& miner_address, difficulty_type& di, uint64_t& height, const blobdata& ex_nonce); bool have_block(const crypto::hash& id) const; size_t get_total_transactions() const; bool get_short_chain_history(std::list& ids) const; @@ -123,9 +129,8 @@ namespace cryptonote bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res) const; bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs) const; bool store_blockchain(); - bool check_tx_input(const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t* pmax_related_block_height = NULL) const; - bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL) const; - bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id) const; + + bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id, bool kept_by_block = false); uint64_t get_current_cumulative_blocksize_limit() const; bool is_storing_blockchain()const{return m_is_blockchain_storing;} uint64_t block_difficulty(uint64_t i) const; @@ -145,11 +150,23 @@ namespace cryptonote void set_enforce_dns_checkpoints(bool enforce); bool update_checkpoints(const std::string& file_path, bool check_dns); + // user options, must be called before calling init() + void set_user_options(uint64_t block_threads, uint64_t blocks_per_sync, + blockchain_db_sync_mode sync_mode, bool fast_sync); + + void set_show_time_stats(bool stats) { m_show_time_stats = stats; } + BlockchainDB& get_db() { return *m_db; } + void output_scan_worker(const uint64_t amount,const std::vector &offsets, + std::vector &outputs, std::unordered_map &txs) const; + + void block_longhash_worker(const uint64_t height, const std::vector &blocks, + std::unordered_map &map) const; private: typedef std::unordered_map blocks_by_id_index; typedef std::unordered_map transactions_container; @@ -168,9 +185,32 @@ namespace cryptonote blocks_container m_blocks; // height -> block_extended_info blocks_by_id_index m_blocks_index; // crypto::hash -> height transactions_container m_transactions; - key_images_container m_spent_keys; size_t m_current_block_cumul_sz_limit; + std::unordered_map>> m_scan_table; + std::unordered_map> m_check_tx_inputs_table; + std::unordered_map m_blocks_longhash_table; + std::unordered_map> m_check_txin_table; + + // SHA-3 hashes for each block and for fast pow checking + std::vector m_blocks_hash_check; + std::vector m_blocks_txs_check; + + blockchain_db_sync_mode m_db_sync_mode; + bool m_fast_sync; + bool m_show_time_stats; + uint64_t m_db_blocks_per_sync; + uint64_t m_max_prepare_blocks_threads; + uint64_t m_fake_pow_calc_time; + uint64_t m_fake_scan_time; + uint64_t m_sync_counter; + std::vector m_timestamps; + std::vector m_difficulties; + uint64_t m_timestamps_and_difficulties_height; + + boost::asio::io_service m_async_service; + boost::thread_group m_async_pool; + std::unique_ptr m_async_work_idle; // all alternative chains blocks_ext_by_hash m_alternative_chains; // crypto::hash -> block_extended_info @@ -185,10 +225,13 @@ namespace cryptonote std::atomic m_is_blockchain_storing; bool m_enforce_dns_checkpoints; + template + inline bool scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t &vis, const crypto::hash &tx_prefix_hash, uint64_t* pmax_related_block_height = NULL) const; + bool check_tx_input(const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, std::vector &output_keys, uint64_t* pmax_related_block_height); + bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL); + bool switch_to_alternative_blockchain(std::list& alt_chain, bool discard_disconnected_chain); block pop_block_from_blockchain(); - bool purge_transaction_from_blockchain(const crypto::hash& tx_id); - bool purge_transaction_keyimages_from_blockchain(const transaction& tx, bool strict_check); bool handle_block_to_main_chain(const block& bl, block_verification_context& bvc); bool handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc); @@ -213,6 +256,9 @@ namespace cryptonote bool update_next_cumulative_size_limit(); bool check_for_double_spend(const transaction& tx, key_images_container& keys_this_block) const; + void get_timestamp_and_difficulty(uint64_t ×tamp, difficulty_type &difficulty, const int offset) const; + void check_ring_signature(const crypto::hash &tx_prefix_hash, const crypto::key_image &key_image, + const std::vector &pubkeys, const std::vector &sig, uint64_t &result); }; diff --git a/src/cryptonote_core/blockchain_storage.h b/src/cryptonote_core/blockchain_storage.h index 2c2fb5250..aeeef31b6 100644 --- a/src/cryptonote_core/blockchain_storage.h +++ b/src/cryptonote_core/blockchain_storage.h @@ -104,9 +104,6 @@ namespace cryptonote bool have_tx_keyimg_as_spent(const crypto::key_image &key_im) const; const transaction *get_tx(const crypto::hash &id) const; - template - bool scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height = NULL) const; - uint64_t get_current_blockchain_height() const; crypto::hash get_tail_id() const; crypto::hash get_tail_id(uint64_t& height) const; @@ -127,9 +124,7 @@ namespace cryptonote bool get_backward_blocks_sizes(size_t from_height, std::vector& sz, size_t count) const; bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs) const; bool store_blockchain(); - bool check_tx_input(const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t* pmax_related_block_height = NULL) const; - bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t* pmax_used_block_height = NULL) const; - bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL) const; + bool check_tx_inputs(const transaction& tx, uint64_t& pmax_used_block_height, crypto::hash& max_used_block_id) const; uint64_t get_current_cumulative_blocksize_limit() const; bool is_storing_blockchain()const{return m_is_blockchain_storing;} @@ -229,6 +224,13 @@ namespace cryptonote bool m_enforce_dns_checkpoints; bool m_testnet; + // made private for consistency with blockchain.h + template + bool scan_outputkeys_for_indexes(const txin_to_key& tx_in_to_key, visitor_t& vis, uint64_t* pmax_related_block_height = NULL) const; + bool check_tx_input(const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t* pmax_related_block_height = NULL) const; + bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t* pmax_used_block_height = NULL) const; + bool check_tx_inputs(const transaction& tx, uint64_t* pmax_used_block_height = NULL) const; + bool switch_to_alternative_blockchain(std::list& alt_chain, bool discard_disconnected_chain); bool pop_block_from_blockchain(); bool purge_block_data_from_blockchain(const block& b, size_t processed_tx_count); diff --git a/src/cryptonote_core/cryptonote_basic.h b/src/cryptonote_core/cryptonote_basic.h index 2be76c0de..07745bf0d 100644 --- a/src/cryptonote_core/cryptonote_basic.h +++ b/src/cryptonote_core/cryptonote_basic.h @@ -57,6 +57,7 @@ namespace cryptonote { const static crypto::hash null_hash = AUTO_VAL_INIT(null_hash); + const static crypto::hash8 null_hash8 = AUTO_VAL_INIT(null_hash8); const static crypto::public_key null_pkey = AUTO_VAL_INIT(null_pkey); typedef std::vector ring_signature; diff --git a/src/cryptonote_core/cryptonote_basic_impl.cpp b/src/cryptonote_core/cryptonote_basic_impl.cpp index abdef64f9..bd0b8a304 100644 --- a/src/cryptonote_core/cryptonote_basic_impl.cpp +++ b/src/cryptonote_core/cryptonote_basic_impl.cpp @@ -46,7 +46,7 @@ namespace cryptonote { struct integrated_address { account_public_address adr; - crypto::hash payment_id; + crypto::hash8 payment_id; BEGIN_SERIALIZE_OBJECT() FIELD(adr) @@ -99,7 +99,11 @@ namespace cryptonote { assert(current_block_size < std::numeric_limits::max()); uint64_t product_hi; - uint64_t product_lo = mul128(base_reward, current_block_size * (2 * median_size - current_block_size), &product_hi); + // BUGFIX: 32-bit saturation bug (e.g. ARM7), the result was being + // treated as 32-bit by default. + uint64_t multiplicand = 2 * median_size - current_block_size; + multiplicand *= current_block_size; + uint64_t product_lo = mul128(base_reward, multiplicand, &product_hi); uint64_t reward_hi; uint64_t reward_lo; @@ -146,7 +150,7 @@ namespace cryptonote { std::string get_account_integrated_address_as_str( bool testnet , account_public_address const & adr - , crypto::hash const & payment_id + , crypto::hash8 const & payment_id ) { uint64_t integrated_address_prefix = testnet ? @@ -172,7 +176,7 @@ namespace cryptonote { bool get_account_integrated_address_from_str( account_public_address& adr , bool& has_payment_id - , crypto::hash& payment_id + , crypto::hash8& payment_id , bool testnet , std::string const & str ) @@ -274,7 +278,7 @@ namespace cryptonote { ) { bool has_payment_id; - crypto::hash payment_id; + crypto::hash8 payment_id; return get_account_integrated_address_from_str(adr, has_payment_id, payment_id, testnet, str); } diff --git a/src/cryptonote_core/cryptonote_basic_impl.h b/src/cryptonote_core/cryptonote_basic_impl.h index 87d6f1024..5c442d558 100644 --- a/src/cryptonote_core/cryptonote_basic_impl.h +++ b/src/cryptonote_core/cryptonote_basic_impl.h @@ -60,7 +60,7 @@ namespace cryptonote { { uint8_t m_ver; account_public_address m_address; - crypto::hash payment_id; + crypto::hash8 payment_id; uint8_t check_sum; }; #pragma pack (pop) @@ -83,13 +83,13 @@ namespace cryptonote { std::string get_account_integrated_address_as_str( bool testnet , const account_public_address& adr - , const crypto::hash& payment_id + , const crypto::hash8& payment_id ); bool get_account_integrated_address_from_str( account_public_address& adr , bool& has_payment_id - , crypto::hash& payment_id + , crypto::hash8& payment_id , bool testnet , const std::string& str ); @@ -110,6 +110,10 @@ template std::ostream &print256(std::ostream &o, const T &v) { return o << "<" << epee::string_tools::pod_to_hex(v) << ">"; } +template +std::ostream &print64(std::ostream &o, const T &v) { + return o << "<" << epee::string_tools::pod_to_hex(v) << ">"; +} bool parse_hash256(const std::string str_hash, crypto::hash& hash); @@ -120,4 +124,5 @@ namespace crypto { inline std::ostream &operator <<(std::ostream &o, const crypto::key_image &v) { return print256(o, v); } inline std::ostream &operator <<(std::ostream &o, const crypto::signature &v) { return print256(o, v); } inline std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return print256(o, v); } + inline std::ostream &operator <<(std::ostream &o, const crypto::hash8 &v) { return print64(o, v); } } diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 2037a8c28..4d90eec1e 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -46,7 +46,7 @@ using namespace epee; #include "cryptonote_core/checkpoints_create.h" #include "blockchain_db/blockchain_db.h" #include "blockchain_db/lmdb/db_lmdb.h" -#ifndef STATICLIB +#if defined(BERKELEY_DB) #include "blockchain_db/berkeleydb/db_bdb.h" #endif @@ -212,18 +212,27 @@ namespace cryptonote #if BLOCKCHAIN_DB == DB_LMDB std::string db_type = command_line::get_arg(vm, daemon_args::arg_db_type); + std::string db_sync_mode = command_line::get_arg(vm, daemon_args::arg_db_sync_mode); + bool fast_sync = command_line::get_arg(vm, daemon_args::arg_fast_block_sync) != 0; + uint64_t blocks_threads = command_line::get_arg(vm, daemon_args::arg_prep_blocks_threads); BlockchainDB* db = nullptr; + uint64_t BDB_FAST_MODE = 0; + uint64_t BDB_FASTEST_MODE = 0; + uint64_t BDB_SAFE_MODE = 0; if (db_type == "lmdb") { db = new BlockchainLMDB(); } else if (db_type == "berkeley") { -#ifndef STATICLIB +#if defined(BERKELEY_DB) db = new BlockchainBDB(); + BDB_FAST_MODE = DB_TXN_WRITE_NOSYNC; + BDB_FASTEST_MODE = DB_TXN_NOSYNC; + BDB_SAFE_MODE = DB_TXN_SYNC; #else - LOG_ERROR("BlockchainBDB not supported on STATIC builds"); + LOG_ERROR("BerkeleyDB support disabled."); return false; #endif } @@ -240,9 +249,71 @@ namespace cryptonote LOG_PRINT_L0("Loading blockchain from folder " << folder.string() << " ..."); const std::string filename = folder.string(); + // temporarily default to fastest:async:1000 + blockchain_db_sync_mode sync_mode = db_async; + uint64_t blocks_per_sync = 1000; + try { - db->open(filename); + uint64_t db_flags = 0; + bool islmdb = db_type == "lmdb"; + + std::vector options; + boost::trim(db_sync_mode); + boost::split(options, db_sync_mode, boost::is_any_of(" :")); + + for(const auto &option : options) + LOG_PRINT_L0("option: " << option); + + // temporarily default to fastest:async:1000 + uint64_t DEFAULT_FLAGS = islmdb ? MDB_WRITEMAP | MDB_MAPASYNC | MDB_NORDAHEAD | MDB_NOMETASYNC | MDB_NOSYNC : + BDB_FASTEST_MODE; + + if(options.size() == 0) + { + // temporarily default to fastest:async:1000 + db_flags = DEFAULT_FLAGS; + } + + bool safemode = false; + if(options.size() >= 1) + { + if(options[0] == "safe") + { + safemode = true; + db_flags = islmdb ? MDB_NORDAHEAD : BDB_SAFE_MODE; + sync_mode = db_nosync; + } + else if(options[0] == "fast") + db_flags = islmdb ? MDB_NOMETASYNC | MDB_NOSYNC | MDB_NORDAHEAD : BDB_FAST_MODE; + else if(options[0] == "fastest") + db_flags = islmdb ? MDB_WRITEMAP | MDB_MAPASYNC | MDB_NORDAHEAD | MDB_NOMETASYNC | MDB_NOSYNC : BDB_FASTEST_MODE; + else + db_flags = DEFAULT_FLAGS; + } + + if(options.size() >= 2 && !safemode) + { + if(options[1] == "sync") + sync_mode = db_sync; + else if(options[1] == "async") + sync_mode = db_async; + } + + if(options.size() >= 3 && !safemode) + { + blocks_per_sync = atoll(options[2].c_str()); + if(blocks_per_sync > 5000) + blocks_per_sync = 5000; + if(blocks_per_sync == 0) + blocks_per_sync = 1; + } + + bool auto_remove_logs = command_line::get_arg(vm, daemon_args::arg_db_auto_remove_logs) != 0; + db->set_auto_remove_logs(auto_remove_logs); + db->open(filename, db_flags); + if(!db->m_open) + return false; } catch (const DB_ERROR& e) { @@ -250,7 +321,13 @@ namespace cryptonote return false; } + m_blockchain_storage.set_user_options(blocks_threads, + blocks_per_sync, sync_mode, fast_sync); + r = m_blockchain_storage.init(db, m_testnet); + + bool show_time_stats = command_line::get_arg(vm, daemon_args::arg_show_time_stats) != 0; + m_blockchain_storage.set_show_time_stats(show_time_stats); #else r = m_blockchain_storage.init(m_config_folder, m_testnet); #endif @@ -438,6 +515,21 @@ namespace cryptonote return true; } //----------------------------------------------------------------------------------------------- + bool core::is_key_image_spent(const crypto::key_image &key_image) + { + return m_blockchain_storage.have_tx_keyimg_as_spent(key_image); + } + //----------------------------------------------------------------------------------------------- + bool core::are_key_images_spent(const std::vector& key_im, std::vector &spent) + { + spent.clear(); + BOOST_FOREACH(auto& ki, key_im) + { + spent.push_back(m_blockchain_storage.have_tx_keyimg_as_spent(ki)); + } + return true; + } + //----------------------------------------------------------------------------------------------- bool core::check_tx_inputs_keyimages_diff(const transaction& tx) { std::unordered_set ki; @@ -587,6 +679,25 @@ namespace cryptonote { return m_blockchain_storage.add_new_block(b, bvc); } + + //----------------------------------------------------------------------------------------------- + bool core::prepare_handle_incoming_blocks(const std::list &blocks) + { +#if BLOCKCHAIN_DB == DB_LMDB + m_blockchain_storage.prepare_handle_incoming_blocks(blocks); +#endif + return true; + } + + //----------------------------------------------------------------------------------------------- + bool core::cleanup_handle_incoming_blocks(bool force_sync) + { +#if BLOCKCHAIN_DB == DB_LMDB + m_blockchain_storage.cleanup_handle_incoming_blocks(force_sync); +#endif + return true; + } + //----------------------------------------------------------------------------------------------- bool core::handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate) { @@ -678,7 +789,8 @@ namespace cryptonote return m_blockchain_storage.get_block_id_by_height(height); } //----------------------------------------------------------------------------------------------- - bool core::get_block_by_hash(const crypto::hash &h, block &blk) { + bool core::get_block_by_hash(const crypto::hash &h, block &blk) + { return m_blockchain_storage.get_block_by_hash(h, blk); } //----------------------------------------------------------------------------------------------- @@ -714,7 +826,7 @@ namespace cryptonote } #if BLOCKCHAIN_DB == DB_LMDB - m_store_blockchain_interval.do_call(boost::bind(&Blockchain::store_blockchain, &m_blockchain_storage)); + // m_store_blockchain_interval.do_call(boost::bind(&Blockchain::store_blockchain, &m_blockchain_storage)); #else m_store_blockchain_interval.do_call(boost::bind(&blockchain_storage::store_blockchain, &m_blockchain_storage)); #endif @@ -723,11 +835,13 @@ namespace cryptonote return true; } //----------------------------------------------------------------------------------------------- - void core::set_target_blockchain_height(uint64_t target_blockchain_height) { + void core::set_target_blockchain_height(uint64_t target_blockchain_height) + { m_target_blockchain_height = target_blockchain_height; } //----------------------------------------------------------------------------------------------- - uint64_t core::get_target_blockchain_height() const { + uint64_t core::get_target_blockchain_height() const + { return m_target_blockchain_height; } //----------------------------------------------------------------------------------------------- diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index ff187b4ce..d700b3b47 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -66,6 +66,9 @@ namespace cryptonote bool on_idle(); bool handle_incoming_tx(const blobdata& tx_blob, tx_verification_context& tvc, bool keeped_by_block); bool handle_incoming_block(const blobdata& block_blob, block_verification_context& bvc, bool update_miner_blocktemplate = true); + bool prepare_handle_incoming_blocks(const std::list &blocks); + bool cleanup_handle_incoming_blocks(bool force_sync = false); + bool check_incoming_block_size(const blobdata& block_blob); i_cryptonote_protocol* get_protocol(){return m_pprotocol;} @@ -142,6 +145,9 @@ namespace cryptonote void stop(); + bool is_key_image_spent(const crypto::key_image& key_im); + bool are_key_images_spent(const std::vector& key_im, std::vector &spent); + private: bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block); bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block); @@ -154,8 +160,6 @@ namespace cryptonote bool check_tx_semantic(const transaction& tx, bool keeped_by_block); //check if tx already in memory pool or in main blockchain - bool is_key_image_spent(const crypto::key_image& key_im); - bool check_tx_ring_signature(const txin_to_key& tx, const crypto::hash& tx_prefix_hash, const std::vector& sig); bool is_tx_spendtime_unlocked(uint64_t unlock_time); bool update_miner_block_template(); diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 1b21894a0..af8e703bf 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -38,6 +38,8 @@ using namespace epee; #include "crypto/crypto.h" #include "crypto/hash.h" +#define ENCRYPTED_PAYMENT_ID_TAIL 0x8d + namespace cryptonote { //--------------------------------------------------------------- @@ -303,6 +305,35 @@ namespace cryptonote return true; } //--------------------------------------------------------------- + bool remove_extra_nonce_tx_extra(std::vector& tx_extra) + { + std::string extra_str(reinterpret_cast(tx_extra.data()), tx_extra.size()); + std::istringstream iss(extra_str); + binary_archive ar(iss); + std::ostringstream oss; + binary_archive newar(oss); + + bool eof = false; + while (!eof) + { + tx_extra_field field; + bool r = ::do_serialize(ar, field); + CHECK_AND_NO_ASSERT_MES(r, false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(tx_extra.data()), tx_extra.size()))); + if (field.type() != typeid(tx_extra_nonce)) + ::do_serialize(newar, field); + + std::ios_base::iostate state = iss.rdstate(); + eof = (EOF == iss.peek()); + iss.clear(state); + } + CHECK_AND_NO_ASSERT_MES(::serialization::check_stream_state(ar), false, "failed to deserialize extra field. extra = " << string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(tx_extra.data()), tx_extra.size()))); + tx_extra.clear(); + std::string s = oss.str(); + tx_extra.reserve(s.size()); + std::copy(s.begin(), s.end(), std::back_inserter(tx_extra)); + return true; + } + //--------------------------------------------------------------- void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id) { extra_nonce.clear(); @@ -311,6 +342,14 @@ namespace cryptonote std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce)); } //--------------------------------------------------------------- + void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id) + { + extra_nonce.clear(); + extra_nonce.push_back(TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID); + const uint8_t* payment_id_ptr = reinterpret_cast(&payment_id); + std::copy(payment_id_ptr, payment_id_ptr + sizeof(payment_id), std::back_inserter(extra_nonce)); + } + //--------------------------------------------------------------- bool get_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash& payment_id) { if(sizeof(crypto::hash) + 1 != extra_nonce.size()) @@ -321,6 +360,54 @@ namespace cryptonote return true; } //--------------------------------------------------------------- + bool get_encrypted_payment_id_from_tx_extra_nonce(const blobdata& extra_nonce, crypto::hash8& payment_id) + { + if(sizeof(crypto::hash8) + 1 != extra_nonce.size()) + return false; + if (TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID != extra_nonce[0]) + return false; + payment_id = *reinterpret_cast(extra_nonce.data() + 1); + return true; + } + //--------------------------------------------------------------- + crypto::public_key get_destination_view_key_pub(const std::vector &destinations, const account_keys &sender_keys) + { + if (destinations.empty()) + return null_pkey; + for (size_t n = 1; n < destinations.size(); ++n) + { + if (!memcmp(&destinations[n].addr, &sender_keys.m_account_address, sizeof(destinations[0].addr))) + continue; + if (memcmp(&destinations[n].addr, &destinations[0].addr, sizeof(destinations[0].addr))) + return null_pkey; + } + return destinations[0].addr.m_view_public_key; + } + //--------------------------------------------------------------- + bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) + { + crypto::key_derivation derivation; + crypto::hash hash; + char data[33]; /* A hash, and an extra byte */ + + if (!generate_key_derivation(public_key, secret_key, derivation)) + return false; + + memcpy(data, &derivation, 32); + data[32] = ENCRYPTED_PAYMENT_ID_TAIL; + cn_fast_hash(data, 33, hash); + + for (size_t b = 0; b < 8; ++b) + payment_id.data[b] ^= hash.data[b]; + + return true; + } + bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key) + { + // Encryption and decryption are the same operation (xor with a key) + return encrypt_payment_id(payment_id, public_key, secret_key); + } + //--------------------------------------------------------------- bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, const std::vector& destinations, std::vector extra, transaction& tx, uint64_t unlock_time) { tx.vin.clear(); @@ -334,6 +421,49 @@ namespace cryptonote keypair txkey = keypair::generate(); add_tx_pub_key_to_extra(tx, 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; + 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::key_derivation derivation; + crypto::public_key view_key_pub = get_destination_view_key_pub(destinations, sender_account_keys); + if (view_key_pub == null_pkey) + { + LOG_ERROR("Destinations have to have exactly one output to support encrypted payment ids"); + return false; + } + + if (!encrypt_payment_id(payment_id, view_key_pub, txkey.sec)) + { + 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_extra_nonce_tx_extra(tx.extra); + 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; diff --git a/src/cryptonote_core/cryptonote_format_utils.h b/src/cryptonote_core/cryptonote_format_utils.h index fd785aafd..319205368 100644 --- a/src/cryptonote_core/cryptonote_format_utils.h +++ b/src/cryptonote_core/cryptonote_format_utils.h @@ -45,6 +45,8 @@ namespace cryptonote bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx, crypto::hash& tx_hash, crypto::hash& tx_prefix_hash); bool parse_and_validate_tx_from_blob(const blobdata& tx_blob, transaction& tx); bool construct_miner_tx(size_t height, size_t median_size, uint64_t already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, transaction& tx, const blobdata& extra_nonce = blobdata(), size_t max_outs = 1); + bool encrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); + bool decrypt_payment_id(crypto::hash8 &payment_id, const crypto::public_key &public_key, const crypto::secret_key &secret_key); struct tx_source_entry { @@ -85,8 +87,11 @@ namespace cryptonote crypto::public_key get_tx_pub_key_from_extra(const transaction& tx); bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key); bool add_extra_nonce_to_tx_extra(std::vector& tx_extra, const blobdata& extra_nonce); + bool remove_extra_nonce_tx_extra(std::vector& tx_extra); void set_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash& payment_id); + void set_encrypted_payment_id_to_tx_extra_nonce(blobdata& extra_nonce, const crypto::hash8& payment_id); 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 txout_to_key& out_key, const crypto::public_key& tx_pub_key, size_t output_index); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered); diff --git a/src/cryptonote_core/difficulty.cpp b/src/cryptonote_core/difficulty.cpp index 6486d8124..2b5466791 100644 --- a/src/cryptonote_core/difficulty.cpp +++ b/src/cryptonote_core/difficulty.cpp @@ -45,10 +45,7 @@ namespace cryptonote { using std::uint64_t; using std::vector; -#if defined(_MSC_VER) || defined(__MINGW32__) -#include -#include - +#if defined(__x86_64__) static inline void mul(uint64_t a, uint64_t b, uint64_t &low, uint64_t &high) { low = mul128(a, b, &high); } diff --git a/src/cryptonote_core/tx_extra.h b/src/cryptonote_core/tx_extra.h index ccfe4d1d9..012f41593 100644 --- a/src/cryptonote_core/tx_extra.h +++ b/src/cryptonote_core/tx_extra.h @@ -40,6 +40,7 @@ #define TX_EXTRA_MERGE_MINING_TAG 0x03 #define TX_EXTRA_NONCE_PAYMENT_ID 0x00 +#define TX_EXTRA_NONCE_ENCRYPTED_PAYMENT_ID 0x01 namespace cryptonote { diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 6dea31c7c..12fd3fe62 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -128,7 +128,11 @@ namespace cryptonote crypto::hash max_used_block_id = null_hash; uint64_t max_used_block_height = 0; +#if BLOCKCHAIN_DB == DB_LMDB + bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id, kept_by_block); +#else bool ch_inp_res = m_blockchain.check_tx_inputs(tx, max_used_block_height, max_used_block_id); +#endif CRITICAL_REGION_LOCAL(m_transactions_lock); if(!ch_inp_res) { @@ -203,6 +207,9 @@ namespace cryptonote bool tx_memory_pool::remove_transaction_keyimages(const transaction& tx) { CRITICAL_REGION_LOCAL(m_transactions_lock); + // ND: Speedup + // 1. Move transaction hash calcuation outside of loop. ._. + crypto::hash actual_hash = get_transaction_hash(tx); BOOST_FOREACH(const txin_v& vi, tx.vin) { CHECKED_GET_SPECIFIC_VARIANT(vi, const txin_to_key, txin, false); @@ -211,11 +218,11 @@ namespace cryptonote << "transaction id = " << get_transaction_hash(tx)); std::unordered_set& key_image_set = it->second; CHECK_AND_ASSERT_MES(key_image_set.size(), false, "empty key_image set, img=" << txin.k_image << ENDL - << "transaction id = " << get_transaction_hash(tx)); + << "transaction id = " << actual_hash); - auto it_in_set = key_image_set.find(get_transaction_hash(tx)); + auto it_in_set = key_image_set.find(actual_hash); CHECK_AND_ASSERT_MES(it_in_set != key_image_set.end(), false, "transaction id not found in key_image set, img=" << txin.k_image << ENDL - << "transaction id = " << get_transaction_hash(tx)); + << "transaction id = " << actual_hash); key_image_set.erase(it_in_set); if(!key_image_set.size()) { @@ -503,7 +510,10 @@ namespace cryptonote // Can not exceed maximum block size if (max_total_size < total_size + tx_it->second.blob_size) + { + sorted_it++; continue; + } // If adding this tx will make the block size // greater than CRYPTONOTE_GETBLOCKTEMPLATE_MAX @@ -511,7 +521,10 @@ namespace cryptonote // keep block sizes from becoming too unwieldly // to propagate at 60s block times. if ( (total_size + tx_it->second.blob_size) > CRYPTONOTE_GETBLOCKTEMPLATE_MAX_BLOCK_SIZE ) + { + sorted_it++; continue; + } // If we've exceeded the penalty free size, // stop including more tx @@ -522,7 +535,10 @@ namespace cryptonote // included into the blockchain or that are // missing key images if (!is_transaction_ready_to_go(tx_it->second) || have_key_images(k_images, tx_it->second.tx)) + { + sorted_it++; continue; + } bl.tx_hashes.push_back(tx_it->first); total_size += tx_it->second.blob_size; diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 1cf66521f..4a046aa45 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -314,7 +314,10 @@ namespace cryptonote LOG_PRINT_CCONTEXT_L2("NOTIFY_NEW_BLOCK (hop " << arg.hop << ")"); if(context.m_state != cryptonote_connection_context::state_normal) return 1; - + m_core.pause_mine(); + std::list blocks; + blocks.push_back(arg.b); + m_core.prepare_handle_incoming_blocks(blocks); 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); @@ -323,14 +326,15 @@ namespace cryptonote { LOG_PRINT_CCONTEXT_L1("Block verification failed: transaction verification failed, dropping connection"); m_p2p->drop_connection(context); + m_core.cleanup_handle_incoming_blocks(); + m_core.resume_mine(); return 1; } } - block_verification_context bvc = boost::value_initialized(); - m_core.pause_mine(); m_core.handle_incoming_block(arg.b.block, bvc); // got block from handle_notify_new_block + m_core.cleanup_handle_incoming_blocks(true); m_core.resume_mine(); if(bvc.m_verifivation_failed) { @@ -536,7 +540,7 @@ namespace cryptonote if (m_core.get_test_drop_download() && m_core.get_test_drop_download_height()) { // DISCARD BLOCKS for testing - + m_core.prepare_handle_incoming_blocks(arg.blocks); BOOST_FOREACH(const block_complete_entry& block_entry, arg.blocks) { // process transactions @@ -550,6 +554,7 @@ namespace cryptonote LOG_ERROR_CCONTEXT("transaction verification failed on NOTIFY_RESPONSE_GET_OBJECTS, \r\ntx_id = " << epee::string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection"); m_p2p->drop_connection(context); + m_core.cleanup_handle_incoming_blocks(); return 1; } } @@ -566,12 +571,14 @@ namespace cryptonote { LOG_PRINT_CCONTEXT_L1("Block verification failed, dropping connection"); m_p2p->drop_connection(context); + m_core.cleanup_handle_incoming_blocks(); return 1; } if(bvc.m_marked_as_orphaned) { LOG_PRINT_CCONTEXT_L1("Block received at sync phase was marked as orphaned, dropping connection"); m_p2p->drop_connection(context); + m_core.cleanup_handle_incoming_blocks(); return 1; } @@ -582,7 +589,7 @@ namespace cryptonote epee::net_utils::data_logger::get_instance().add_data("block_processing", 1); } // each download block - + m_core.cleanup_handle_incoming_blocks(); } // if not DISCARD BLOCK diff --git a/src/daemon/CMakeLists.txt b/src/daemon/CMakeLists.txt index ea93f84df..90b8cf526 100644 --- a/src/daemon/CMakeLists.txt +++ b/src/daemon/CMakeLists.txt @@ -26,6 +26,16 @@ # 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. +set(blocksdat "") +if(PER_BLOCK_CHECKPOINT) + if(APPLE) + add_custom_command(OUTPUT blocksdat.o COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && touch stub.c && ${CMAKE_C_COMPILER} -o stub.o -c stub.c COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && ld -r -sectcreate __DATA __blocks_dat ../blocks/checkpoints.dat -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o stub.o && rm -f stub.*) + else() + add_custom_command(OUTPUT blocksdat.o COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && cp ../blocks/checkpoints.dat blocks.dat && ld -r -b binary -o ${CMAKE_CURRENT_BINARY_DIR}/blocksdat.o blocks.dat && rm -f blocks.dat) + endif() + set(blocksdat "blocksdat.o") +endif() + set(daemon_sources command_parser_executor.cpp command_server.cpp @@ -69,7 +79,9 @@ bitmonero_private_headers(daemon bitmonero_add_executable(daemon ${daemon_sources} ${daemon_headers} - ${daemon_private_headers}) + ${daemon_private_headers} + ${blocksdat} +) target_link_libraries(daemon LINK_PRIVATE rpc diff --git a/src/daemon/command_line_args.h b/src/daemon/command_line_args.h index 2aa212b5e..ba98a6ea1 100644 --- a/src/daemon/command_line_args.h +++ b/src/daemon/command_line_args.h @@ -75,7 +75,32 @@ namespace daemon_args , "Specify database type" , "lmdb" }; - + const command_line::arg_descriptor arg_prep_blocks_threads = { + "prep-blocks-threads" + , "Max number of threads to use when preparing block hashes in groups." + , 4 + }; + const command_line::arg_descriptor arg_fast_block_sync = { + "fast-block-sync" + , "Test fast block-sync option using temporarily embedded known block hashes." + , 1 + }; + const command_line::arg_descriptor arg_show_time_stats = { + "show-time-stats" + , "Show time-stats when processing blocks/txs and disk synchronization." + , 1 + }; + const command_line::arg_descriptor arg_db_auto_remove_logs = { + "db-auto-remove-logs" + , "For BerkeleyDB only. Remove transactions logs automatically." + , 1 + }; + const command_line::arg_descriptor arg_db_sync_mode = { + "db-sync-mode" + , "Specify sync option, using format [safe|fast|fastest]:[sync|async]:[nblocks_per_sync]." + , "fastest:async:1000" + }; +; } // namespace daemon_args #endif // DAEMON_COMMAND_LINE_ARGS_H diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 58cb475ab..e6666c443 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -180,6 +180,26 @@ bool t_command_parser_executor::print_transaction(const std::vector return true; } +bool t_command_parser_executor::is_key_image_spent(const std::vector& args) +{ + if (args.empty()) + { + std::cout << "expected: is_key_image_spent " << std::endl; + return true; + } + + const std::string& str = args.front(); + crypto::key_image ki; + crypto::hash hash; + if (parse_hash256(str, hash)) + { + memcpy(&ki, &hash, sizeof(ki)); + m_executor.is_key_image_spent(ki); + } + + return true; +} + bool t_command_parser_executor::print_transaction_pool_long(const std::vector& args) { if (!args.empty()) return false; diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h index d1e299877..ddc207cfe 100644 --- a/src/daemon/command_parser_executor.h +++ b/src/daemon/command_parser_executor.h @@ -75,6 +75,8 @@ public: bool print_transaction(const std::vector& args); + bool is_key_image_spent(const std::vector& args); + bool print_transaction_pool_long(const std::vector& args); bool print_transaction_pool_short(const std::vector& args); diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 65bceff75..047b52c3e 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -84,6 +84,11 @@ t_command_server::t_command_server( , std::bind(&t_command_parser_executor::print_transaction, &m_parser, p::_1) , "Print transaction, print_tx " ); + m_command_lookup.set_handler( + "is_key_image_spent" + , std::bind(&t_command_parser_executor::is_key_image_spent, &m_parser, p::_1) + , "Prints whether a given key image is in the spent key images set, is_key_image_spent " + ); m_command_lookup.set_handler( "start_mining" , std::bind(&t_command_parser_executor::start_mining, &m_parser, p::_1) diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 8ae06c55f..2cf92c3d3 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -154,6 +154,7 @@ void t_daemon::stop() } mp_internals->p2p.stop(); mp_internals.reset(nullptr); // Ensure resources are cleaned up before we return + IPC::Daemon::stop(); } void t_daemon::stop_p2p() diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 0b34aa41e..b7d95ba27 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -86,6 +86,12 @@ int main(int argc, char const * argv[]) command_line::add_arg(core_settings, daemon_args::arg_testnet_on); command_line::add_arg(core_settings, daemon_args::arg_dns_checkpoints); command_line::add_arg(core_settings, daemon_args::arg_db_type); + command_line::add_arg(core_settings, daemon_args::arg_prep_blocks_threads); + command_line::add_arg(core_settings, daemon_args::arg_fast_block_sync); + command_line::add_arg(core_settings, daemon_args::arg_db_sync_mode); + command_line::add_arg(core_settings, daemon_args::arg_show_time_stats); + command_line::add_arg(core_settings, daemon_args::arg_db_auto_remove_logs); + daemonizer::init_options(hidden_options, visible_options); daemonize::t_executor::init_options(core_settings); diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 4ba9a5f32..62f254c76 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -482,6 +482,7 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) { } else { + req.txs_hashes.push_back(epee::string_tools::pod_to_hex(transaction_hash)); if (!m_rpc_server->on_get_transactions(req, res)) { tools::fail_msg_writer() << fail_message.c_str(); @@ -491,11 +492,65 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) { if (1 == res.txs_as_hex.size()) { + // first as hex tools::success_msg_writer() << res.txs_as_hex.front(); + + // then as json + crypto::hash tx_hash, tx_prefix_hash; + cryptonote::transaction tx; + cryptonote::blobdata blob; + if (!string_tools::parse_hexstr_to_binbuff(res.txs_as_hex.front(), blob)) + { + tools::fail_msg_writer() << "Failed to parse tx"; + } + else if (!cryptonote::parse_and_validate_tx_from_blob(blob, tx, tx_hash, tx_prefix_hash)) + { + tools::fail_msg_writer() << "Failed to parse tx blob"; + } + else + { + tools::success_msg_writer() << cryptonote::obj_to_json_str(tx) << std::endl; + } } else { - tools::fail_msg_writer() << "transaction wasn't found: <" << transaction_hash << '>' << std::endl; + tools::fail_msg_writer() << "transaction wasn't found: " << transaction_hash << std::endl; + } + + return true; +} + +bool t_rpc_command_executor::is_key_image_spent(const crypto::key_image &ki) { + cryptonote::COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req; + cryptonote::COMMAND_RPC_IS_KEY_IMAGE_SPENT::response res; + + std::string fail_message = "Problem checkking key image"; + + req.key_images.push_back(epee::string_tools::pod_to_hex(ki)); + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(req, res, "/is_key_image_spent", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_is_key_image_spent(req, res)) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + if (1 == res.spent_status.size()) + { + // first as hex + tools::success_msg_writer() << ki << ": " << (res.spent_status.front() ? "spent" : "unspent"); + } + else + { + tools::fail_msg_writer() << "key image status could not be determined" << std::endl; } return true; diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index 5e332f3fc..b40a67bf8 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -87,6 +87,8 @@ public: bool print_transaction(crypto::hash transaction_hash); + bool is_key_image_spent(const crypto::key_image &ki); + bool print_transaction_pool_long(); bool print_transaction_pool_short(); diff --git a/src/ipc/daemon_ipc_handlers.cpp b/src/ipc/daemon_ipc_handlers.cpp index aad5941fc..c86536fcd 100644 --- a/src/ipc/daemon_ipc_handlers.cpp +++ b/src/ipc/daemon_ipc_handlers.cpp @@ -390,6 +390,19 @@ namespace IPC typedef cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outs_for_amount; typedef cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; + std::stringstream ss; + std::for_each(res.outs.begin(), res.outs.end(), [&](outs_for_amount& ofa) + { + ss << "[" << ofa.amount << "]:"; + CHECK_AND_ASSERT_MES(ofa.outs.size(), ;, "internal error: ofa.outs.size() is empty for amount " << ofa.amount); + std::for_each(ofa.outs.begin(), ofa.outs.end(), [&](out_entry& oe) + { + ss << oe.global_amount_index << " "; + }); + ss << ENDL; + }); + std::string s = ss.str(); + LOG_PRINT_L2("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " << ENDL << s); for (unsigned int i = 0; i < res.outs.size(); i++) { rapidjson::Value output(rapidjson::kObjectType); outs_for_amount out = res.outs[i]; @@ -417,19 +430,6 @@ namespace IPC zframe_t *frame = zframe_new(block_string.c_str(), block_string.length()); wap_proto_set_random_outputs(message, &frame); - std::stringstream ss; - std::for_each(res.outs.begin(), res.outs.end(), [&](outs_for_amount& ofa) - { - ss << "[" << ofa.amount << "]:"; - CHECK_AND_ASSERT_MES(ofa.outs.size(), ;, "internal error: ofa.outs.size() is empty for amount " << ofa.amount); - std::for_each(ofa.outs.begin(), ofa.outs.end(), [&](out_entry& oe) - { - ss << oe.global_amount_index << " "; - }); - ss << ENDL; - }); - std::string s = ss.str(); - LOG_PRINT_L2("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " << ENDL << s); wap_proto_set_status(message, STATUS_OK); } diff --git a/src/ipc/include/wap_client_engine.inc b/src/ipc/include/wap_client_engine.inc index 621c5d295..202970bb8 100644 --- a/src/ipc/include/wap_client_engine.inc +++ b/src/ipc/include/wap_client_engine.inc @@ -218,14 +218,17 @@ typedef struct { bool connected; // True if client is connected bool terminated; // True if client is shutdown bool fsm_stopped; // "terminate" action called - size_t timeout; // inactivity timeout, msecs + size_t expiry; // Expiry timer, msecs + size_t heartbeat; // Heartbeat timer, msecs state_t state; // Current state event_t event; // Current event event_t next_event; // The next event event_t exception; // Exception event, if any - int expiry_timer; // zloop timer for timeouts + int expiry_timer; // zloop timer for expiry int wakeup_timer; // zloop timer for alarms + int heartbeat_timer; // zloop timer for heartbeat event_t wakeup_event; // Wake up with this event + char log_prefix [41]; // Log prefix string } s_client_t; static int @@ -239,7 +242,7 @@ static void static int s_client_handle_wakeup (zloop_t *loop, int timer_id, void *argument); static int - s_client_handle_timeout (zloop_t *loop, int timer_id, void *argument); + s_client_handle_expiry (zloop_t *loop, int timer_id, void *argument); static void s_satisfy_pedantic_compilers (void); static void @@ -335,6 +338,10 @@ s_client_new (zsock_t *cmdpipe, zsock_t *msgpipe) assert ((s_client_t *) &self->client == self); self->cmdpipe = cmdpipe; self->msgpipe = msgpipe; + self->state = start_state; + self->event = NULL_event; + snprintf (self->log_prefix, sizeof (self->log_prefix) - 1, + "%6d:%-33s", randof (1000000), "wap_client"); self->dealer = zsock_new (ZMQ_DEALER); if (self->dealer) self->message = wap_proto_new (); @@ -342,8 +349,6 @@ s_client_new (zsock_t *cmdpipe, zsock_t *msgpipe) self->loop = zloop_new (); if (self->loop) { // Give application chance to initialize and set next event - self->state = start_state; - self->event = NULL_event; self->client.cmdpipe = self->cmdpipe; self->client.msgpipe = self->msgpipe; self->client.dealer = self->dealer; @@ -430,25 +435,42 @@ engine_set_wakeup_event (client_t *client, size_t delay, event_t event) } } -// Set heartbeat timeout. By default, the timeout is zero, meaning -// infinite. Setting a non-zero timeout causes the state machine to -// receive an "expired" event if is no incoming traffic for that many -// milliseconds. This cycles over and over until/unless the code sets -// a zero timeout. The state machine must handle the "expired" event. +// Set a heartbeat timer. The interval is in msecs and must be +// non-zero. The state machine must handle the "heartbeat" event. +// The heartbeat happens every interval no matter what traffic the +// client is sending or receiving. static void -engine_set_timeout (client_t *client, size_t timeout) +engine_set_heartbeat (client_t *client, size_t heartbeat) { if (client) { s_client_t *self = (s_client_t *) client; - self->timeout = timeout; + self->heartbeat = heartbeat; + } +} + + +// Set expiry timer. Setting a non-zero expiry causes the state machine +// to receive an "expired" event if is no incoming traffic for that many +// milliseconds. This cycles over and over until/unless the code sets a +// zero expiry. The state machine must handle the "expired" event. + +// Macro to support deprecated name: remove after 2016-07-31 +#define engine_set_timeout engine_set_expiry + +static void +engine_set_expiry (client_t *client, size_t expiry) +{ + if (client) { + s_client_t *self = (s_client_t *) client; + self->expiry = expiry; if (self->expiry_timer) { zloop_timer_end (self->loop, self->expiry_timer); self->expiry_timer = 0; } - if (self->timeout) + if (self->expiry) self->expiry_timer = zloop_timer ( - self->loop, self->timeout, 1, s_client_handle_timeout, self); + self->loop, self->expiry, 1, s_client_handle_expiry, self); } } @@ -490,7 +512,8 @@ s_satisfy_pedantic_compilers (void) { engine_set_next_event (NULL, NULL_event); engine_set_exception (NULL, NULL_event); - engine_set_timeout (NULL, 0); + engine_set_heartbeat (NULL, 0); + engine_set_expiry (NULL, 0); engine_set_wakeup_event (NULL, 0, NULL_event); engine_handle_socket (NULL, 0, NULL); engine_set_connected (NULL, 0); @@ -627,7 +650,8 @@ s_protocol_event (s_client_t *self, wap_proto_t *message) return error_event; break; default: - zsys_error ("wap_client: unknown command %s, halting", wap_proto_command (message)); + zsys_error ("%s: unknown command %s, halting", + self->log_prefix, wap_proto_command (message)); self->terminated = true; return NULL_event; } @@ -653,8 +677,10 @@ s_client_execute (s_client_t *self, event_t event) self->next_event = NULL_event; self->exception = NULL_event; if (wap_client_verbose) { - zsys_debug ("wap_client: %s:", s_state_name [self->state]); - zsys_debug ("wap_client: %s", s_event_name [self->event]); + zsys_debug ("%s: %s:", + self->log_prefix, s_state_name [self->state]); + zsys_debug ("%s: %s", + self->log_prefix, s_event_name [self->event]); } switch (self->state) { case start_state: @@ -662,25 +688,26 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // connect to server endpoint if (wap_client_verbose) - zsys_debug ("wap_client: $ connect to server endpoint"); + zsys_debug ("%s: $ connect to server endpoint", self->log_prefix); connect_to_server_endpoint (&self->client); } if (!self->exception) { // set client identity if (wap_client_verbose) - zsys_debug ("wap_client: $ set client identity"); + zsys_debug ("%s: $ set client identity", self->log_prefix); set_client_identity (&self->client); } if (!self->exception) { // use connect timeout if (wap_client_verbose) - zsys_debug ("wap_client: $ use connect timeout"); + zsys_debug ("%s: $ use connect timeout", self->log_prefix); use_connect_timeout (&self->client); } if (!self->exception) { // send OPEN if (wap_client_verbose) - zsys_debug ("wap_client: $ send OPEN"); + zsys_debug ("%s: $ send OPEN", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_OPEN); wap_proto_send (self->message, self->dealer); } @@ -692,20 +719,22 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal bad endpoint if (wap_client_verbose) - zsys_debug ("wap_client: $ signal bad endpoint"); + zsys_debug ("%s: $ signal bad endpoint", self->log_prefix); signal_bad_endpoint (&self->client); } if (!self->exception) { // terminate if (wap_client_verbose) - zsys_debug ("wap_client: $ terminate"); + zsys_debug ("%s: $ terminate", self->log_prefix); self->fsm_stopped = true; } } else { // Handle unexpected internal events - zsys_warning ("wap_client: unhandled event %s in %s", - s_event_name [self->event], s_state_name [self->state]); + zsys_warning ("%s: unhandled event %s in %s", + self->log_prefix, + s_event_name [self->event], + s_state_name [self->state]); assert (false); } break; @@ -715,13 +744,13 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal success if (wap_client_verbose) - zsys_debug ("wap_client: $ signal success"); + zsys_debug ("%s: $ signal success", self->log_prefix); signal_success (&self->client); } if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } if (!self->exception) @@ -732,13 +761,13 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal server not present if (wap_client_verbose) - zsys_debug ("wap_client: $ signal server not present"); + zsys_debug ("%s: $ signal server not present", self->log_prefix); signal_server_not_present (&self->client); } if (!self->exception) { // terminate if (wap_client_verbose) - zsys_debug ("wap_client: $ terminate"); + zsys_debug ("%s: $ terminate", self->log_prefix); self->fsm_stopped = true; } } @@ -747,7 +776,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -756,7 +785,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -764,15 +793,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -781,13 +804,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // prepare blocks command if (wap_client_verbose) - zsys_debug ("wap_client: $ prepare blocks command"); + zsys_debug ("%s: $ prepare blocks command", self->log_prefix); prepare_blocks_command (&self->client); } if (!self->exception) { // send BLOCKS if (wap_client_verbose) - zsys_debug ("wap_client: $ send BLOCKS"); + zsys_debug ("%s: $ send BLOCKS", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_BLOCKS); wap_proto_send (self->message, self->dealer); } @@ -799,13 +823,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // prepare get command if (wap_client_verbose) - zsys_debug ("wap_client: $ prepare get command"); + zsys_debug ("%s: $ prepare get command", self->log_prefix); prepare_get_command (&self->client); } if (!self->exception) { // send GET if (wap_client_verbose) - zsys_debug ("wap_client: $ send GET"); + zsys_debug ("%s: $ send GET", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_GET); wap_proto_send (self->message, self->dealer); } @@ -817,13 +842,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // prepare put command if (wap_client_verbose) - zsys_debug ("wap_client: $ prepare put command"); + zsys_debug ("%s: $ prepare put command", self->log_prefix); prepare_put_command (&self->client); } if (!self->exception) { // send PUT if (wap_client_verbose) - zsys_debug ("wap_client: $ send PUT"); + zsys_debug ("%s: $ send PUT", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_PUT); wap_proto_send (self->message, self->dealer); } @@ -835,7 +861,8 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // send SAVE_BC if (wap_client_verbose) - zsys_debug ("wap_client: $ send SAVE_BC"); + zsys_debug ("%s: $ send SAVE_BC", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_SAVE_BC); wap_proto_send (self->message, self->dealer); } @@ -847,13 +874,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // prepare start command if (wap_client_verbose) - zsys_debug ("wap_client: $ prepare start command"); + zsys_debug ("%s: $ prepare start command", self->log_prefix); prepare_start_command (&self->client); } if (!self->exception) { // send START if (wap_client_verbose) - zsys_debug ("wap_client: $ send START"); + zsys_debug ("%s: $ send START", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_START); wap_proto_send (self->message, self->dealer); } @@ -865,7 +893,8 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // send STOP if (wap_client_verbose) - zsys_debug ("wap_client: $ send STOP"); + zsys_debug ("%s: $ send STOP", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_STOP); wap_proto_send (self->message, self->dealer); } @@ -877,13 +906,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // prepare get output indexes command if (wap_client_verbose) - zsys_debug ("wap_client: $ prepare get output indexes command"); + zsys_debug ("%s: $ prepare get output indexes command", self->log_prefix); prepare_get_output_indexes_command (&self->client); } if (!self->exception) { // send OUTPUT_INDEXES if (wap_client_verbose) - zsys_debug ("wap_client: $ send OUTPUT_INDEXES"); + zsys_debug ("%s: $ send OUTPUT_INDEXES", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_OUTPUT_INDEXES); wap_proto_send (self->message, self->dealer); } @@ -895,13 +925,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // prepare get random outs command if (wap_client_verbose) - zsys_debug ("wap_client: $ prepare get random outs command"); + zsys_debug ("%s: $ prepare get random outs command", self->log_prefix); prepare_get_random_outs_command (&self->client); } if (!self->exception) { // send RANDOM_OUTS if (wap_client_verbose) - zsys_debug ("wap_client: $ send RANDOM_OUTS"); + zsys_debug ("%s: $ send RANDOM_OUTS", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_RANDOM_OUTS); wap_proto_send (self->message, self->dealer); } @@ -913,7 +944,8 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // send GET_HEIGHT if (wap_client_verbose) - zsys_debug ("wap_client: $ send GET_HEIGHT"); + zsys_debug ("%s: $ send GET_HEIGHT", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_GET_HEIGHT); wap_proto_send (self->message, self->dealer); } @@ -925,7 +957,8 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // send GET_INFO if (wap_client_verbose) - zsys_debug ("wap_client: $ send GET_INFO"); + zsys_debug ("%s: $ send GET_INFO", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_GET_INFO); wap_proto_send (self->message, self->dealer); } @@ -937,7 +970,8 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // send GET_PEER_LIST if (wap_client_verbose) - zsys_debug ("wap_client: $ send GET_PEER_LIST"); + zsys_debug ("%s: $ send GET_PEER_LIST", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_GET_PEER_LIST); wap_proto_send (self->message, self->dealer); } @@ -949,7 +983,8 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // send GET_MINING_STATUS if (wap_client_verbose) - zsys_debug ("wap_client: $ send GET_MINING_STATUS"); + zsys_debug ("%s: $ send GET_MINING_STATUS", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_GET_MINING_STATUS); wap_proto_send (self->message, self->dealer); } @@ -961,13 +996,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // prepare set log hash rate command if (wap_client_verbose) - zsys_debug ("wap_client: $ prepare set log hash rate command"); + zsys_debug ("%s: $ prepare set log hash rate command", self->log_prefix); prepare_set_log_hash_rate_command (&self->client); } if (!self->exception) { // send SET_LOG_HASH_RATE if (wap_client_verbose) - zsys_debug ("wap_client: $ send SET_LOG_HASH_RATE"); + zsys_debug ("%s: $ send SET_LOG_HASH_RATE", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_SET_LOG_HASH_RATE); wap_proto_send (self->message, self->dealer); } @@ -979,13 +1015,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // prepare set log level command if (wap_client_verbose) - zsys_debug ("wap_client: $ prepare set log level command"); + zsys_debug ("%s: $ prepare set log level command", self->log_prefix); prepare_set_log_level_command (&self->client); } if (!self->exception) { // send SET_LOG_LEVEL if (wap_client_verbose) - zsys_debug ("wap_client: $ send SET_LOG_LEVEL"); + zsys_debug ("%s: $ send SET_LOG_LEVEL", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_SET_LOG_LEVEL); wap_proto_send (self->message, self->dealer); } @@ -997,7 +1034,8 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // send START_SAVE_GRAPH if (wap_client_verbose) - zsys_debug ("wap_client: $ send START_SAVE_GRAPH"); + zsys_debug ("%s: $ send START_SAVE_GRAPH", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_START_SAVE_GRAPH); wap_proto_send (self->message, self->dealer); } @@ -1009,7 +1047,8 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // send STOP_SAVE_GRAPH if (wap_client_verbose) - zsys_debug ("wap_client: $ send STOP_SAVE_GRAPH"); + zsys_debug ("%s: $ send STOP_SAVE_GRAPH", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_STOP_SAVE_GRAPH); wap_proto_send (self->message, self->dealer); } @@ -1021,13 +1060,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // prepare get block hash command if (wap_client_verbose) - zsys_debug ("wap_client: $ prepare get block hash command"); + zsys_debug ("%s: $ prepare get block hash command", self->log_prefix); prepare_get_block_hash_command (&self->client); } if (!self->exception) { // send GET_BLOCK_HASH if (wap_client_verbose) - zsys_debug ("wap_client: $ send GET_BLOCK_HASH"); + zsys_debug ("%s: $ send GET_BLOCK_HASH", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_GET_BLOCK_HASH); wap_proto_send (self->message, self->dealer); } @@ -1039,13 +1079,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // prepare get block template command if (wap_client_verbose) - zsys_debug ("wap_client: $ prepare get block template command"); + zsys_debug ("%s: $ prepare get block template command", self->log_prefix); prepare_get_block_template_command (&self->client); } if (!self->exception) { // send GET_BLOCK_TEMPLATE if (wap_client_verbose) - zsys_debug ("wap_client: $ send GET_BLOCK_TEMPLATE"); + zsys_debug ("%s: $ send GET_BLOCK_TEMPLATE", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_GET_BLOCK_TEMPLATE); wap_proto_send (self->message, self->dealer); } @@ -1057,7 +1098,8 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // send CLOSE if (wap_client_verbose) - zsys_debug ("wap_client: $ send CLOSE"); + zsys_debug ("%s: $ send CLOSE", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_CLOSE); wap_proto_send (self->message, self->dealer); } @@ -1069,13 +1111,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check if connection is dead if (wap_client_verbose) - zsys_debug ("wap_client: $ check if connection is dead"); + zsys_debug ("%s: $ check if connection is dead", self->log_prefix); check_if_connection_is_dead (&self->client); } if (!self->exception) { // send PING if (wap_client_verbose) - zsys_debug ("wap_client: $ send PING"); + zsys_debug ("%s: $ send PING", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_PING); wap_proto_send (self->message, self->dealer); } @@ -1085,7 +1128,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1094,7 +1137,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1102,15 +1145,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1119,7 +1156,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have blocks ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have blocks ok"); + zsys_debug ("%s: $ signal have blocks ok", self->log_prefix); signal_have_blocks_ok (&self->client); } if (!self->exception) @@ -1130,7 +1167,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1139,7 +1176,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1147,15 +1184,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1164,7 +1195,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have get ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have get ok"); + zsys_debug ("%s: $ signal have get ok", self->log_prefix); signal_have_get_ok (&self->client); } if (!self->exception) @@ -1175,7 +1206,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1184,7 +1215,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1192,15 +1223,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1209,7 +1234,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have put ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have put ok"); + zsys_debug ("%s: $ signal have put ok", self->log_prefix); signal_have_put_ok (&self->client); } if (!self->exception) @@ -1220,7 +1245,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1229,7 +1254,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1237,15 +1262,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1254,7 +1273,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have save bc ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have save bc ok"); + zsys_debug ("%s: $ signal have save bc ok", self->log_prefix); signal_have_save_bc_ok (&self->client); } if (!self->exception) @@ -1265,7 +1284,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1274,7 +1293,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1282,15 +1301,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1299,7 +1312,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have start ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have start ok"); + zsys_debug ("%s: $ signal have start ok", self->log_prefix); signal_have_start_ok (&self->client); } if (!self->exception) @@ -1310,7 +1323,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1319,7 +1332,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1327,15 +1340,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1344,7 +1351,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have stop ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have stop ok"); + zsys_debug ("%s: $ signal have stop ok", self->log_prefix); signal_have_stop_ok (&self->client); } if (!self->exception) @@ -1355,7 +1362,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1364,7 +1371,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1372,15 +1379,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1389,7 +1390,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have output indexes ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have output indexes ok"); + zsys_debug ("%s: $ signal have output indexes ok", self->log_prefix); signal_have_output_indexes_ok (&self->client); } if (!self->exception) @@ -1400,7 +1401,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1409,7 +1410,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1417,15 +1418,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1434,7 +1429,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have random outs ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have random outs ok"); + zsys_debug ("%s: $ signal have random outs ok", self->log_prefix); signal_have_random_outs_ok (&self->client); } if (!self->exception) @@ -1445,7 +1440,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1454,7 +1449,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1462,15 +1457,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1479,7 +1468,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have get height ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have get height ok"); + zsys_debug ("%s: $ signal have get height ok", self->log_prefix); signal_have_get_height_ok (&self->client); } if (!self->exception) @@ -1490,7 +1479,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1499,7 +1488,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1507,15 +1496,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1524,7 +1507,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have get info ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have get info ok"); + zsys_debug ("%s: $ signal have get info ok", self->log_prefix); signal_have_get_info_ok (&self->client); } if (!self->exception) @@ -1535,7 +1518,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1544,7 +1527,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1552,15 +1535,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1569,7 +1546,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have get peer list ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have get peer list ok"); + zsys_debug ("%s: $ signal have get peer list ok", self->log_prefix); signal_have_get_peer_list_ok (&self->client); } if (!self->exception) @@ -1580,7 +1557,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1589,7 +1566,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1597,15 +1574,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1614,7 +1585,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have get mining status ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have get mining status ok"); + zsys_debug ("%s: $ signal have get mining status ok", self->log_prefix); signal_have_get_mining_status_ok (&self->client); } if (!self->exception) @@ -1625,7 +1596,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1634,7 +1605,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1642,15 +1613,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1659,7 +1624,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have set log hash rate ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have set log hash rate ok"); + zsys_debug ("%s: $ signal have set log hash rate ok", self->log_prefix); signal_have_set_log_hash_rate_ok (&self->client); } if (!self->exception) @@ -1670,7 +1635,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1679,7 +1644,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1687,15 +1652,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1704,7 +1663,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have set log level ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have set log level ok"); + zsys_debug ("%s: $ signal have set log level ok", self->log_prefix); signal_have_set_log_level_ok (&self->client); } if (!self->exception) @@ -1715,7 +1674,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1724,7 +1683,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1732,15 +1691,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1749,7 +1702,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have start save graph ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have start save graph ok"); + zsys_debug ("%s: $ signal have start save graph ok", self->log_prefix); signal_have_start_save_graph_ok (&self->client); } if (!self->exception) @@ -1760,7 +1713,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1769,7 +1722,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1777,15 +1730,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1794,7 +1741,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have stop save graph ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have stop save graph ok"); + zsys_debug ("%s: $ signal have stop save graph ok", self->log_prefix); signal_have_stop_save_graph_ok (&self->client); } if (!self->exception) @@ -1805,7 +1752,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1814,7 +1761,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1822,15 +1769,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1839,7 +1780,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have get block hash ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have get block hash ok"); + zsys_debug ("%s: $ signal have get block hash ok", self->log_prefix); signal_have_get_block_hash_ok (&self->client); } if (!self->exception) @@ -1850,7 +1791,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1859,7 +1800,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1867,15 +1808,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1884,7 +1819,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal have get block template ok if (wap_client_verbose) - zsys_debug ("wap_client: $ signal have get block template ok"); + zsys_debug ("%s: $ signal have get block template ok", self->log_prefix); signal_have_get_block_template_ok (&self->client); } if (!self->exception) @@ -1895,7 +1830,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1904,7 +1839,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1912,15 +1847,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1929,13 +1858,13 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal success if (wap_client_verbose) - zsys_debug ("wap_client: $ signal success"); + zsys_debug ("%s: $ signal success", self->log_prefix); signal_success (&self->client); } if (!self->exception) { // terminate if (wap_client_verbose) - zsys_debug ("wap_client: $ terminate"); + zsys_debug ("%s: $ terminate", self->log_prefix); self->fsm_stopped = true; } } @@ -1944,13 +1873,13 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal failure if (wap_client_verbose) - zsys_debug ("wap_client: $ signal failure"); + zsys_debug ("%s: $ signal failure", self->log_prefix); signal_failure (&self->client); } if (!self->exception) { // terminate if (wap_client_verbose) - zsys_debug ("wap_client: $ terminate"); + zsys_debug ("%s: $ terminate", self->log_prefix); self->fsm_stopped = true; } } @@ -1959,7 +1888,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -1968,7 +1897,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -1976,15 +1905,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -1993,7 +1916,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -2002,7 +1925,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -2010,15 +1933,9 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; @@ -2027,13 +1944,14 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // use connect timeout if (wap_client_verbose) - zsys_debug ("wap_client: $ use connect timeout"); + zsys_debug ("%s: $ use connect timeout", self->log_prefix); use_connect_timeout (&self->client); } if (!self->exception) { // send OPEN if (wap_client_verbose) - zsys_debug ("wap_client: $ send OPEN"); + zsys_debug ("%s: $ send OPEN", + self->log_prefix); wap_proto_set_id (self->message, WAP_PROTO_OPEN); wap_proto_send (self->message, self->dealer); } @@ -2045,20 +1963,22 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // signal unhandled error if (wap_client_verbose) - zsys_debug ("wap_client: $ signal unhandled error"); + zsys_debug ("%s: $ signal unhandled error", self->log_prefix); signal_unhandled_error (&self->client); } if (!self->exception) { // terminate if (wap_client_verbose) - zsys_debug ("wap_client: $ terminate"); + zsys_debug ("%s: $ terminate", self->log_prefix); self->fsm_stopped = true; } } else { // Handle unexpected internal events - zsys_warning ("wap_client: unhandled event %s in %s", - s_event_name [self->event], s_state_name [self->state]); + zsys_warning ("%s: unhandled event %s in %s", + self->log_prefix, + s_event_name [self->event], + s_state_name [self->state]); assert (false); } break; @@ -2068,7 +1988,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } if (!self->exception) @@ -2079,7 +1999,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // client is connected if (wap_client_verbose) - zsys_debug ("wap_client: $ client is connected"); + zsys_debug ("%s: $ client is connected", self->log_prefix); client_is_connected (&self->client); } } @@ -2088,7 +2008,7 @@ s_client_execute (s_client_t *self, event_t event) if (!self->exception) { // check status code if (wap_client_verbose) - zsys_debug ("wap_client: $ check status code"); + zsys_debug ("%s: $ check status code", self->log_prefix); check_status_code (&self->client); } if (!self->exception) @@ -2096,43 +2016,39 @@ s_client_execute (s_client_t *self, event_t event) } else if (self->event == exception_event) { - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ exception"); } else { // Handle unexpected protocol events - // No action - just logging - if (wap_client_verbose) - zsys_debug ("wap_client: $ *"); } break; } // If we had an exception event, interrupt normal programming if (self->exception) { if (wap_client_verbose) - zsys_debug ("wap_client: ! %s", s_event_name [self->exception]); + zsys_debug ("%s: ! %s", + self->log_prefix, s_event_name [self->exception]); self->next_event = self->exception; } else if (wap_client_verbose) - zsys_debug ("wap_client: > %s", s_state_name [self->state]); + zsys_debug ("%s: > %s", + self->log_prefix, s_state_name [self->state]); } } -// zloop callback when client inactivity timer expires +// zloop callback when client expiry timeout expires static int -s_client_handle_timeout (zloop_t *loop, int timer_id, void *argument) +s_client_handle_expiry (zloop_t *loop, int timer_id, void *argument) { s_client_t *self = (s_client_t *) argument; s_client_execute (self, expired_event); if (self->terminated) return -1; - if (self->timeout > 0) + if (self->expiry > 0) self->expiry_timer = zloop_timer ( - loop, self->timeout, 1, s_client_handle_timeout, self); + loop, self->expiry, 1, s_client_handle_expiry, self); return 0; } @@ -2157,7 +2073,7 @@ s_client_handle_cmdpipe (zloop_t *loop, zsock_t *reader, void *argument) if (!method) return -1; // Interrupted; exit zloop if (wap_client_verbose) - zsys_debug ("wap_client: API command=%s", method); + zsys_debug ("%s: API command=%s", self->log_prefix, method); if (streq (method, "$TERM")) self->terminated = true; // Shutdown the engine @@ -2266,7 +2182,8 @@ s_client_handle_cmdpipe (zloop_t *loop, zsock_t *reader, void *argument) } // Cleanup pipe if any argument frames are still waiting to be eaten if (zsock_rcvmore (self->cmdpipe)) { - zsys_error ("wap_client: trailing API command frames (%s)", method); + zsys_error ("%s: trailing API command frames (%s)", + self->log_prefix, method); zmsg_t *more = zmsg_recv (self->cmdpipe); zmsg_print (more); zmsg_destroy (&more); @@ -2290,7 +2207,7 @@ s_client_handle_msgpipe (zloop_t *loop, zsock_t *reader, void *argument) if (!method) return -1; // Interrupted; exit zloop if (wap_client_verbose) - zsys_debug ("wap_client: API message=%s", method); + zsys_debug ("%s: API message=%s", self->log_prefix, method); // Front-end shuts down msgpipe before cmdpipe, this little // handshake just ensures all traffic on the msgpipe has been @@ -2300,7 +2217,7 @@ s_client_handle_msgpipe (zloop_t *loop, zsock_t *reader, void *argument) zsock_signal (self->cmdpipe, 0); // Cleanup pipe if any argument frames are still waiting to be eaten if (zsock_rcvmore (self->msgpipe)) { - zsys_error ("wap_client: trailing API message frames (%s)", method); + zsys_error ("%s: trailing API message frames (%s)", self->log_prefix, method); zmsg_t *more = zmsg_recv (self->msgpipe); zmsg_print (more); zmsg_destroy (&more); @@ -2329,10 +2246,10 @@ s_client_handle_protocol (zloop_t *loop, zsock_t *reader, void *argument) zloop_timer_end (self->loop, self->expiry_timer); self->expiry_timer = 0; } - // Reset expiry timer if timeout is not zero - if (self->timeout) + // Reset expiry timer if expiry timeout not zero + if (self->expiry) self->expiry_timer = zloop_timer ( - self->loop, self->timeout, 1, s_client_handle_timeout, self); + self->loop, self->expiry, 1, s_client_handle_expiry, self); s_client_execute (self, s_protocol_event (self, self->message)); if (self->terminated) return -1; diff --git a/src/ipc/include/wap_server_engine.inc b/src/ipc/include/wap_server_engine.inc index 58c66c6ea..4f4f5443e 100644 --- a/src/ipc/include/wap_server_engine.inc +++ b/src/ipc/include/wap_server_engine.inc @@ -281,21 +281,27 @@ engine_broadcast_event (server_t *server, client_t *client, event_t event) } } -// Poll socket for activity, invoke handler on any received message. -// Handler must be a CZMQ zloop_fn function; receives server as arg. +// Poll actor or zsock for activity, invoke handler on any received +// message. Handler must be a CZMQ zloop_fn function; receives server +// as arg. static void -engine_handle_socket (server_t *server, zsock_t *socket, zloop_reader_fn handler) +engine_handle_socket (server_t *server, void *sock, zloop_reader_fn handler) { if (server) { s_server_t *self = (s_server_t *) server; + // Resolve zactor_t -> zsock_t + if (zactor_is (sock)) + sock = zactor_sock ((zactor_t *) sock); + else + assert (zsock_is (sock)); if (handler != NULL) { - int rc = zloop_reader (self->loop, socket, handler, self); + int rc = zloop_reader (self->loop, (zsock_t *) sock, handler, self); assert (rc == 0); - zloop_reader_set_tolerant (self->loop, socket); + zloop_reader_set_tolerant (self->loop, (zsock_t *) sock); } else - zloop_reader_end (self->loop, socket); + zloop_reader_end (self->loop, (zsock_t *) sock); } } @@ -1263,8 +1269,8 @@ static int s_client_handle_ticket (zloop_t *loop, int timer_id, void *argument) { s_client_t *self = (s_client_t *) argument; - s_client_execute (self, expired_event); self->ticket = NULL; // Ticket is now dead + s_client_execute (self, expired_event); return 0; } diff --git a/src/ipc/wap_client/wap_client.c b/src/ipc/wap_client/wap_client.c index 40b577691..78726a90d 100644 --- a/src/ipc/wap_client/wap_client.c +++ b/src/ipc/wap_client/wap_client.c @@ -362,6 +362,7 @@ static void prepare_get_random_outs_command (client_t *self) { wap_proto_set_amounts (self->message, &self->args->amounts); + wap_proto_set_outs_count (self->message, self->args->outs_count); } diff --git a/src/ipc/wap_proto.c b/src/ipc/wap_proto.c index bc4522d7c..4a4e52e46 100644 --- a/src/ipc/wap_proto.c +++ b/src/ipc/wap_proto.c @@ -2495,8 +2495,8 @@ wap_proto_test (bool verbose) { printf (" * wap_proto:"); - // Silence an "unused" warning by "using" the verbose variable - if (verbose) {;} + if (verbose) + printf ("\n"); // @selftest // Simple create/destroy test @@ -2556,6 +2556,7 @@ wap_proto_test (bool verbose) wap_proto_recv (self, input); assert (wap_proto_routing_id (self)); zlist_t *block_ids = wap_proto_get_block_ids (self); + assert (block_ids); assert (zlist_size (block_ids) == 2); assert (streq ((char *) zlist_first (block_ids), "Name: Brutus")); assert (streq ((char *) zlist_next (block_ids), "Age: 43")); @@ -2585,7 +2586,8 @@ wap_proto_test (bool verbose) char *content = zmsg_popstr (wap_proto_block_data (self)); assert (streq (content, "Captcha Diem")); zstr_free (&content); - zmsg_destroy (&blocks_ok_block_data); + if (instance == 1) + zmsg_destroy (&blocks_ok_block_data); } wap_proto_set_id (self, WAP_PROTO_PUT); @@ -2599,7 +2601,8 @@ wap_proto_test (bool verbose) wap_proto_recv (self, input); assert (wap_proto_routing_id (self)); assert (memcmp (zchunk_data (wap_proto_tx_as_hex (self)), "Captcha Diem", 12) == 0); - zchunk_destroy (&put_tx_as_hex); + if (instance == 1) + zchunk_destroy (&put_tx_as_hex); } wap_proto_set_id (self, WAP_PROTO_PUT_OK); @@ -2625,7 +2628,8 @@ wap_proto_test (bool verbose) wap_proto_recv (self, input); assert (wap_proto_routing_id (self)); assert (memcmp (zchunk_data (wap_proto_tx_id (self)), "Captcha Diem", 12) == 0); - zchunk_destroy (&output_indexes_tx_id); + if (instance == 1) + zchunk_destroy (&output_indexes_tx_id); } wap_proto_set_id (self, WAP_PROTO_OUTPUT_INDEXES_OK); @@ -2641,7 +2645,8 @@ wap_proto_test (bool verbose) assert (wap_proto_routing_id (self)); assert (wap_proto_status (self) == 123); assert (zframe_streq (wap_proto_o_indexes (self), "Captcha Diem")); - zframe_destroy (&output_indexes_ok_o_indexes); + if (instance == 1) + zframe_destroy (&output_indexes_ok_o_indexes); } wap_proto_set_id (self, WAP_PROTO_RANDOM_OUTS); @@ -2657,7 +2662,8 @@ wap_proto_test (bool verbose) assert (wap_proto_routing_id (self)); assert (wap_proto_outs_count (self) == 123); assert (zframe_streq (wap_proto_amounts (self), "Captcha Diem")); - zframe_destroy (&random_outs_amounts); + if (instance == 1) + zframe_destroy (&random_outs_amounts); } wap_proto_set_id (self, WAP_PROTO_RANDOM_OUTS_OK); @@ -2673,7 +2679,8 @@ wap_proto_test (bool verbose) assert (wap_proto_routing_id (self)); assert (wap_proto_status (self) == 123); assert (zframe_streq (wap_proto_random_outputs (self), "Captcha Diem")); - zframe_destroy (&random_outs_ok_random_outputs); + if (instance == 1) + zframe_destroy (&random_outs_ok_random_outputs); } wap_proto_set_id (self, WAP_PROTO_GET_HEIGHT); @@ -2711,7 +2718,8 @@ wap_proto_test (bool verbose) wap_proto_recv (self, input); assert (wap_proto_routing_id (self)); assert (memcmp (zchunk_data (wap_proto_tx_id (self)), "Captcha Diem", 12) == 0); - zchunk_destroy (&get_tx_id); + if (instance == 1) + zchunk_destroy (&get_tx_id); } wap_proto_set_id (self, WAP_PROTO_GET_OK); @@ -2725,7 +2733,8 @@ wap_proto_test (bool verbose) wap_proto_recv (self, input); assert (wap_proto_routing_id (self)); assert (memcmp (zchunk_data (wap_proto_tx_data (self)), "Captcha Diem", 12) == 0); - zchunk_destroy (&get_ok_tx_data); + if (instance == 1) + zchunk_destroy (&get_ok_tx_data); } wap_proto_set_id (self, WAP_PROTO_SAVE_BC); @@ -2762,7 +2771,8 @@ wap_proto_test (bool verbose) wap_proto_recv (self, input); assert (wap_proto_routing_id (self)); assert (memcmp (zchunk_data (wap_proto_address (self)), "Captcha Diem", 12) == 0); - zchunk_destroy (&start_address); + if (instance == 1) + zchunk_destroy (&start_address); assert (wap_proto_thread_count (self) == 123); } wap_proto_set_id (self, WAP_PROTO_START_OK); @@ -2845,9 +2855,11 @@ wap_proto_test (bool verbose) assert (wap_proto_routing_id (self)); assert (wap_proto_status (self) == 123); assert (zframe_streq (wap_proto_white_list (self), "Captcha Diem")); - zframe_destroy (&get_peer_list_ok_white_list); + if (instance == 1) + zframe_destroy (&get_peer_list_ok_white_list); assert (zframe_streq (wap_proto_gray_list (self), "Captcha Diem")); - zframe_destroy (&get_peer_list_ok_gray_list); + if (instance == 1) + zframe_destroy (&get_peer_list_ok_gray_list); } wap_proto_set_id (self, WAP_PROTO_GET_MINING_STATUS); @@ -2879,7 +2891,8 @@ wap_proto_test (bool verbose) assert (wap_proto_speed (self) == 123); assert (wap_proto_thread_count (self) == 123); assert (memcmp (zchunk_data (wap_proto_address (self)), "Captcha Diem", 12) == 0); - zchunk_destroy (&get_mining_status_ok_address); + if (instance == 1) + zchunk_destroy (&get_mining_status_ok_address); } wap_proto_set_id (self, WAP_PROTO_SET_LOG_HASH_RATE); @@ -2999,7 +3012,8 @@ wap_proto_test (bool verbose) assert (wap_proto_routing_id (self)); assert (wap_proto_status (self) == 123); assert (memcmp (zchunk_data (wap_proto_hash (self)), "Captcha Diem", 12) == 0); - zchunk_destroy (&get_block_hash_ok_hash); + if (instance == 1) + zchunk_destroy (&get_block_hash_ok_hash); } wap_proto_set_id (self, WAP_PROTO_GET_BLOCK_TEMPLATE); @@ -3015,7 +3029,8 @@ wap_proto_test (bool verbose) assert (wap_proto_routing_id (self)); assert (wap_proto_reserve_size (self) == 123); assert (memcmp (zchunk_data (wap_proto_address (self)), "Captcha Diem", 12) == 0); - zchunk_destroy (&get_block_template_address); + if (instance == 1) + zchunk_destroy (&get_block_template_address); } wap_proto_set_id (self, WAP_PROTO_GET_BLOCK_TEMPLATE_OK); @@ -3039,9 +3054,11 @@ wap_proto_test (bool verbose) assert (wap_proto_height (self) == 123); assert (wap_proto_difficulty (self) == 123); assert (memcmp (zchunk_data (wap_proto_prev_hash (self)), "Captcha Diem", 12) == 0); - zchunk_destroy (&get_block_template_ok_prev_hash); + if (instance == 1) + zchunk_destroy (&get_block_template_ok_prev_hash); assert (memcmp (zchunk_data (wap_proto_block_template_blob (self)), "Captcha Diem", 12) == 0); - zchunk_destroy (&get_block_template_ok_block_template_blob); + if (instance == 1) + zchunk_destroy (&get_block_template_ok_block_template_blob); } wap_proto_set_id (self, WAP_PROTO_STOP); diff --git a/src/mnemonics/CMakeLists.txt b/src/mnemonics/CMakeLists.txt index ce9520956..ec298c271 100644 --- a/src/mnemonics/CMakeLists.txt +++ b/src/mnemonics/CMakeLists.txt @@ -34,10 +34,13 @@ set(mnemonics_headers) set(mnemonics_private_headers electrum-words.h english.h + german.h + italian.h japanese.h language_base.h old_english.h portuguese.h + russian.h singleton.h spanish.h) diff --git a/src/mnemonics/electrum-words.cpp b/src/mnemonics/electrum-words.cpp index 9c42c5792..47c0165b8 100644 --- a/src/mnemonics/electrum-words.cpp +++ b/src/mnemonics/electrum-words.cpp @@ -52,9 +52,12 @@ #include #include "english.h" +#include "italian.h" +#include "german.h" #include "spanish.h" #include "portuguese.h" #include "japanese.h" +#include "russian.h" #include "old_english.h" #include "language_base.h" #include "singleton.h" @@ -78,8 +81,11 @@ namespace std::vector language_instances({ Language::Singleton::instance(), Language::Singleton::instance(), + Language::Singleton::instance(), + Language::Singleton::instance(), Language::Singleton::instance(), Language::Singleton::instance(), + Language::Singleton::instance(), Language::Singleton::instance() }); @@ -293,6 +299,18 @@ namespace crypto { language = Language::Singleton::instance(); } + else if (language_name == "Italian") + { + language = Language::Singleton::instance(); + } + else if (language_name == "German") + { + language = Language::Singleton::instance(); + } + else if (language_name == "Russian") + { + language = Language::Singleton::instance(); + } else { return false; @@ -340,7 +358,10 @@ namespace crypto std::vector language_instances({ Language::Singleton::instance(), Language::Singleton::instance(), + Language::Singleton::instance(), + Language::Singleton::instance(), Language::Singleton::instance(), + Language::Singleton::instance(), Language::Singleton::instance() }); for (std::vector::iterator it = language_instances.begin(); diff --git a/src/mnemonics/english.h b/src/mnemonics/english.h index fee428817..c6d32a78e 100644 --- a/src/mnemonics/english.h +++ b/src/mnemonics/english.h @@ -1,5 +1,3 @@ -// Word list originally created as part of the Electrum project, Copyright (C) 2014 Thomas Voegtlin -// // Copyright (c) 2014-2015, The Monero Project // // All rights reserved. diff --git a/src/mnemonics/german.h b/src/mnemonics/german.h new file mode 100644 index 000000000..431550c86 --- /dev/null +++ b/src/mnemonics/german.h @@ -0,0 +1,1693 @@ +// Word list created by Monero contributor Shrikez +// +// Copyright (c) 2014-2015, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/*! + * \file german.h + * + * \brief German word list and map. + */ + +#ifndef GERMAN_H +#define GERMAN_H + +#include +#include +#include "language_base.h" +#include + +/*! + * \namespace Language + * \brief Mnemonic language related namespace. + */ +namespace Language +{ + class German: public Base + { + public: + German() + { + word_list = new std::vector({ + "Abakus", + "Abart", + "abbilden", + "Abbruch", + "Abdrift", + "Abendrot", + "Abfahrt", + "abfeuern", + "Abflug", + "abfragen", + "Abglanz", + "abhärten", + "abheben", + "Abhilfe", + "Abitur", + "Abkehr", + "Ablauf", + "ablecken", + "Ablösung", + "Abnehmer", + "abnutzen", + "Abonnent", + "Abrasion", + "Abrede", + "abrüsten", + "Absicht", + "Absprung", + "Abstand", + "absuchen", + "Abteil", + "Abundanz", + "abwarten", + "Abwurf", + "Abzug", + "Achse", + "Achtung", + "Acker", + "Aderlass", + "Adler", + "Admiral", + "Adresse", + "Affe", + "Affront", + "Afrika", + "Aggregat", + "Agilität", + "ähneln", + "Ahnung", + "Ahorn", + "Akazie", + "Akkord", + "Akrobat", + "Aktfoto", + "Aktivist", + "Albatros", + "Alchimie", + "Alemanne", + "Alibi", + "Alkohol", + "Allee", + "Allüre", + "Almosen", + "Almweide", + "Aloe", + "Alpaka", + "Alpental", + "Alphabet", + "Alpinist", + "Alraune", + "Altbier", + "Alter", + "Altflöte", + "Altruist", + "Alublech", + "Aludose", + "Amateur", + "Amazonas", + "Ameise", + "Amnesie", + "Amok", + "Ampel", + "Amphibie", + "Ampulle", + "Amsel", + "Amulett", + "Anakonda", + "Analogie", + "Ananas", + "Anarchie", + "Anatomie", + "Anbau", + "Anbeginn", + "anbieten", + "Anblick", + "ändern", + "andocken", + "Andrang", + "anecken", + "Anflug", + "Anfrage", + "Anführer", + "Angebot", + "Angler", + "Anhalter", + "Anhöhe", + "Animator", + "Anis", + "Anker", + "ankleben", + "Ankunft", + "Anlage", + "anlocken", + "Anmut", + "Annahme", + "Anomalie", + "Anonymus", + "Anorak", + "anpeilen", + "Anrecht", + "Anruf", + "Ansage", + "Anschein", + "Ansicht", + "Ansporn", + "Anteil", + "Antlitz", + "Antrag", + "Antwort", + "Anwohner", + "Aorta", + "Apfel", + "Appetit", + "Applaus", + "Aquarium", + "Arbeit", + "Arche", + "Argument", + "Arktis", + "Armband", + "Aroma", + "Asche", + "Askese", + "Asphalt", + "Asteroid", + "Ästhetik", + "Astronom", + "Atelier", + "Athlet", + "Atlantik", + "Atmung", + "Audienz", + "aufatmen", + "Auffahrt", + "aufholen", + "aufregen", + "Aufsatz", + "Auftritt", + "Aufwand", + "Augapfel", + "Auktion", + "Ausbruch", + "Ausflug", + "Ausgabe", + "Aushilfe", + "Ausland", + "Ausnahme", + "Aussage", + "Autobahn", + "Avocado", + "Axthieb", + "Bach", + "backen", + "Badesee", + "Bahnhof", + "Balance", + "Balkon", + "Ballett", + "Balsam", + "Banane", + "Bandage", + "Bankett", + "Barbar", + "Barde", + "Barett", + "Bargeld", + "Barkasse", + "Barriere", + "Bart", + "Bass", + "Bastler", + "Batterie", + "Bauch", + "Bauer", + "Bauholz", + "Baujahr", + "Baum", + "Baustahl", + "Bauteil", + "Bauweise", + "Bazar", + "beachten", + "Beatmung", + "beben", + "Becher", + "Becken", + "bedanken", + "beeilen", + "beenden", + "Beere", + "befinden", + "Befreier", + "Begabung", + "Begierde", + "begrüßen", + "Beiboot", + "Beichte", + "Beifall", + "Beigabe", + "Beil", + "Beispiel", + "Beitrag", + "beizen", + "bekommen", + "beladen", + "Beleg", + "bellen", + "belohnen", + "Bemalung", + "Bengel", + "Benutzer", + "Benzin", + "beraten", + "Bereich", + "Bergluft", + "Bericht", + "Bescheid", + "Besitz", + "besorgen", + "Bestand", + "Besuch", + "betanken", + "beten", + "betören", + "Bett", + "Beule", + "Beute", + "Bewegung", + "bewirken", + "Bewohner", + "bezahlen", + "Bezug", + "biegen", + "Biene", + "Bierzelt", + "bieten", + "Bikini", + "Bildung", + "Billard", + "binden", + "Biobauer", + "Biologe", + "Bionik", + "Biotop", + "Birke", + "Bison", + "Bitte", + "Biwak", + "Bizeps", + "blasen", + "Blatt", + "Blauwal", + "Blende", + "Blick", + "Blitz", + "Blockade", + "Blödelei", + "Blondine", + "Blues", + "Blume", + "Blut", + "Bodensee", + "Bogen", + "Boje", + "Bollwerk", + "Bonbon", + "Bonus", + "Boot", + "Bordarzt", + "Börse", + "Böschung", + "Boudoir", + "Boxkampf", + "Boykott", + "Brahms", + "Brandung", + "Brauerei", + "Brecher", + "Breitaxt", + "Bremse", + "brennen", + "Brett", + "Brief", + "Brigade", + "Brillanz", + "bringen", + "brodeln", + "Brosche", + "Brötchen", + "Brücke", + "Brunnen", + "Brüste", + "Brutofen", + "Buch", + "Büffel", + "Bugwelle", + "Bühne", + "Buletten", + "Bullauge", + "Bumerang", + "bummeln", + "Buntglas", + "Bürde", + "Burgherr", + "Bursche", + "Busen", + "Buslinie", + "Bussard", + "Butangas", + "Butter", + "Cabrio", + "campen", + "Captain", + "Cartoon", + "Cello", + "Chalet", + "Charisma", + "Chefarzt", + "Chiffon", + "Chipsatz", + "Chirurg", + "Chor", + "Chronik", + "Chuzpe", + "Clubhaus", + "Cockpit", + "Codewort", + "Cognac", + "Coladose", + "Computer", + "Coupon", + "Cousin", + "Cracking", + "Crash", + "Curry", + "Dach", + "Dackel", + "daddeln", + "daliegen", + "Dame", + "Dammbau", + "Dämon", + "Dampflok", + "Dank", + "Darm", + "Datei", + "Datsche", + "Datteln", + "Datum", + "Dauer", + "Daunen", + "Deckel", + "Decoder", + "Defekt", + "Degen", + "Dehnung", + "Deiche", + "Dekade", + "Dekor", + "Delfin", + "Demut", + "denken", + "Deponie", + "Design", + "Desktop", + "Dessert", + "Detail", + "Detektiv", + "Dezibel", + "Diadem", + "Diagnose", + "Dialekt", + "Diamant", + "Dichter", + "Dickicht", + "Diesel", + "Diktat", + "Diplom", + "Direktor", + "Dirne", + "Diskurs", + "Distanz", + "Docht", + "Dohle", + "Dolch", + "Domäne", + "Donner", + "Dorade", + "Dorf", + "Dörrobst", + "Dorsch", + "Dossier", + "Dozent", + "Drachen", + "Draht", + "Drama", + "Drang", + "Drehbuch", + "Dreieck", + "Dressur", + "Drittel", + "Drossel", + "Druck", + "Duell", + "Duft", + "Düne", + "Dünung", + "dürfen", + "Duschbad", + "Düsenjet", + "Dynamik", + "Ebbe", + "Echolot", + "Echse", + "Eckball", + "Edding", + "Edelweiß", + "Eden", + "Edition", + "Efeu", + "Effekte", + "Egoismus", + "Ehre", + "Eiablage", + "Eiche", + "Eidechse", + "Eidotter", + "Eierkopf", + "Eigelb", + "Eiland", + "Eilbote", + "Eimer", + "einatmen", + "Einband", + "Eindruck", + "Einfall", + "Eingang", + "Einkauf", + "einladen", + "Einöde", + "Einrad", + "Eintopf", + "Einwurf", + "Einzug", + "Eisbär", + "Eisen", + "Eishöhle", + "Eismeer", + "Eiweiß", + "Ekstase", + "Elan", + "Elch", + "Elefant", + "Eleganz", + "Element", + "Elfe", + "Elite", + "Elixier", + "Ellbogen", + "Eloquenz", + "Emigrant", + "Emission", + "Emotion", + "Empathie", + "Empfang", + "Endzeit", + "Energie", + "Engpass", + "Enkel", + "Enklave", + "Ente", + "entheben", + "Entität", + "entladen", + "Entwurf", + "Episode", + "Epoche", + "erachten", + "Erbauer", + "erblühen", + "Erdbeere", + "Erde", + "Erdgas", + "Erdkunde", + "Erdnuss", + "Erdöl", + "Erdteil", + "Ereignis", + "Eremit", + "erfahren", + "Erfolg", + "erfreuen", + "erfüllen", + "Ergebnis", + "erhitzen", + "erkalten", + "erkennen", + "erleben", + "Erlösung", + "ernähren", + "erneuern", + "Ernte", + "Eroberer", + "eröffnen", + "Erosion", + "Erotik", + "Erpel", + "erraten", + "Erreger", + "erröten", + "Ersatz", + "Erstflug", + "Ertrag", + "Eruption", + "erwarten", + "erwidern", + "Erzbau", + "Erzeuger", + "erziehen", + "Esel", + "Eskimo", + "Eskorte", + "Espe", + "Espresso", + "essen", + "Etage", + "Etappe", + "Etat", + "Ethik", + "Etikett", + "Etüde", + "Eule", + "Euphorie", + "Europa", + "Everest", + "Examen", + "Exil", + "Exodus", + "Extrakt", + "Fabel", + "Fabrik", + "Fachmann", + "Fackel", + "Faden", + "Fagott", + "Fahne", + "Faible", + "Fairness", + "Fakt", + "Fakultät", + "Falke", + "Fallobst", + "Fälscher", + "Faltboot", + "Familie", + "Fanclub", + "Fanfare", + "Fangarm", + "Fantasie", + "Farbe", + "Farmhaus", + "Farn", + "Fasan", + "Faser", + "Fassung", + "fasten", + "Faulheit", + "Fauna", + "Faust", + "Favorit", + "Faxgerät", + "Fazit", + "fechten", + "Federboa", + "Fehler", + "Feier", + "Feige", + "feilen", + "Feinripp", + "Feldbett", + "Felge", + "Fellpony", + "Felswand", + "Ferien", + "Ferkel", + "Fernweh", + "Ferse", + "Fest", + "Fettnapf", + "Feuer", + "Fiasko", + "Fichte", + "Fiktion", + "Film", + "Filter", + "Filz", + "Finanzen", + "Findling", + "Finger", + "Fink", + "Finnwal", + "Fisch", + "Fitness", + "Fixpunkt", + "Fixstern", + "Fjord", + "Flachbau", + "Flagge", + "Flamenco", + "Flanke", + "Flasche", + "Flaute", + "Fleck", + "Flegel", + "flehen", + "Fleisch", + "fliegen", + "Flinte", + "Flirt", + "Flocke", + "Floh", + "Floskel", + "Floß", + "Flöte", + "Flugzeug", + "Flunder", + "Flusstal", + "Flutung", + "Fockmast", + "Fohlen", + "Föhnlage", + "Fokus", + "folgen", + "Foliant", + "Folklore", + "Fontäne", + "Förde", + "Forelle", + "Format", + "Forscher", + "Fortgang", + "Forum", + "Fotograf", + "Frachter", + "Fragment", + "Fraktion", + "fräsen", + "Frauenpo", + "Freak", + "Fregatte", + "Freiheit", + "Freude", + "Frieden", + "Frohsinn", + "Frosch", + "Frucht", + "Frühjahr", + "Fuchs", + "Fügung", + "fühlen", + "Füller", + "Fundbüro", + "Funkboje", + "Funzel", + "Furnier", + "Fürsorge", + "Fusel", + "Fußbad", + "Futteral", + "Gabelung", + "gackern", + "Gage", + "gähnen", + "Galaxie", + "Galeere", + "Galopp", + "Gameboy", + "Gamsbart", + "Gandhi", + "Gang", + "Garage", + "Gardine", + "Garküche", + "Garten", + "Gasthaus", + "Gattung", + "gaukeln", + "Gazelle", + "Gebäck", + "Gebirge", + "Gebräu", + "Geburt", + "Gedanke", + "Gedeck", + "Gedicht", + "Gefahr", + "Gefieder", + "Geflügel", + "Gefühl", + "Gegend", + "Gehirn", + "Gehöft", + "Gehweg", + "Geige", + "Geist", + "Gelage", + "Geld", + "Gelenk", + "Gelübde", + "Gemälde", + "Gemeinde", + "Gemüse", + "genesen", + "Genuss", + "Gepäck", + "Geranie", + "Gericht", + "Germane", + "Geruch", + "Gesang", + "Geschenk", + "Gesetz", + "Gesindel", + "Gesöff", + "Gespan", + "Gestade", + "Gesuch", + "Getier", + "Getränk", + "Getümmel", + "Gewand", + "Geweih", + "Gewitter", + "Gewölbe", + "Geysir", + "Giftzahn", + "Gipfel", + "Giraffe", + "Gitarre", + "glänzen", + "Glasauge", + "Glatze", + "Gleis", + "Globus", + "Glück", + "glühen", + "Glutofen", + "Goldzahn", + "Gondel", + "gönnen", + "Gottheit", + "graben", + "Grafik", + "Grashalm", + "Graugans", + "greifen", + "Grenze", + "grillen", + "Groschen", + "Grotte", + "Grube", + "Grünalge", + "Gruppe", + "gruseln", + "Gulasch", + "Gummibär", + "Gurgel", + "Gürtel", + "Güterzug", + "Haarband", + "Habicht", + "hacken", + "hadern", + "Hafen", + "Hagel", + "Hähnchen", + "Haifisch", + "Haken", + "Halbaffe", + "Halsader", + "halten", + "Halunke", + "Handbuch", + "Hanf", + "Harfe", + "Harnisch", + "härten", + "Harz", + "Hasenohr", + "Haube", + "hauchen", + "Haupt", + "Haut", + "Havarie", + "Hebamme", + "hecheln", + "Heck", + "Hedonist", + "Heiler", + "Heimat", + "Heizung", + "Hektik", + "Held", + "helfen", + "Helium", + "Hemd", + "hemmen", + "Hengst", + "Herd", + "Hering", + "Herkunft", + "Hermelin", + "Herrchen", + "Herzdame", + "Heulboje", + "Hexe", + "Hilfe", + "Himbeere", + "Himmel", + "Hingabe", + "hinhören", + "Hinweis", + "Hirsch", + "Hirte", + "Hitzkopf", + "Hobel", + "Hochform", + "Hocker", + "hoffen", + "Hofhund", + "Hofnarr", + "Höhenzug", + "Hohlraum", + "Hölle", + "Holzboot", + "Honig", + "Honorar", + "horchen", + "Hörprobe", + "Höschen", + "Hotel", + "Hubraum", + "Hufeisen", + "Hügel", + "huldigen", + "Hülle", + "Humbug", + "Hummer", + "Humor", + "Hund", + "Hunger", + "Hupe", + "Hürde", + "Hurrikan", + "Hydrant", + "Hypnose", + "Ibis", + "Idee", + "Idiot", + "Igel", + "Illusion", + "Imitat", + "impfen", + "Import", + "Inferno", + "Ingwer", + "Inhalte", + "Inland", + "Insekt", + "Ironie", + "Irrfahrt", + "Irrtum", + "Isolator", + "Istwert", + "Jacke", + "Jade", + "Jagdhund", + "Jäger", + "Jaguar", + "Jahr", + "Jähzorn", + "Jazzfest", + "Jetpilot", + "jobben", + "Jochbein", + "jodeln", + "Jodsalz", + "Jolle", + "Journal", + "Jubel", + "Junge", + "Junimond", + "Jupiter", + "Jutesack", + "Juwel", + "Kabarett", + "Kabine", + "Kabuff", + "Käfer", + "Kaffee", + "Kahlkopf", + "Kaimauer", + "Kajüte", + "Kaktus", + "Kaliber", + "Kaltluft", + "Kamel", + "kämmen", + "Kampagne", + "Kanal", + "Känguru", + "Kanister", + "Kanone", + "Kante", + "Kanu", + "kapern", + "Kapitän", + "Kapuze", + "Karneval", + "Karotte", + "Käsebrot", + "Kasper", + "Kastanie", + "Katalog", + "Kathode", + "Katze", + "kaufen", + "Kaugummi", + "Kauz", + "Kehle", + "Keilerei", + "Keksdose", + "Kellner", + "Keramik", + "Kerze", + "Kessel", + "Kette", + "keuchen", + "kichern", + "Kielboot", + "Kindheit", + "Kinnbart", + "Kinosaal", + "Kiosk", + "Kissen", + "Klammer", + "Klang", + "Klapprad", + "Klartext", + "kleben", + "Klee", + "Kleinod", + "Klima", + "Klingel", + "Klippe", + "Klischee", + "Kloster", + "Klugheit", + "Klüngel", + "kneten", + "Knie", + "Knöchel", + "knüpfen", + "Kobold", + "Kochbuch", + "Kohlrabi", + "Koje", + "Kokosöl", + "Kolibri", + "Kolumne", + "Kombüse", + "Komiker", + "kommen", + "Konto", + "Konzept", + "Kopfkino", + "Kordhose", + "Korken", + "Korsett", + "Kosename", + "Krabbe", + "Krach", + "Kraft", + "Krähe", + "Kralle", + "Krapfen", + "Krater", + "kraulen", + "Kreuz", + "Krokodil", + "Kröte", + "Kugel", + "Kuhhirt", + "Kühnheit", + "Künstler", + "Kurort", + "Kurve", + "Kurzfilm", + "kuscheln", + "küssen", + "Kutter", + "Labor", + "lachen", + "Lackaffe", + "Ladeluke", + "Lagune", + "Laib", + "Lakritze", + "Lammfell", + "Land", + "Langmut", + "Lappalie", + "Last", + "Laterne", + "Latzhose", + "Laubsäge", + "laufen", + "Laune", + "Lausbub", + "Lavasee", + "Leben", + "Leder", + "Leerlauf", + "Lehm", + "Lehrer", + "leihen", + "Lektüre", + "Lenker", + "Lerche", + "Leseecke", + "Leuchter", + "Lexikon", + "Libelle", + "Libido", + "Licht", + "Liebe", + "liefern", + "Liftboy", + "Limonade", + "Lineal", + "Linoleum", + "List", + "Liveband", + "Lobrede", + "locken", + "Löffel", + "Logbuch", + "Logik", + "Lohn", + "Loipe", + "Lokal", + "Lorbeer", + "Lösung", + "löten", + "Lottofee", + "Löwe", + "Luchs", + "Luder", + "Luftpost", + "Luke", + "Lümmel", + "Lunge", + "lutschen", + "Luxus", + "Macht", + "Magazin", + "Magier", + "Magnet", + "mähen", + "Mahlzeit", + "Mahnmal", + "Maibaum", + "Maisbrei", + "Makel", + "malen", + "Mammut", + "Maniküre", + "Mantel", + "Marathon", + "Marder", + "Marine", + "Marke", + "Marmor", + "Märzluft", + "Maske", + "Maßanzug", + "Maßkrug", + "Mastkorb", + "Material", + "Matratze", + "Mauerbau", + "Maulkorb", + "Mäuschen", + "Mäzen", + "Medium", + "Meinung", + "melden", + "Melodie", + "Mensch", + "Merkmal", + "Messe", + "Metall", + "Meteor", + "Methode", + "Metzger", + "Mieze", + "Milchkuh", + "Mimose", + "Minirock", + "Minute", + "mischen", + "Missetat", + "mitgehen", + "Mittag", + "Mixtape", + "Möbel", + "Modul", + "mögen", + "Möhre", + "Molch", + "Moment", + "Monat", + "Mondflug", + "Monitor", + "Monokini", + "Monster", + "Monument", + "Moorhuhn", + "Moos", + "Möpse", + "Moral", + "Mörtel", + "Motiv", + "Motorrad", + "Möwe", + "Mühe", + "Mulatte", + "Müller", + "Mumie", + "Mund", + "Münze", + "Muschel", + "Muster", + "Mythos", + "Nabel", + "Nachtzug", + "Nackedei", + "Nagel", + "Nähe", + "Nähnadel", + "Namen", + "Narbe", + "Narwal", + "Nasenbär", + "Natur", + "Nebel", + "necken", + "Neffe", + "Neigung", + "Nektar", + "Nenner", + "Neptun", + "Nerz", + "Nessel", + "Nestbau", + "Netz", + "Neubau", + "Neuerung", + "Neugier", + "nicken", + "Niere", + "Nilpferd", + "nisten", + "Nocke", + "Nomade", + "Nordmeer", + "Notdurft", + "Notstand", + "Notwehr", + "Nudismus", + "Nuss", + "Nutzhanf", + "Oase", + "Obdach", + "Oberarzt", + "Objekt", + "Oboe", + "Obsthain", + "Ochse", + "Odyssee", + "Ofenholz", + "öffnen", + "Ohnmacht", + "Ohrfeige", + "Ohrwurm", + "Ökologie", + "Oktave", + "Ölberg", + "Olive", + "Ölkrise", + "Omelett", + "Onkel", + "Oper", + "Optiker", + "Orange", + "Orchidee", + "ordnen", + "Orgasmus", + "Orkan", + "Ortskern", + "Ortung", + "Ostasien", + "Ozean", + "Paarlauf", + "Packeis", + "paddeln", + "Paket", + "Palast", + "Pandabär", + "Panik", + "Panorama", + "Panther", + "Papagei", + "Papier", + "Paprika", + "Paradies", + "Parka", + "Parodie", + "Partner", + "Passant", + "Patent", + "Patzer", + "Pause", + "Pavian", + "Pedal", + "Pegel", + "peilen", + "Perle", + "Person", + "Pfad", + "Pfau", + "Pferd", + "Pfleger", + "Physik", + "Pier", + "Pilotwal", + "Pinzette", + "Piste", + "Plakat", + "Plankton", + "Platin", + "Plombe", + "plündern", + "Pobacke", + "Pokal", + "polieren", + "Popmusik", + "Porträt", + "Posaune", + "Postamt", + "Pottwal", + "Pracht", + "Pranke", + "Preis", + "Primat", + "Prinzip", + "Protest", + "Proviant", + "Prüfung", + "Pubertät", + "Pudding", + "Pullover", + "Pulsader", + "Punkt", + "Pute", + "Putsch", + "Puzzle", + "Python", + "quaken", + "Qualle", + "Quark", + "Quellsee", + "Querkopf", + "Quitte", + "Quote", + "Rabauke", + "Rache", + "Radclub", + "Radhose", + "Radio", + "Radtour", + "Rahmen", + "Rampe", + "Randlage", + "Ranzen", + "Rapsöl", + "Raserei", + "rasten", + "Rasur", + "Rätsel", + "Raubtier", + "Raumzeit", + "Rausch", + "Reaktor", + "Realität", + "Rebell", + "Rede", + "Reetdach", + "Regatta", + "Regen", + "Rehkitz", + "Reifen", + "Reim", + "Reise", + "Reizung", + "Rekord", + "Relevanz", + "Rennboot", + "Respekt", + "Restmüll", + "retten", + "Reue", + "Revolte", + "Rhetorik", + "Rhythmus", + "Richtung", + "Riegel", + "Rindvieh", + "Rippchen", + "Ritter", + "Robbe", + "Roboter", + "Rockband", + "Rohdaten", + "Roller", + "Roman", + "röntgen", + "Rose", + "Rosskur", + "Rost", + "Rotahorn", + "Rotglut", + "Rotznase", + "Rubrik", + "Rückweg", + "Rufmord", + "Ruhe", + "Ruine", + "Rumpf", + "Runde", + "Rüstung", + "rütteln", + "Saaltür", + "Saatguts", + "Säbel", + "Sachbuch", + "Sack", + "Saft", + "sagen", + "Sahneeis", + "Salat", + "Salbe", + "Salz", + "Sammlung", + "Samt", + "Sandbank", + "Sanftmut", + "Sardine", + "Satire", + "Sattel", + "Satzbau", + "Sauerei", + "Saum", + "Säure", + "Schall", + "Scheitel", + "Schiff", + "Schlager", + "Schmied", + "Schnee", + "Scholle", + "Schrank", + "Schulbus", + "Schwan", + "Seeadler", + "Seefahrt", + "Seehund", + "Seeufer", + "segeln", + "Sehnerv", + "Seide", + "Seilzug", + "Senf", + "Sessel", + "Seufzer", + "Sexgott", + "Sichtung", + "Signal", + "Silber", + "singen", + "Sinn", + "Sirup", + "Sitzbank", + "Skandal", + "Skikurs", + "Skipper", + "Skizze", + "Smaragd", + "Socke", + "Sohn", + "Sommer", + "Songtext", + "Sorte", + "Spagat", + "Spannung", + "Spargel", + "Specht", + "Speiseöl", + "Spiegel", + "Sport", + "spülen", + "Stadtbus", + "Stall", + "Stärke", + "Stativ", + "staunen", + "Stern", + "Stiftung", + "Stollen", + "Strömung", + "Sturm", + "Substanz", + "Südalpen", + "Sumpf", + "surfen", + "Tabak", + "Tafel", + "Tagebau", + "takeln", + "Taktung", + "Talsohle", + "Tand", + "Tanzbär", + "Tapir", + "Tarantel", + "Tarnname", + "Tasse", + "Tatnacht", + "Tatsache", + "Tatze", + "Taube", + "tauchen", + "Taufpate", + "Taumel", + "Teelicht", + "Teich", + "teilen", + "Tempo", + "Tenor", + "Terrasse", + "Testflug", + "Theater", + "Thermik", + "ticken", + "Tiefflug", + "Tierart", + "Tigerhai", + "Tinte", + "Tischler", + "toben", + "Toleranz", + "Tölpel", + "Tonband", + "Topf", + "Topmodel", + "Torbogen", + "Torlinie", + "Torte", + "Tourist", + "Tragesel", + "trampeln", + "Trapez", + "Traum", + "treffen", + "Trennung", + "Treue", + "Trick", + "trimmen", + "Trödel", + "Trost", + "Trumpf", + "tüfteln", + "Turban", + "Turm", + "Übermut", + "Ufer", + "Uhrwerk", + "umarmen", + "Umbau", + "Umfeld", + "Umgang", + "Umsturz", + "Unart", + "Unfug", + "Unimog", + "Unruhe", + "Unwucht", + "Uranerz", + "Urlaub", + "Urmensch", + "Utopie", + "Vakuum", + "Valuta", + "Vandale", + "Vase", + "Vektor", + "Ventil", + "Verb", + "Verdeck", + "Verfall", + "Vergaser", + "verhexen", + "Verlag", + "Vers", + "Vesper", + "Vieh", + "Viereck", + "Vinyl", + "Virus", + "Vitrine", + "Vollblut", + "Vorbote", + "Vorrat", + "Vorsicht", + "Vulkan", + "Wachstum", + "Wade", + "Wagemut", + "Wahlen", + "Wahrheit", + "Wald", + "Walhai", + "Wallach", + "Walnuss", + "Walzer", + "wandeln", + "Wanze", + "wärmen", + "Warnruf", + "Wäsche", + "Wasser", + "Weberei", + "wechseln", + "Wegegeld", + "wehren", + "Weiher", + "Weinglas", + "Weißbier", + "Weitwurf", + "Welle", + "Weltall", + "Werkbank", + "Werwolf", + "Wetter", + "wiehern", + "Wildgans", + "Wind", + "Wohl", + "Wohnort", + "Wolf", + "Wollust", + "Wortlaut", + "Wrack", + "Wunder", + "Wurfaxt", + "Wurst", + "Yacht", + "Yeti", + "Zacke", + "Zahl", + "zähmen", + "Zahnfee", + "Zäpfchen", + "Zaster", + "Zaumzeug", + "Zebra", + "zeigen", + "Zeitlupe", + "Zellkern", + "Zeltdach", + "Zensor", + "Zerfall", + "Zeug", + "Ziege", + "Zielfoto", + "Zimteis", + "Zobel", + "Zollhund", + "Zombie", + "Zöpfe", + "Zucht", + "Zufahrt", + "Zugfahrt", + "Zugvogel", + "Zündung", + "Zweck", + "Zyklop" + }); + unique_prefix_length = 4; + word_map = new std::unordered_map; + trimmed_word_map = new std::unordered_map; + language_name = "German"; + populate_maps(); + } + }; +} + +#endif diff --git a/src/mnemonics/italian.h b/src/mnemonics/italian.h new file mode 100644 index 000000000..41101203b --- /dev/null +++ b/src/mnemonics/italian.h @@ -0,0 +1,1693 @@ +// Word list created by Monero contributor Shrikez +// +// Copyright (c) 2014-2015, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/*! + * \file italian.h + * + * \brief Italian word list and map. + */ + +#ifndef ITALIAN_H +#define ITALIAN_H + +#include +#include +#include "language_base.h" +#include + +/*! + * \namespace Language + * \brief Mnemonic language related namespace. + */ +namespace Language +{ + class Italian: public Base + { + public: + Italian() + { + word_list = new std::vector({ + "abbinare", + "abbonato", + "abisso", + "abitare", + "abominio", + "accadere", + "accesso", + "acciaio", + "accordo", + "accumulo", + "acido", + "acqua", + "acrobata", + "acustico", + "adattare", + "addetto", + "addio", + "addome", + "adeguato", + "aderire", + "adorare", + "adottare", + "adozione", + "adulto", + "aereo", + "aerobica", + "affare", + "affetto", + "affidare", + "affogato", + "affronto", + "africano", + "afrodite", + "agenzia", + "aggancio", + "aggeggio", + "aggiunta", + "agio", + "agire", + "agitare", + "aglio", + "agnello", + "agosto", + "aiutare", + "albero", + "albo", + "alce", + "alchimia", + "alcool", + "alfabeto", + "algebra", + "alimento", + "allarme", + "alleanza", + "allievo", + "alloggio", + "alluce", + "alpi", + "alterare", + "altro", + "aluminio", + "amante", + "amarezza", + "ambiente", + "ambrosia", + "america", + "amico", + "ammalare", + "ammirare", + "amnesia", + "amnistia", + "amore", + "ampliare", + "amputare", + "analisi", + "anamnesi", + "ananas", + "anarchia", + "anatra", + "anca", + "ancorato", + "andare", + "androide", + "aneddoto", + "anello", + "angelo", + "angolino", + "anguilla", + "anidride", + "anima", + "annegare", + "anno", + "annuncio", + "anomalia", + "antenna", + "anticipo", + "aperto", + "apostolo", + "appalto", + "appello", + "appiglio", + "applauso", + "appoggio", + "appurare", + "aprile", + "aquila", + "arabo", + "arachidi", + "aragosta", + "arancia", + "arbitrio", + "archivio", + "arco", + "argento", + "argilla", + "aria", + "ariete", + "arma", + "armonia", + "aroma", + "arrivare", + "arrosto", + "arsenale", + "arte", + "artiglio", + "asfalto", + "asfissia", + "asino", + "asparagi", + "aspirina", + "assalire", + "assegno", + "assolto", + "assurdo", + "asta", + "astratto", + "atlante", + "atletica", + "atomo", + "atropina", + "attacco", + "attesa", + "attico", + "atto", + "attrarre", + "auguri", + "aula", + "aumento", + "aurora", + "auspicio", + "autista", + "auto", + "autunno", + "avanzare", + "avarizia", + "avere", + "aviatore", + "avido", + "avorio", + "avvenire", + "avviso", + "avvocato", + "azienda", + "azione", + "azzardo", + "azzurro", + "babbuino", + "bacio", + "badante", + "baffi", + "bagaglio", + "bagliore", + "bagno", + "balcone", + "balena", + "ballare", + "balordo", + "balsamo", + "bambola", + "bancomat", + "banda", + "barato", + "barba", + "barista", + "barriera", + "basette", + "basilico", + "bassista", + "bastare", + "battello", + "bavaglio", + "beccare", + "beduino", + "bellezza", + "bene", + "benzina", + "berretto", + "bestia", + "bevitore", + "bianco", + "bibbia", + "biberon", + "bibita", + "bici", + "bidone", + "bilancia", + "biliardo", + "binario", + "binocolo", + "biologia", + "biondina", + "biopsia", + "biossido", + "birbante", + "birra", + "biscotto", + "bisogno", + "bistecca", + "bivio", + "blindare", + "bloccare", + "bocca", + "bollire", + "bombola", + "bonifico", + "borghese", + "borsa", + "bottino", + "botulino", + "braccio", + "bradipo", + "branco", + "bravo", + "bresaola", + "bretelle", + "brevetto", + "briciola", + "brigante", + "brillare", + "brindare", + "brivido", + "broccoli", + "brontolo", + "bruciare", + "brufolo", + "bucare", + "buddista", + "budino", + "bufera", + "buffo", + "bugiardo", + "buio", + "buono", + "burrone", + "bussola", + "bustina", + "buttare", + "cabernet", + "cabina", + "cacao", + "cacciare", + "cactus", + "cadavere", + "caffe", + "calamari", + "calcio", + "caldaia", + "calmare", + "calunnia", + "calvario", + "calzone", + "cambiare", + "camera", + "camion", + "cammello", + "campana", + "canarino", + "cancello", + "candore", + "cane", + "canguro", + "cannone", + "canoa", + "cantare", + "canzone", + "caos", + "capanna", + "capello", + "capire", + "capo", + "capperi", + "capra", + "capsula", + "caraffa", + "carbone", + "carciofo", + "cardigan", + "carenza", + "caricare", + "carota", + "carrello", + "carta", + "casa", + "cascare", + "caserma", + "cashmere", + "casino", + "cassetta", + "castello", + "catalogo", + "catena", + "catorcio", + "cattivo", + "causa", + "cauzione", + "cavallo", + "caverna", + "caviglia", + "cavo", + "cazzotto", + "celibato", + "cemento", + "cenare", + "centrale", + "ceramica", + "cercare", + "ceretta", + "cerniera", + "certezza", + "cervello", + "cessione", + "cestino", + "cetriolo", + "chiave", + "chiedere", + "chilo", + "chimera", + "chiodo", + "chirurgo", + "chitarra", + "chiudere", + "ciabatta", + "ciao", + "cibo", + "ciccia", + "cicerone", + "ciclone", + "cicogna", + "cielo", + "cifra", + "cigno", + "ciliegia", + "cimitero", + "cinema", + "cinque", + "cintura", + "ciondolo", + "ciotola", + "cipolla", + "cippato", + "circuito", + "cisterna", + "citofono", + "ciuccio", + "civetta", + "civico", + "clausola", + "cliente", + "clima", + "clinica", + "cobra", + "coccole", + "cocktail", + "cocomero", + "codice", + "coesione", + "cogliere", + "cognome", + "colla", + "colomba", + "colpire", + "coltello", + "comando", + "comitato", + "commedia", + "comodino", + "compagna", + "comune", + "concerto", + "condotto", + "conforto", + "congiura", + "coniglio", + "consegna", + "conto", + "convegno", + "coperta", + "copia", + "coprire", + "corazza", + "corda", + "corleone", + "cornice", + "corona", + "corpo", + "corrente", + "corsa", + "cortesia", + "corvo", + "coso", + "costume", + "cotone", + "cottura", + "cozza", + "crampo", + "cratere", + "cravatta", + "creare", + "credere", + "crema", + "crescere", + "crimine", + "criterio", + "croce", + "crollare", + "cronaca", + "crostata", + "croupier", + "cubetto", + "cucciolo", + "cucina", + "cultura", + "cuoco", + "cuore", + "cupido", + "cupola", + "cura", + "curva", + "cuscino", + "custode", + "danzare", + "data", + "decennio", + "decidere", + "decollo", + "dedicare", + "dedurre", + "definire", + "delegare", + "delfino", + "delitto", + "demone", + "dentista", + "denuncia", + "deposito", + "derivare", + "deserto", + "designer", + "destino", + "detonare", + "dettagli", + "diagnosi", + "dialogo", + "diamante", + "diario", + "diavolo", + "dicembre", + "difesa", + "digerire", + "digitare", + "diluvio", + "dinamica", + "dipinto", + "diploma", + "diramare", + "dire", + "dirigere", + "dirupo", + "discesa", + "disdetta", + "disegno", + "disporre", + "dissenso", + "distacco", + "dito", + "ditta", + "diva", + "divenire", + "dividere", + "divorare", + "docente", + "dolcetto", + "dolore", + "domatore", + "domenica", + "dominare", + "donatore", + "donna", + "dorato", + "dormire", + "dorso", + "dosaggio", + "dottore", + "dovere", + "download", + "dragone", + "dramma", + "dubbio", + "dubitare", + "duetto", + "durata", + "ebbrezza", + "eccesso", + "eccitare", + "eclissi", + "economia", + "edera", + "edificio", + "editore", + "edizione", + "educare", + "effetto", + "egitto", + "egiziano", + "elastico", + "elefante", + "eleggere", + "elemento", + "elenco", + "elezione", + "elmetto", + "elogio", + "embrione", + "emergere", + "emettere", + "eminenza", + "emisfero", + "emozione", + "empatia", + "energia", + "enfasi", + "enigma", + "entrare", + "enzima", + "epidemia", + "epilogo", + "episodio", + "epoca", + "equivoco", + "erba", + "erede", + "eroe", + "erotico", + "errore", + "eruzione", + "esaltare", + "esame", + "esaudire", + "eseguire", + "esempio", + "esigere", + "esistere", + "esito", + "esperto", + "espresso", + "essere", + "estasi", + "esterno", + "estrarre", + "eterno", + "etica", + "euforico", + "europa", + "evacuare", + "evasione", + "evento", + "evidenza", + "evitare", + "evolvere", + "fabbrica", + "facciata", + "fagiano", + "fagotto", + "falco", + "fame", + "famiglia", + "fanale", + "fango", + "fantasia", + "farfalla", + "farmacia", + "faro", + "fase", + "fastidio", + "faticare", + "fatto", + "favola", + "febbre", + "femmina", + "femore", + "fenomeno", + "fermata", + "feromoni", + "ferrari", + "fessura", + "festa", + "fiaba", + "fiamma", + "fianco", + "fiat", + "fibbia", + "fidare", + "fieno", + "figa", + "figlio", + "figura", + "filetto", + "filmato", + "filosofo", + "filtrare", + "finanza", + "finestra", + "fingere", + "finire", + "finta", + "finzione", + "fiocco", + "fioraio", + "firewall", + "firmare", + "fisico", + "fissare", + "fittizio", + "fiume", + "flacone", + "flagello", + "flirtare", + "flusso", + "focaccia", + "foglio", + "fognario", + "follia", + "fonderia", + "fontana", + "forbici", + "forcella", + "foresta", + "forgiare", + "formare", + "fornace", + "foro", + "fortuna", + "forzare", + "fosforo", + "fotoni", + "fracasso", + "fragola", + "frantumi", + "fratello", + "frazione", + "freccia", + "freddo", + "frenare", + "fresco", + "friggere", + "frittata", + "frivolo", + "frizione", + "fronte", + "frullato", + "frumento", + "frusta", + "frutto", + "fucile", + "fuggire", + "fulmine", + "fumare", + "funzione", + "fuoco", + "furbizia", + "furgone", + "furia", + "furore", + "fusibile", + "fuso", + "futuro", + "gabbiano", + "galassia", + "gallina", + "gamba", + "gancio", + "garanzia", + "garofano", + "gasolio", + "gatto", + "gazebo", + "gazzetta", + "gelato", + "gemelli", + "generare", + "genitori", + "gennaio", + "geologia", + "germania", + "gestire", + "gettare", + "ghepardo", + "ghiaccio", + "giaccone", + "giaguaro", + "giallo", + "giappone", + "giardino", + "gigante", + "gioco", + "gioiello", + "giorno", + "giovane", + "giraffa", + "giudizio", + "giurare", + "giusto", + "globo", + "gloria", + "glucosio", + "gnocca", + "gocciola", + "godere", + "gomito", + "gomma", + "gonfiare", + "gorilla", + "governo", + "gradire", + "graffiti", + "granchio", + "grappolo", + "grasso", + "grattare", + "gridare", + "grissino", + "grondaia", + "grugnito", + "gruppo", + "guadagno", + "guaio", + "guancia", + "guardare", + "gufo", + "guidare", + "guscio", + "gusto", + "icona", + "idea", + "identico", + "idolo", + "idoneo", + "idrante", + "idrogeno", + "igiene", + "ignoto", + "imbarco", + "immagine", + "immobile", + "imparare", + "impedire", + "impianto", + "importo", + "impresa", + "impulso", + "incanto", + "incendio", + "incidere", + "incontro", + "incrocia", + "incubo", + "indagare", + "indice", + "indotto", + "infanzia", + "inferno", + "infinito", + "infranto", + "ingerire", + "inglese", + "ingoiare", + "ingresso", + "iniziare", + "innesco", + "insalata", + "inserire", + "insicuro", + "insonnia", + "insulto", + "interno", + "introiti", + "invasori", + "inverno", + "invito", + "invocare", + "ipnosi", + "ipocrita", + "ipotesi", + "ironia", + "irrigare", + "iscritto", + "isola", + "ispirare", + "isterico", + "istinto", + "istruire", + "italiano", + "jazz", + "labbra", + "labrador", + "ladro", + "lago", + "lamento", + "lampone", + "lancetta", + "lanterna", + "lapide", + "larva", + "lasagne", + "lasciare", + "lastra", + "latte", + "laurea", + "lavagna", + "lavorare", + "leccare", + "legare", + "leggere", + "lenzuolo", + "leone", + "lepre", + "letargo", + "lettera", + "levare", + "levitare", + "lezione", + "liberare", + "libidine", + "libro", + "licenza", + "lievito", + "limite", + "lince", + "lingua", + "liquore", + "lire", + "listino", + "litigare", + "litro", + "locale", + "lottare", + "lucciola", + "lucidare", + "luglio", + "luna", + "macchina", + "madama", + "madre", + "maestro", + "maggio", + "magico", + "maglione", + "magnolia", + "mago", + "maialino", + "maionese", + "malattia", + "male", + "malloppo", + "mancare", + "mandorla", + "mangiare", + "manico", + "manopola", + "mansarda", + "mantello", + "manubrio", + "manzo", + "mappa", + "mare", + "margine", + "marinaio", + "marmotta", + "marocco", + "martello", + "marzo", + "maschera", + "matrice", + "maturare", + "mazzetta", + "meandri", + "medaglia", + "medico", + "medusa", + "megafono", + "melone", + "membrana", + "menta", + "mercato", + "meritare", + "merluzzo", + "mese", + "mestiere", + "metafora", + "meteo", + "metodo", + "mettere", + "miele", + "miglio", + "miliardo", + "mimetica", + "minatore", + "minuto", + "miracolo", + "mirtillo", + "missile", + "mistero", + "misura", + "mito", + "mobile", + "moda", + "moderare", + "moglie", + "molecola", + "molle", + "momento", + "moneta", + "mongolia", + "monologo", + "montagna", + "morale", + "morbillo", + "mordere", + "mosaico", + "mosca", + "mostro", + "motivare", + "moto", + "mulino", + "mulo", + "muovere", + "muraglia", + "muscolo", + "museo", + "musica", + "mutande", + "nascere", + "nastro", + "natale", + "natura", + "nave", + "navigare", + "negare", + "negozio", + "nemico", + "nero", + "nervo", + "nessuno", + "nettare", + "neutroni", + "neve", + "nevicare", + "nicotina", + "nido", + "nipote", + "nocciola", + "noleggio", + "nome", + "nonno", + "norvegia", + "notare", + "notizia", + "nove", + "nucleo", + "nuda", + "nuotare", + "nutrire", + "obbligo", + "occhio", + "occupare", + "oceano", + "odissea", + "odore", + "offerta", + "officina", + "offrire", + "oggetto", + "oggi", + "olfatto", + "olio", + "oliva", + "ombelico", + "ombrello", + "omuncolo", + "ondata", + "onore", + "opera", + "opinione", + "opuscolo", + "opzione", + "orario", + "orbita", + "orchidea", + "ordine", + "orecchio", + "orgasmo", + "orgoglio", + "origine", + "orologio", + "oroscopo", + "orso", + "oscurare", + "ospedale", + "ospite", + "ossigeno", + "ostacolo", + "ostriche", + "ottenere", + "ottimo", + "ottobre", + "ovest", + "pacco", + "pace", + "pacifico", + "padella", + "pagare", + "pagina", + "pagnotta", + "palazzo", + "palestra", + "palpebre", + "pancetta", + "panfilo", + "panino", + "pannello", + "panorama", + "papa", + "paperino", + "paradiso", + "parcella", + "parente", + "parlare", + "parodia", + "parrucca", + "partire", + "passare", + "pasta", + "patata", + "patente", + "patogeno", + "patriota", + "pausa", + "pazienza", + "peccare", + "pecora", + "pedalare", + "pelare", + "pena", + "pendenza", + "penisola", + "pennello", + "pensare", + "pentirsi", + "percorso", + "perdono", + "perfetto", + "perizoma", + "perla", + "permesso", + "persona", + "pesare", + "pesce", + "peso", + "petardo", + "petrolio", + "pezzo", + "piacere", + "pianeta", + "piastra", + "piatto", + "piazza", + "piccolo", + "piede", + "piegare", + "pietra", + "pigiama", + "pigliare", + "pigrizia", + "pilastro", + "pilota", + "pinguino", + "pioggia", + "piombo", + "pionieri", + "piovra", + "pipa", + "pirata", + "pirolisi", + "piscina", + "pisolino", + "pista", + "pitone", + "piumino", + "pizza", + "plastica", + "platino", + "poesia", + "poiana", + "polaroid", + "polenta", + "polimero", + "pollo", + "polmone", + "polpetta", + "poltrona", + "pomodoro", + "pompa", + "popolo", + "porco", + "porta", + "porzione", + "possesso", + "postino", + "potassio", + "potere", + "poverino", + "pranzo", + "prato", + "prefisso", + "prelievo", + "premio", + "prendere", + "prestare", + "pretesa", + "prezzo", + "primario", + "privacy", + "problema", + "processo", + "prodotto", + "profeta", + "progetto", + "promessa", + "pronto", + "proposta", + "proroga", + "prossimo", + "proteina", + "prova", + "prudenza", + "pubblico", + "pudore", + "pugilato", + "pulire", + "pulsante", + "puntare", + "pupazzo", + "puzzle", + "quaderno", + "qualcuno", + "quarzo", + "quercia", + "quintale", + "rabbia", + "racconto", + "radice", + "raffica", + "ragazza", + "ragione", + "rammento", + "ramo", + "rana", + "randagio", + "rapace", + "rapinare", + "rapporto", + "rasatura", + "ravioli", + "reagire", + "realista", + "reattore", + "reazione", + "recitare", + "recluso", + "record", + "recupero", + "redigere", + "regalare", + "regina", + "regola", + "relatore", + "reliquia", + "remare", + "rendere", + "reparto", + "resina", + "resto", + "rete", + "retorica", + "rettile", + "revocare", + "riaprire", + "ribadire", + "ribelle", + "ricambio", + "ricetta", + "richiamo", + "ricordo", + "ridurre", + "riempire", + "riferire", + "riflesso", + "righello", + "rilancio", + "rilevare", + "rilievo", + "rimanere", + "rimborso", + "rinforzo", + "rinuncia", + "riparo", + "ripetere", + "riposare", + "ripulire", + "risalita", + "riscatto", + "riserva", + "riso", + "rispetto", + "ritaglio", + "ritmo", + "ritorno", + "ritratto", + "rituale", + "riunione", + "riuscire", + "riva", + "robotica", + "rondine", + "rosa", + "rospo", + "rosso", + "rotonda", + "rotta", + "roulotte", + "rubare", + "rubrica", + "ruffiano", + "rumore", + "ruota", + "ruscello", + "sabbia", + "sacco", + "saggio", + "sale", + "salire", + "salmone", + "salto", + "salutare", + "salvia", + "sangue", + "sanzioni", + "sapere", + "sapienza", + "sarcasmo", + "sardine", + "sartoria", + "sbalzo", + "sbarcare", + "sberla", + "sborsare", + "scadenza", + "scafo", + "scala", + "scambio", + "scappare", + "scarpa", + "scatola", + "scelta", + "scena", + "sceriffo", + "scheggia", + "schiuma", + "sciarpa", + "scienza", + "scimmia", + "sciopero", + "scivolo", + "sclerare", + "scolpire", + "sconto", + "scopa", + "scordare", + "scossa", + "scrivere", + "scrupolo", + "scuderia", + "scultore", + "scuola", + "scusare", + "sdraiare", + "secolo", + "sedativo", + "sedere", + "sedia", + "segare", + "segreto", + "seguire", + "semaforo", + "seme", + "senape", + "seno", + "sentiero", + "separare", + "sepolcro", + "sequenza", + "serata", + "serpente", + "servizio", + "sesso", + "seta", + "settore", + "sfamare", + "sfera", + "sfidare", + "sfiorare", + "sfogare", + "sgabello", + "sicuro", + "siepe", + "sigaro", + "silenzio", + "silicone", + "simbiosi", + "simpatia", + "simulare", + "sinapsi", + "sindrome", + "sinergia", + "sinonimo", + "sintonia", + "sirena", + "siringa", + "sistema", + "sito", + "smalto", + "smentire", + "smontare", + "soccorso", + "socio", + "soffitto", + "software", + "soggetto", + "sogliola", + "sognare", + "soldi", + "sole", + "sollievo", + "solo", + "sommario", + "sondare", + "sonno", + "sorpresa", + "sorriso", + "sospiro", + "sostegno", + "sovrano", + "spaccare", + "spada", + "spagnolo", + "spalla", + "sparire", + "spavento", + "spazio", + "specchio", + "spedire", + "spegnere", + "spendere", + "speranza", + "spessore", + "spezzare", + "spiaggia", + "spiccare", + "spiegare", + "spiffero", + "spingere", + "sponda", + "sporcare", + "spostare", + "spremuta", + "spugna", + "spumante", + "spuntare", + "squadra", + "squillo", + "staccare", + "stadio", + "stagione", + "stallone", + "stampa", + "stancare", + "starnuto", + "statura", + "stella", + "stendere", + "sterzo", + "stilista", + "stimolo", + "stinco", + "stiva", + "stoffa", + "storia", + "strada", + "stregone", + "striscia", + "studiare", + "stufa", + "stupendo", + "subire", + "successo", + "sudare", + "suono", + "superare", + "supporto", + "surfista", + "sussurro", + "svelto", + "svenire", + "sviluppo", + "svolta", + "svuotare", + "tabacco", + "tabella", + "tabu", + "tacchino", + "tacere", + "taglio", + "talento", + "tangente", + "tappeto", + "tartufo", + "tassello", + "tastiera", + "tavolo", + "tazza", + "teatro", + "tedesco", + "telaio", + "telefono", + "tema", + "temere", + "tempo", + "tendenza", + "tenebre", + "tensione", + "tentare", + "teologia", + "teorema", + "termica", + "terrazzo", + "teschio", + "tesi", + "tesoro", + "tessera", + "testa", + "thriller", + "tifoso", + "tigre", + "timbrare", + "timido", + "tinta", + "tirare", + "tisana", + "titano", + "titolo", + "toccare", + "togliere", + "topolino", + "torcia", + "torrente", + "tovaglia", + "traffico", + "tragitto", + "training", + "tramonto", + "transito", + "trapezio", + "trasloco", + "trattore", + "trazione", + "treccia", + "tregua", + "treno", + "triciclo", + "tridente", + "trilogia", + "tromba", + "troncare", + "trota", + "trovare", + "trucco", + "tubo", + "tulipano", + "tumulto", + "tunisia", + "tuono", + "turista", + "tuta", + "tutelare", + "tutore", + "ubriaco", + "uccello", + "udienza", + "udito", + "uffa", + "umanoide", + "umore", + "unghia", + "unguento", + "unicorno", + "unione", + "universo", + "uomo", + "uragano", + "uranio", + "urlare", + "uscire", + "utente", + "utilizzo", + "vacanza", + "vacca", + "vaglio", + "vagonata", + "valle", + "valore", + "valutare", + "valvola", + "vampiro", + "vaniglia", + "vanto", + "vapore", + "variante", + "vasca", + "vaselina", + "vassoio", + "vedere", + "vegetale", + "veglia", + "veicolo", + "vela", + "veleno", + "velivolo", + "velluto", + "vendere", + "venerare", + "venire", + "vento", + "veranda", + "verbo", + "verdura", + "vergine", + "verifica", + "vernice", + "vero", + "verruca", + "versare", + "vertebra", + "vescica", + "vespaio", + "vestito", + "vesuvio", + "veterano", + "vetro", + "vetta", + "viadotto", + "viaggio", + "vibrare", + "vicenda", + "vichingo", + "vietare", + "vigilare", + "vigneto", + "villa", + "vincere", + "violino", + "vipera", + "virgola", + "virtuoso", + "visita", + "vita", + "vitello", + "vittima", + "vivavoce", + "vivere", + "viziato", + "voglia", + "volare", + "volpe", + "volto", + "volume", + "vongole", + "voragine", + "vortice", + "votare", + "vulcano", + "vuotare", + "zabaione", + "zaffiro", + "zainetto", + "zampa", + "zanzara", + "zattera", + "zavorra", + "zenzero", + "zero", + "zingaro", + "zittire", + "zoccolo", + "zolfo", + "zombie", + "zucchero" + }); + unique_prefix_length = 4; + word_map = new std::unordered_map; + trimmed_word_map = new std::unordered_map; + language_name = "Italian"; + populate_maps(); + } + }; +} + +#endif diff --git a/src/mnemonics/japanese.h b/src/mnemonics/japanese.h index 5f7adce18..ad06a58a2 100644 --- a/src/mnemonics/japanese.h +++ b/src/mnemonics/japanese.h @@ -1681,7 +1681,7 @@ namespace Language "びじゅつかん", "ひしょ" }); - unique_prefix_length = 4; + unique_prefix_length = 3; word_map = new std::unordered_map; trimmed_word_map = new std::unordered_map; language_name = "Japanese"; diff --git a/src/mnemonics/portuguese.h b/src/mnemonics/portuguese.h index f60991a4d..5ec98e904 100644 --- a/src/mnemonics/portuguese.h +++ b/src/mnemonics/portuguese.h @@ -587,7 +587,7 @@ namespace Language "feerico", "feixe", "felicidade", - "felipe", + "felpudo", "feltro", "femur", "fenotipo", @@ -712,7 +712,7 @@ namespace Language "gume", "guru", "gustativo", - "gustavo", + "grelhado", "gutural", "habitue", "haitiano", @@ -1334,7 +1334,7 @@ namespace Language "rins", "rios", "riqueza", - "riquixa", + "respeito", "rissole", "ritualistico", "rivalizar", diff --git a/src/mnemonics/russian.h b/src/mnemonics/russian.h new file mode 100644 index 000000000..6ce8ba99e --- /dev/null +++ b/src/mnemonics/russian.h @@ -0,0 +1,1693 @@ +// Word list created by Monero contributor sammy007 +// +// Copyright (c) 2014-2015, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +/*! + * \file russian.h + * + * \brief Russian word list and map. + */ + +#ifndef RUSSIAN_H +#define RUSSIAN_H + +#include +#include +#include "language_base.h" +#include + +/*! + * \namespace Language + * \brief Mnemonic language related namespace. + */ +namespace Language +{ + class Russian: public Base + { + public: + Russian() + { + word_list = new std::vector({ + "абажур", + "абзац", + "абонент", + "абрикос", + "абсурд", + "авангард", + "август", + "авиация", + "авоська", + "автор", + "агат", + "агент", + "агитатор", + "агнец", + "агония", + "агрегат", + "адвокат", + "адмирал", + "адрес", + "ажиотаж", + "азарт", + "азбука", + "азот", + "аист", + "айсберг", + "академия", + "аквариум", + "аккорд", + "акробат", + "аксиома", + "актер", + "акула", + "акция", + "алгоритм", + "алебарда", + "аллея", + "алмаз", + "алтарь", + "алфавит", + "алхимик", + "алый", + "альбом", + "алюминий", + "амбар", + "аметист", + "амнезия", + "ампула", + "амфора", + "анализ", + "ангел", + "анекдот", + "анимация", + "анкета", + "аномалия", + "ансамбль", + "антенна", + "апатия", + "апельсин", + "апофеоз", + "аппарат", + "апрель", + "аптека", + "арабский", + "арбуз", + "аргумент", + "арест", + "ария", + "арка", + "армия", + "аромат", + "арсенал", + "артист", + "архив", + "аршин", + "асбест", + "аскетизм", + "аспект", + "ассорти", + "астроном", + "асфальт", + "атака", + "ателье", + "атлас", + "атом", + "атрибут", + "аудитор", + "аукцион", + "аура", + "афера", + "афиша", + "ахинея", + "ацетон", + "аэропорт", + "бабушка", + "багаж", + "бадья", + "база", + "баклажан", + "балкон", + "бампер", + "банк", + "барон", + "бассейн", + "батарея", + "бахрома", + "башня", + "баян", + "бегство", + "бедро", + "бездна", + "бекон", + "белый", + "бензин", + "берег", + "беседа", + "бетонный", + "биатлон", + "библия", + "бивень", + "бигуди", + "бидон", + "бизнес", + "бикини", + "билет", + "бинокль", + "биология", + "биржа", + "бисер", + "битва", + "бицепс", + "благо", + "бледный", + "близкий", + "блок", + "блуждать", + "блюдо", + "бляха", + "бобер", + "богатый", + "бодрый", + "боевой", + "бокал", + "большой", + "борьба", + "босой", + "ботинок", + "боцман", + "бочка", + "боярин", + "брать", + "бревно", + "бригада", + "бросать", + "брызги", + "брюки", + "бублик", + "бугор", + "будущее", + "буква", + "бульвар", + "бумага", + "бунт", + "бурный", + "бусы", + "бутылка", + "буфет", + "бухта", + "бушлат", + "бывалый", + "быль", + "быстрый", + "быть", + "бюджет", + "бюро", + "бюст", + "вагон", + "важный", + "ваза", + "вакцина", + "валюта", + "вампир", + "ванная", + "вариант", + "вассал", + "вата", + "вафля", + "вахта", + "вдова", + "вдыхать", + "ведущий", + "веер", + "вежливый", + "везти", + "веко", + "великий", + "вена", + "верить", + "веселый", + "ветер", + "вечер", + "вешать", + "вещь", + "веяние", + "взаимный", + "взбучка", + "взвод", + "взгляд", + "вздыхать", + "взлетать", + "взмах", + "взнос", + "взор", + "взрыв", + "взывать", + "взятка", + "вибрация", + "визит", + "вилка", + "вино", + "вирус", + "висеть", + "витрина", + "вихрь", + "вишневый", + "включать", + "вкус", + "власть", + "влечь", + "влияние", + "влюблять", + "внешний", + "внимание", + "внук", + "внятный", + "вода", + "воевать", + "вождь", + "воздух", + "войти", + "вокзал", + "волос", + "вопрос", + "ворота", + "восток", + "впадать", + "впускать", + "врач", + "время", + "вручать", + "всадник", + "всеобщий", + "вспышка", + "встреча", + "вторник", + "вулкан", + "вурдалак", + "входить", + "въезд", + "выбор", + "вывод", + "выгодный", + "выделять", + "выезжать", + "выживать", + "вызывать", + "выигрыш", + "вылезать", + "выносить", + "выпивать", + "высокий", + "выходить", + "вычет", + "вышка", + "выяснять", + "вязать", + "вялый", + "гавань", + "гадать", + "газета", + "гаишник", + "галстук", + "гамма", + "гарантия", + "гастроли", + "гвардия", + "гвоздь", + "гектар", + "гель", + "генерал", + "геолог", + "герой", + "гешефт", + "гибель", + "гигант", + "гильза", + "гимн", + "гипотеза", + "гитара", + "глаз", + "глина", + "глоток", + "глубокий", + "глыба", + "глядеть", + "гнать", + "гнев", + "гнить", + "гном", + "гнуть", + "говорить", + "годовой", + "голова", + "гонка", + "город", + "гость", + "готовый", + "граница", + "грех", + "гриб", + "громкий", + "группа", + "грызть", + "грязный", + "губа", + "гудеть", + "гулять", + "гуманный", + "густой", + "гуща", + "давать", + "далекий", + "дама", + "данные", + "дарить", + "дать", + "дача", + "дверь", + "движение", + "двор", + "дебют", + "девушка", + "дедушка", + "дежурный", + "дезертир", + "действие", + "декабрь", + "дело", + "демократ", + "день", + "депутат", + "держать", + "десяток", + "детский", + "дефицит", + "дешевый", + "деятель", + "джаз", + "джинсы", + "джунгли", + "диалог", + "диван", + "диета", + "дизайн", + "дикий", + "динамика", + "диплом", + "директор", + "диск", + "дитя", + "дичь", + "длинный", + "дневник", + "добрый", + "доверие", + "договор", + "дождь", + "доза", + "документ", + "должен", + "домашний", + "допрос", + "дорога", + "доход", + "доцент", + "дочь", + "дощатый", + "драка", + "древний", + "дрожать", + "друг", + "дрянь", + "дубовый", + "дуга", + "дудка", + "дукат", + "дуло", + "думать", + "дупло", + "дурак", + "дуть", + "духи", + "душа", + "дуэт", + "дымить", + "дыня", + "дыра", + "дыханье", + "дышать", + "дьявол", + "дюжина", + "дюйм", + "дюна", + "дядя", + "дятел", + "егерь", + "единый", + "едкий", + "ежевика", + "ежик", + "езда", + "елка", + "емкость", + "ерунда", + "ехать", + "жадный", + "жажда", + "жалеть", + "жанр", + "жара", + "жать", + "жгучий", + "ждать", + "жевать", + "желание", + "жемчуг", + "женщина", + "жертва", + "жесткий", + "жечь", + "живой", + "жидкость", + "жизнь", + "жилье", + "жирный", + "житель", + "журнал", + "жюри", + "забывать", + "завод", + "загадка", + "задача", + "зажечь", + "зайти", + "закон", + "замечать", + "занимать", + "западный", + "зарплата", + "засыпать", + "затрата", + "захват", + "зацепка", + "зачет", + "защита", + "заявка", + "звать", + "звезда", + "звонить", + "звук", + "здание", + "здешний", + "здоровье", + "зебра", + "зевать", + "зеленый", + "земля", + "зенит", + "зеркало", + "зефир", + "зигзаг", + "зима", + "зиять", + "злак", + "злой", + "змея", + "знать", + "зной", + "зодчий", + "золотой", + "зомби", + "зона", + "зоопарк", + "зоркий", + "зрачок", + "зрение", + "зритель", + "зубной", + "зыбкий", + "зять", + "игла", + "иголка", + "играть", + "идея", + "идиот", + "идол", + "идти", + "иерархия", + "избрать", + "известие", + "изгонять", + "издание", + "излагать", + "изменять", + "износ", + "изоляция", + "изрядный", + "изучать", + "изымать", + "изящный", + "икона", + "икра", + "иллюзия", + "имбирь", + "иметь", + "имидж", + "иммунный", + "империя", + "инвестор", + "индивид", + "инерция", + "инженер", + "иномарка", + "институт", + "интерес", + "инфекция", + "инцидент", + "ипподром", + "ирис", + "ирония", + "искать", + "история", + "исходить", + "исчезать", + "итог", + "июль", + "июнь", + "кабинет", + "кавалер", + "кадр", + "казарма", + "кайф", + "кактус", + "калитка", + "камень", + "канал", + "капитан", + "картина", + "касса", + "катер", + "кафе", + "качество", + "каша", + "каюта", + "квартира", + "квинтет", + "квота", + "кедр", + "кекс", + "кенгуру", + "кепка", + "керосин", + "кетчуп", + "кефир", + "кибитка", + "кивнуть", + "кидать", + "километр", + "кино", + "киоск", + "кипеть", + "кирпич", + "кисть", + "китаец", + "класс", + "клетка", + "клиент", + "клоун", + "клуб", + "клык", + "ключ", + "клятва", + "книга", + "кнопка", + "кнут", + "князь", + "кобура", + "ковер", + "коготь", + "кодекс", + "кожа", + "козел", + "койка", + "коктейль", + "колено", + "компания", + "конец", + "копейка", + "короткий", + "костюм", + "котел", + "кофе", + "кошка", + "красный", + "кресло", + "кричать", + "кровь", + "крупный", + "крыша", + "крючок", + "кубок", + "кувшин", + "кудрявый", + "кузов", + "кукла", + "культура", + "кумир", + "купить", + "курс", + "кусок", + "кухня", + "куча", + "кушать", + "кювет", + "лабиринт", + "лавка", + "лагерь", + "ладонь", + "лазерный", + "лайнер", + "лакей", + "лампа", + "ландшафт", + "лапа", + "ларек", + "ласковый", + "лауреат", + "лачуга", + "лаять", + "лгать", + "лебедь", + "левый", + "легкий", + "ледяной", + "лежать", + "лекция", + "лента", + "лепесток", + "лесной", + "лето", + "лечь", + "леший", + "лживый", + "либерал", + "ливень", + "лига", + "лидер", + "ликовать", + "лиловый", + "лимон", + "линия", + "липа", + "лирика", + "лист", + "литр", + "лифт", + "лихой", + "лицо", + "личный", + "лишний", + "лобовой", + "ловить", + "логика", + "лодка", + "ложка", + "лозунг", + "локоть", + "ломать", + "лоно", + "лопата", + "лорд", + "лось", + "лоток", + "лохматый", + "лошадь", + "лужа", + "лукавый", + "луна", + "лупить", + "лучший", + "лыжный", + "лысый", + "львиный", + "льгота", + "льдина", + "любить", + "людской", + "люстра", + "лютый", + "лягушка", + "магазин", + "мадам", + "мазать", + "майор", + "максимум", + "мальчик", + "манера", + "март", + "масса", + "мать", + "мафия", + "махать", + "мачта", + "машина", + "маэстро", + "маяк", + "мгла", + "мебель", + "медведь", + "мелкий", + "мемуары", + "менять", + "мера", + "место", + "метод", + "механизм", + "мечтать", + "мешать", + "миграция", + "мизинец", + "микрофон", + "миллион", + "минута", + "мировой", + "миссия", + "митинг", + "мишень", + "младший", + "мнение", + "мнимый", + "могила", + "модель", + "мозг", + "мойка", + "мокрый", + "молодой", + "момент", + "монах", + "море", + "мост", + "мотор", + "мохнатый", + "мочь", + "мошенник", + "мощный", + "мрачный", + "мстить", + "мудрый", + "мужчина", + "музыка", + "мука", + "мумия", + "мундир", + "муравей", + "мусор", + "мутный", + "муфта", + "муха", + "мучить", + "мушкетер", + "мыло", + "мысль", + "мыть", + "мычать", + "мышь", + "мэтр", + "мюзикл", + "мягкий", + "мякиш", + "мясо", + "мятый", + "мячик", + "набор", + "навык", + "нагрузка", + "надежда", + "наемный", + "нажать", + "называть", + "наивный", + "накрыть", + "налог", + "намерен", + "наносить", + "написать", + "народ", + "натура", + "наука", + "нация", + "начать", + "небо", + "невеста", + "негодяй", + "неделя", + "нежный", + "незнание", + "нелепый", + "немалый", + "неправда", + "нервный", + "нести", + "нефть", + "нехватка", + "нечистый", + "неясный", + "нива", + "нижний", + "низкий", + "никель", + "нирвана", + "нить", + "ничья", + "ниша", + "нищий", + "новый", + "нога", + "ножницы", + "ноздря", + "ноль", + "номер", + "норма", + "нота", + "ночь", + "ноша", + "ноябрь", + "нрав", + "нужный", + "нутро", + "нынешний", + "нырнуть", + "ныть", + "нюанс", + "нюхать", + "няня", + "оазис", + "обаяние", + "обвинять", + "обгонять", + "обещать", + "обжигать", + "обзор", + "обида", + "область", + "обмен", + "обнимать", + "оборона", + "образ", + "обучение", + "обходить", + "обширный", + "общий", + "объект", + "обычный", + "обязать", + "овальный", + "овес", + "овощи", + "овраг", + "овца", + "овчарка", + "огненный", + "огонь", + "огромный", + "огурец", + "одежда", + "одинокий", + "одобрить", + "ожидать", + "ожог", + "озарение", + "озеро", + "означать", + "оказать", + "океан", + "оклад", + "окно", + "округ", + "октябрь", + "окурок", + "олень", + "опасный", + "операция", + "описать", + "оплата", + "опора", + "оппонент", + "опрос", + "оптимизм", + "опускать", + "опыт", + "орать", + "орбита", + "орган", + "орден", + "орел", + "оригинал", + "оркестр", + "орнамент", + "оружие", + "осадок", + "освещать", + "осень", + "осина", + "осколок", + "осмотр", + "основной", + "особый", + "осуждать", + "отбор", + "отвечать", + "отдать", + "отец", + "отзыв", + "открытие", + "отмечать", + "относить", + "отпуск", + "отрасль", + "отставка", + "оттенок", + "отходить", + "отчет", + "отъезд", + "офицер", + "охапка", + "охота", + "охрана", + "оценка", + "очаг", + "очередь", + "очищать", + "очки", + "ошейник", + "ошибка", + "ощущение", + "павильон", + "падать", + "паек", + "пакет", + "палец", + "память", + "панель", + "папка", + "партия", + "паспорт", + "патрон", + "пауза", + "пафос", + "пахнуть", + "пациент", + "пачка", + "пашня", + "певец", + "педагог", + "пейзаж", + "пельмень", + "пенсия", + "пепел", + "период", + "песня", + "петля", + "пехота", + "печать", + "пешеход", + "пещера", + "пианист", + "пиво", + "пиджак", + "пиковый", + "пилот", + "пионер", + "пирог", + "писать", + "пить", + "пицца", + "пишущий", + "пища", + "план", + "плечо", + "плита", + "плохой", + "плыть", + "плюс", + "пляж", + "победа", + "повод", + "погода", + "подумать", + "поехать", + "пожимать", + "позиция", + "поиск", + "покой", + "получать", + "помнить", + "пони", + "поощрять", + "попадать", + "порядок", + "пост", + "поток", + "похожий", + "поцелуй", + "почва", + "пощечина", + "поэт", + "пояснить", + "право", + "предмет", + "проблема", + "пруд", + "прыгать", + "прямой", + "психолог", + "птица", + "публика", + "пугать", + "пудра", + "пузырь", + "пуля", + "пункт", + "пурга", + "пустой", + "путь", + "пухлый", + "пучок", + "пушистый", + "пчела", + "пшеница", + "пыль", + "пытка", + "пыхтеть", + "пышный", + "пьеса", + "пьяный", + "пятно", + "работа", + "равный", + "радость", + "развитие", + "район", + "ракета", + "рамка", + "ранний", + "рапорт", + "рассказ", + "раунд", + "рация", + "рвать", + "реальный", + "ребенок", + "реветь", + "регион", + "редакция", + "реестр", + "режим", + "резкий", + "рейтинг", + "река", + "религия", + "ремонт", + "рента", + "реплика", + "ресурс", + "реформа", + "рецепт", + "речь", + "решение", + "ржавый", + "рисунок", + "ритм", + "рифма", + "робкий", + "ровный", + "рогатый", + "родитель", + "рождение", + "розовый", + "роковой", + "роль", + "роман", + "ронять", + "рост", + "рота", + "роща", + "рояль", + "рубль", + "ругать", + "руда", + "ружье", + "руины", + "рука", + "руль", + "румяный", + "русский", + "ручка", + "рыба", + "рывок", + "рыдать", + "рыжий", + "рынок", + "рысь", + "рыть", + "рыхлый", + "рыцарь", + "рычаг", + "рюкзак", + "рюмка", + "рябой", + "рядовой", + "сабля", + "садовый", + "сажать", + "салон", + "самолет", + "сани", + "сапог", + "сарай", + "сатира", + "сауна", + "сахар", + "сбегать", + "сбивать", + "сбор", + "сбыт", + "свадьба", + "свет", + "свидание", + "свобода", + "связь", + "сгорать", + "сдвигать", + "сеанс", + "северный", + "сегмент", + "седой", + "сезон", + "сейф", + "секунда", + "сельский", + "семья", + "сентябрь", + "сердце", + "сеть", + "сечение", + "сеять", + "сигнал", + "сидеть", + "сизый", + "сила", + "символ", + "синий", + "сирота", + "система", + "ситуация", + "сиять", + "сказать", + "скважина", + "скелет", + "скидка", + "склад", + "скорый", + "скрывать", + "скучный", + "слава", + "слеза", + "слияние", + "слово", + "случай", + "слышать", + "слюна", + "смех", + "смирение", + "смотреть", + "смутный", + "смысл", + "смятение", + "снаряд", + "снег", + "снижение", + "сносить", + "снять", + "событие", + "совет", + "согласие", + "сожалеть", + "сойти", + "сокол", + "солнце", + "сомнение", + "сонный", + "сообщать", + "соперник", + "сорт", + "состав", + "сотня", + "соус", + "социолог", + "сочинять", + "союз", + "спать", + "спешить", + "спина", + "сплошной", + "способ", + "спутник", + "средство", + "срок", + "срывать", + "стать", + "ствол", + "стена", + "стихи", + "сторона", + "страна", + "студент", + "стыд", + "субъект", + "сувенир", + "сугроб", + "судьба", + "суета", + "суждение", + "сукно", + "сулить", + "сумма", + "сунуть", + "супруг", + "суровый", + "сустав", + "суть", + "сухой", + "суша", + "существо", + "сфера", + "схема", + "сцена", + "счастье", + "счет", + "считать", + "сшивать", + "съезд", + "сынок", + "сыпать", + "сырье", + "сытый", + "сыщик", + "сюжет", + "сюрприз", + "таблица", + "таежный", + "таинство", + "тайна", + "такси", + "талант", + "таможня", + "танец", + "тарелка", + "таскать", + "тахта", + "тачка", + "таять", + "тварь", + "твердый", + "творить", + "театр", + "тезис", + "текст", + "тело", + "тема", + "тень", + "теория", + "теплый", + "терять", + "тесный", + "тетя", + "техника", + "течение", + "тигр", + "типичный", + "тираж", + "титул", + "тихий", + "тишина", + "ткань", + "товарищ", + "толпа", + "тонкий", + "топливо", + "торговля", + "тоска", + "точка", + "тощий", + "традиция", + "тревога", + "трибуна", + "трогать", + "труд", + "трюк", + "тряпка", + "туалет", + "тугой", + "туловище", + "туман", + "тундра", + "тупой", + "турнир", + "тусклый", + "туфля", + "туча", + "туша", + "тыкать", + "тысяча", + "тьма", + "тюльпан", + "тюрьма", + "тяга", + "тяжелый", + "тянуть", + "убеждать", + "убирать", + "убогий", + "убыток", + "уважение", + "уверять", + "увлекать", + "угнать", + "угол", + "угроза", + "удар", + "удивлять", + "удобный", + "уезд", + "ужас", + "ужин", + "узел", + "узкий", + "узнавать", + "узор", + "уйма", + "уклон", + "укол", + "уксус", + "улетать", + "улица", + "улучшать", + "улыбка", + "уметь", + "умиление", + "умный", + "умолять", + "умысел", + "унижать", + "уносить", + "уныние", + "упасть", + "уплата", + "упор", + "упрекать", + "упускать", + "уран", + "урна", + "уровень", + "усадьба", + "усердие", + "усилие", + "ускорять", + "условие", + "усмешка", + "уснуть", + "успеть", + "усыпать", + "утешать", + "утка", + "уточнять", + "утро", + "утюг", + "уходить", + "уцелеть", + "участие", + "ученый", + "учитель", + "ушко", + "ущерб", + "уютный", + "уяснять", + "фабрика", + "фаворит", + "фаза", + "файл", + "факт", + "фамилия", + "фантазия", + "фара", + "фасад", + "февраль", + "фельдшер", + "феномен", + "ферма", + "фигура", + "физика", + "фильм", + "финал", + "фирма", + "фишка", + "флаг", + "флейта", + "флот", + "фокус", + "фольклор", + "фонд", + "форма", + "фото", + "фраза", + "фреска", + "фронт", + "фрукт", + "функция", + "фуражка", + "футбол", + "фыркать", + "халат", + "хамство", + "хаос", + "характер", + "хата", + "хватать", + "хвост", + "хижина", + "хилый", + "химия", + "хирург", + "хитрый", + "хищник", + "хлам", + "хлеб", + "хлопать", + "хмурый", + "ходить", + "хозяин", + "хоккей", + "холодный", + "хороший", + "хотеть", + "хохотать", + "храм", + "хрен", + "хриплый", + "хроника", + "хрупкий", + "художник", + "хулиган", + "хутор", + "царь", + "цвет", + "цель", + "цемент", + "центр", + "цепь", + "церковь", + "цикл", + "цилиндр", + "циничный", + "цирк", + "цистерна", + "цитата", + "цифра", + "цыпленок", + "чадо", + "чайник", + "часть", + "чашка", + "человек", + "чемодан", + "чепуха", + "черный", + "честь", + "четкий", + "чехол", + "чиновник", + "число", + "читать", + "членство", + "чреватый", + "чтение", + "чувство", + "чугунный", + "чудо", + "чужой", + "чукча", + "чулок", + "чума", + "чуткий", + "чучело", + "чушь", + "шаблон", + "шагать", + "шайка", + "шакал", + "шалаш", + "шампунь", + "шанс", + "шапка", + "шарик", + "шасси", + "шатер", + "шахта", + "шашлык", + "швейный", + "швырять", + "шевелить", + "шедевр", + "шейка", + "шелковый", + "шептать", + "шерсть", + "шестерка", + "шикарный", + "шинель", + "шипеть", + "широкий", + "шить", + "шишка", + "шкаф", + "школа", + "шкура", + "шланг", + "шлем", + "шлюпка", + "шляпа", + "шнур", + "шоколад", + "шорох", + "шоссе", + "шофер", + "шпага", + "шпион", + "шприц", + "шрам", + "шрифт", + "штаб", + "штора", + "штраф", + "штука", + "штык", + "шуба", + "шуметь", + "шуршать", + "шутка", + "щадить", + "щедрый", + "щека", + "щель", + "щенок", + "щепка", + "щетка", + "щука", + "эволюция", + "эгоизм", + "экзамен", + "экипаж", + "экономия", + "экран", + "эксперт", + "элемент", + "элита", + "эмблема", + "эмигрант", + "эмоция", + "энергия", + "эпизод", + "эпоха", + "эскиз", + "эссе", + "эстрада", + "этап", + "этика", + "этюд", + "эфир", + "эффект", + "эшелон", + "юбилей", + "юбка", + "южный", + "юмор", + "юноша", + "юрист", + "яблоко", + "явление", + "ягода", + "ядерный", + "ядовитый", + "ядро", + "язва", + "язык", + "яйцо", + "якорь", + "январь", + "японец", + "яркий", + "ярмарка", + "ярость", + "ярус", + "ясный", + "яхта", + "ячейка", + "ящик" + }); + unique_prefix_length = 4; + word_map = new std::unordered_map; + trimmed_word_map = new std::unordered_map; + language_name = "Russian"; + populate_maps(); + } + }; +} + +#endif diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index df726703f..3eb125208 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -209,11 +209,12 @@ namespace nodetool bool set_rate_up_limit(const boost::program_options::variables_map& vm, int64_t limit); bool set_rate_down_limit(const boost::program_options::variables_map& vm, int64_t limit); - bool set_rate_limit(const boost::program_options::variables_map& vm, uint64_t limit); + bool set_rate_limit(const boost::program_options::variables_map& vm, int64_t limit); void kill() { ///< will be called e.g. from deinit() _info("Killing the net_node"); is_closing = true; + if(mPeersLoggerThread != nullptr) mPeersLoggerThread->join(); // make sure the thread finishes _info("Joined extra background net_node threads"); } diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 66ee5cb53..0561ac584 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -67,6 +67,8 @@ namespace nodetool { namespace { + const int64_t default_limit_up = 2048; + const int64_t default_limit_down = 8192; const command_line::arg_descriptor arg_p2p_bind_ip = {"p2p-bind-ip", "Interface for p2p network protocol", "0.0.0.0"}; const command_line::arg_descriptor arg_p2p_bind_port = { "p2p-bind-port" @@ -93,7 +95,7 @@ namespace nodetool const command_line::arg_descriptor arg_limit_rate_up = {"limit-rate-up", "set limit-rate-up [kB/s]", -1}; const command_line::arg_descriptor arg_limit_rate_down = {"limit-rate-down", "set limit-rate-down [kB/s]", -1}; - const command_line::arg_descriptor arg_limit_rate = {"limit-rate", "set limit-rate [kB/s]", 128}; + const command_line::arg_descriptor arg_limit_rate = {"limit-rate", "set limit-rate [kB/s]", -1}; const command_line::arg_descriptor arg_save_graph = {"save-graph", "Save data for dr monero", false}; } @@ -319,7 +321,7 @@ namespace nodetool try { - addr_list = tools::DNSResolver().get_ipv4(addr_str, avail, valid); + addr_list = tools::DNSResolver::instance().get_ipv4(addr_str, avail, valid); LOG_PRINT_L4("dns_threads[" << result_index << "] DNS resolve done"); boost::this_thread::interruption_point(); } @@ -1446,7 +1448,7 @@ namespace nodetool this->islimitup=true; if (limit==-1) { - limit=128; + limit=default_limit_up; this->islimitup=false; } @@ -1461,7 +1463,7 @@ namespace nodetool { this->islimitdown=true; if(limit==-1) { - limit=128; + limit=default_limit_down; this->islimitdown=false; } limit *= 1024; @@ -1471,19 +1473,28 @@ namespace nodetool } template - bool node_server::set_rate_limit(const boost::program_options::variables_map& vm, uint64_t limit) + bool node_server::set_rate_limit(const boost::program_options::variables_map& vm, int64_t limit) { - limit *= 1024; - if(this->islimitdown==false && this->islimitup==false) { - epee::net_utils::connection >::set_rate_up_limit( limit ); - epee::net_utils::connection >::set_rate_down_limit( limit ); - LOG_PRINT_L0("Set limit to " << limit/1024 << " kB/s"); + int64_t limit_up = 0; + int64_t limit_down = 0; + + if(limit == -1) + { + limit_up = default_limit_up * 1024; + limit_down = default_limit_down * 1024; } - else if(this->islimitdown==false && this->islimitup==true ) { - epee::net_utils::connection >::set_rate_down_limit( limit ); - } - else if(this->islimitdown==true && this->islimitup==false ) { - epee::net_utils::connection >::set_rate_up_limit( limit ); + else + { + limit_up = limit * 1024; + limit_down = limit * 1024; + } + if(!this->islimitup) { + epee::net_utils::connection >::set_rate_up_limit(limit_up); + LOG_PRINT_L0("Set limit-up to " << limit_up/1024 << " kB/s"); + } + if(!this->islimitdown) { + epee::net_utils::connection >::set_rate_down_limit(limit_down); + LOG_PRINT_L0("Set limit-down to " << limit_down/1024 << " kB/s"); } return true; diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 24c7d242f..80bd7e6cd 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -225,6 +225,29 @@ namespace cryptonote res.status = "Failed"; return true; } + LOG_PRINT_L2("Found " << txs.size() << "/" << vh.size() << " transactions on the blockchain"); + + // try the pool for any missing txes + size_t found_in_pool = 0; + if (!missed_txs.empty()) + { + std::list pool_txs; + bool r = m_core.get_pool_transactions(pool_txs); + if(r) + { + for (std::list::const_iterator i = pool_txs.begin(); i != pool_txs.end(); ++i) + { + std::list::iterator mi = std::find(missed_txs.begin(), missed_txs.end(), get_transaction_hash(*i)); + if (mi != missed_txs.end()) + { + missed_txs.erase(mi); + txs.push_back(*i); + ++found_in_pool; + } + } + } + LOG_PRINT_L2("Found " << found_in_pool << "/" << vh.size() << " transactions in the pool"); + } BOOST_FOREACH(auto& tx, txs) { @@ -237,6 +260,40 @@ namespace cryptonote res.missed_tx.push_back(string_tools::pod_to_hex(miss_tx)); } + LOG_PRINT_L2(res.txs_as_hex.size() << " transactions found, " << res.missed_tx.size() << " not found"); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res) + { + CHECK_CORE_BUSY(); + std::vector key_images; + BOOST_FOREACH(const auto& ki_hex_str, req.key_images) + { + blobdata b; + if(!string_tools::parse_hexstr_to_binbuff(ki_hex_str, b)) + { + res.status = "Failed to parse hex representation of key image"; + return true; + } + if(b.size() != sizeof(crypto::key_image)) + { + res.status = "Failed, size of data mismatch"; + } + key_images.push_back(*reinterpret_cast(b.data())); + } + std::vector spent_status; + bool r = m_core.are_key_images_spent(key_images, spent_status); + if(!r) + { + res.status = "Failed"; + return true; + } + res.spent_status.clear(); + for (size_t n = 0; n < spent_status.size(); ++n) + res.spent_status.push_back(spent_status[n]); + res.status = CORE_RPC_STATUS_OK; return true; } diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index 6152dea03..3213e6b1c 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -77,6 +77,7 @@ namespace cryptonote MAP_URI_AUTO_BIN2("/get_o_indexes.bin", on_get_indexes, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES) MAP_URI_AUTO_BIN2("/getrandom_outs.bin", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS) MAP_URI_AUTO_JON2("/gettransactions", on_get_transactions, COMMAND_RPC_GET_TRANSACTIONS) + MAP_URI_AUTO_JON2("/is_key_image_spent", on_is_key_image_spent, COMMAND_RPC_IS_KEY_IMAGE_SPENT) MAP_URI_AUTO_JON2("/sendrawtransaction", on_send_raw_tx, COMMAND_RPC_SEND_RAW_TX) MAP_URI_AUTO_JON2("/start_mining", on_start_mining, COMMAND_RPC_START_MINING) MAP_URI_AUTO_JON2("/stop_mining", on_stop_mining, COMMAND_RPC_STOP_MINING) @@ -108,6 +109,7 @@ namespace cryptonote bool on_get_height(const COMMAND_RPC_GET_HEIGHT::request& req, COMMAND_RPC_GET_HEIGHT::response& res); bool on_get_blocks(const COMMAND_RPC_GET_BLOCKS_FAST::request& req, COMMAND_RPC_GET_BLOCKS_FAST::response& res); bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res); + bool on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res); bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res); bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res); bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res); diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index b6a2edd0b..b2fdd9930 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -116,6 +116,31 @@ namespace cryptonote }; }; + //----------------------------------------------- + struct COMMAND_RPC_IS_KEY_IMAGE_SPENT + { + struct request + { + std::vector key_images; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(key_images) + END_KV_SERIALIZE_MAP() + }; + + + struct response + { + std::vector spent_status; + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(spent_status) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + //----------------------------------------------- struct COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES { diff --git a/src/serialization/crypto.h b/src/serialization/crypto.h index f18e85b12..575697c06 100644 --- a/src/serialization/crypto.h +++ b/src/serialization/crypto.h @@ -79,12 +79,14 @@ bool do_serialize(Archive &ar, std::vector &v) BLOB_SERIALIZER(crypto::chacha8_iv); BLOB_SERIALIZER(crypto::hash); +BLOB_SERIALIZER(crypto::hash8); BLOB_SERIALIZER(crypto::public_key); BLOB_SERIALIZER(crypto::secret_key); BLOB_SERIALIZER(crypto::key_derivation); BLOB_SERIALIZER(crypto::key_image); BLOB_SERIALIZER(crypto::signature); VARIANT_TAG(debug_archive, crypto::hash, "hash"); +VARIANT_TAG(debug_archive, crypto::hash8, "hash8"); VARIANT_TAG(debug_archive, crypto::public_key, "public_key"); VARIANT_TAG(debug_archive, crypto::secret_key, "secret_key"); VARIANT_TAG(debug_archive, crypto::key_derivation, "key_derivation"); diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 04ebbf051..785265ecc 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -37,10 +37,13 @@ #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 "p2p/net_node.h" @@ -67,6 +70,7 @@ using namespace cryptonote; using boost::lexical_cast; namespace po = boost::program_options; namespace bf = boost::filesystem; +typedef cryptonote::simple_wallet sw; #define EXTENDED_LOGS_FILE "wallet_details.log" @@ -76,20 +80,20 @@ unsigned int epee::g_test_dbg_lock_sleep = 0; namespace { - const command_line::arg_descriptor arg_wallet_file = {"wallet-file", "Use wallet ", ""}; - const command_line::arg_descriptor arg_generate_new_wallet = {"generate-new-wallet", "Generate new wallet and save it to or
      .wallet by default", ""}; - const command_line::arg_descriptor arg_generate_from_view_key = {"generate-from-view-key", "Generate wallet from (address:viewkey:filename) and save it to ", ""}; - const command_line::arg_descriptor arg_daemon_address = {"daemon-address", "Use daemon instance at :", ""}; - const command_line::arg_descriptor arg_daemon_host = {"daemon-host", "Use daemon instance at host instead of localhost", ""}; - const command_line::arg_descriptor arg_password = {"password", "Wallet password", "", true}; - const command_line::arg_descriptor arg_electrum_seed = {"electrum-seed", "Specify electrum seed for wallet recovery/creation", ""}; - const command_line::arg_descriptor arg_restore_deterministic_wallet = {"restore-deterministic-wallet", "Recover wallet using electrum-style mnemonic", false}; - const command_line::arg_descriptor arg_non_deterministic = {"non-deterministic", "creates non-deterministic view and spend keys", false}; - const command_line::arg_descriptor arg_daemon_port = {"daemon-port", "Use daemon instance at port instead of 8081", 0}; + const command_line::arg_descriptor arg_wallet_file = {"wallet-file", sw::tr("Use wallet "), ""}; + const command_line::arg_descriptor arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to or
      .wallet by default"), ""}; + const command_line::arg_descriptor arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate wallet from (address:viewkey:filename) and save it to "), ""}; + const command_line::arg_descriptor arg_daemon_address = {"daemon-address", sw::tr("Use daemon instance at :"), ""}; + const command_line::arg_descriptor arg_daemon_host = {"daemon-host", sw::tr("Use daemon instance at host instead of localhost"), ""}; + const command_line::arg_descriptor arg_password = {"password", sw::tr("Wallet password"), "", true}; + 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"), false}; + const command_line::arg_descriptor arg_non_deterministic = {"non-deterministic", sw::tr("creates non-deterministic view and spend keys"), false}; + const command_line::arg_descriptor arg_daemon_port = {"daemon-port", sw::tr("Use daemon instance at port instead of 8081"), 0}; const command_line::arg_descriptor arg_log_level = {"log-level", "", LOG_LEVEL_0}; - const command_line::arg_descriptor arg_log_file = {"log-file", "Specify log file", ""}; - const command_line::arg_descriptor arg_testnet = {"testnet", "Used to deploy test nets. The daemon must be launched with --testnet flag", false}; - const command_line::arg_descriptor arg_restricted = {"restricted-rpc", "Restricts RPC to view only commands", false}; + const command_line::arg_descriptor arg_log_file = {"log-file", sw::tr("Specify log file"), ""}; + const command_line::arg_descriptor arg_testnet = {"testnet", sw::tr("Used to deploy test nets. The daemon must be launched with --testnet flag"), false}; + const command_line::arg_descriptor arg_restricted = {"restricted-rpc", sw::tr("Restricts RPC to view only commands"), false}; const command_line::arg_descriptor< std::vector > arg_command = {"command", ""}; @@ -100,7 +104,7 @@ namespace { if (status == CORE_RPC_STATUS_BUSY) { - err = "daemon is busy. Please try later"; + err = sw::tr("daemon is busy. Please try later"); } else if (status != CORE_RPC_STATUS_OK) { @@ -109,7 +113,7 @@ namespace } else { - err = "possible lost connection to daemon"; + err = sw::tr("possible lost connection to daemon"); } return err; } @@ -190,7 +194,21 @@ namespace message_writer fail_msg_writer() { - return message_writer(epee::log_space::console_color_red, true, "Error: ", LOG_LEVEL_0); + return message_writer(epee::log_space::console_color_red, true, sw::tr("Error: "), LOG_LEVEL_0); + } + + bool is_it_true(std::string s) + { + std::transform(s.begin(), s.end(), s.begin(), ::tolower); + if (s == "true") + return true; + if (s == "1") + return true; + if (s == "y" || s == "yes") + return true; + if (s == sw::tr("yes")) + return true; + return false; } } @@ -198,7 +216,7 @@ namespace std::string simple_wallet::get_commands_str() { std::stringstream ss; - ss << "Commands: " << ENDL; + ss << tr("Commands: ") << ENDL; std::string usage = m_cmd_binder.get_usage(); boost::replace_all(usage, "\n", "\n "); usage.insert(0, " "); @@ -229,7 +247,7 @@ bool simple_wallet::seed(const std::vector &args/* = std::vectorwatch_only()) { - fail_msg_writer() << "This wallet is watch-only and cannot have a seed."; + fail_msg_writer() << tr("This wallet is watch-only and cannot have a seed."); return true; } if (m_wallet->is_deterministic()) @@ -249,7 +267,7 @@ bool simple_wallet::seed(const std::vector &args/* = std::vector &args/* = s bool success = false; if (m_wallet->watch_only()) { - fail_msg_writer() << "This wallet is watch-only and doesn't have a seed."; + fail_msg_writer() << tr("This wallet is watch-only and doesn't have a seed."); return true; } if (!m_wallet->is_deterministic()) { - fail_msg_writer() << "This wallet is non-deterministic and doesn't have a seed."; + fail_msg_writer() << tr("This wallet is non-deterministic and doesn't have a seed."); return true; } tools::password_container pwd_container; success = pwd_container.read_password(); if (!success) { - fail_msg_writer() << "failed to read wallet password"; + fail_msg_writer() << tr("failed to read wallet password"); return true; } @@ -279,7 +297,7 @@ bool simple_wallet::seed_set_language(const std::vector &args/* = s success = m_wallet->verify_password(pwd_container.password()); if (!success) { - fail_msg_writer() << "invalid password"; + fail_msg_writer() << tr("invalid password"); return true; } @@ -289,6 +307,35 @@ bool simple_wallet::seed_set_language(const std::vector &args/* = s return true; } +bool simple_wallet::set_always_confirm_transfers(const std::vector &args/* = std::vector()*/) +{ + bool success = false; + if (m_wallet->watch_only()) + { + fail_msg_writer() << tr("This wallet is watch-only and cannot transfer."); + return true; + } + tools::password_container pwd_container; + success = pwd_container.read_password(); + if (!success) + { + fail_msg_writer() << tr("failed to read wallet password"); + return true; + } + + /* verify password before using so user doesn't accidentally set a new password for rewritten wallet */ + success = m_wallet->verify_password(pwd_container.password()); + if (!success) + { + fail_msg_writer() << tr("invalid password"); + return true; + } + + m_wallet->always_confirm_transfers(is_it_true(args[1])); + m_wallet->rewrite(m_wallet_file, pwd_container.password()); + return true; +} + bool simple_wallet::help(const std::vector &args/* = std::vector()*/) { success_msg_writer() << get_commands_str(); @@ -299,33 +346,35 @@ simple_wallet::simple_wallet() : m_daemon_port(0) , m_refresh_progress_reporter(*this) { - m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "start_mining [] - Start mining in daemon"); - m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon"); - m_cmd_binder.set_handler("save_bc", boost::bind(&simple_wallet::save_bc, this, _1), "Save current blockchain data"); - m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance"); - m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance"); - m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), "incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability"); - m_cmd_binder.set_handler("payments", boost::bind(&simple_wallet::show_payments, this, _1), "payments [ ... ] - Show payments , ... "); - m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), "Show blockchain height"); - m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer [] [ ... ] [payment_id] - Transfer ,... to ,... , respectively. is the number of transactions yours is indistinguishable from (from 0 to maximum available)"); - m_cmd_binder.set_handler("sweep_dust", boost::bind(&simple_wallet::sweep_dust, this, _1), "Send all dust outputs to the same address with mixin 0"); - m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "set_log - Change current log detalization level, is a number 0-4"); - m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address"); - m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::print_integrated_address, this, _1), "Convert a payment ID to an integrated address for the current wallet public address (no arguments use a random payment ID), or display standard addres and payment ID corresponding to an integrated addres"); - m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data"); - m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this, _1), "Save watch only keys file"); - m_cmd_binder.set_handler("viewkey", boost::bind(&simple_wallet::viewkey, this, _1), "Get viewkey"); - m_cmd_binder.set_handler("spendkey", boost::bind(&simple_wallet::spendkey, this, _1), "Get spendkey"); - m_cmd_binder.set_handler("seed", boost::bind(&simple_wallet::seed, this, _1), "Get deterministic seed"); - m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), "available options: seed language - Set wallet seed langage"); - m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), "Show this help"); + m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), tr("start_mining [] - Start mining in daemon")); + m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), tr("Stop mining in daemon")); + m_cmd_binder.set_handler("save_bc", boost::bind(&simple_wallet::save_bc, this, _1), tr("Save current blockchain data")); + m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, _1), tr("Resynchronize transactions and balance")); + m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, _1), tr("Show current wallet balance")); + m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), tr("incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability")); + m_cmd_binder.set_handler("payments", boost::bind(&simple_wallet::show_payments, this, _1), tr("payments [ ... ] - Show payments , ... ")); + m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), tr("Show blockchain height")); + m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), tr("transfer [] [ ... ] [payment_id] - Transfer ,... to ,... , respectively. is the number of transactions yours is indistinguishable from (from 0 to maximum available)")); + m_cmd_binder.set_handler("transfer_new", boost::bind(&simple_wallet::transfer_new, this, _1), tr("Same as transfer, but using a new transaction building algorithm")); + m_cmd_binder.set_handler("sweep_dust", boost::bind(&simple_wallet::sweep_dust, this, _1), tr("Send all dust outputs to the same address with mixin 0")); + m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), tr("set_log - Change current log detalization level, is a number 0-4")); + m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), tr("Show current wallet public address")); + m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::print_integrated_address, this, _1), tr("Convert a payment ID to an integrated address for the current wallet public address (no arguments use a random payment ID), or display standard addres and payment ID corresponding to an integrated addres")); + m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), tr("Save wallet synchronized data")); + m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this, _1), tr("Save watch only keys file")); + m_cmd_binder.set_handler("viewkey", boost::bind(&simple_wallet::viewkey, this, _1), tr("Get viewkey")); + m_cmd_binder.set_handler("spendkey", boost::bind(&simple_wallet::spendkey, this, _1), tr("Get spendkey")); + m_cmd_binder.set_handler("seed", boost::bind(&simple_wallet::seed, this, _1), tr("Get deterministic seed")); + m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr("available options: seed language - Set wallet seed langage; always-confirm-transfers <1|0> - whether to confirm unsplit txes")); + m_cmd_binder.set_handler("rescan_spent", boost::bind(&simple_wallet::rescan_spent, this, _1), tr("Rescan blockchain for spent outputs")); + m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), tr("Show this help")); } //---------------------------------------------------------------------------------------------------- bool simple_wallet::set_variable(const std::vector &args) { if (args.empty()) { - fail_msg_writer() << "set: needs an argument. available options: seed"; + fail_msg_writer() << tr("set: needs an argument. available options: seed, always-confirm-transfers"); return true; } else @@ -334,7 +383,7 @@ bool simple_wallet::set_variable(const std::vector &args) { if (args.size() == 1) { - fail_msg_writer() << "set seed: needs an argument. available options: language"; + fail_msg_writer() << tr("set seed: needs an argument. available options: language"); return true; } else if (args[1] == "language") @@ -345,8 +394,23 @@ bool simple_wallet::set_variable(const std::vector &args) return true; } } + else if (args[0] == "always-confirm-transfers") + { + if (args.size() <= 1) + { + fail_msg_writer() << tr("set always-confirm-transfers: needs an argument (0 or 1)"); + return true; + } + else + { + std::vector local_args = args; + local_args.erase(local_args.begin(), local_args.begin()+2); + set_always_confirm_transfers(local_args); + return true; + } + } } - fail_msg_writer() << "set: unrecognized argument(s)"; + fail_msg_writer() << tr("set: unrecognized argument(s)"); return true; } //---------------------------------------------------------------------------------------------------- @@ -354,18 +418,18 @@ bool simple_wallet::set_log(const std::vector &args) { if(args.size() != 1) { - fail_msg_writer() << "use: set_log "; + fail_msg_writer() << tr("use: set_log "); return true; } uint16_t l = 0; if(!epee::string_tools::get_xtype_from_string(l, args[0])) { - fail_msg_writer() << "wrong number format, use: set_log "; + fail_msg_writer() << tr("wrong number format, use: set_log "); return true; } if(LOG_LEVEL_4 < l) { - fail_msg_writer() << "wrong number range, use: set_log "; + fail_msg_writer() << tr("wrong number range, use: set_log "); return true; } @@ -380,13 +444,13 @@ bool simple_wallet::ask_wallet_create_if_needed() bool valid_path = false; do { wallet_path = command_line::input_line( - "Specify wallet file name (e.g., wallet.bin). If the wallet doesn't exist, it will be created.\n" - "Wallet file name: " + tr("Specify wallet file name (e.g., wallet.bin). If the wallet doesn't exist, it will be created.\n" + "Wallet file name: ") ); valid_path = tools::wallet2::wallet_valid_path_format(wallet_path); if (!valid_path) { - fail_msg_writer() << "wallet file path not valid: " << wallet_path; + fail_msg_writer() << tr("wallet file path not valid: ") << wallet_path; } } while (!valid_path); @@ -405,7 +469,7 @@ bool simple_wallet::ask_wallet_create_if_needed() { if (!m_generate_new.empty() || m_restore_deterministic_wallet || !m_generate_from_view_key.empty()) { - fail_msg_writer() << "Attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting."; + fail_msg_writer() << tr("Attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting."); return false; } } @@ -419,12 +483,12 @@ bool simple_wallet::ask_wallet_create_if_needed() { if(!wallet_file_exists) { - std::cout << "The wallet doesn't exist, generating new one" << std::endl; + std::cout << tr("The wallet doesn't exist, generating new one") << std::endl; m_generate_new = wallet_path; r = true; }else { - fail_msg_writer() << "failed to open wallet \"" << wallet_path << "\". Keys file wasn't found"; + fail_msg_writer() << tr("Keys file wasn't found: failed to open wallet: ") << "\"" << wallet_path << "\"."; r = false; } } @@ -438,9 +502,9 @@ bool simple_wallet::ask_wallet_create_if_needed() */ void simple_wallet::print_seed(std::string seed) { - success_msg_writer(true) << "\nPLEASE NOTE: the following 25 words can be used to recover access to your wallet. " << - "Please write them down and store them somewhere safe and secure. Please do not store them in " << - "your email or on file storage services outside of your immediate control.\n"; + success_msg_writer(true) << "\n" << tr("PLEASE NOTE: the following 25 words can be used to recover access to your wallet. " + "Please write them down and store them somewhere safe and secure. Please do not store them in " + "your email or on file storage services outside of your immediate control.\n"); boost::replace_nth(seed, " ", 15, "\n"); boost::replace_nth(seed, " ", 7, "\n"); // don't log @@ -454,13 +518,13 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (!m_daemon_address.empty() && !m_daemon_host.empty() && 0 != m_daemon_port) { - fail_msg_writer() << "you can't specify daemon host or port several times"; + fail_msg_writer() << tr("you can't specify daemon host or port several times"); return false; } if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) > 1) { - fail_msg_writer() << "Specifying more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\" and --generate-from-keys doesn't make sense!"; + fail_msg_writer() << tr("Specifying more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\" and --generate-from-keys doesn't make sense!"); return false; } else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty()) @@ -491,7 +555,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) bool r = pwd_container.read_password(); if (!r) { - fail_msg_writer() << "failed to read wallet password"; + fail_msg_writer() << tr("failed to read wallet password"); return false; } } @@ -506,7 +570,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) { if (m_non_deterministic) { - fail_msg_writer() << "Cannot specify both --restore-deterministic-wallet and --non-deterministic"; + fail_msg_writer() << tr("Cannot specify both --restore-deterministic-wallet and --non-deterministic"); return false; } @@ -515,14 +579,14 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) m_electrum_seed = command_line::input_line("Specify electrum seed: "); if (m_electrum_seed.empty()) { - fail_msg_writer() << "specify a recovery parameter with the --electrum-seed=\"words list here\""; + fail_msg_writer() << tr("specify a recovery parameter with the --electrum-seed=\"words list here\""); return false; } } if (!crypto::ElectrumWords::words_to_bytes(m_electrum_seed, m_recovery_key, old_language)) { - fail_msg_writer() << "electrum-style word list failed verification"; + fail_msg_writer() << tr("electrum-style word list failed verification"); return false; } } @@ -533,17 +597,17 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) boost::split(parts,m_generate_from_view_key, boost::is_any_of(":")); if (parts.size() < 3) { - fail_msg_writer() << "--generate-from-view-key needs a address:viewkey:filename triple"; + fail_msg_writer() << tr("--generate-from-view-key needs a address:viewkey:filename triple"); return false; } // parse address cryptonote::account_public_address address; bool has_payment_id; - crypto::hash new_payment_id; + crypto::hash8 new_payment_id; if(!get_account_integrated_address_from_str(address, has_payment_id, new_payment_id, testnet, parts[0])) { - fail_msg_writer() << "Failed to parse address"; + fail_msg_writer() << tr("Failed to parse address"); return false; } @@ -551,7 +615,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) cryptonote::blobdata viewkey_data; if(!epee::string_tools::parse_hexstr_to_binbuff(parts[1], viewkey_data)) { - fail_msg_writer() << "Failed to parse view key secret key"; + fail_msg_writer() << tr("Failed to parse view key secret key"); return false; } crypto::secret_key viewkey = *reinterpret_cast(viewkey_data.data()); @@ -606,9 +670,9 @@ bool simple_wallet::try_connect_to_daemon() { if (!m_wallet->check_connection()) { - fail_msg_writer() << "wallet failed to connect to daemon (" << m_daemon_address << "). " << - "Daemon either is not started or passed wrong port. " << - "Please, make sure that daemon is running or restart the wallet with correct daemon address."; + fail_msg_writer() << tr("wallet failed to connect to daemon: ") << m_daemon_address << ". " << + tr("Daemon either is not started or passed wrong port. " + "Please, make sure that daemon is running or restart the wallet with correct daemon address."); return false; } return true; @@ -627,7 +691,7 @@ std::string simple_wallet::get_mnemonic_language() std::string language_choice; int language_number = -1; crypto::ElectrumWords::get_language_list(language_list); - std::cout << "List of available languages for your wallet's seed:" << std::endl; + std::cout << tr("List of available languages for your wallet's seed:") << std::endl; int ii; std::vector::iterator it; for (it = language_list.begin(), ii = 0; it != language_list.end(); it++, ii++) @@ -636,19 +700,19 @@ std::string simple_wallet::get_mnemonic_language() } while (language_number < 0) { - language_choice = command_line::input_line("Enter the number corresponding to the language of your choice: "); + language_choice = command_line::input_line(tr("Enter the number corresponding to the language of your choice: ")); try { language_number = std::stoi(language_choice); if (!((language_number >= 0) && (static_cast(language_number) < language_list.size()))) { language_number = -1; - fail_msg_writer() << "Invalid language choice passed. Please try again.\n"; + fail_msg_writer() << tr("Invalid language choice passed. Please try again.\n"); } } catch (std::exception &e) { - fail_msg_writer() << "Invalid language choice passed. Please try again.\n"; + fail_msg_writer() << tr("Invalid language choice passed. Please try again.\n"); } } return language_list[language_number]; @@ -671,8 +735,8 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string if (was_deprecated_wallet) { // The user had used an older version of the wallet with old style mnemonics. - message_writer(epee::log_space::console_color_green, false) << "\nYou had been using " << - "a deprecated version of the wallet. Please use the new seed that we provide.\n"; + message_writer(epee::log_space::console_color_green, false) << "\n" << tr("You had been using " + "a deprecated version of the wallet. Please use the new seed that we provide.\n"); } mnemonic_language = get_mnemonic_language(); } @@ -687,13 +751,13 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string try { recovery_val = m_wallet->generate(wallet_file, password, recovery_key, recover, two_random); - message_writer(epee::log_space::console_color_white, true) << "Generated new wallet: " + message_writer(epee::log_space::console_color_white, true) << tr("Generated new wallet: ") << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); - std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << ENDL; + std::cout << tr("view key: ") << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << ENDL; } catch (const std::exception& e) { - fail_msg_writer() << "failed to generate new wallet: " << e.what(); + fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); return false; } @@ -706,12 +770,12 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string success_msg_writer() << "**********************************************************************\n" << - "Your wallet has been generated.\n" << - "To start synchronizing with the daemon use \"refresh\" command.\n" << - "Use \"help\" command to see the list of available commands.\n" << - "Always use \"exit\" command when closing simplewallet to save\n" << - "current session's state. Otherwise, you will possibly need to synchronize \n" << - "your wallet again. Your wallet key is NOT under risk anyway.\n" + tr("Your wallet has been generated.\n" + "To start synchronizing with the daemon use \"refresh\" command.\n" + "Use \"help\" command to see the list of available commands.\n" + "Always use \"exit\" command when closing simplewallet to save\n" + "current session's state. Otherwise, you will possibly need to synchronize \n" + "your wallet again. Your wallet key is NOT under risk anyway.\n") ; if (!two_random) @@ -734,13 +798,13 @@ bool simple_wallet::new_wallet(const std::string &wallet_file, const std::string try { m_wallet->generate(wallet_file, password, address, viewkey); - message_writer(epee::log_space::console_color_white, true) << "Generated new watch-only wallet: " + message_writer(epee::log_space::console_color_white, true) << tr("Generated new watch-only wallet: ") << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); - std::cout << "view key: " << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << ENDL; + std::cout << tr("view key: ") << string_tools::pod_to_hex(m_wallet->get_account().get_keys().m_view_secret_key) << ENDL; } catch (const std::exception& e) { - fail_msg_writer() << "failed to generate new wallet: " << e.what(); + fail_msg_writer() << tr("failed to generate new wallet: ") << e.what(); return false; } @@ -753,7 +817,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa { if (!tools::wallet2::wallet_valid_path_format(wallet_file)) { - fail_msg_writer() << "wallet file path not valid: " << wallet_file; + fail_msg_writer() << tr("wallet file path not valid: ") << wallet_file; return false; } @@ -764,8 +828,8 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa try { m_wallet->load(m_wallet_file, password); - std::string wallet_type = m_wallet->watch_only() ? "watch-only wallet" : "wallet"; - message_writer(epee::log_space::console_color_white, true) << "Opened " << wallet_type << ": " + message_writer(epee::log_space::console_color_white, true) << + (m_wallet->watch_only() ? tr("Opened watch-only wallet") : tr("Opened wallet")) << ": " << m_wallet->get_account().get_public_address_str(m_wallet->testnet()); // If the wallet file is deprecated, we should ask for mnemonic language again and store // everything in the new format. @@ -774,8 +838,8 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa { if (m_wallet->is_deterministic()) { - message_writer(epee::log_space::console_color_green, false) << "\nYou had been using " << - "a deprecated version of the wallet. Please proceed to upgrade your wallet.\n"; + message_writer(epee::log_space::console_color_green, false) << "\n" << tr("You had been using " + "a deprecated version of the wallet. Please proceed to upgrade your wallet.\n"); std::string mnemonic_language = get_mnemonic_language(); m_wallet->set_seed_language(mnemonic_language); m_wallet->rewrite(m_wallet_file, password); @@ -787,15 +851,15 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa } else { - message_writer(epee::log_space::console_color_green, false) << "\nYou had been using " << - "a deprecated version of the wallet. Your wallet file format is being upgraded now.\n"; + message_writer(epee::log_space::console_color_green, false) << "\n" << tr("You had been using " + "a deprecated version of the wallet. Your wallet file format is being upgraded now.\n"); m_wallet->rewrite(m_wallet_file, password); } } } catch (const std::exception& e) { - fail_msg_writer() << "failed to load wallet: " << e.what(); + fail_msg_writer() << tr("failed to load wallet: ") << e.what(); return false; } @@ -804,7 +868,7 @@ bool simple_wallet::open_wallet(const string &wallet_file, const std::string& pa refresh(std::vector()); success_msg_writer() << "**********************************************************************\n" << - "Use \"help\" command to see the list of available commands.\n" << + tr("Use \"help\" command to see the list of available commands.\n") << "**********************************************************************"; return true; } @@ -814,7 +878,7 @@ bool simple_wallet::close_wallet() bool r = m_wallet->deinit(); if (!r) { - fail_msg_writer() << "failed to deinit wallet"; + fail_msg_writer() << tr("failed to deinit wallet"); return false; } @@ -836,7 +900,7 @@ bool simple_wallet::save(const std::vector &args) try { m_wallet->store(); - success_msg_writer() << "Wallet data saved"; + success_msg_writer() << tr("Wallet data saved"); } catch (const std::exception& e) { @@ -851,22 +915,22 @@ bool simple_wallet::save_watch_only(const std::vector &args/* = std bool success = false; tools::password_container pwd_container; - success = pwd_container.read_password("Password for the new watch-only wallet"); + success = pwd_container.read_password(tr("Password for the new watch-only wallet")); if (!success) { - fail_msg_writer() << "failed to read wallet password"; + fail_msg_writer() << tr("failed to read wallet password"); return true; } std::string password = pwd_container.password(); - success = pwd_container.read_password("Enter new password again"); + success = pwd_container.read_password(tr("Enter new password again")); if (!success) { - fail_msg_writer() << "failed to read wallet password"; + fail_msg_writer() << tr("failed to read wallet password"); return true; } if (password != pwd_container.password()) { - fail_msg_writer() << "passwords do not match"; + fail_msg_writer() << tr("passwords do not match"); return true; } @@ -907,8 +971,8 @@ bool simple_wallet::start_mining(const std::vector& args) if (!ok) { - fail_msg_writer() << "invalid arguments. Please use start_mining [], " << - " should be from 1 to " << max_mining_threads_count; + fail_msg_writer() << tr("invalid arguments. Please use start_mining [], " + " should be from 1 to ") << max_mining_threads_count; return true; } @@ -922,6 +986,7 @@ bool simple_wallet::start_mining(const std::vector& args) success_msg_writer() << "Mining started in daemon"; else fail_msg_writer() << "mining has NOT been started: " << status; + return true; } //---------------------------------------------------------------------------------------------------- @@ -939,6 +1004,7 @@ bool simple_wallet::stop_mining(const std::vector& args) success_msg_writer() << "Mining stopped in daemon"; else fail_msg_writer() << "mining has NOT been stopped: " << status; + return true; } //---------------------------------------------------------------------------------------------------- @@ -956,6 +1022,7 @@ bool simple_wallet::save_bc(const std::vector& args) success_msg_writer() << "Blockchain saved"; else fail_msg_writer() << "Blockchain can't be saved: " << status; + return true; } //---------------------------------------------------------------------------------------------------- @@ -967,27 +1034,27 @@ void simple_wallet::on_new_block(uint64_t height, const cryptonote::block& block void simple_wallet::on_money_received(uint64_t height, const cryptonote::transaction& tx, size_t out_index) { message_writer(epee::log_space::console_color_green, false) << - "Height " << height << - ", transaction " << get_transaction_hash(tx) << - ", received " << print_money(tx.vout[out_index].amount); + tr("Height ") << height << ", " << + tr("transaction ") << get_transaction_hash(tx) << ", " << + tr("received ") << print_money(tx.vout[out_index].amount); m_refresh_progress_reporter.update(height, true); } //---------------------------------------------------------------------------------------------------- void simple_wallet::on_money_spent(uint64_t height, const cryptonote::transaction& in_tx, size_t out_index, const cryptonote::transaction& spend_tx) { message_writer(epee::log_space::console_color_magenta, false) << - "Height " << height << - ", transaction " << get_transaction_hash(spend_tx) << - ", spent " << print_money(in_tx.vout[out_index].amount); + tr("Height ") << height << ", " << + tr("transaction ") << get_transaction_hash(spend_tx) << ", " << + tr("spent ") << print_money(in_tx.vout[out_index].amount); m_refresh_progress_reporter.update(height, true); } //---------------------------------------------------------------------------------------------------- void simple_wallet::on_skip_transaction(uint64_t height, const cryptonote::transaction& tx) { message_writer(epee::log_space::console_color_red, true) << - "Height " << height << - ", transaction " << get_transaction_hash(tx) << - ", unsupported transaction format"; + tr("Height ") << height << ", " << + tr("transaction ") << get_transaction_hash(tx) << ", " << + tr("unsupported transaction format"); m_refresh_progress_reporter.update(height, true); } //---------------------------------------------------------------------------------------------------- @@ -996,7 +1063,7 @@ bool simple_wallet::refresh(const std::vector& args) if (!try_connect_to_daemon()) return true; - message_writer() << "Starting refresh..."; + message_writer() << tr("Starting refresh..."); size_t fetched_blocks = 0; size_t start_height = 0; @@ -1019,46 +1086,46 @@ bool simple_wallet::refresh(const std::vector& args) ok = true; // Clear line "Height xxx of xxx" std::cout << "\r \r"; - success_msg_writer(true) << "Refresh done, blocks received: " << fetched_blocks; + success_msg_writer(true) << tr("Refresh done, blocks received: ") << fetched_blocks; show_balance(); } catch (const tools::error::daemon_busy&) { - ss << "daemon is busy. Please try later"; + ss << tr("daemon is busy. Please try later"); } catch (const tools::error::no_connection_to_daemon&) { - ss << "no connection to daemon. Please, make sure daemon is running"; + ss << tr("no connection to daemon. Please, make sure daemon is running"); } catch (const tools::error::wallet_rpc_error& e) { LOG_ERROR("Unknown RPC error: " << e.to_string()); - ss << "RPC error \"" << e.what() << '"'; + ss << tr("RPC error: ") << e.what(); } catch (const tools::error::refresh_error& e) { LOG_ERROR("refresh error: " << e.to_string()); - ss << e.what(); + ss << tr("Error refreshing: ") << e.what(); } catch (const tools::error::wallet_internal_error& e) { LOG_ERROR("internal error: " << e.to_string()); - ss << "internal error: " << e.what(); + ss << tr("internal error: ") << e.what(); } catch (const std::exception& e) { LOG_ERROR("unexpected error: " << e.what()); - ss << "unexpected error: " << e.what(); + ss << tr("unexpected error: ") << e.what(); } catch (...) { LOG_ERROR("Unknown error"); - ss << "unknown error"; + ss << tr("unknown error"); } if (!ok) { - fail_msg_writer() << "refresh failed: " << ss.str() << ". Blocks received: " << fetched_blocks; + fail_msg_writer() << tr("refresh failed: ") << ss.str() << ". " << tr("Blocks received: ") << fetched_blocks; } return true; @@ -1066,8 +1133,9 @@ bool simple_wallet::refresh(const std::vector& args) //---------------------------------------------------------------------------------------------------- bool simple_wallet::show_balance(const std::vector& args/* = std::vector()*/) { - success_msg_writer() << "balance: " << print_money(m_wallet->balance()) << ", unlocked balance: " << print_money(m_wallet->unlocked_balance()) - << ", including unlocked dust: " << print_money(m_wallet->unlocked_dust_balance(tools::tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD))); + success_msg_writer() << tr("balance: ") << print_money(m_wallet->balance()) << ", " + << tr("unlocked balance: ") << print_money(m_wallet->unlocked_balance()) << ", " + << tr("including unlocked dust: ") << print_money(m_wallet->unlocked_dust_balance(tools::tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD))); return true; } //---------------------------------------------------------------------------------------------------- @@ -1099,14 +1167,15 @@ bool simple_wallet::show_incoming_transfers(const std::vector& args { if (!transfers_found) { - message_writer() << " amount \tspent\tglobal index\t tx id"; + message_writer() << boost::format("%21s%8s%16s%68s") % tr("amount") % tr("spent") % tr("global index") % tr("tx id"); transfers_found = true; } message_writer(td.m_spent ? epee::log_space::console_color_magenta : epee::log_space::console_color_green, false) << - std::setw(21) << print_money(td.amount()) << '\t' << - std::setw(3) << (td.m_spent ? 'T' : 'F') << " \t" << - std::setw(12) << td.m_global_output_index << '\t' << - get_transaction_hash(td.m_tx); + boost::format("%21s%8s%16u%68s") % + print_money(td.amount()) % + (td.m_spent ? "T" : "F") % + td.m_global_output_index % + get_transaction_hash (td.m_tx); } } @@ -1114,15 +1183,15 @@ bool simple_wallet::show_incoming_transfers(const std::vector& args { if (!filter) { - success_msg_writer() << "No incoming transfers"; + success_msg_writer() << tr("No incoming transfers"); } else if (available) { - success_msg_writer() << "No incoming available transfers"; + success_msg_writer() << tr("No incoming available transfers"); } else { - success_msg_writer() << "No incoming unavailable transfers"; + success_msg_writer() << tr("No incoming unavailable transfers"); } } @@ -1133,13 +1202,12 @@ bool simple_wallet::show_payments(const std::vector &args) { if(args.empty()) { - fail_msg_writer() << "expected at least one payment_id"; + fail_msg_writer() << tr("expected at least one payment_id"); return true; } - message_writer() << " payment \t" << - " transaction \t" << - " height\t amount \tunlock time"; + message_writer() << boost::format("%68s%68s%12s%21s%16s") % + tr("payment") % tr("transaction") % tr("height") % tr("amount") % tr("unlock time"); bool payments_found = false; for(std::string arg : args) @@ -1151,7 +1219,7 @@ bool simple_wallet::show_payments(const std::vector &args) m_wallet->get_payments(payment_id, payments); if(payments.empty()) { - success_msg_writer() << "No payments with id " << payment_id; + success_msg_writer() << tr("No payments with id ") << payment_id; continue; } @@ -1162,16 +1230,17 @@ bool simple_wallet::show_payments(const std::vector &args) payments_found = true; } success_msg_writer(true) << - payment_id << '\t' << - pd.m_tx_hash << '\t' << - std::setw(8) << pd.m_block_height << '\t' << - std::setw(21) << print_money(pd.m_amount) << '\t' << + boost::format("%68s%68s%12s%21s%16s") % + payment_id % + pd.m_tx_hash % + pd.m_block_height % + print_money(pd.m_amount) % pd.m_unlock_time; } } else { - fail_msg_writer() << "payment id has invalid format: \"" << arg << "\", expected 64-character string"; + fail_msg_writer() << tr("payment id has invalid format, expected 64-character string: ") << arg; } } @@ -1204,12 +1273,51 @@ bool simple_wallet::show_blockchain_height(const std::vector& args) if (err.empty()) success_msg_writer() << bc_height; else - fail_msg_writer() << "failed to get blockchain height: " << err; + fail_msg_writer() << tr("failed to get blockchain height: ") << err; return true; } - //---------------------------------------------------------------------------------------------------- -bool simple_wallet::transfer(const std::vector &args_) +bool simple_wallet::rescan_spent(const std::vector &args) +{ + if (!try_connect_to_daemon()) + return true; + + try + { + m_wallet->rescan_spent(); + } + catch (const tools::error::daemon_busy&) + { + fail_msg_writer() << tr("daemon is busy. Please try 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::is_key_image_spent_error&) + { + fail_msg_writer() << tr("failed to get spent status"); + } + catch (const tools::error::wallet_rpc_error& e) + { + LOG_ERROR("Unknown RPC error: " << e.to_string()); + fail_msg_writer() << tr("RPC error: ") << e.what(); + } + 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 simple_wallet::transfer_main(bool new_algorithm, const std::vector &args_) { if (!try_connect_to_daemon()) return true; @@ -1230,13 +1338,13 @@ bool simple_wallet::transfer(const std::vector &args_) if(local_args.size() < 2) { - fail_msg_writer() << "wrong number of arguments"; + fail_msg_writer() << tr("wrong number of arguments"); return true; } if(m_wallet->watch_only()) { - fail_msg_writer() << "This is a watch only wallet"; + fail_msg_writer() << tr("This is a watch only wallet"); return true; } @@ -1248,29 +1356,39 @@ bool simple_wallet::transfer(const std::vector &args_) local_args.pop_back(); crypto::hash payment_id; - bool r = tools::wallet2::parse_payment_id(payment_id_str, payment_id); + bool r = tools::wallet2::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::wallet2::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() << "payment id has invalid format: \"" << payment_id_str << "\", expected 64-character string"; + fail_msg_writer() << tr("payment id has invalid format, expected 16 or 64 character string: ") << payment_id_str; return true; } payment_id_seen = true; } vector dsts; - crypto::hash payment_id = null_hash; for (size_t i = 0; i < local_args.size(); i += 2) { cryptonote::tx_destination_entry de; bool has_payment_id; - crypto::hash new_payment_id; + crypto::hash8 new_payment_id; if(!get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet->testnet(), local_args[i])) { // if treating as an address fails, try as url @@ -1291,70 +1409,69 @@ bool simple_wallet::transfer(const std::vector &args_) std::string dnssec_str; if (dnssec_ok) { - dnssec_str = "DNSSEC validation passed"; + dnssec_str = tr("DNSSEC validation passed"); } else { - dnssec_str = "WARNING: DNSSEC validation was unsuccessful, this address may not be correct!"; + dnssec_str = tr("WARNING: DNSSEC validation was unsuccessful, this address may not be correct!"); } std::stringstream prompt; - prompt << "For URL: " << url + prompt << tr("For URL: ") << url << ", " << dnssec_str << std::endl - << " Monero Address = " << addresses_from_dns[0] + << tr(" Monero Address = ") << addresses_from_dns[0] << std::endl - << "Is this OK? (Y/n) " + << tr("Is this OK? (Y/n) ") ; // prompt the user for confirmation given the dns query and dnssec status std::string confirm_dns_ok = command_line::input_line(prompt.str()); - if (confirm_dns_ok != "Y" && confirm_dns_ok != "y" && confirm_dns_ok != "Yes" && confirm_dns_ok != "yes") + if (confirm_dns_ok != "Y" && confirm_dns_ok != "y" && confirm_dns_ok != "Yes" && confirm_dns_ok != "yes" + && confirm_dns_ok != tr("yes") && confirm_dns_ok != tr("no")) { - fail_msg_writer() << "You have cancelled the transfer request"; + fail_msg_writer() << tr("You have cancelled the transfer request"); return true; } } else { - fail_msg_writer() << "Failed to get a Monero address from: " << local_args[i]; + fail_msg_writer() << tr("Failed to get a Monero address from: ") << local_args[i]; return true; } } else if (addresses_from_dns.size() > 1) { - fail_msg_writer() << "Multiple Monero addresses found for given URL: " << url << ", this is not yet supported."; + fail_msg_writer() << tr("Not yet supported: Multiple Monero addresses found for given URL: ") << url; } else { - fail_msg_writer() << "Wrong address: " << local_args[i]; + fail_msg_writer() << tr("Wrong address: ") << local_args[i]; return true; } } - if (has_payment_id) { - if (payment_id_seen && payment_id != new_payment_id) { - fail_msg_writer() << "A single transaction cannot use more than one payment id: " << local_args[i]; + if (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; } - if (!payment_id_seen) + std::string extra_nonce; + set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, new_payment_id); + bool r = add_extra_nonce_to_tx_extra(extra, extra_nonce); + if(!r) { - std::string extra_nonce; - set_payment_id_to_tx_extra_nonce(extra_nonce, new_payment_id); - bool r = add_extra_nonce_to_tx_extra(extra, extra_nonce); - if(!r) - { - fail_msg_writer() << "Failed to set up payment id, though it was decoded correctly"; - return true; - } - payment_id = new_payment_id; + fail_msg_writer() << tr("Failed to set up payment id, though it was decoded correctly"); + return true; } } bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]); if(!ok || 0 == de.amount) { - fail_msg_writer() << "amount is wrong: " << local_args[i] << ' ' << local_args[i + 1] << - ", expected number from 0 to " << print_money(std::numeric_limits::max()); + 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; } @@ -1364,19 +1481,28 @@ bool simple_wallet::transfer(const std::vector &args_) try { // figure out what tx will be necessary - auto ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); + std::vector ptx_vector; + if (new_algorithm) + ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); + else + ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, 0 /* unused fee arg*/, extra); // if more than one tx necessary, prompt user to confirm - if (ptx_vector.size() > 1) + if (m_wallet->always_confirm_transfers() || ptx_vector.size() > 1) { - std::string prompt_str = "Your transaction needs to be split into "; - prompt_str += std::to_string(ptx_vector.size()); - prompt_str += " transactions. This will result in a transaction fee being applied to each transaction"; - prompt_str += ". Is this okay? (Y/Yes/N/No)"; + uint64_t total_fee = 0; + for (size_t n = 0; n < ptx_vector.size(); ++n) + { + total_fee += ptx_vector[n].fee; + } + + std::string prompt_str = (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. Is this okay? (Y/Yes/N/No)")) % + ((unsigned long long)ptx_vector.size()) % print_money(total_fee)).str(); std::string accepted = command_line::input_line(prompt_str); if (accepted != "Y" && accepted != "y" && accepted != "Yes" && accepted != "yes") { - fail_msg_writer() << "Transaction cancelled."; + fail_msg_writer() << tr("Transaction cancelled."); // would like to return false, because no tx made, but everything else returns true // and I don't know what returning false might adversely affect. *sigh* @@ -1389,7 +1515,7 @@ bool simple_wallet::transfer(const std::vector &args_) { auto & ptx = ptx_vector.back(); m_wallet->commit_tx(ptx); - success_msg_writer(true) << "Money successfully sent, transaction " << get_transaction_hash(ptx.tx); + success_msg_writer(true) << tr("Money successfully sent, transaction ") << get_transaction_hash(ptx.tx); // if no exception, remove element from vector ptx_vector.pop_back(); @@ -1397,43 +1523,45 @@ bool simple_wallet::transfer(const std::vector &args_) } catch (const tools::error::daemon_busy&) { - fail_msg_writer() << "daemon is busy. Please try later"; + fail_msg_writer() << tr("daemon is busy. Please try later"); } catch (const tools::error::no_connection_to_daemon&) { - fail_msg_writer() << "no connection to daemon. Please, make sure daemon is running."; + fail_msg_writer() << tr("no connection to daemon. Please, make sure daemon is running."); } catch (const tools::error::wallet_rpc_error& e) { LOG_ERROR("Unknown RPC error: " << e.to_string()); - fail_msg_writer() << "RPC error \"" << e.what() << '"'; + fail_msg_writer() << tr("RPC error: ") << e.what(); } catch (const tools::error::get_random_outs_error&) { - fail_msg_writer() << "failed to get random outputs to mix"; + fail_msg_writer() << tr("failed to get random outputs to mix"); } catch (const tools::error::not_enough_money& e) { - fail_msg_writer() << "not enough money to transfer, available only " << print_money(e.available()) << - ", transaction amount " << print_money(e.tx_amount() + e.fee()) << " = " << print_money(e.tx_amount()) << - " + " << print_money(e.fee()) << " (fee)"; + fail_msg_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()); } catch (const tools::error::not_enough_outs_to_mix& e) { auto writer = fail_msg_writer(); - writer << "not enough outputs for specified mixin_count = " << e.mixin_count() << ":"; + writer << tr("not enough outputs for specified mixin_count") << " = " << e.mixin_count() << ":"; for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs()) { - writer << "\noutput amount = " << print_money(outs_for_amount.amount) << ", fount outputs to mix = " << outs_for_amount.outs.size(); + writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.amount) << ", " << tr("found outputs to mix") << " = " << outs_for_amount.outs.size(); } } catch (const tools::error::tx_not_constructed&) { - fail_msg_writer() << "transaction was not constructed"; + fail_msg_writer() << tr("transaction was not constructed"); } catch (const tools::error::tx_rejected& e) { - fail_msg_writer() << "transaction " << get_transaction_hash(e.tx()) << " was rejected by daemon with status \"" << e.status() << '"'; + fail_msg_writer() << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); } catch (const tools::error::tx_sum_overflow& e) { @@ -1441,35 +1569,45 @@ bool simple_wallet::transfer(const std::vector &args_) } catch (const tools::error::zero_destination&) { - fail_msg_writer() << "one of destinations is zero"; + fail_msg_writer() << tr("one of destinations is zero"); } catch (const tools::error::tx_too_big& e) { - fail_msg_writer() << "Failed to find a suitable way to split transactions"; + fail_msg_writer() << tr("Failed to find a suitable way to split transactions"); } catch (const tools::error::transfer_error& e) { LOG_ERROR("unknown transfer error: " << e.to_string()); - fail_msg_writer() << "unknown transfer error: " << e.what(); + 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() << "internal error: " << e.what(); + fail_msg_writer() << tr("internal error: ") << e.what(); } catch (const std::exception& e) { LOG_ERROR("unexpected error: " << e.what()); - fail_msg_writer() << "unexpected error: " << e.what(); + fail_msg_writer() << tr("unexpected error: ") << e.what(); } catch (...) { LOG_ERROR("Unknown error"); - fail_msg_writer() << "unknown error"; + fail_msg_writer() << tr("unknown error"); } return true; } +//---------------------------------------------------------------------------------------------------- +bool simple_wallet::transfer(const std::vector &args_) +{ + return transfer_main(false, args_); +} +//---------------------------------------------------------------------------------------------------- +bool simple_wallet::transfer_new(const std::vector &args_) +{ + return transfer_main(true, args_); +} //---------------------------------------------------------------------------------------------------- bool simple_wallet::sweep_dust(const std::vector &args_) @@ -1479,7 +1617,7 @@ bool simple_wallet::sweep_dust(const std::vector &args_) if(m_wallet->watch_only()) { - fail_msg_writer() << "This is a watch only wallet"; + fail_msg_writer() << tr("This is a watch only wallet"); return true; } @@ -1497,18 +1635,22 @@ bool simple_wallet::sweep_dust(const std::vector &args_) total_fee += ptx_vector[n].fee; } - std::string prompt_str = "Sweeping " + print_money(total_dust); + std::string prompt_str = tr("Sweeping ") + print_money(total_dust); if (ptx_vector.size() > 1) { - prompt_str += " in "; - prompt_str += std::to_string(ptx_vector.size()); - prompt_str += " transactions"; + prompt_str = (boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No)")) % + print_money(total_dust) % + ((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)")) % + print_money(total_dust) % + print_money(total_fee)).str(); } - prompt_str += " for a total fee of " + print_money(total_fee); - prompt_str += ". Is this okay? (Y/Yes/N/No)"; std::string accepted = command_line::input_line(prompt_str); if (accepted != "Y" && accepted != "y" && accepted != "Yes" && accepted != "yes") { - fail_msg_writer() << "Transaction cancelled."; + fail_msg_writer() << tr("Transaction cancelled."); // would like to return false, because no tx made, but everything else returns true // and I don't know what returning false might adversely affect. *sigh* @@ -1520,7 +1662,7 @@ bool simple_wallet::sweep_dust(const std::vector &args_) { auto & ptx = ptx_vector.back(); m_wallet->commit_tx(ptx); - success_msg_writer(true) << "Money successfully sent, transaction " << get_transaction_hash(ptx.tx); + success_msg_writer(true) << tr("Money successfully sent, transaction: ") << get_transaction_hash(ptx.tx); // if no exception, remove element from vector ptx_vector.pop_back(); @@ -1528,43 +1670,45 @@ bool simple_wallet::sweep_dust(const std::vector &args_) } catch (const tools::error::daemon_busy&) { - fail_msg_writer() << "daemon is busy. Please try later"; + fail_msg_writer() << tr("daemon is busy. Please try later"); } catch (const tools::error::no_connection_to_daemon&) { - fail_msg_writer() << "no connection to daemon. Please, make sure daemon is running."; + fail_msg_writer() << tr("no connection to daemon. Please, make sure daemon is running."); } catch (const tools::error::wallet_rpc_error& e) { LOG_ERROR("Unknown RPC error: " << e.to_string()); - fail_msg_writer() << "RPC error \"" << e.what() << '"'; + fail_msg_writer() << tr("RPC error: ") << e.what(); } catch (const tools::error::get_random_outs_error&) { - fail_msg_writer() << "failed to get random outputs to mix"; + fail_msg_writer() << tr("failed to get random outputs to mix"); } catch (const tools::error::not_enough_money& e) { - fail_msg_writer() << "not enough money to transfer, available only " << print_money(e.available()) << - ", transaction amount " << print_money(e.tx_amount() + e.fee()) << " = " << print_money(e.tx_amount()) << - " + " << print_money(e.fee()) << " (fee)"; + fail_msg_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()); } catch (const tools::error::not_enough_outs_to_mix& e) { auto writer = fail_msg_writer(); - writer << "not enough outputs for specified mixin_count = " << e.mixin_count() << ":"; + writer << tr("not enough outputs for specified mixin_count") << " = " << e.mixin_count() << ":"; for (const cryptonote::COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& outs_for_amount : e.scanty_outs()) { - writer << "\noutput amount = " << print_money(outs_for_amount.amount) << ", fount outputs to mix = " << outs_for_amount.outs.size(); + writer << "\n" << tr("output amount") << " = " << print_money(outs_for_amount.amount) << ", " << tr("found outputs to mix") << " = " << outs_for_amount.outs.size(); } } catch (const tools::error::tx_not_constructed&) { - fail_msg_writer() << "transaction was not constructed"; + fail_msg_writer() << tr("transaction was not constructed"); } catch (const tools::error::tx_rejected& e) { - fail_msg_writer() << "transaction " << get_transaction_hash(e.tx()) << " was rejected by daemon with status \"" << e.status() << '"'; + fail_msg_writer() << (boost::format(tr("transaction %s was rejected by daemon with status: ")) % get_transaction_hash(e.tx())) << e.status(); } catch (const tools::error::tx_sum_overflow& e) { @@ -1572,31 +1716,31 @@ bool simple_wallet::sweep_dust(const std::vector &args_) } catch (const tools::error::zero_destination&) { - fail_msg_writer() << "one of destinations is zero"; + fail_msg_writer() << tr("one of destinations is zero"); } catch (const tools::error::tx_too_big& e) { - fail_msg_writer() << "Failed to find a suitable way to split transactions"; + fail_msg_writer() << tr("Failed to find a suitable way to split transactions"); } catch (const tools::error::transfer_error& e) { LOG_ERROR("unknown transfer error: " << e.to_string()); - fail_msg_writer() << "unknown transfer error: " << e.what(); + 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() << "internal error: " << e.what(); + fail_msg_writer() << tr("internal error: ") << e.what(); } catch (const std::exception& e) { LOG_ERROR("unexpected error: " << e.what()); - fail_msg_writer() << "unexpected error: " << e.what(); + fail_msg_writer() << tr("unexpected error: ") << e.what(); } catch (...) { LOG_ERROR("Unknown error"); - fail_msg_writer() << "unknown error"; + fail_msg_writer() << tr("unknown error"); } return true; @@ -1605,7 +1749,7 @@ bool simple_wallet::sweep_dust(const std::vector &args_) bool simple_wallet::run() { std::string addr_start = m_wallet->get_account().get_public_address_str(m_wallet->testnet()).substr(0, 6); - return m_cmd_binder.run_handling("[wallet " + addr_start + "]: ", ""); + return m_cmd_binder.run_handling(std::string("[") + tr("wallet") + " " + addr_start + "]: ", ""); } //---------------------------------------------------------------------------------------------------- void simple_wallet::stop() @@ -1622,42 +1766,43 @@ bool simple_wallet::print_address(const std::vector &args/* = std:: //---------------------------------------------------------------------------------------------------- bool simple_wallet::print_integrated_address(const std::vector &args/* = std::vector()*/) { - crypto::hash payment_id; + crypto::hash8 payment_id; if (args.size() > 1) { - fail_msg_writer() << "integrated_address only takes one or zero arguments"; + fail_msg_writer() << tr("integrated_address only takes one or zero arguments"); return true; } if (args.size() == 0) { - crypto::generate_random_bytes(32, payment_id.data); - success_msg_writer() << "Random payment ID: " << payment_id; - success_msg_writer() << "Matching integrated address: " << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->testnet()); + crypto::generate_random_bytes(8, payment_id.data); + success_msg_writer() << tr("Random payment ID: ") << payment_id; + success_msg_writer() << tr("Matching integrated address: ") << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->testnet()); return true; } - if(tools::wallet2::parse_payment_id(args.back(), payment_id)) + if(tools::wallet2::parse_short_payment_id(args.back(), payment_id)) { success_msg_writer() << m_wallet->get_account().get_public_integrated_address_str(payment_id, m_wallet->testnet()); return true; } else { bool has_payment_id; - crypto::hash payment_id; + crypto::hash8 payment_id; account_public_address addr; if(get_account_integrated_address_from_str(addr, has_payment_id, payment_id, m_wallet->testnet(), args.back())) { if (has_payment_id) { - success_msg_writer() << "Integrated address: account " << get_account_address_as_str(m_wallet->testnet(),addr) << ", payment id " << payment_id; + success_msg_writer() << boost::format(tr("Integrated address: account %s, payment id %s")) % + get_account_address_as_str(m_wallet->testnet(),addr) % epee::string_tools::pod_to_hex(payment_id); } else { - success_msg_writer() << "Standard address: account " << get_account_address_as_str(m_wallet->testnet(),addr); + success_msg_writer() << tr("Standard address: account: ") << get_account_address_as_str(m_wallet->testnet(),addr); } return true; } } - fail_msg_writer() << "Failed to parse payment id or address"; + fail_msg_writer() << tr("Failed to parse payment id or address"); return true; } //---------------------------------------------------------------------------------------------------- @@ -1676,11 +1821,11 @@ int main(int argc, char* argv[]) string_tools::set_module_name_and_folder(argv[0]); - po::options_description desc_general("General options"); + po::options_description desc_general(sw::tr("General options")); command_line::add_arg(desc_general, command_line::arg_help); command_line::add_arg(desc_general, command_line::arg_version); - po::options_description desc_params("Wallet options"); + po::options_description desc_params(sw::tr("Wallet options")); command_line::add_arg(desc_params, arg_wallet_file); command_line::add_arg(desc_params, arg_generate_new_wallet); command_line::add_arg(desc_params, arg_generate_from_view_key); @@ -1692,8 +1837,23 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_log_level); bf::path default_log {log_space::log_singletone::get_default_log_folder()}; - default_log /= log_space::log_singletone::get_default_log_file(); - std::cout << "default_log: " << default_log << ENDL; + std::string log_file_name = log_space::log_singletone::get_default_log_file(); + if (log_file_name.empty()) + { + // Sanity check: File path should also be empty if file name is. If not, + // this would be a problem in epee's discovery of current process's file + // path. + if (! default_log.empty()) + { + fail_msg_writer() << sw::tr("Unexpected empty log file name in presence of non-empty file path"); + return false; + } + // epee didn't find path to executable from argv[0], so use this default file name. + log_file_name = "simplewallet.log"; + // The full path will use cwd because epee also returned an empty default log folder. + } + default_log /= log_file_name; + command_line::add_arg(desc_params, arg_log_file, default_log.string()); command_line::add_arg(desc_params, arg_restore_deterministic_wallet ); @@ -1707,6 +1867,8 @@ int main(int argc, char* argv[]) po::positional_options_description positional_options; positional_options.add(arg_command.name, -1); + i18n_set_language("translations", "monero"); + po::options_description desc_all; desc_all.add(desc_general).add(desc_params); cryptonote::simple_wallet w; @@ -1717,14 +1879,14 @@ int main(int argc, char* argv[]) if (command_line::get_arg(vm, command_line::arg_help)) { - success_msg_writer() << CRYPTONOTE_NAME << " wallet v" << MONERO_VERSION_FULL; - success_msg_writer() << "Usage: simplewallet [--wallet-file=|--generate-new-wallet=] [--daemon-address=:] []"; + success_msg_writer() << CRYPTONOTE_NAME << " " << sw::tr("wallet") << " v" << MONERO_VERSION_FULL; + success_msg_writer() << sw::tr("Usage:") << " simplewallet [--wallet-file=|--generate-new-wallet=] [--daemon-address=:] []"; success_msg_writer() << desc_all << '\n' << w.get_commands_str(); return false; } else if (command_line::get_arg(vm, command_line::arg_version)) { - success_msg_writer() << CRYPTONOTE_NAME << " wallet v" << MONERO_VERSION_FULL; + success_msg_writer() << CRYPTONOTE_NAME << " " << sw::tr("wallet") << " v" << MONERO_VERSION_FULL; return false; } @@ -1737,7 +1899,9 @@ int main(int argc, char* argv[]) return 0; // log_file_path - // default: /simplewallet.log + // default: < argv[0] directory >/simplewallet.log + // so if ran as "simplewallet" (no path), log file will be in cwd + // // if log-file argument given: // absolute path // relative path: relative to cwd @@ -1755,12 +1919,14 @@ int main(int argc, char* argv[]) LOG_LEVEL_4 ); - message_writer(epee::log_space::console_color_white, true) << CRYPTONOTE_NAME << " wallet v" << MONERO_VERSION_FULL; + message_writer(epee::log_space::console_color_white, true) << CRYPTONOTE_NAME << " " << sw::tr("wallet") << " v" << MONERO_VERSION_FULL; if(command_line::has_arg(vm, arg_log_level)) log_level = command_line::get_arg(vm, arg_log_level); LOG_PRINT_L0("Setting log level = " << log_level); - message_writer(epee::log_space::console_color_white, true) << "Logging at log level " << log_level << " to " << log_file_path.string(); + LOG_PRINT_L0(sw::tr("default_log: ") << default_log.string()); + message_writer(epee::log_space::console_color_white, true) << boost::format(sw::tr("Logging at log level %d to %s")) % + log_level % log_file_path.string(); log_space::get_set_log_detalisation_level(true, log_level); if (command_line::has_arg(vm, RPC::Wallet::arg_rpc_bind_port)) @@ -1769,17 +1935,17 @@ int main(int argc, char* argv[]) //runs wallet with rpc interface if(!command_line::has_arg(vm, arg_wallet_file) ) { - LOG_ERROR("Wallet file not set."); + LOG_ERROR(sw::tr("Wallet file not set.")); return 1; } if(!command_line::has_arg(vm, arg_daemon_address) ) { - LOG_ERROR("Daemon address not set."); + LOG_ERROR(sw::tr("Daemon address not set.")); return 1; } if(!command_line::has_arg(vm, arg_password) ) { - LOG_ERROR("Wallet password not set."); + LOG_ERROR(sw::tr("Wallet password not set.")); return 1; } @@ -1801,15 +1967,15 @@ int main(int argc, char* argv[]) // RPC::Wallet::init(&wal); try { - LOG_PRINT_L0("Loading wallet..."); + LOG_PRINT_L0(sw::tr("Loading wallet...")); wal.load(wallet_file, wallet_password); wal.init(daemon_address); wal.refresh(); - LOG_PRINT_GREEN("Loaded ok", LOG_LEVEL_0); + LOG_PRINT_GREEN(sw::tr("Loaded ok"), LOG_LEVEL_0); } catch (const std::exception& e) { - LOG_ERROR("Wallet initialize failed: " << e.what()); + LOG_ERROR(sw::tr("Wallet initialization failed: ") << e.what()); return 1; } // std::string ip_address, port; @@ -1818,7 +1984,7 @@ int main(int argc, char* argv[]) tools::wallet_rpc_server wrpc(wal); bool r = wrpc.init(vm); - CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet rpc server"); + CHECK_AND_ASSERT_MES(r, 1, sw::tr("Failed to initialize wallet rpc server")); /*tools::signal_handler::install([&rpc_server, &wal] { rpc_server.stop(); @@ -1828,19 +1994,20 @@ int main(int argc, char* argv[]) wrpc.send_stop_signal(); wal.store(); }); - LOG_PRINT_L0("Starting wallet rpc server"); + LOG_PRINT_L0(sw::tr("Starting wallet rpc server")); wrpc.run(); - LOG_PRINT_L0("Stopped wallet rpc server"); + + LOG_PRINT_L0(sw::tr("Stopped wallet rpc server")); wal.stop_ipc_client(); try { - LOG_PRINT_L0("Storing wallet..."); + LOG_PRINT_L0(sw::tr("Storing wallet...")); wal.store(); - LOG_PRINT_GREEN("Stored ok", LOG_LEVEL_0); + LOG_PRINT_GREEN(sw::tr("Stored ok"), LOG_LEVEL_0); } catch (const std::exception& e) { - LOG_ERROR("Failed to store wallet: " << e.what()); + LOG_ERROR(sw::tr("Failed to store wallet: ") << e.what()); return 1; } } @@ -1848,7 +2015,7 @@ int main(int argc, char* argv[]) { //runs wallet with console interface r = w.init(vm); - CHECK_AND_ASSERT_MES(r, 1, "Failed to initialize wallet"); + CHECK_AND_ASSERT_MES(r, 1, sw::tr("Failed to initialize wallet")); std::vector command = command_line::get_arg(vm, arg_command); if (!command.empty()) diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 2b8ca0ed2..8aca93210 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -57,6 +57,9 @@ namespace cryptonote */ class simple_wallet : public tools::i_wallet2_callback { + public: + static const char *tr(const char *str) { return i18n_translate(str, "cryptonote::simple_wallet"); } + public: typedef std::vector command_type; @@ -95,6 +98,7 @@ namespace cryptonote * \return success status */ bool seed_set_language(const std::vector &args = std::vector()); + bool set_always_confirm_transfers(const std::vector &args = std::vector()); bool help(const std::vector &args = std::vector()); bool start_mining(const std::vector &args); bool stop_mining(const std::vector &args); @@ -104,7 +108,9 @@ namespace cryptonote bool show_incoming_transfers(const std::vector &args); bool show_payments(const std::vector &args); bool show_blockchain_height(const std::vector &args); + bool transfer_main(bool new_algorithm, const std::vector &args); bool transfer(const std::vector &args); + bool transfer_new(const std::vector &args); bool sweep_dust(const std::vector &args); std::vector> split_amounts( std::vector dsts, size_t num_splits @@ -114,6 +120,7 @@ namespace cryptonote bool save(const std::vector &args); bool save_watch_only(const std::vector &args); bool set_variable(const std::vector &args); + bool rescan_spent(const std::vector &args); bool set_log(const std::vector &args); uint64_t get_daemon_blockchain_height(std::string& err); @@ -165,7 +172,7 @@ namespace cryptonote if (std::chrono::milliseconds(1) < current_time - m_print_time || force) { - std::cout << "Height " << height << " of " << m_blockchain_height << '\r'; + std::cout << QT_TRANSLATE_NOOP("cryptonote::simple_wallet", "Height ") << height << " / " << m_blockchain_height << '\r'; m_print_time = current_time; } } diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index dce4ad5af..56541ba27 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -59,6 +59,12 @@ extern "C" } using namespace cryptonote; +// used to choose when to stop adding outputs to a tx +#define APPROXIMATE_INPUT_BYTES 80 + +// used to target a given block size (additional outputs may be added on top to build fee) +#define TX_SIZE_TARGET(bytes) (bytes*2/3) + namespace { void do_prepare_file_names(const std::string& file_path, std::string& keys_file, std::string& wallet_file) @@ -145,6 +151,7 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_ process_unconfirmed(tx); std::vector outs; uint64_t tx_money_got_in_outs = 0; + crypto::public_key tx_pub_key = null_pkey; std::vector tx_extra_fields; if(!parse_tx_extra(tx.extra, tx_extra_fields)) @@ -165,14 +172,14 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_ return; } - crypto::public_key tx_pub_key = pub_key_field.pub_key; + tx_pub_key = pub_key_field.pub_key; bool r = lookup_acc_outs(m_account.get_keys(), tx, tx_pub_key, outs, tx_money_got_in_outs); THROW_WALLET_EXCEPTION_IF(!r, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys()); if(!outs.empty() && tx_money_got_in_outs) { connect_to_daemon(); - THROW_WALLET_EXCEPTION_IF(ipc_client == NULL, error::no_connection_to_daemon, "get_output_indexes"); + THROW_WALLET_EXCEPTION_IF(!check_connection(), error::no_connection_to_daemon, "get_output_indexes"); //good news - got money! take care about it //usually we have only one transfer for user in transaction @@ -245,9 +252,34 @@ void wallet2::process_new_transaction(const cryptonote::transaction& tx, uint64_ crypto::hash payment_id = null_hash; if (find_tx_extra_field_by_type(tx_extra_fields, extra_nonce)) { - if(get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) + crypto::hash8 payment_id8 = null_hash8; + if(get_encrypted_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id8)) { // We got a payment ID to go with this tx + LOG_PRINT_L2("Found encrypted payment ID: " << payment_id8); + if (tx_pub_key != null_pkey) + { + if (!decrypt_payment_id(payment_id8, tx_pub_key, m_account.get_keys().m_view_secret_key)) + { + LOG_PRINT_L0("Failed to decrypt payment ID: " << payment_id8); + } + else + { + LOG_PRINT_L2("Decrypted payment ID: " << payment_id8); + // put the 64 bit decrypted payment id in the first 8 bytes + memcpy(payment_id.data, payment_id8.data, 8); + // rest is already 0, but guard against code changes above + memset(payment_id.data + 8, 0, 24); + } + } + else + { + LOG_PRINT_L1("No public key found in tx, unable to decrypt payment id"); + } + } + else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id)) + { + LOG_PRINT_L2("Found unencrypted payment ID: " << payment_id); } } uint64_t received = (tx_money_spent_in_ins < tx_money_got_in_outs) ? tx_money_got_in_outs - tx_money_spent_in_ins : 0; @@ -350,7 +382,7 @@ void wallet2::get_blocks_from_zmq_msg(zmsg_t *msg, std::list block_ids; get_short_chain_history(block_ids); @@ -558,6 +590,9 @@ bool wallet2::store_keys(const std::string& keys_file_name, const std::string& p value2.SetInt(watch_only ? 1 :0); // WTF ? JSON has different true and false types, and not boolean ?? json.AddMember("watch_only", value2, json.GetAllocator()); + value2.SetInt(m_always_confirm_transfers ? 1 :0); + json.AddMember("always_confirm_transfers", value2, json.GetAllocator()); + // Serialize the JSON object rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); @@ -618,6 +653,7 @@ void wallet2::load_keys(const std::string& keys_file_name, const std::string& pa { is_old_file_format = true; m_watch_only = false; + m_always_confirm_transfers = false; } else { @@ -636,6 +672,7 @@ void wallet2::load_keys(const std::string& keys_file_name, const std::string& pa { m_watch_only = false; } + m_always_confirm_transfers = json.HasMember("always_confirm_transfers") && (json["always_confirm_transfers"].GetInt() != 0); } const cryptonote::account_keys& keys = m_account.get_keys(); @@ -716,6 +753,7 @@ crypto::secret_key wallet2::generate(const std::string& wallet_, const std::stri crypto::secret_key retval = m_account.generate(recovery_param, recover, two_random); m_account_public_address = m_account.get_keys().m_account_address; + m_watch_only = false; bool r = store_keys(m_keys_file, password, false); THROW_WALLET_EXCEPTION_IF(!r, error::file_save_error, m_keys_file); @@ -809,7 +847,7 @@ bool wallet2::wallet_valid_path_format(const std::string& file_path) return !file_path.empty(); } //---------------------------------------------------------------------------------------------------- -bool wallet2::parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id) +bool wallet2::parse_long_payment_id(const std::string& payment_id_str, crypto::hash& payment_id) { cryptonote::blobdata payment_id_data; if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data)) @@ -822,6 +860,33 @@ bool wallet2::parse_payment_id(const std::string& payment_id_str, crypto::hash& return true; } //---------------------------------------------------------------------------------------------------- +bool wallet2::parse_short_payment_id(const std::string& payment_id_str, crypto::hash8& payment_id) +{ + cryptonote::blobdata payment_id_data; + if(!epee::string_tools::parse_hexstr_to_binbuff(payment_id_str, payment_id_data)) + return false; + + if(sizeof(crypto::hash8) != payment_id_data.size()) + return false; + + payment_id = *reinterpret_cast(payment_id_data.data()); + return true; +} +//---------------------------------------------------------------------------------------------------- +bool wallet2::parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id) +{ + if (parse_long_payment_id(payment_id_str, payment_id)) + return true; + crypto::hash8 payment_id8; + if (parse_short_payment_id(payment_id_str, payment_id8)) + { + memcpy(payment_id.data, payment_id8.data, 8); + memset(payment_id.data + 8, 0, 24); + return true; + } + return false; +} +//---------------------------------------------------------------------------------------------------- bool wallet2::prepare_file_names(const std::string& file_path) { do_prepare_file_names(file_path, m_keys_file, m_wallet_file); @@ -941,6 +1006,47 @@ void wallet2::get_payments(std::list key_images; + + // make a list of key images for all our outputs + for (size_t i = 0; i < m_transfers.size(); ++i) + { + const transfer_details& td = m_transfers[i]; + key_images.push_back(string_tools::pod_to_hex(td.m_key_image)); + } + + COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req); + COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp); + req.key_images = key_images; + bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/is_key_image_spent", req, daemon_resp, m_http_client, 200000); + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent"); + THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent"); + THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status); + THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != key_images.size(), error::wallet_internal_error, + "daemon returned wrong response for is_key_image_spent, wrong amounts count = " + + std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(key_images.size())); + + // update spent status + for (size_t i = 0; i < m_transfers.size(); ++i) + { + transfer_details& td = m_transfers[i]; + if (td.m_spent != daemon_resp.spent_status[i]) + { + if (td.m_spent) + { + LOG_PRINT_L1("Marking output " << i << " as unspent, it was marked as spent"); + } + else + { + LOG_PRINT_L1("Marking output " << i << " as spent, it was marked as unspent"); + } + td.m_spent = daemon_resp.spent_status[i]; + } + } +} +//---------------------------------------------------------------------------------------------------- bool wallet2::is_transfer_unlocked(const transfer_details& td) const { if(!is_tx_spendtime_unlocked(td.m_tx.unlock_time)) @@ -976,11 +1082,10 @@ bool wallet2::is_tx_spendtime_unlocked(uint64_t unlock_time) const namespace { template - T pop_random_value(std::vector& vec) + T pop_index(std::vector& vec, size_t idx) { CHECK_AND_ASSERT_MES(!vec.empty(), T(), "Vector must be non-empty"); - size_t idx = crypto::rand() % vec.size(); T res = vec[idx]; if (idx + 1 != vec.size()) { @@ -990,6 +1095,15 @@ namespace return res; } + + template + T pop_random_value(std::vector& vec) + { + CHECK_AND_ASSERT_MES(!vec.empty(), T(), "Vector must be non-empty"); + + size_t idx = crypto::rand() % vec.size(); + return pop_index (vec, idx); + } } //---------------------------------------------------------------------------------------------------- // Select random input sources for transaction. @@ -1184,7 +1298,7 @@ void wallet2::commit_tx(pending_tx& ptx) using namespace cryptonote; connect_to_daemon(); - THROW_WALLET_EXCEPTION_IF(ipc_client == NULL, error::no_connection_to_daemon, "send_raw_transaction"); + THROW_WALLET_EXCEPTION_IF(!check_connection(), error::no_connection_to_daemon, "send_raw_transaction"); std::string tx_as_hex_string = epee::string_tools::buff_to_hex_nodelimer(tx_to_blob(ptx.tx)); zchunk_t *tx_as_hex = zchunk_new((void*)tx_as_hex_string.c_str(), tx_as_hex_string.length()); int rc = wap_client_put(ipc_client, &tx_as_hex); @@ -1320,6 +1434,421 @@ std::vector wallet2::create_transactions(std::vector +void wallet2::transfer_selected(const std::vector& dsts, const std::list selected_transfers, size_t fake_outputs_count, + 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) +{ + using namespace cryptonote; + // throw if attempting a transaction with no destinations + THROW_WALLET_EXCEPTION_IF(dsts.empty(), error::zero_destination); + + uint64_t needed_money = fee; + LOG_PRINT_L2("transfer: starting with fee " << print_money (needed_money)); + + // calculate total amount being sent to all destinations + // throw if total amount overflows uint64_t + BOOST_FOREACH(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_testnet); + } + + uint64_t found_money = 0; + BOOST_FOREACH(auto it, selected_transfers) + { + found_money += it->amount(); + } + + 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_money, found_money, needed_money - fee, fee); + + typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; + typedef cryptonote::tx_source_entry::output_entry tx_output_entry; + + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response daemon_resp = AUTO_VAL_INIT(daemon_resp); + if(fake_outputs_count) + { + connect_to_daemon(); + THROW_WALLET_EXCEPTION_IF(!check_connection(), error::no_connection_to_daemon, "get_random_outs"); + uint64_t outs_count = fake_outputs_count + 1; + std::vector amounts; + BOOST_FOREACH(transfer_container::iterator it, selected_transfers) + { + THROW_WALLET_EXCEPTION_IF(it->m_tx.vout.size() <= it->m_internal_output_index, error::wallet_internal_error, + "m_internal_output_index = " + std::to_string(it->m_internal_output_index) + + " is greater or equal to outputs count = " + std::to_string(it->m_tx.vout.size())); + amounts.push_back(it->amount()); + } + zframe_t *amounts_frame = zframe_new(&amounts[0], amounts.size() * sizeof(uint64_t)); + int rc = wap_client_random_outs(ipc_client, outs_count, &amounts_frame); + uint64_t status = wap_client_status(ipc_client); + THROW_WALLET_EXCEPTION_IF(status == IPC::STATUS_CORE_BUSY, error::daemon_busy, "getrandomouts"); + // TODO: Use a code to string mapping of errors + THROW_WALLET_EXCEPTION_IF(status == IPC::STATUS_RANDOM_OUTS_FAILED, error::get_random_outs_error, "IPC::STATUS_RANDOM_OUTS_FAILED"); + THROW_WALLET_EXCEPTION_IF(status != IPC::STATUS_OK, error::get_random_outs_error, "!IPC:STATUS_OK"); + // Convert ZMQ response back into RPC response object. + zframe_t *outputs_frame = wap_client_random_outputs(ipc_client); + uint64_t frame_size = zframe_size(outputs_frame); + char *frame_data = reinterpret_cast(zframe_data(outputs_frame)); + rapidjson::Document json; + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response daemon_resp = AUTO_VAL_INIT(daemon_resp); + THROW_WALLET_EXCEPTION_IF(json.Parse(frame_data, frame_size).HasParseError(), error::get_random_outs_error, "Couldn't JSON parse random outputs."); + for (rapidjson::SizeType i = 0; i < json["outputs"].Size(); i++) { + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount output; + output.amount = json["outputs"][i]["amount"].GetInt64(); + for (rapidjson::SizeType j = 0; j < json["outputs"][i]["outs"].Size(); j++) { + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry entry; + entry.global_amount_index = json["outputs"][i]["outs"][j]["global_amount_index"].GetInt64(); + std::string out_key(json["outputs"][i]["outs"][j]["out_key"].GetString(), json["outputs"][i]["outs"][j]["out_key"].GetStringLength()); + memcpy(entry.out_key.data, out_key.c_str(), 32); + output.outs.push_back(entry); + } + daemon_resp.outs.push_back(output); + } + + THROW_WALLET_EXCEPTION_IF(daemon_resp.outs.size() != selected_transfers.size(), error::wallet_internal_error, + "daemon returned wrong response for getrandom_outs.bin, wrong amounts count = " + + std::to_string(daemon_resp.outs.size()) + ", expected " + std::to_string(selected_transfers.size())); + + std::vector scanty_outs; + BOOST_FOREACH(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& amount_outs, daemon_resp.outs) + { + if (amount_outs.outs.size() < fake_outputs_count) + { + scanty_outs.push_back(amount_outs); + } + } + THROW_WALLET_EXCEPTION_IF(!scanty_outs.empty(), error::not_enough_outs_to_mix, scanty_outs, fake_outputs_count); + } + + //prepare inputs + size_t i = 0; + std::vector sources; + BOOST_FOREACH(transfer_container::iterator it, selected_transfers) + { + sources.resize(sources.size()+1); + cryptonote::tx_source_entry& src = sources.back(); + transfer_details& td = *it; + src.amount = td.amount(); + //paste mixin transaction + if(daemon_resp.outs.size()) + { + daemon_resp.outs[i].outs.sort([](const out_entry& a, const out_entry& b){return a.global_amount_index < b.global_amount_index;}); + BOOST_FOREACH(out_entry& daemon_oe, daemon_resp.outs[i].outs) + { + if(td.m_global_output_index == daemon_oe.global_amount_index) + continue; + tx_output_entry oe; + oe.first = daemon_oe.global_amount_index; + oe.second = daemon_oe.out_key; + src.outputs.push_back(oe); + if(src.outputs.size() >= fake_outputs_count) + break; + } + } + + //paste real transaction to the random index + auto it_to_insert = std::find_if(src.outputs.begin(), src.outputs.end(), [&](const tx_output_entry& a) + { + return a.first >= td.m_global_output_index; + }); + //size_t real_index = src.outputs.size() ? (rand() % src.outputs.size() ):0; + tx_output_entry real_oe; + real_oe.first = td.m_global_output_index; + real_oe.second = boost::get(td.m_tx.vout[td.m_internal_output_index].target).key; + auto interted_it = src.outputs.insert(it_to_insert, real_oe); + 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; + detail::print_source_entry(src); + ++i; + } + + cryptonote::tx_destination_entry change_dts = AUTO_VAL_INIT(change_dts); + if (needed_money < found_money) + { + change_dts.addr = m_account.get_keys().m_account_address; + change_dts.amount = found_money - needed_money; + } + + uint64_t dust = 0; + std::vector splitted_dsts; + destination_split_strategy(dsts, change_dts, dust_policy.dust_threshold, splitted_dsts, dust); + THROW_WALLET_EXCEPTION_IF(dust_policy.dust_threshold < dust, error::wallet_internal_error, "invalid dust value: dust = " + + std::to_string(dust) + ", dust_threshold = " + std::to_string(dust_policy.dust_threshold)); + if (0 != dust && !dust_policy.add_to_fee) + { + splitted_dsts.push_back(cryptonote::tx_destination_entry(dust, dust_policy.addr_for_dust)); + } + + bool r = cryptonote::construct_tx(m_account.get_keys(), sources, splitted_dsts, extra, tx, unlock_time); + THROW_WALLET_EXCEPTION_IF(!r, error::tx_not_constructed, sources, splitted_dsts, unlock_time, m_testnet); + THROW_WALLET_EXCEPTION_IF(m_upper_transaction_size_limit <= get_object_blobsize(tx), error::tx_too_big, tx, m_upper_transaction_size_limit); + + 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); + + ptx.key_images = key_images; + ptx.fee = fee; + ptx.dust = dust; + ptx.tx = tx; + ptx.change_dts = change_dts; + ptx.selected_transfers = selected_transfers; + +} + +// Another implementation of transaction creation that is hopefully better +// While there is anything left to pay, it goes through random outputs and tries +// to fill the next destination/amount. If it fully fills it, it will use the +// remainder to try to fill the next one as well. +// The tx size if roughly estimated as a linear function of only inputs, and a +// new tx will be created when that size goes above a given fraction of the +// max tx size. At that point, more outputs may be added if the fee cannot be +// satisfied. +// If the next output in the next tx would go to the same destination (ie, we +// cut off at a tx boundary in the middle of paying a given destination), the +// fee will be carved out of the current input if possible, to avoid having to +// add another output just for the fee and getting change. +// This system allows for sending (almost) the entire balance, since it does +// not generate spurious change in all txes, thus decreasing the instantaneous +// usable balance. +std::vector wallet2::create_transactions_2(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra) +{ + std::vector unused_transfers_indices; + std::vector unused_dust_indices; + uint64_t needed_money; + uint64_t accumulated_fee, accumulated_outputs, accumulated_change; + struct TX { + std::list selected_transfers; + std::vector dsts; + cryptonote::transaction tx; + pending_tx ptx; + size_t bytes; + + void add(const account_public_address &addr, uint64_t amount) { + 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.push_back(tx_destination_entry(amount,addr)); + else + i->amount += amount; + } + }; + std::vector txes; + bool adding_fee; // true if new outputs go towards fee, rather than destinations + uint64_t needed_fee, available_for_fee = 0; + + // 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 + needed_money = 0; + BOOST_FOREACH(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, 0, m_testnet); + } + + // throw if attempting a transaction with no money + THROW_WALLET_EXCEPTION_IF(needed_money == 0, error::zero_destination); + + // gather all our dust and non dust outputs + for (size_t i = 0; i < m_transfers.size(); ++i) + { + const transfer_details& td = m_transfers[i]; + if (!td.m_spent && is_transfer_unlocked(td)) + { + if (::config::DEFAULT_DUST_THRESHOLD <= td.amount()) + unused_transfers_indices.push_back(i); + else + unused_dust_indices.push_back(i); + } + } + LOG_PRINT_L2("Starting with " << unused_transfers_indices.size() << " non-dust outputs and " << unused_dust_indices.size() << " dust outputs"); + + // start with an empty tx + txes.push_back(TX()); + accumulated_fee = 0; + accumulated_outputs = 0; + accumulated_change = 0; + adding_fee = false; + needed_fee = 0; + + // while we have something to send + while ((!dsts.empty() && dsts[0].amount > 0) || adding_fee) { + TX &tx = txes.back(); + + // if we need to spend money and don't have any left, we fail + if (unused_dust_indices.empty() && unused_transfers_indices.empty()) { + LOG_PRINT_L2("No more outputs to choose from"); + THROW_WALLET_EXCEPTION_IF(1, error::not_enough_money, unlocked_balance(), needed_money, accumulated_fee + needed_fee); + } + + // get a random unspent 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 = !unused_transfers_indices.empty() ? pop_random_value(unused_transfers_indices) : pop_random_value(unused_dust_indices); + + const transfer_details &td = m_transfers[idx]; + LOG_PRINT_L2("Picking output " << idx << ", amount " << print_money(td.amount())); + + // add this output to the list to spend + tx.selected_transfers.push_back(m_transfers.begin() + idx); + uint64_t available_amount = td.amount(); + accumulated_outputs += available_amount; + + if (adding_fee) + { + LOG_PRINT_L2("We need more fee, adding it to fee"); + available_for_fee += available_amount; + } + else + { + while (!dsts.empty() && dsts[0].amount <= available_amount) + { + // we can fully pay that destination + LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_testnet, dsts[0].addr) << + " for " << print_money(dsts[0].amount)); + tx.add(dsts[0].addr, dsts[0].amount); + available_amount -= dsts[0].amount; + dsts[0].amount = 0; + pop_index(dsts, 0); + } + + if (available_amount > 0 && !dsts.empty()) { + // we can partially fill that destination + LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_testnet, dsts[0].addr) << + " for " << print_money(available_amount) << "/" << print_money(dsts[0].amount)); + tx.add(dsts[0].addr, available_amount); + dsts[0].amount -= available_amount; + available_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 " + << m_upper_transaction_size_limit); + bool try_tx; + 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 + { + try_tx = dsts.empty() || (tx.selected_transfers.size() * (fake_outs_count+1) * APPROXIMATE_INPUT_BYTES >= TX_SIZE_TARGET(m_upper_transaction_size_limit)); + } + + if (try_tx) { + cryptonote::transaction test_tx; + pending_tx test_ptx; + + needed_fee = 0; + + LOG_PRINT_L2("Trying to create a tx now, with " << tx.dsts.size() << " destinations and " << + tx.selected_transfers.size() << " outputs"); + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra, + detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); + auto txBlob = t_serializable_object_to_blob(test_ptx.tx); + uint64_t txSize = txBlob.size(); + uint64_t numKB = txSize / 1024; + if (txSize % 1024) + { + numKB++; + } + needed_fee = numKB * FEE_PER_KB; + available_for_fee = test_ptx.fee + test_ptx.change_dts.amount; + LOG_PRINT_L2("Made a " << numKB << " kB tx, with " << print_money(available_for_fee) << " available for fee (" << + print_money(needed_fee) << " needed)"); + + if (needed_fee > available_for_fee && 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 + 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_testnet, i->addr) << " from " << + print_money(i->amount) << " to " << print_money(new_paid_amount) << " to accomodate " << + 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 (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"); + transfer_selected(tx.dsts, tx.selected_transfers, fake_outs_count, unlock_time, needed_fee, extra, + detail::digit_split_strategy, tx_dust_policy(::config::DEFAULT_DUST_THRESHOLD), test_tx, test_ptx); + txBlob = t_serializable_object_to_blob(test_ptx.tx); + LOG_PRINT_L2("Made a final " << ((txBlob.size() + 1023)/1024) << " kB tx, with " << print_money(test_ptx.fee) << + " fee and " << print_money(test_ptx.change_dts.amount) << " change"); + + tx.tx = test_tx; + tx.ptx = test_ptx; + tx.bytes = txBlob.size(); + accumulated_fee += test_ptx.fee; + accumulated_change += test_ptx.change_dts.amount; + adding_fee = false; + if (!dsts.empty()) + { + LOG_PRINT_L2("We have more to pay, starting another tx"); + txes.push_back(TX()); + } + } + } + } + + if (adding_fee) + { + LOG_PRINT_L1("We ran out of outputs while trying to gather final fee"); + THROW_WALLET_EXCEPTION_IF(1, error::not_enough_money, unlocked_balance(), needed_money, accumulated_fee + needed_fee); + } + + LOG_PRINT_L1("Done creating " << txes.size() << " transactions, " << print_money(accumulated_fee) << + " total fee, " << print_money(accumulated_change) << " total change"); + + std::vector ptx_vector; + for (std::vector::iterator i = txes.begin(); i != txes.end(); ++i) + { + TX &tx = *i; + uint64_t tx_money = 0; + for (std::list::const_iterator mi = tx.selected_transfers.begin(); mi != tx.selected_transfers.end(); ++mi) + tx_money += (*mi)->amount(); + LOG_PRINT_L1(" Transaction " << (1+std::distance(txes.begin(), i)) << "/" << txes.size() << + ": " << (tx.bytes+1023)/1024 << " kB, sending " << print_money(tx_money) << " in " << tx.selected_transfers.size() << + " outputs to " << tx.dsts.size() << " destination(s), including " << + print_money(tx.ptx.fee) << " fee, " << print_money(tx.ptx.change_dts.amount) << " change"); + ptx_vector.push_back(tx.ptx); + } + + // if we made it this far, we're OK to actually send the transactions + return ptx_vector; +} + uint64_t wallet2::unlocked_dust_balance(const tx_dust_policy &dust_policy) const { uint64_t money = 0; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index eea7908ac..20e10e4a1 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -81,7 +81,7 @@ namespace tools class wallet2 { - wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false) {}; + wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers (false) {}; public: wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet) { ipc_client = NULL; @@ -235,15 +235,21 @@ namespace tools void transfer(const std::vector& dsts, size_t fake_outputs_count, uint64_t unlock_time, uint64_t fee, const std::vector& extra, cryptonote::transaction& tx, pending_tx& ptx); template void transfer_dust(size_t num_outputs, uint64_t unlock_time, uint64_t needed_fee, T destination_split_strategy, const tx_dust_policy& dust_policy, const std::vector& extra, cryptonote::transaction& tx, pending_tx &ptx); + template + void transfer_selected(const std::vector& dsts, const std::list selected_transfers, size_t fake_outputs_count, + 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 commit_tx(pending_tx& ptx_vector); void commit_tx(std::vector& ptx_vector); std::vector create_transactions(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee, const std::vector extra); + std::vector create_transactions_2(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, const uint64_t fee_UNUSED, const std::vector extra); std::vector create_dust_sweep_transactions(); bool check_connection(); void get_transfers(wallet2::transfer_container& incoming_transfers) const; void get_payments(const crypto::hash& payment_id, std::list& payments, uint64_t min_height = 0) const; void get_payments(std::list>& payments, uint64_t min_height) const; uint64_t get_blockchain_current_height() const { return m_local_bc_height; } + void rescan_spent(); template inline void serialize(t_archive &a, const unsigned int ver) { @@ -276,6 +282,8 @@ namespace tools */ static bool wallet_valid_path_format(const std::string& file_path); + static bool parse_long_payment_id(const std::string& payment_id_str, crypto::hash& payment_id); + static bool parse_short_payment_id(const std::string& payment_id_str, crypto::hash8& payment_id); static bool parse_payment_id(const std::string& payment_id_str, crypto::hash& payment_id); static std::vector addresses_from_url(const std::string& url, bool& dnssec_valid); @@ -286,6 +294,10 @@ namespace tools uint64_t stop_mining(); uint64_t get_height(uint64_t &height); uint64_t save_bc(); + + bool always_confirm_transfers() const { return m_always_confirm_transfers; } + void always_confirm_transfers(bool always) { m_always_confirm_transfers = always; } + private: /*! * \brief Stores wallet information to wallet file. @@ -342,6 +354,7 @@ namespace tools bool is_old_file_format; /*!< Whether the wallet file is of an old file format */ wap_client_t *ipc_client; bool m_watch_only; /*!< no spend key */ + bool m_always_confirm_transfers; }; } BOOST_CLASS_VERSION(tools::wallet2, 7) @@ -487,7 +500,7 @@ namespace tools if(fake_outputs_count) { connect_to_daemon(); - THROW_WALLET_EXCEPTION_IF(ipc_client == NULL, error::no_connection_to_daemon, "get_random_outs"); + THROW_WALLET_EXCEPTION_IF(!check_connection(), error::no_connection_to_daemon, "get_random_outs"); uint64_t outs_count = fake_outputs_count + 1; std::vector amounts; BOOST_FOREACH(transfer_container::iterator it, selected_transfers) diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index 95120269d..797a0b944 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -73,6 +73,7 @@ namespace tools // wallet_rpc_error * // daemon_busy // no_connection_to_daemon + // is_key_image_spent_error // wallet_files_doesnt_correspond // // * - class with protected ctor @@ -581,6 +582,14 @@ namespace tools } }; //---------------------------------------------------------------------------------------------------- + struct is_key_image_spent_error : public wallet_rpc_error + { + explicit is_key_image_spent_error(std::string&& loc, const std::string& request) + : wallet_rpc_error(std::move(loc), "error from is_key_image_spent call", request) + { + } + }; + //---------------------------------------------------------------------------------------------------- struct wallet_files_doesnt_correspond : public wallet_logic_error { explicit wallet_files_doesnt_correspond(std::string&& loc, const std::string& keys_file, const std::string& wallet_file) diff --git a/src/wallet/wallet_rpc_server.cpp b/src/wallet/wallet_rpc_server.cpp index 7c82e69f8..7dfd64eef 100644 --- a/src/wallet/wallet_rpc_server.cpp +++ b/src/wallet/wallet_rpc_server.cpp @@ -119,12 +119,13 @@ namespace tools //------------------------------------------------------------------------------------------------------------------------------ bool wallet_rpc_server::validate_transfer(const std::list destinations, std::string payment_id, std::vector& dsts, std::vector& extra, epee::json_rpc::error& er) { - crypto::hash integrated_payment_id = cryptonote::null_hash; + crypto::hash8 integrated_payment_id = cryptonote::null_hash8; + std::string extra_nonce; for (auto it = destinations.begin(); it != destinations.end(); it++) { cryptonote::tx_destination_entry de; bool has_payment_id; - crypto::hash new_payment_id; + crypto::hash8 new_payment_id; if(!get_account_integrated_address_from_str(de.addr, has_payment_id, new_payment_id, m_wallet.testnet(), it->address)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_ADDRESS; @@ -136,13 +137,14 @@ namespace tools if (has_payment_id) { - if (!payment_id.empty() || integrated_payment_id != cryptonote::null_hash) + if (!payment_id.empty() || integrated_payment_id != cryptonote::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 = new_payment_id; + cryptonote::set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, integrated_payment_id); } } @@ -152,17 +154,23 @@ namespace tools /* Just to clarify */ const std::string& payment_id_str = payment_id; - crypto::hash payment_id; + crypto::hash long_payment_id; + crypto::hash8 short_payment_id; + /* Parse payment ID */ - if (!wallet2::parse_payment_id(payment_id_str, payment_id)) { + if (wallet2::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 (!wallet2::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 64-character string"; + er.message = "Payment id has invalid format: \"" + payment_id_str + "\", expected 16 or 64 character string"; return false; } - std::string extra_nonce; - cryptonote::set_payment_id_to_tx_extra_nonce(extra_nonce, 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; @@ -254,7 +262,11 @@ namespace tools try { - std::vector ptx_vector = m_wallet.create_transactions(dsts, req.mixin, req.unlock_time, req.fee, extra); + std::vector ptx_vector; + if (req.new_algorithm) + ptx_vector = m_wallet.create_transactions_2(dsts, req.mixin, req.unlock_time, req.fee, extra); + else + ptx_vector = m_wallet.create_transactions(dsts, req.mixin, req.unlock_time, req.fee, extra); m_wallet.commit_tx(ptx_vector); @@ -335,14 +347,14 @@ namespace tools { try { - crypto::hash payment_id; + crypto::hash8 payment_id; if (req.payment_id.empty()) { - crypto::generate_random_bytes(32, payment_id.data); + crypto::generate_random_bytes(8, payment_id.data); } else { - if (!tools::wallet2::parse_payment_id(req.payment_id,payment_id)) + if (!tools::wallet2::parse_short_payment_id(req.payment_id,payment_id)) { er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; er.message = "Invalid payment ID"; @@ -367,7 +379,7 @@ namespace tools try { cryptonote::account_public_address address; - crypto::hash payment_id; + crypto::hash8 payment_id; bool has_payment_id; if(!get_account_integrated_address_from_str(address, has_payment_id, payment_id, m_wallet.testnet(), req.integrated_address)) @@ -481,6 +493,7 @@ namespace tools for (auto & payment_id_str : req.payment_ids) { crypto::hash payment_id; + crypto::hash8 payment_id8; cryptonote::blobdata payment_id_blob; // TODO - should the whole thing fail because of one bad id? @@ -492,15 +505,23 @@ namespace tools return false; } - if(sizeof(payment_id) != payment_id_blob.size()) + if(sizeof(payment_id) == payment_id_blob.size()) + { + payment_id = *reinterpret_cast(payment_id_blob.data()); + } + else if(sizeof(payment_id8) == payment_id_blob.size()) + { + payment_id8 = *reinterpret_cast(payment_id_blob.data()); + memcpy(payment_id.data, payment_id8.data, 8); + memset(payment_id.data + 8, 0, 24); + } + else { er.code = WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID; er.message = "Payment ID has invalid size: " + payment_id_str; return false; } - payment_id = *reinterpret_cast(payment_id_blob.data()); - std::list payment_list; m_wallet.get_payments(payment_id, payment_list, req.min_block_height); diff --git a/src/wallet/wallet_rpc_server_commands_defs.h b/src/wallet/wallet_rpc_server_commands_defs.h index bff2cbf93..7786ab009 100644 --- a/src/wallet/wallet_rpc_server_commands_defs.h +++ b/src/wallet/wallet_rpc_server_commands_defs.h @@ -126,6 +126,7 @@ namespace wallet_rpc uint64_t mixin; uint64_t unlock_time; std::string payment_id; + bool new_algorithm; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(destinations) @@ -133,6 +134,7 @@ namespace wallet_rpc KV_SERIALIZE(mixin) KV_SERIALIZE(unlock_time) KV_SERIALIZE(payment_id) + KV_SERIALIZE(new_algorithm) END_KV_SERIALIZE_MAP() }; diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h index 09582da40..6b131e9eb 100644 --- a/tests/core_proxy/core_proxy.h +++ b/tests/core_proxy/core_proxy.h @@ -85,5 +85,7 @@ namespace tests cryptonote::blockchain_storage &get_blockchain_storage() { throw std::runtime_error("Called invalid member function: please never call get_blockchain_storage on the TESTING class proxy_core."); } bool get_test_drop_download() {return true;} bool get_test_drop_download_height() {return true;} + bool prepare_handle_incoming_blocks(const std::list &blocks) { return true; } + bool cleanup_handle_incoming_blocks(bool force_sync = false) { return true; } }; } diff --git a/tests/unit_tests/block_reward.cpp b/tests/unit_tests/block_reward.cpp index a572d2b75..7eed3a778 100644 --- a/tests/unit_tests/block_reward.cpp +++ b/tests/unit_tests/block_reward.cpp @@ -49,28 +49,28 @@ namespace #define TEST_ALREADY_GENERATED_COINS(already_generated_coins, expected_reward) \ m_block_not_too_big = get_block_reward(0, current_block_size, already_generated_coins, m_block_reward); \ ASSERT_TRUE(m_block_not_too_big); \ - ASSERT_EQ(m_block_reward, UINT64_C(expected_reward)); + ASSERT_EQ(m_block_reward, expected_reward); TEST_F(block_reward_and_already_generated_coins, handles_first_values) { // 17592186044415 from neozaru, confirmed by fluffypony - TEST_ALREADY_GENERATED_COINS(0, 17592186044415); - TEST_ALREADY_GENERATED_COINS(m_block_reward, 17592169267200); - TEST_ALREADY_GENERATED_COINS(UINT64_C(2756434948434199641), 14963444829249); + TEST_ALREADY_GENERATED_COINS(0, UINT64_C(17592186044415)); + TEST_ALREADY_GENERATED_COINS(m_block_reward, UINT64_C(17592169267200)); + TEST_ALREADY_GENERATED_COINS(UINT64_C(2756434948434199641), UINT64_C(14963444829249)); } TEST_F(block_reward_and_already_generated_coins, correctly_steps_from_2_to_1) { - TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((2 << 20) + 1), 2); - TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - (2 << 20) , 2); - TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((2 << 20) - 1), 1); + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((2 << 20) + 1), FINAL_SUBSIDY_PER_MINUTE); + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - (2 << 20) , FINAL_SUBSIDY_PER_MINUTE); + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((2 << 20) - 1), FINAL_SUBSIDY_PER_MINUTE); } TEST_F(block_reward_and_already_generated_coins, handles_max) { - TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((1 << 20) + 1), 1); - TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - (1 << 20) , 1); - TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((1 << 20) - 1), 0); + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((1 << 20) + 1), FINAL_SUBSIDY_PER_MINUTE); + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - (1 << 20) , FINAL_SUBSIDY_PER_MINUTE); + TEST_ALREADY_GENERATED_COINS(MONEY_SUPPLY - ((1 << 20) - 1), FINAL_SUBSIDY_PER_MINUTE); } //-------------------------------------------------------------------------------------------------------------------- diff --git a/translations/monero.ts b/translations/monero.ts new file mode 100644 index 000000000..7909266cc --- /dev/null +++ b/translations/monero.ts @@ -0,0 +1,1013 @@ + + + + + cryptonote::simple_wallet + + + Commands: + + + + + This wallet is watch-only and cannot have a seed. + + + + + The wallet is non-deterministic. Cannot display seed. + + + + + This wallet is watch-only and doesn't have a seed. + + + + + This wallet is non-deterministic and doesn't have a seed. + + + + + + + + + failed to read wallet password + + + + + + invalid password + + + + + This wallet is watch-only and cannot transfer. + + + + + start_mining [<number_of_threads>] - Start mining in daemon + + + + + Stop mining in daemon + + + + + Save current blockchain data + + + + + Resynchronize transactions and balance + + + + + Show current wallet balance + + + + + incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability + + + + + payments <payment_id_1> [<payment_id_2> ... <payment_id_N>] - Show payments <payment_id_1>, ... <payment_id_N> + + + + + Show blockchain height + + + + + transfer [<mixin_count>] <addr_1> <amount_1> [<addr_2> <amount_2> ... <addr_N> <amount_N>] [payment_id] - Transfer <amount_1>,... <amount_N> to <address_1>,... <address_N>, respectively. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available) + + + + + Send all dust outputs to the same address with mixin 0 + + + + + set_log <level> - Change current log detalization level, <level> is a number 0-4 + + + + + Show current wallet public address + + + + + Convert a payment ID to an integrated address for the current wallet public address (no arguments use a random payment ID), or display standard addres and payment ID corresponding to an integrated addres + + + + + Save wallet synchronized data + + + + + Save watch only keys file + + + + + Get viewkey + + + + + Get spendkey + + + + + Get deterministic seed + + + + + Show this help + + + + + available options: seed language - Set wallet seed langage; always-confirm-transfers <1|0> - whether to confirm unsplit txes + + + + + set: needs an argument. available options: seed, always-confirm-transfers + + + + + set seed: needs an argument. available options: language + + + + + set always-confirm-transfers: needs an argument (0 or 1) + + + + + set: unrecognized argument(s) + + + + + use: set_log <log_level_number_0-4> + + + + + wrong number format, use: set_log <log_level_number_0-4> + + + + + wrong number range, use: set_log <log_level_number_0-4> + + + + + Specify wallet file name (e.g., wallet.bin). If the wallet doesn't exist, it will be created. +Wallet file name: + + + + + + wallet file path not valid: + + + + + Attempting to generate or restore wallet, but specified file(s) exist. Exiting to not risk overwriting. + + + + + The wallet doesn't exist, generating new one + + + + + Keys file wasn't found: failed to open wallet: + + + + + PLEASE NOTE: the following 25 words can be used to recover access to your wallet. Please write them down and store them somewhere safe and secure. Please do not store them in your email or on file storage services outside of your immediate control. + + + + + + you can't specify daemon host or port several times + + + + + Specifying more than one of --generate-new-wallet="wallet_name", --wallet-file="wallet_name" and --generate-from-keys doesn't make sense! + + + + + Cannot specify both --restore-deterministic-wallet and --non-deterministic + + + + + specify a recovery parameter with the --electrum-seed="words list here" + + + + + electrum-style word list failed verification + + + + + --generate-from-view-key needs a address:viewkey:filename triple + + + + + Failed to parse address + + + + + Failed to parse view key secret key + + + + + wallet failed to connect to daemon: + + + + + Daemon either is not started or passed wrong port. Please, make sure that daemon is running or restart the wallet with correct daemon address. + + + + + List of available languages for your wallet's seed: + + + + + Enter the number corresponding to the language of your choice: + + + + + + Invalid language choice passed. Please try again. + + + + + + You had been using a deprecated version of the wallet. Please use the new seed that we provide. + + + + + + Generated new wallet: + + + + + + view key: + + + + + + failed to generate new wallet: + + + + + Your wallet has been generated. +To start synchronizing with the daemon use "refresh" command. +Use "help" command to see the list of available commands. +Always use "exit" command when closing simplewallet to save +current session's state. Otherwise, you will possibly need to synchronize +your wallet again. Your wallet key is NOT under risk anyway. + + + + + + Generated new watch-only wallet: + + + + + Opened watch-only wallet + + + + + Opened wallet + + + + + You had been using a deprecated version of the wallet. Please proceed to upgrade your wallet. + + + + + + You had been using a deprecated version of the wallet. Your wallet file format is being upgraded now. + + + + + + failed to load wallet: + + + + + Use "help" command to see the list of available commands. + + + + + + failed to deinit wallet + + + + + Wallet data saved + + + + + Password for the new watch-only wallet + + + + + Enter new password again + + + + + passwords do not match + + + + + invalid arguments. Please use start_mining [<number_of_threads>], <number_of_threads> should be from 1 to + + + + + Mining started in daemon + + + + + mining has NOT been started: + + + + + Mining stopped in daemon + + + + + mining has NOT been stopped: + + + + + Blockchain saved + + + + + Blockchain can't be saved: + + + + + + + Height + + + + + + + transaction + + + + + received + + + + + spent + + + + + unsupported transaction format + + + + + Starting refresh... + + + + + Refresh done, blocks received: + + + + + + + daemon is busy. Please try later + + + + + no connection to daemon. Please, make sure daemon is running + + + + + + + RPC error: + + + + + Error refreshing: + + + + + + + internal error: + + + + + + + unexpected error: + + + + + + + unknown error + + + + + refresh failed: + + + + + Blocks received: + + + + + balance: + + + + + unlocked balance: + + + + + including unlocked dust: + + + + + + amount + + + + + spent + + + + + global index + + + + + tx id + + + + + No incoming transfers + + + + + No incoming available transfers + + + + + No incoming unavailable transfers + + + + + expected at least one payment_id + + + + + payment + + + + + transaction + + + + + height + + + + + unlock time + + + + + No payments with id + + + + + + payment id has invalid format, expected 64-character string: + + + + + failed to get blockchain height: + + + + + wrong number of arguments + + + + + + This is a watch only wallet + + + + + DNSSEC validation passed + + + + + WARNING: DNSSEC validation was unsuccessful, this address may not be correct! + + + + + For URL: + + + + + Monero Address = + + + + + Is this OK? (Y/n) + + + + + yes + + + + + no + + + + + You have cancelled the transfer request + + + + + Failed to get a Monero address from: + + + + + Not yet supported: Multiple Monero addresses found for given URL: + + + + + Wrong address: + + + + + A single transaction cannot use more than one payment id: + + + + + Failed to set up payment id, though it was decoded correctly + + + + + amount is wrong: + + + + + expected number from 0 to + + + + + 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. Is this okay? (Y/Yes/N/No) + + + + + + Transaction cancelled. + + + + + Money successfully sent, transaction + + + + + + no connection to daemon. Please, make sure daemon is running. + + + + + + failed to get random outputs to mix + + + + + + not enough money to transfer, available only %s, transaction amount %s = %s + %s (fee) + + + + + + not enough outputs for specified mixin_count + + + + + + output amount + + + + + + found outputs to mix + + + + + + transaction was not constructed + + + + + + transaction %s was rejected by daemon with status: + + + + + + one of destinations is zero + + + + + + Failed to find a suitable way to split transactions + + + + + + unknown transfer error: + + + + + Sweeping + + + + + Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No) + + + + + Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No) + + + + + Money successfully sent, transaction: + + + + + wallet + + + + + integrated_address only takes one or zero arguments + + + + + Random payment ID: + + + + + Matching integrated address: + + + + + Integrated address: account %s, payment id %s + + + + + Standard address: account: + + + + + Failed to parse payment id or address + + + + + sw + + + Use wallet <arg> + + + + + Generate new wallet and save it to <arg> or <address>.wallet by default + + + + + Generate wallet from (address:viewkey:filename) and save it to <filename> + + + + + Use daemon instance at <host>:<port> + + + + + Use daemon instance at host <arg> instead of localhost + + + + + Wallet password + + + + + Specify electrum seed for wallet recovery/creation + + + + + Recover wallet using electrum-style mnemonic + + + + + creates non-deterministic view and spend keys + + + + + Use daemon instance at port <arg> instead of 8081 + + + + + Specify log file + + + + + Used to deploy test nets. The daemon must be launched with --testnet flag + + + + + Restricts RPC to view only commands + + + + + daemon is busy. Please try later + + + + + possible lost connection to daemon + + + + + Error: + + + + + yes + + + + + General options + + + + + Wallet options + + + + + default_log: + + + + + + + wallet + + + + + Usage: + + + + + Logging at log level %d to %s + + + + + Wallet file not set. + + + + + Daemon address not set. + + + + + Wallet password not set. + + + + + Loading wallet... + + + + + Loaded ok + + + + + Wallet initialization failed: + + + + + Failed to initialize wallet rpc server + + + + + Starting wallet rpc server + + + + + Stopped wallet rpc server + + + + + Storing wallet... + + + + + Stored ok + + + + + Failed to store wallet: + + + + + Failed to initialize wallet + + + + diff --git a/utils/translations/build-translations.sh b/utils/translations/build-translations.sh new file mode 100755 index 000000000..0956e633f --- /dev/null +++ b/utils/translations/build-translations.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +lrelease=`which lrelease 2> /dev/null` +if test -z "$lrelease" +then + lrelease=`which lrelease-qt4 2> /dev/null` +fi +if test -z "$lrelease" +then + echo "lrelease not found" + exit 1 +fi + +echo "using $lrelease" +"$lrelease" translations/*.ts + diff --git a/utils/translations/update-translations.sh b/utils/translations/update-translations.sh new file mode 100755 index 000000000..778aa5176 --- /dev/null +++ b/utils/translations/update-translations.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +lupdate=`which lupdate 2> /dev/null` +if test -z "$lupdate" +then + lupdate=`which lupdate-qt4 2> /dev/null` +fi +if test -z "$lupdate" +then + echo "lupdate not found" + exit 1 +fi + +echo "using $lupdate" +"$lupdate" `find src -name \*.cpp` -ts translations/*.ts +