From 8addf7d335ec1205cb5d4a1c0eddf2c71bd31f29 Mon Sep 17 00:00:00 2001 From: aeonix Date: Sun, 22 Jun 2014 14:15:24 +0200 Subject: [PATCH] fixes --- CMakeLists.txt | 14 +- Doxyfile | 2 +- src/CMakeLists.txt | 8 +- src/common/command_line.cpp | 12 + src/common/command_line.h | 3 + src/crypto/slow-hash.c | 420 +++++++++++++----- src/cryptonote_config.h | 2 + src/cryptonote_core/checkpoints_create.h | 4 +- src/cryptonote_core/cryptonote_core.cpp | 13 + src/cryptonote_core/cryptonote_core.h | 1 + .../cryptonote_format_utils.cpp | 5 +- src/cryptonote_core/miner.cpp | 5 +- src/cryptonote_core/tx_pool.cpp | 26 ++ src/cryptonote_core/tx_pool.h | 8 +- src/rpc/core_rpc_server.cpp | 24 +- src/rpc/core_rpc_server_error_codes.h | 3 +- tests/CMakeLists.txt | 14 +- 17 files changed, 425 insertions(+), 139 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28130e5..6f084ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ function(set_static_flags) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++") endif() endfunction(set_static_flags) - + include_directories(src contrib/epee/include external "${CMAKE_BINARY_DIR}/version") if(APPLE) @@ -21,6 +21,11 @@ endif() set(STATIC ${MSVC} CACHE BOOL "Link libraries statically") +if (UNIX AND NOT APPLE) + # Note that at the time of this writing the -Wstrict-prototypes flag added below will make this fail + find_package(Threads REQUIRED) +endif() + if(MSVC) add_definitions("/bigobj /MP /W3 /GS- /D_CRT_SECURE_NO_WARNINGS /wd4996 /wd4345 /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /FIinline_c.h /D__SSE4_1__") # set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /Dinline=__inline") @@ -44,6 +49,11 @@ else() else() set(WARNINGS "${WARNINGS} -Wlogical-op -Wno-error=maybe-uninitialized") endif() + # Since gcc 4.9 the LTO format is non-standard (slim), so we need the gcc-specific ar and ranlib binaries + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9.0)) + set(CMAKE_AR "gcc-ar") + set(CMAKE_RANLIB "gcc-ranlib") + endif() if(MINGW) set(WARNINGS "${WARNINGS} -Wno-error=unused-value") set(MINGW_FLAG "-DWIN32_LEAN_AND_MEAN") @@ -70,7 +80,7 @@ else() set(DEBUG_FLAGS "-g3 -O0") endif() set(RELEASE_FLAGS "-Ofast -DNDEBUG -Wno-unused-variable") - if(NOT APPLE) + if(NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") # There is a clang bug that does not allow to compile code that uses AES-NI intrinsics if -flto is enabled set(RELEASE_FLAGS "${RELEASE_FLAGS} -flto") endif() diff --git a/Doxyfile b/Doxyfile index a70ef81..2de98fc 100644 --- a/Doxyfile +++ b/Doxyfile @@ -32,7 +32,7 @@ DOXYFILE_ENCODING = UTF-8 # title of most generated pages and in a few other places. # The default value is: My Project. -PROJECT_NAME = "Bitmonero" +PROJECT_NAME = "Aeon" # The PROJECT_NUMBER tag can be used to enter a project or revision number. This # could be handy for archiving the generated documentation or if some version diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ac0eb4a..7dcf6d3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,13 +30,13 @@ add_library(cryptonote_core ${CRYPTONOTE_CORE}) add_executable(daemon ${DAEMON} ${P2P} ${CRYPTONOTE_PROTOCOL}) add_executable(connectivity_tool ${CONN_TOOL}) add_executable(simpleminer ${MINER}) -target_link_libraries(daemon rpc cryptonote_core crypto common upnpc-static ${Boost_LIBRARIES}) -target_link_libraries(connectivity_tool cryptonote_core crypto common ${Boost_LIBRARIES}) -target_link_libraries(simpleminer cryptonote_core crypto common ${Boost_LIBRARIES}) +target_link_libraries(daemon rpc cryptonote_core crypto common upnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(connectivity_tool cryptonote_core crypto common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(simpleminer cryptonote_core crypto common ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) add_library(rpc ${RPC}) add_library(wallet ${WALLET}) add_executable(simplewallet ${SIMPLEWALLET} ) -target_link_libraries(simplewallet wallet rpc cryptonote_core crypto common upnpc-static ${Boost_LIBRARIES}) +target_link_libraries(simplewallet wallet rpc cryptonote_core crypto common upnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) add_dependencies(daemon version) add_dependencies(rpc version) add_dependencies(simplewallet version) diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp index 0b90345..d507f36 100644 --- a/src/common/command_line.cpp +++ b/src/common/command_line.cpp @@ -3,9 +3,21 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "command_line.h" +#include "string_tools.h" namespace command_line { + std::string input_line(const std::string& prompt) + { + std::cout << prompt; + + std::string buf; + std::getline(std::cin, buf); + + return epee::string_tools::trim(buf); + + } + const arg_descriptor arg_help = {"help", "Produce help message"}; const arg_descriptor arg_version = {"version", "Output version information"}; const arg_descriptor arg_data_dir = {"data-dir", "Specify data directory"}; diff --git a/src/common/command_line.h b/src/common/command_line.h index 8606537..a6f7856 100644 --- a/src/common/command_line.h +++ b/src/common/command_line.h @@ -14,6 +14,9 @@ namespace command_line { + + std::string input_line(const std::string& prompt); + template struct arg_descriptor; diff --git a/src/crypto/slow-hash.c b/src/crypto/slow-hash.c index 35438dc..b4a1c80 100644 --- a/src/crypto/slow-hash.c +++ b/src/crypto/slow-hash.c @@ -13,8 +13,9 @@ #include -#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +#if defined(_MSC_VER) #include +#include #define STATIC #define INLINE __inline #if !defined(RDATA_ALIGN16) @@ -22,6 +23,7 @@ #endif #else #include +#include #define STATIC static #define INLINE inline #if !defined(RDATA_ALIGN16) @@ -29,16 +31,66 @@ #endif #endif +#if defined(__INTEL_COMPILER) +#define ASM __asm__ +#elif !defined(_MSC_VER) +#define ASM __asm__ +#else +#define ASM __asm +#endif + #define MEMORY (1 << 21) // 2MB scratchpad #define ITER (1 << 20) #define AES_BLOCK_SIZE 16 #define AES_KEY_SIZE 32 #define INIT_SIZE_BLK 8 #define INIT_SIZE_BYTE (INIT_SIZE_BLK * AES_BLOCK_SIZE) +#define TOTALBLOCKS (MEMORY / AES_BLOCK_SIZE) #define U64(x) ((uint64_t *) (x)) #define R128(x) ((__m128i *) (x)) +#define state_index(x) (((*((uint64_t *)x) >> 4) & (TOTALBLOCKS - 1)) << 4) +#if defined(_MSC_VER) +#if !defined(_WIN64) +#define __mul() lo = mul128(c[0], b[0], &hi); +#else +#define __mul() lo = _umul128(c[0], b[0], &hi); +#endif +#else +#if defined(__x86_64__) +#define __mul() ASM("mulq %3\n\t" : "=d"(hi), "=a"(lo) : "%a" (c[0]), "rm" (b[0]) : "cc"); +#else +#define __mul() lo = mul128(c[0], b[0], &hi); +#endif +#endif + +#define pre_aes() \ + j = state_index(a); \ + _c = _mm_load_si128(R128(&hp_state[j])); \ + _a = _mm_load_si128(R128(a)); \ + +// dga's optimized scratchpad twiddling +#define post_aes() \ + _mm_store_si128(R128(c), _c); \ + _b = _mm_xor_si128(_b, _c); \ + _mm_store_si128(R128(&hp_state[j]), _b); \ + j = state_index(c); \ + p = U64(&hp_state[j]); \ + b[0] = p[0]; b[1] = p[1]; \ + __mul(); \ + a[0] += hi; a[1] += lo; \ + p = U64(&hp_state[j]); \ + p[0] = a[0]; p[1] = a[1]; \ + a[0] ^= b[0]; a[1] ^= b[1]; \ + _b = _c; \ + +#if defined(_MSC_VER) +#define THREADV __declspec(thread) +#else +#define THREADV __thread +#endif + extern int aesb_single_round(const uint8_t *in, uint8_t*out, const uint8_t *expandedKey); extern int aesb_pseudo_round(const uint8_t *in, uint8_t *out, const uint8_t *expandedKey); @@ -54,59 +106,26 @@ union cn_slow_hash_state }; #pragma pack(pop) -#if defined(_MSC_VER) || defined(__INTEL_COMPILER) +THREADV uint8_t *hp_state = NULL; +THREADV int hp_allocated = 0; + +#if defined(_MSC_VER) #define cpuid(info,x) __cpuidex(info,x,0) #else void cpuid(int CPUInfo[4], int InfoType) { - __asm__ __volatile__ + ASM __volatile__ ( - "cpuid": + "cpuid": "=a" (CPUInfo[0]), "=b" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) : - "a" (InfoType), "c" (0) - ); + "a" (InfoType), "c" (0) + ); } #endif -STATIC INLINE void mul(const uint8_t *a, const uint8_t *b, uint8_t *res) -{ - uint64_t a0, b0; - uint64_t hi, lo; - - a0 = U64(a)[0]; - b0 = U64(b)[0]; - lo = mul128(a0, b0, &hi); - U64(res)[0] = hi; - U64(res)[1] = lo; -} - -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]; @@ -125,74 +144,253 @@ STATIC INLINE int check_aes_hw(void) return supported = cpuid_results[2] & (1 << 25); } -STATIC INLINE void aesni_pseudo_round(const uint8_t *in, uint8_t *out, - const uint8_t *expandedKey) +STATIC INLINE void aes_256_assist1(__m128i* t1, __m128i * t2) +{ + __m128i t4; + *t2 = _mm_shuffle_epi32(*t2, 0xff); + t4 = _mm_slli_si128(*t1, 0x04); + *t1 = _mm_xor_si128(*t1, t4); + t4 = _mm_slli_si128(t4, 0x04); + *t1 = _mm_xor_si128(*t1, t4); + t4 = _mm_slli_si128(t4, 0x04); + *t1 = _mm_xor_si128(*t1, t4); + *t1 = _mm_xor_si128(*t1, *t2); +} + +STATIC INLINE void aes_256_assist2(__m128i* t1, __m128i * t3) +{ + __m128i t2, t4; + t4 = _mm_aeskeygenassist_si128(*t1, 0x00); + t2 = _mm_shuffle_epi32(t4, 0xaa); + t4 = _mm_slli_si128(*t3, 0x04); + *t3 = _mm_xor_si128(*t3, t4); + t4 = _mm_slli_si128(t4, 0x04); + *t3 = _mm_xor_si128(*t3, t4); + t4 = _mm_slli_si128(t4, 0x04); + *t3 = _mm_xor_si128(*t3, t4); + *t3 = _mm_xor_si128(*t3, t2); +} + +STATIC INLINE void aes_expand_key(const uint8_t *key, uint8_t *expandedKey) +{ + __m128i *ek = R128(expandedKey); + __m128i t1, t2, t3; + + t1 = _mm_loadu_si128(R128(key)); + t3 = _mm_loadu_si128(R128(key + 16)); + + ek[0] = t1; + ek[1] = t3; + + t2 = _mm_aeskeygenassist_si128(t3, 0x01); + aes_256_assist1(&t1, &t2); + ek[2] = t1; + aes_256_assist2(&t1, &t3); + ek[3] = t3; + + t2 = _mm_aeskeygenassist_si128(t3, 0x02); + aes_256_assist1(&t1, &t2); + ek[4] = t1; + aes_256_assist2(&t1, &t3); + ek[5] = t3; + + t2 = _mm_aeskeygenassist_si128(t3, 0x04); + aes_256_assist1(&t1, &t2); + ek[6] = t1; + aes_256_assist2(&t1, &t3); + ek[7] = t3; + + t2 = _mm_aeskeygenassist_si128(t3, 0x08); + aes_256_assist1(&t1, &t2); + ek[8] = t1; + aes_256_assist2(&t1, &t3); + ek[9] = t3; + + t2 = _mm_aeskeygenassist_si128(t3, 0x10); + aes_256_assist1(&t1, &t2); + ek[10] = t1; +} + +STATIC INLINE void aes_pseudo_round(const uint8_t *in, uint8_t *out, + const uint8_t *expandedKey, int nblocks) { __m128i *k = R128(expandedKey); __m128i d; + int i; - d = _mm_loadu_si128(R128(in)); - d = _mm_aesenc_si128(d, *R128(&k[0])); - d = _mm_aesenc_si128(d, *R128(&k[1])); - d = _mm_aesenc_si128(d, *R128(&k[2])); - d = _mm_aesenc_si128(d, *R128(&k[3])); - d = _mm_aesenc_si128(d, *R128(&k[4])); - d = _mm_aesenc_si128(d, *R128(&k[5])); - d = _mm_aesenc_si128(d, *R128(&k[6])); - d = _mm_aesenc_si128(d, *R128(&k[7])); - d = _mm_aesenc_si128(d, *R128(&k[8])); - d = _mm_aesenc_si128(d, *R128(&k[9])); - _mm_storeu_si128((R128(out)), d); + for(i = 0; i < nblocks; i++) + { + d = _mm_loadu_si128(R128(in + i * AES_BLOCK_SIZE)); + d = _mm_aesenc_si128(d, *R128(&k[0])); + d = _mm_aesenc_si128(d, *R128(&k[1])); + d = _mm_aesenc_si128(d, *R128(&k[2])); + d = _mm_aesenc_si128(d, *R128(&k[3])); + d = _mm_aesenc_si128(d, *R128(&k[4])); + d = _mm_aesenc_si128(d, *R128(&k[5])); + d = _mm_aesenc_si128(d, *R128(&k[6])); + d = _mm_aesenc_si128(d, *R128(&k[7])); + d = _mm_aesenc_si128(d, *R128(&k[8])); + d = _mm_aesenc_si128(d, *R128(&k[9])); + _mm_storeu_si128((R128(out + i * AES_BLOCK_SIZE)), d); + } +} + +STATIC INLINE void aes_pseudo_round_xor(const uint8_t *in, uint8_t *out, + const uint8_t *expandedKey, const uint8_t *xor, int nblocks) +{ + __m128i *k = R128(expandedKey); + __m128i *x = R128(xor); + __m128i d; + int i; + + for(i = 0; i < nblocks; i++) + { + d = _mm_loadu_si128(R128(in + i * AES_BLOCK_SIZE)); + d = _mm_xor_si128(d, *R128(x++)); + d = _mm_aesenc_si128(d, *R128(&k[0])); + d = _mm_aesenc_si128(d, *R128(&k[1])); + d = _mm_aesenc_si128(d, *R128(&k[2])); + d = _mm_aesenc_si128(d, *R128(&k[3])); + d = _mm_aesenc_si128(d, *R128(&k[4])); + d = _mm_aesenc_si128(d, *R128(&k[5])); + d = _mm_aesenc_si128(d, *R128(&k[6])); + d = _mm_aesenc_si128(d, *R128(&k[7])); + d = _mm_aesenc_si128(d, *R128(&k[8])); + d = _mm_aesenc_si128(d, *R128(&k[9])); + _mm_storeu_si128((R128(out + i * AES_BLOCK_SIZE)), d); + } +} + +#if defined(_MSC_VER) +BOOL SetLockPagesPrivilege(HANDLE hProcess, BOOL bEnable) +{ + struct + { + DWORD count; + LUID_AND_ATTRIBUTES privilege[1]; + } info; + + HANDLE token; + if(!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &token)) + return FALSE; + + info.count = 1; + info.privilege[0].Attributes = bEnable ? SE_PRIVILEGE_ENABLED : 0; + + if(!LookupPrivilegeValue(NULL, SE_LOCK_MEMORY_NAME, &(info.privilege[0].Luid))) + return FALSE; + + if(!AdjustTokenPrivileges(token, FALSE, (PTOKEN_PRIVILEGES) &info, 0, NULL, NULL)) + return FALSE; + + if (GetLastError() != ERROR_SUCCESS) + return FALSE; + + CloseHandle(token); + + return TRUE; + +} +#endif + +void slow_hash_allocate_state(void) +{ + int state = 0; + if(hp_state != NULL) + return; + +#if defined(_MSC_VER) + SetLockPagesPrivilege(GetCurrentProcess(), TRUE); + hp_state = (uint8_t *) VirtualAlloc(hp_state, MEMORY, MEM_LARGE_PAGES | + MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +#else +#if defined(__APPLE__) + hp_state = mmap(0, MEMORY, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, 0, 0); +#else + hp_state = mmap(0, MEMORY, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, 0, 0); +#endif + if(hp_state == MAP_FAILED) + hp_state = NULL; +#endif + hp_allocated = 1; + if(hp_state == NULL) + { + hp_allocated = 0; + hp_state = (uint8_t *) malloc(MEMORY); + } +} + +void slow_hash_free_state(void) +{ + if(hp_state == NULL) + return; + + if(!hp_allocated) + free(hp_state); + else + { +#if defined(_MSC_VER) + VirtualFree(hp_state, MEMORY, MEM_RELEASE); +#else + munmap(hp_state, MEMORY); +#endif + } + + hp_state = NULL; + hp_allocated = 0; } 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]; + RDATA_ALIGN16 uint8_t expandedKey[240]; + uint8_t text[INIT_SIZE_BYTE]; + RDATA_ALIGN16 uint64_t a[2]; + RDATA_ALIGN16 uint64_t b[2]; + RDATA_ALIGN16 uint64_t c[2]; + RDATA_ALIGN16 uint8_t aes_key[AES_KEY_SIZE]; union cn_slow_hash_state state; + __m128i _a, _b, _c; + uint64_t hi, lo; size_t i, j; - uint8_t *p = NULL; + uint64_t *p = NULL; oaes_ctx *aes_ctx; - int useAes = check_aes_hw(); + static void (*const extra_hashes[4])(const void *, size_t, char *) = { hash_extra_blake, hash_extra_groestl, hash_extra_jh, hash_extra_skein }; + // this isn't supposed to happen, but guard against it for now. + if(hp_state == NULL) + slow_hash_allocate_state(); + 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); - if(useAes) { + aes_expand_key(state.hs.b, expandedKey); for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) { - for(j = 0; j < INIT_SIZE_BLK; j++) - aesni_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], expandedKey); - memcpy(&long_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE); + aes_pseudo_round(text, text, expandedKey, INIT_SIZE_BLK); + memcpy(&hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE); } } else { + aes_ctx = (oaes_ctx *) oaes_alloc(); + oaes_key_import_data(aes_ctx, state.hs.b, AES_KEY_SIZE); 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); + aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], aes_ctx->key->exp_data); - memcpy(&long_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE); + memcpy(&hp_state[i * INIT_SIZE_BYTE], text, INIT_SIZE_BYTE); } } @@ -201,60 +399,52 @@ void cn_slow_hash(const void *data, size_t length, char *hash) 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 TOTALBLOCKS (MEMORY / AES_BLOCK_SIZE) - #define state_index(x) (((*((uint64_t *)x) >> 4) & (TOTALBLOCKS - 1)) << 4) - - // Iteration 1 - p = &long_state[state_index(a)]; - - if(useAes) - _mm_storeu_si128(R128(p), _mm_aesenc_si128(_mm_loadu_si128(R128(p)), _mm_loadu_si128(R128(a)))); - else - 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); + _b = _mm_load_si128(R128(b)); + // this is ugly but the branching affects the loop somewhat so put it outside. if(useAes) { - for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) + for(i = 0; i < ITER / 2; 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]); - aesni_pseudo_round(&text[j * AES_BLOCK_SIZE], &text[j * AES_BLOCK_SIZE], expandedKey); - } + pre_aes(); + _c = _mm_aesenc_si128(_c, _a); + // post_aes(), optimized scratchpad twiddling (credits to dga) + post_aes(); } } else { + for(i = 0; i < ITER / 2; i++) + { + pre_aes(); + aesb_single_round((uint8_t *) &_c, (uint8_t *) &_c, (uint8_t *) &_a); + post_aes(); + } + } + + memcpy(text, state.init, INIT_SIZE_BYTE); + if(useAes) + { + aes_expand_key(&state.hs.b[32], expandedKey); + for(i = 0; i < MEMORY / INIT_SIZE_BYTE; i++) + { + // add the xor to the pseudo round + aes_pseudo_round_xor(text, text, expandedKey, &hp_state[i * INIT_SIZE_BYTE], INIT_SIZE_BLK); + } + } + else + { + oaes_key_import_data(aes_ctx, &state.hs.b[32], AES_KEY_SIZE); 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); + xor_blocks(&text[j * AES_BLOCK_SIZE], &hp_state[i * INIT_SIZE_BYTE + j * AES_BLOCK_SIZE]); + aesb_pseudo_round(&text[AES_BLOCK_SIZE * j], &text[AES_BLOCK_SIZE * j], aes_ctx->key->exp_data); } } + oaes_free((OAES_CTX **) &aes_ctx); } - 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); diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index e29e785..bc07e26 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -51,6 +51,8 @@ #define BLOCKS_SYNCHRONIZING_DEFAULT_COUNT 200 //by default, blocks count in blocks downloading #define CRYPTONOTE_PROTOCOL_HOP_RELAX_COUNT 3 //value of hop, after which we use only announce of new block +#define CRYPTONOTE_MEMPOOL_TX_LIVETIME 86400 //seconds, one day +#define CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME 604800 //seconds, one week #define P2P_DEFAULT_PORT 11180 #define RPC_DEFAULT_PORT 11181 diff --git a/src/cryptonote_core/checkpoints_create.h b/src/cryptonote_core/checkpoints_create.h index 8dff85d..d2109d5 100644 --- a/src/cryptonote_core/checkpoints_create.h +++ b/src/cryptonote_core/checkpoints_create.h @@ -11,7 +11,9 @@ namespace cryptonote { inline bool create_checkpoints(cryptonote::checkpoints& checkpoints) - { + { + ADD_CHECKPOINT(10000, "1ac1ebd25baf0d6ec593daa3389f1aa7e860ff2cc29f3cf1be586d245b379da4"); + ADD_CHECKPOINT(15000, "15567af42afc1ed00538f53b5e3822d421e3ed6372ca79f4ea4e3e3bab709a87"); return true; } } diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index b2389fc..2609fc1 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -432,6 +432,18 @@ namespace cryptonote return true; } //----------------------------------------------------------------------------------------------- + // Used by the RPC server to check the size of an incoming + // block_blob + bool core::check_incoming_block_size(const blobdata& block_blob) + { + if(block_blob.size() > get_max_block_size()) + { + LOG_PRINT_L0("WRONG BLOCK BLOB, too big size " << block_blob.size() << ", rejected"); + return false; + } + return true; + } + //----------------------------------------------------------------------------------------------- crypto::hash core::get_tail_id() { return m_blockchain_storage.get_tail_id(); @@ -514,6 +526,7 @@ namespace cryptonote m_store_blockchain_interval.do_call(boost::bind(&blockchain_storage::store_blockchain, &m_blockchain_storage)); m_miner.on_idle(); + m_mempool.on_idle(); return true; } //----------------------------------------------------------------------------------------------- diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 7ef0f8b..1f1b6ee 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -34,6 +34,7 @@ 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 check_incoming_block_size(const blobdata& block_blob); i_cryptonote_protocol* get_protocol(){return m_pprotocol;} //-------------------- i_miner_handler ----------------------- diff --git a/src/cryptonote_core/cryptonote_format_utils.cpp b/src/cryptonote_core/cryptonote_format_utils.cpp index 44c85a7..58210f4 100644 --- a/src/cryptonote_core/cryptonote_format_utils.cpp +++ b/src/cryptonote_core/cryptonote_format_utils.cpp @@ -617,6 +617,7 @@ namespace cryptonote //genesis block bl = boost::value_initialized(); + account_public_address ac = boost::value_initialized(); std::vector sz; construct_miner_tx(0, 0, 0, 0, 0, ac, bl.miner_tx); // zero fee in genesis @@ -630,8 +631,8 @@ namespace cryptonote string_tools::parse_hexstr_to_binbuff(genesis_coinbase_tx_hex, tx_bl); bool r = parse_and_validate_tx_from_blob(tx_bl, bl.miner_tx); CHECK_AND_ASSERT_MES(r, false, "failed to parse coinbase tx from hard coded blob"); - bl.major_version = 1; - bl.minor_version = 0; + bl.major_version = CURRENT_BLOCK_MAJOR_VERSION; + bl.minor_version = CURRENT_BLOCK_MINOR_VERSION; bl.timestamp = 0; bl.nonce = 10000; miner::find_nonce_for_given_block(bl, 1, 0); diff --git a/src/cryptonote_core/miner.cpp b/src/cryptonote_core/miner.cpp index 2055bb1..d021b05 100644 --- a/src/cryptonote_core/miner.cpp +++ b/src/cryptonote_core/miner.cpp @@ -23,7 +23,8 @@ using namespace epee; #include "miner.h" - +extern "C" void slow_hash_allocate_state(); +extern "C" void slow_hash_free_state(); namespace cryptonote { @@ -320,6 +321,7 @@ namespace cryptonote difficulty_type local_diff = 0; uint32_t local_template_ver = 0; block b; + slow_hash_allocate_state(); while(!m_stop) { if(m_pausers_count)//anti split workaround @@ -368,6 +370,7 @@ namespace cryptonote nonce+=m_threads_total; ++m_hashes; } + slow_hash_free_state(); LOG_PRINT_L0("Miner thread stopped ["<< th_local_index << "]"); return true; } diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp index 4c4c6ae..ce1bc1a 100644 --- a/src/cryptonote_core/tx_pool.cpp +++ b/src/cryptonote_core/tx_pool.cpp @@ -83,6 +83,7 @@ namespace cryptonote txd_p.first->second.max_used_block_id = null_hash; txd_p.first->second.max_used_block_height = 0; txd_p.first->second.kept_by_block = kept_by_block; + txd_p.first->second.receive_time = time(nullptr); tvc.m_verifivation_impossible = true; tvc.m_added_to_pool = true; }else @@ -104,6 +105,7 @@ namespace cryptonote txd_p.first->second.max_used_block_height = max_used_block_height; txd_p.first->second.last_failed_height = 0; txd_p.first->second.last_failed_id = null_hash; + txd_p.first->second.receive_time = time(nullptr); tvc.m_added_to_pool = true; if(txd_p.first->second.fee > 0) @@ -178,6 +180,30 @@ namespace cryptonote return true; } //--------------------------------------------------------------------------------- + void tx_memory_pool::on_idle() + { + m_remove_stuck_tx_interval.do_call([this](){return remove_stuck_transactions();}); + } + //--------------------------------------------------------------------------------- + //proper tx_pool handling courtesy of CryptoZoidberg and Boolberry + bool tx_memory_pool::remove_stuck_transactions() + { + CRITICAL_REGION_LOCAL(m_transactions_lock); + for(auto it = m_transactions.begin(); it!= m_transactions.end();) + { + uint64_t tx_age = time(nullptr) - it->second.receive_time; + + if((tx_age > CRYPTONOTE_MEMPOOL_TX_LIVETIME && !it->second.kept_by_block) || + (tx_age > CRYPTONOTE_MEMPOOL_TX_FROM_ALT_BLOCK_LIVETIME && it->second.kept_by_block) ) + { + LOG_PRINT_L0("Tx " << it->first << " removed from tx pool due to outdated, age: " << tx_age ); + m_transactions.erase(it++); + }else + ++it; + } + return true; + } + //--------------------------------------------------------------------------------- size_t tx_memory_pool::get_transactions_count() { CRITICAL_REGION_LOCAL(m_transactions_lock); diff --git a/src/cryptonote_core/tx_pool.h b/src/cryptonote_core/tx_pool.h index 26d273a..649af41 100644 --- a/src/cryptonote_core/tx_pool.h +++ b/src/cryptonote_core/tx_pool.h @@ -13,6 +13,7 @@ #include "string_tools.h" #include "syncobj.h" +#include "math_helper.h" #include "cryptonote_basic_impl.h" #include "verification_context.h" #include "crypto/hash.h" @@ -40,6 +41,7 @@ namespace cryptonote bool on_blockchain_inc(uint64_t new_block_height, const crypto::hash& top_block_id); bool on_blockchain_dec(uint64_t new_block_height, const crypto::hash& top_block_id); + void on_idle(); void lock(); void unlock(); @@ -59,7 +61,7 @@ namespace cryptonote /*bool flush_pool(const std::strig& folder); bool inflate_pool(const std::strig& folder);*/ -#define CURRENT_MEMPOOL_ARCHIVE_VER 7 +#define CURRENT_MEMPOOL_ARCHIVE_VER 8 template void serialize(archive_t & a, const unsigned int version) @@ -82,9 +84,11 @@ namespace cryptonote // uint64_t last_failed_height; crypto::hash last_failed_id; + time_t receive_time; }; private: + bool remove_stuck_transactions(); bool is_transaction_ready_to_go(tx_details& txd); typedef std::unordered_map transactions_container; typedef std::unordered_map > key_images_container; @@ -92,6 +96,7 @@ namespace cryptonote epee::critical_section m_transactions_lock; transactions_container m_transactions; key_images_container m_spent_key_images; + epee::math_helper::once_a_time_seconds<30> m_remove_stuck_tx_interval; //transactions_container m_alternative_transactions; @@ -159,6 +164,7 @@ namespace boost ar & td.max_used_block_id; ar & td.last_failed_height; ar & td.last_failed_id; + ar & td.receive_time; } } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 03af66f..c3f9856 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -438,9 +438,27 @@ namespace cryptonote error_resp.message = "Wrong block blob"; return false; } - cryptonote::block_verification_context bvc = AUTO_VAL_INIT(bvc); - m_core.handle_incoming_block(blockblob, bvc); - if(!bvc.m_added_to_main_chain) + + // Fixing of high orphan issue for most pools + // Thanks Boolberry! + block b = AUTO_VAL_INIT(b); + if(!parse_and_validate_block_from_blob(blockblob, b)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB; + error_resp.message = "Wrong block blob"; + return false; + } + + // Fix from Boolberry neglects to check block + // size, do that with the function below + if(!m_core.check_incoming_block_size(blockblob)) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB_SIZE; + error_resp.message = "Block bloc size is too big, rejecting block"; + return false; + } + + if(!m_core.handle_block_found(b)) { error_resp.code = CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED; error_resp.message = "Block not accepted"; diff --git a/src/rpc/core_rpc_server_error_codes.h b/src/rpc/core_rpc_server_error_codes.h index 10785f8..273a8b8 100644 --- a/src/rpc/core_rpc_server_error_codes.h +++ b/src/rpc/core_rpc_server_error_codes.h @@ -13,7 +13,6 @@ #define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB -6 #define CORE_RPC_ERROR_CODE_BLOCK_NOT_ACCEPTED -7 #define CORE_RPC_ERROR_CODE_CORE_BUSY -9 - - +#define CORE_RPC_ERROR_CODE_WRONG_BLOCKBLOB_SIZE -10 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 855b4d8..1d0c91d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -31,16 +31,16 @@ add_executable(unit_tests ${UNIT_TESTS}) add_executable(net_load_tests_clt net_load_tests/clt.cpp) add_executable(net_load_tests_srv net_load_tests/srv.cpp) -target_link_libraries(core_proxy cryptonote_core common crypto upnpc-static ${Boost_LIBRARIES}) -target_link_libraries(coretests cryptonote_core common crypto ${Boost_LIBRARIES}) +target_link_libraries(core_proxy cryptonote_core common crypto upnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(coretests cryptonote_core common crypto ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(difficulty-tests cryptonote_core) -target_link_libraries(functional_tests cryptonote_core wallet common crypto ${Boost_LIBRARIES}) +target_link_libraries(functional_tests cryptonote_core wallet common crypto ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(hash-tests crypto) target_link_libraries(hash-target-tests crypto cryptonote_core) -target_link_libraries(performance_tests cryptonote_core common crypto ${Boost_LIBRARIES}) -target_link_libraries(unit_tests cryptonote_core common crypto gtest_main ${Boost_LIBRARIES}) -target_link_libraries(net_load_tests_clt cryptonote_core common crypto gtest_main ${Boost_LIBRARIES}) -target_link_libraries(net_load_tests_srv cryptonote_core common crypto gtest_main ${Boost_LIBRARIES}) +target_link_libraries(performance_tests cryptonote_core common crypto ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(unit_tests cryptonote_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(net_load_tests_clt cryptonote_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(net_load_tests_srv cryptonote_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) if(NOT MSVC) set_property(TARGET gtest gtest_main unit_tests net_load_tests_clt net_load_tests_srv APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-undef -Wno-sign-compare")