diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a0376c9..562dde60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -157,7 +157,7 @@ endif() message(STATUS "Boost: ${Boost_VERSION} from ${Boost_LIBRARY_DIRS}") -include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) +include_directories(SYSTEM ${Boost_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/contrib/ethereum/libethash) if(MINGW) set(Boost_LIBRARIES "${Boost_LIBRARIES};ws2_32;mswsock") elseif(NOT MSVC) diff --git a/README.md b/README.md index 07adf327..954d15bb 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,11 @@ Building Recommended OS version: Ubuntu 17.04 LTS. -1. `$ sudo apt install git g++ cmake unzip libicu-dev mesa-common-dev libglu1-mesa-dev qt5-default qtwebengine5-dev` +1. For server version: \ +`$ sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git libboost-all-dev screen`\ +For GUI version:\ +`$ sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git libboost-all-dev screen mesa-common-dev libglu1-mesa-dev qt5-default qtwebengine5-dev` + 2. `$ cd zano/ && make -j$(nproc) gui` 3. Look for the binaries, including the `Zano` GUI, in the build directory diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index 46ed7497..599de9f8 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -4,7 +4,7 @@ set(UPNPC_BUILD_TESTS OFF CACHE BOOL "Build test executables") add_subdirectory(miniupnpc) add_subdirectory(zlib) add_subdirectory(db) - +add_subdirectory(ethereum) set_property(TARGET upnpc-static PROPERTY FOLDER "contrib") @@ -13,6 +13,7 @@ set_property(TARGET lmdb PROPERTY FOLDER "contrib") + if(MSVC) set_property(TARGET upnpc-static APPEND_STRING PROPERTY COMPILE_FLAGS " -wd4244 -wd4267") else() diff --git a/contrib/ethereum/CMakeLists.txt b/contrib/ethereum/CMakeLists.txt new file mode 100644 index 00000000..359ad19e --- /dev/null +++ b/contrib/ethereum/CMakeLists.txt @@ -0,0 +1,10 @@ +add_subdirectory(libethash) + +set_property(TARGET ethash PROPERTY FOLDER "contrib") + +if(MSVC) + target_compile_options(ethash PRIVATE /wd4477 /wd4267) +else() + target_compile_options(ethash PRIVATE -Wno-format -Wno-aggregate-return -Wno-empty-body) +endif() + diff --git a/contrib/ethereum/libethash/CMakeLists.txt b/contrib/ethereum/libethash/CMakeLists.txt new file mode 100644 index 00000000..8205079d --- /dev/null +++ b/contrib/ethereum/libethash/CMakeLists.txt @@ -0,0 +1,33 @@ +# ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +# Copyright 2018 Pawel Bylica. +# Licensed under the Apache License, Version 2.0. See the LICENSE file. + +# set(include_dir ${PROJECT_SOURCE_DIR}/include) + + +add_library( + ethash + bit_manipulation.h + builtins.h + endianness.hpp + ethash/ethash.h + ethash/ethash.hpp + ethash-internal.hpp + ethash.cpp + ethash/hash_types.h + managed.cpp + ethash/keccak.h + ethash/keccak.hpp + keccak.c + keccakf800.c + keccakf1600.c + kiss99.hpp + primes.h + primes.c + ethash/progpow.hpp + progpow.cpp +) + + + + diff --git a/contrib/ethereum/libethash/bit_manipulation.h b/contrib/ethereum/libethash/bit_manipulation.h new file mode 100644 index 00000000..3fa22948 --- /dev/null +++ b/contrib/ethereum/libethash/bit_manipulation.h @@ -0,0 +1,81 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +#pragma once + +#include "builtins.h" +#include "support/attributes.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +static inline uint32_t rotl32(uint32_t n, unsigned int c) +{ + const unsigned int mask = 31; + + c &= mask; + unsigned int neg_c = (unsigned int)(-(int)c); + return (n << c) | (n >> (neg_c & mask)); +} + +static inline uint32_t rotr32(uint32_t n, unsigned int c) +{ + const unsigned int mask = 31; + + c &= mask; + unsigned int neg_c = (unsigned int)(-(int)c); + return (n >> c) | (n << (neg_c & mask)); +} + +static inline uint32_t clz32(uint32_t x) +{ + return x ? (uint32_t)__builtin_clz(x) : 32; +} + +static inline uint32_t popcount32(uint32_t x) +{ + return (uint32_t)__builtin_popcount(x); +} + +static inline uint32_t mul_hi32(uint32_t x, uint32_t y) +{ + return (uint32_t)(((uint64_t)x * (uint64_t)y) >> 32); +} + + +/** FNV 32-bit prime. */ +static const uint32_t fnv_prime = 0x01000193; + +/** FNV 32-bit offset basis. */ +static const uint32_t fnv_offset_basis = 0x811c9dc5; + +/** + * The implementation of FNV-1 hash. + * + * See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1_hash. + */ +NO_SANITIZE("unsigned-integer-overflow") +static inline uint32_t fnv1(uint32_t u, uint32_t v) noexcept +{ + return (u * fnv_prime) ^ v; +} + +/** + * The implementation of FNV-1a hash. + * + * See https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash. + */ +NO_SANITIZE("unsigned-integer-overflow") +static inline uint32_t fnv1a(uint32_t u, uint32_t v) noexcept +{ + return (u ^ v) * fnv_prime; +} + +#ifdef __cplusplus +} +#endif diff --git a/contrib/ethereum/libethash/builtins.h b/contrib/ethereum/libethash/builtins.h new file mode 100644 index 00000000..6cf6a285 --- /dev/null +++ b/contrib/ethereum/libethash/builtins.h @@ -0,0 +1,43 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +/** + * @file + * Implementation of GCC/clang builtins for MSVC compiler. + */ + +#pragma once + +#ifdef _MSC_VER +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Returns the number of leading 0-bits in `x`, starting at the most significant bit position. + * If `x` is 0, the result is undefined. + */ +static inline int __builtin_clz(unsigned int x) +{ + unsigned long most_significant_bit; + _BitScanReverse(&most_significant_bit, x); + return 31 - (int)most_significant_bit; +} + +/** + * Returns the number of 1-bits in `x`. + */ +static inline int __builtin_popcount(unsigned int x) +{ + return (int)__popcnt(x); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/contrib/ethereum/libethash/endianness.hpp b/contrib/ethereum/libethash/endianness.hpp new file mode 100644 index 00000000..34724778 --- /dev/null +++ b/contrib/ethereum/libethash/endianness.hpp @@ -0,0 +1,98 @@ +// Copyright 2018 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. See the LICENSE file. + +/// @file +/// This file contains helper functions to handle big-endian architectures. +/// The Ethash algorithm is naturally defined for little-endian architectures +/// so for those the helpers are just no-op empty functions. +/// For big-endian architectures we need 32-bit and 64-bit byte swapping in +/// some places. + +#pragma once + +#include + +#if _WIN32 + +#include + +#define bswap32 _byteswap_ulong +#define bswap64 _byteswap_uint64 + +// On Windows assume little endian. +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __BYTE_ORDER __LITTLE_ENDIAN + +#elif __APPLE__ + +#include + +#define bswap32 __builtin_bswap32 +#define bswap64 __builtin_bswap64 + +#else + +#include + +#define bswap32 __builtin_bswap32 +#define bswap64 __builtin_bswap64 + +#endif + +namespace ethash +{ +#if __BYTE_ORDER == __LITTLE_ENDIAN + +struct le +{ + static uint32_t uint32(uint32_t x) noexcept { return x; } + static uint64_t uint64(uint64_t x) noexcept { return x; } + + static const hash1024& uint32s(const hash1024& h) noexcept { return h; } + static const hash512& uint32s(const hash512& h) noexcept { return h; } + static const hash256& uint32s(const hash256& h) noexcept { return h; } +}; + +struct be +{ + static uint64_t uint64(uint64_t x) noexcept { return bswap64(x); } +}; + + +#elif __BYTE_ORDER == __BIG_ENDIAN + +struct le +{ + static uint32_t uint32(uint32_t x) noexcept { return bswap32(x); } + static uint64_t uint64(uint64_t x) noexcept { return bswap64(x); } + + static hash1024 uint32s(hash1024 h) noexcept + { + for (auto& w : h.word32s) + w = uint32(w); + return h; + } + + static hash512 uint32s(hash512 h) noexcept + { + for (auto& w : h.word32s) + w = uint32(w); + return h; + } + + static hash256 uint32s(hash256 h) noexcept + { + for (auto& w : h.word32s) + w = uint32(w); + return h; + } +}; + +struct be +{ + static uint64_t uint64(uint64_t x) noexcept { return x; } +}; + +#endif +} // namespace ethash \ No newline at end of file diff --git a/contrib/ethereum/libethash/ethash-internal.hpp b/contrib/ethereum/libethash/ethash-internal.hpp new file mode 100644 index 00000000..96209bd1 --- /dev/null +++ b/contrib/ethereum/libethash/ethash-internal.hpp @@ -0,0 +1,69 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. See the LICENSE file. + +/// @file +/// Contains declarations of internal ethash functions to allow them to be +/// unit-tested. + +#pragma once + +#include + +#include "endianness.hpp" + +#include +#include + +extern "C" struct ethash_epoch_context_full : ethash_epoch_context +{ + ethash_hash1024* full_dataset; + + constexpr ethash_epoch_context_full(int epoch_number, int light_cache_num_items, + const ethash_hash512* light_cache, const uint32_t* l1_cache, int full_dataset_num_items, + ethash_hash1024* full_dataset) noexcept + : ethash_epoch_context{epoch_number, light_cache_num_items, light_cache, l1_cache, + full_dataset_num_items}, + full_dataset{full_dataset} + {} +}; + +namespace ethash +{ +inline bool is_less_or_equal(const hash256& a, const hash256& b) noexcept +{ + for (size_t i = 0; i < (sizeof(a) / sizeof(a.word64s[0])); ++i) + { + if (be::uint64(a.word64s[i]) > be::uint64(b.word64s[i])) + return false; + if (be::uint64(a.word64s[i]) < be::uint64(b.word64s[i])) + return true; + } + return true; +} + +inline bool is_equal(const hash256& a, const hash256& b) noexcept +{ + return std::memcmp(a.bytes, b.bytes, sizeof(a)) == 0; +} + +void build_light_cache(hash512 cache[], int num_items, const hash256& seed) noexcept; + +hash512 calculate_dataset_item_512(const epoch_context& context, int64_t index) noexcept; +hash1024 calculate_dataset_item_1024(const epoch_context& context, uint32_t index) noexcept; +hash2048 calculate_dataset_item_2048(const epoch_context& context, uint32_t index) noexcept; + +namespace generic +{ +using hash_fn_512 = hash512 (*)(const uint8_t* data, size_t size); +using build_light_cache_fn = void (*)(hash512 cache[], int num_items, const hash256& seed); + +void build_light_cache( + hash_fn_512 hash_fn, hash512 cache[], int num_items, const hash256& seed) noexcept; + +epoch_context_full* create_epoch_context( + build_light_cache_fn build_fn, int epoch_number, bool full) noexcept; + +} // namespace generic + +} // namespace ethash diff --git a/contrib/ethereum/libethash/ethash.cpp b/contrib/ethereum/libethash/ethash.cpp new file mode 100644 index 00000000..f12faab7 --- /dev/null +++ b/contrib/ethereum/libethash/ethash.cpp @@ -0,0 +1,441 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. See the LICENSE file. + +#include "ethash-internal.hpp" + +#include "bit_manipulation.h" +#include "endianness.hpp" +#include "primes.h" +#include "support/attributes.h" +#include +#include + +#include +#include +#include +#include + +namespace ethash +{ +// Internal constants: +constexpr static int light_cache_init_size = 1 << 24; +constexpr static int light_cache_growth = 1 << 17; +constexpr static int light_cache_rounds = 3; +constexpr static int full_dataset_init_size = 1 << 30; +constexpr static int full_dataset_growth = 1 << 23; +constexpr static int full_dataset_item_parents = 256; + +// Verify constants: +static_assert(sizeof(hash512) == ETHASH_LIGHT_CACHE_ITEM_SIZE, ""); +static_assert(sizeof(hash1024) == ETHASH_FULL_DATASET_ITEM_SIZE, ""); +static_assert(light_cache_item_size == ETHASH_LIGHT_CACHE_ITEM_SIZE, ""); +static_assert(full_dataset_item_size == ETHASH_FULL_DATASET_ITEM_SIZE, ""); + + +namespace +{ +using ::fnv1; + +inline hash512 fnv1(const hash512& u, const hash512& v) noexcept +{ + hash512 r; + for (size_t i = 0; i < sizeof(r) / sizeof(r.word32s[0]); ++i) + r.word32s[i] = fnv1(u.word32s[i], v.word32s[i]); + return r; +} + +inline hash512 bitwise_xor(const hash512& x, const hash512& y) noexcept +{ + hash512 z; + for (size_t i = 0; i < sizeof(z) / sizeof(z.word64s[0]); ++i) + z.word64s[i] = x.word64s[i] ^ y.word64s[i]; + return z; +} +} // namespace + +int find_epoch_number(const hash256& seed) noexcept +{ + static constexpr int num_tries = 30000; // Divisible by 16. + + // Thread-local cache of the last search. + static thread_local int cached_epoch_number = 0; + static thread_local hash256 cached_seed = {}; + + // Load from memory once (memory will be clobbered by keccak256()). + const uint32_t seed_part = seed.word32s[0]; + const int e = cached_epoch_number; + hash256 s = cached_seed; + + if (s.word32s[0] == seed_part) + return e; + + // Try the next seed, will match for sequential epoch access. + s = keccak256(s); + if (s.word32s[0] == seed_part) + { + cached_seed = s; + cached_epoch_number = e + 1; + return e + 1; + } + + // Search for matching seed starting from epoch 0. + s = {}; + for (int i = 0; i < num_tries; ++i) + { + if (s.word32s[0] == seed_part) + { + cached_seed = s; + cached_epoch_number = i; + return i; + } + + s = keccak256(s); + } + + return -1; +} + +namespace generic +{ +void build_light_cache( + hash_fn_512 hash_fn, hash512 cache[], int num_items, const hash256& seed) noexcept +{ + hash512 item = hash_fn(seed.bytes, sizeof(seed)); + cache[0] = item; + for (int i = 1; i < num_items; ++i) + { + item = hash_fn(item.bytes, sizeof(item)); + cache[i] = item; + } + + for (int q = 0; q < light_cache_rounds; ++q) + { + for (int i = 0; i < num_items; ++i) + { + const uint32_t index_limit = static_cast(num_items); + + // Fist index: 4 first bytes of the item as little-endian integer. + const uint32_t t = le::uint32(cache[i].word32s[0]); + const uint32_t v = t % index_limit; + + // Second index. + const uint32_t w = static_cast(num_items + (i - 1)) % index_limit; + + const hash512 x = bitwise_xor(cache[v], cache[w]); + cache[i] = hash_fn(x.bytes, sizeof(x)); + } + } +} + +epoch_context_full* create_epoch_context( + build_light_cache_fn build_fn, int epoch_number, bool full) noexcept +{ + static_assert(sizeof(epoch_context_full) < sizeof(hash512), "epoch_context too big"); + static constexpr size_t context_alloc_size = sizeof(hash512); + + const int light_cache_num_items = calculate_light_cache_num_items(epoch_number); + const int full_dataset_num_items = calculate_full_dataset_num_items(epoch_number); + const size_t light_cache_size = get_light_cache_size(light_cache_num_items); + const size_t full_dataset_size = + full ? static_cast(full_dataset_num_items) * sizeof(hash1024) : + progpow::l1_cache_size; + + const size_t alloc_size = context_alloc_size + light_cache_size + full_dataset_size; + + char* const alloc_data = static_cast(std::calloc(1, alloc_size)); + if (!alloc_data) + return nullptr; // Signal out-of-memory by returning null pointer. + + hash512* const light_cache = reinterpret_cast(alloc_data + context_alloc_size); + const hash256 epoch_seed = calculate_epoch_seed(epoch_number); + build_fn(light_cache, light_cache_num_items, epoch_seed); + + uint32_t* const l1_cache = + reinterpret_cast(alloc_data + context_alloc_size + light_cache_size); + + hash1024* full_dataset = full ? reinterpret_cast(l1_cache) : nullptr; + + epoch_context_full* const context = new (alloc_data) epoch_context_full{ + epoch_number, + light_cache_num_items, + light_cache, + l1_cache, + full_dataset_num_items, + full_dataset, + }; + + auto* full_dataset_2048 = reinterpret_cast(l1_cache); + for (uint32_t i = 0; i < progpow::l1_cache_size / sizeof(full_dataset_2048[0]); ++i) + full_dataset_2048[i] = calculate_dataset_item_2048(*context, i); + return context; +} +} // namespace generic + +void build_light_cache(hash512 cache[], int num_items, const hash256& seed) noexcept +{ + return generic::build_light_cache(keccak512, cache, num_items, seed); +} + +struct item_state +{ + const hash512* const cache; + const int64_t num_cache_items; + const uint32_t seed; + + hash512 mix; + + ALWAYS_INLINE item_state(const epoch_context& context, int64_t index) noexcept + : cache{context.light_cache}, + num_cache_items{context.light_cache_num_items}, + seed{static_cast(index)} + { + mix = cache[index % num_cache_items]; + mix.word32s[0] ^= le::uint32(seed); + mix = le::uint32s(keccak512(mix)); + } + + ALWAYS_INLINE void update(uint32_t round) noexcept + { + static constexpr size_t num_words = sizeof(mix) / sizeof(uint32_t); + const uint32_t t = fnv1(seed ^ round, mix.word32s[round % num_words]); + const int64_t parent_index = t % num_cache_items; + mix = fnv1(mix, le::uint32s(cache[parent_index])); + } + + ALWAYS_INLINE hash512 final() noexcept { return keccak512(le::uint32s(mix)); } +}; + +hash512 calculate_dataset_item_512(const epoch_context& context, int64_t index) noexcept +{ + item_state item0{context, index}; + for (uint32_t j = 0; j < full_dataset_item_parents; ++j) + item0.update(j); + return item0.final(); +} + +/// Calculates a full dataset item +/// +/// This consist of two 512-bit items produced by calculate_dataset_item_partial(). +/// Here the computation is done interleaved for better performance. +hash1024 calculate_dataset_item_1024(const epoch_context& context, uint32_t index) noexcept +{ + item_state item0{context, int64_t(index) * 2}; + item_state item1{context, int64_t(index) * 2 + 1}; + + for (uint32_t j = 0; j < full_dataset_item_parents; ++j) + { + item0.update(j); + item1.update(j); + } + + return hash1024{{item0.final(), item1.final()}}; +} + +hash2048 calculate_dataset_item_2048(const epoch_context& context, uint32_t index) noexcept +{ + item_state item0{context, int64_t(index) * 4}; + item_state item1{context, int64_t(index) * 4 + 1}; + item_state item2{context, int64_t(index) * 4 + 2}; + item_state item3{context, int64_t(index) * 4 + 3}; + + for (uint32_t j = 0; j < full_dataset_item_parents; ++j) + { + item0.update(j); + item1.update(j); + item2.update(j); + item3.update(j); + } + + return hash2048{{item0.final(), item1.final(), item2.final(), item3.final()}}; +} + +namespace +{ +using lookup_fn = hash1024 (*)(const epoch_context&, uint32_t); + +inline hash512 hash_seed(const hash256& header_hash, uint64_t nonce) noexcept +{ + nonce = le::uint64(nonce); + uint8_t init_data[sizeof(header_hash) + sizeof(nonce)]; + std::memcpy(&init_data[0], &header_hash, sizeof(header_hash)); + std::memcpy(&init_data[sizeof(header_hash)], &nonce, sizeof(nonce)); + + return keccak512(init_data, sizeof(init_data)); +} + +inline hash256 hash_final(const hash512& seed, const hash256& mix_hash) +{ + uint8_t final_data[sizeof(seed) + sizeof(mix_hash)]; + std::memcpy(&final_data[0], seed.bytes, sizeof(seed)); + std::memcpy(&final_data[sizeof(seed)], mix_hash.bytes, sizeof(mix_hash)); + return keccak256(final_data, sizeof(final_data)); +} + +inline hash256 hash_kernel( + const epoch_context& context, const hash512& seed, lookup_fn lookup) noexcept +{ + static constexpr size_t num_words = sizeof(hash1024) / sizeof(uint32_t); + const uint32_t index_limit = static_cast(context.full_dataset_num_items); + const uint32_t seed_init = le::uint32(seed.word32s[0]); + + hash1024 mix{{le::uint32s(seed), le::uint32s(seed)}}; + + for (uint32_t i = 0; i < num_dataset_accesses; ++i) + { + const uint32_t p = fnv1(i ^ seed_init, mix.word32s[i % num_words]) % index_limit; + const hash1024 newdata = le::uint32s(lookup(context, p)); + + for (size_t j = 0; j < num_words; ++j) + mix.word32s[j] = fnv1(mix.word32s[j], newdata.word32s[j]); + } + + hash256 mix_hash; + for (size_t i = 0; i < num_words; i += 4) + { + const uint32_t h1 = fnv1(mix.word32s[i], mix.word32s[i + 1]); + const uint32_t h2 = fnv1(h1, mix.word32s[i + 2]); + const uint32_t h3 = fnv1(h2, mix.word32s[i + 3]); + mix_hash.word32s[i / 4] = h3; + } + + return le::uint32s(mix_hash); +} +} // namespace + +result hash(const epoch_context& context, const hash256& header_hash, uint64_t nonce) noexcept +{ + const hash512 seed = hash_seed(header_hash, nonce); + const hash256 mix_hash = hash_kernel(context, seed, calculate_dataset_item_1024); + return {hash_final(seed, mix_hash), mix_hash}; +} + +result hash(const epoch_context_full& context, const hash256& header_hash, uint64_t nonce) noexcept +{ + static const auto lazy_lookup = [](const epoch_context& context, uint32_t index) noexcept + { + auto full_dataset = static_cast(context).full_dataset; + hash1024& item = full_dataset[index]; + if (item.word64s[0] == 0) + { + // TODO: Copy elision here makes it thread-safe? + item = calculate_dataset_item_1024(context, index); + } + + return item; + }; + + const hash512 seed = hash_seed(header_hash, nonce); + const hash256 mix_hash = hash_kernel(context, seed, lazy_lookup); + return {hash_final(seed, mix_hash), mix_hash}; +} + +bool verify_final_hash(const hash256& header_hash, const hash256& mix_hash, uint64_t nonce, + const hash256& boundary) noexcept +{ + const hash512 seed = hash_seed(header_hash, nonce); + return is_less_or_equal(hash_final(seed, mix_hash), boundary); +} + +bool verify(const epoch_context& context, const hash256& header_hash, const hash256& mix_hash, + uint64_t nonce, const hash256& boundary) noexcept +{ + const hash512 seed = hash_seed(header_hash, nonce); + if (!is_less_or_equal(hash_final(seed, mix_hash), boundary)) + return false; + + const hash256 expected_mix_hash = hash_kernel(context, seed, calculate_dataset_item_1024); + return is_equal(expected_mix_hash, mix_hash); +} + +search_result search_light(const epoch_context& context, const hash256& header_hash, + const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept +{ + const uint64_t end_nonce = start_nonce + iterations; + for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) + { + result r = hash(context, header_hash, nonce); + if (is_less_or_equal(r.final_hash, boundary)) + return {r, nonce}; + } + return {}; +} + +search_result search(const epoch_context_full& context, const hash256& header_hash, + const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept +{ + const uint64_t end_nonce = start_nonce + iterations; + for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) + { + result r = hash(context, header_hash, nonce); + if (is_less_or_equal(r.final_hash, boundary)) + return {r, nonce}; + } + return {}; +} +} // namespace ethash + +using namespace ethash; + +extern "C" { + +ethash_hash256 ethash_calculate_epoch_seed(int epoch_number) noexcept +{ + ethash_hash256 epoch_seed = {}; + for (int i = 0; i < epoch_number; ++i) + epoch_seed = ethash_keccak256_32(epoch_seed.bytes); + return epoch_seed; +} + +int ethash_calculate_light_cache_num_items(int epoch_number) noexcept +{ + static constexpr int item_size = sizeof(hash512); + static constexpr int num_items_init = light_cache_init_size / item_size; + static constexpr int num_items_growth = light_cache_growth / item_size; + static_assert( + light_cache_init_size % item_size == 0, "light_cache_init_size not multiple of item size"); + static_assert( + light_cache_growth % item_size == 0, "light_cache_growth not multiple of item size"); + + int num_items_upper_bound = num_items_init + epoch_number * num_items_growth; + int num_items = ethash_find_largest_prime(num_items_upper_bound); + return num_items; +} + +int ethash_calculate_full_dataset_num_items(int epoch_number) noexcept +{ + static constexpr int item_size = sizeof(hash1024); + static constexpr int num_items_init = full_dataset_init_size / item_size; + static constexpr int num_items_growth = full_dataset_growth / item_size; + static_assert(full_dataset_init_size % item_size == 0, + "full_dataset_init_size not multiple of item size"); + static_assert( + full_dataset_growth % item_size == 0, "full_dataset_growth not multiple of item size"); + + int num_items_upper_bound = num_items_init + epoch_number * num_items_growth; + int num_items = ethash_find_largest_prime(num_items_upper_bound); + return num_items; +} + +epoch_context* ethash_create_epoch_context(int epoch_number) noexcept +{ + return generic::create_epoch_context(build_light_cache, epoch_number, false); +} + +epoch_context_full* ethash_create_epoch_context_full(int epoch_number) noexcept +{ + return generic::create_epoch_context(build_light_cache, epoch_number, true); +} + +void ethash_destroy_epoch_context_full(epoch_context_full* context) noexcept +{ + ethash_destroy_epoch_context(context); +} + +void ethash_destroy_epoch_context(epoch_context* context) noexcept +{ + context->~epoch_context(); + std::free(context); +} + +} // extern "C" diff --git a/contrib/ethereum/libethash/ethash/ethash.h b/contrib/ethereum/libethash/ethash/ethash.h new file mode 100644 index 00000000..b12f1aa9 --- /dev/null +++ b/contrib/ethereum/libethash/ethash/ethash.h @@ -0,0 +1,99 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +#pragma once + +#include + +#include + +#ifdef __cplusplus +#define NOEXCEPT noexcept +#else +#define NOEXCEPT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The Ethash algorithm revision implemented as specified in the Ethash spec + * https://github.com/ethereum/wiki/wiki/Ethash. + */ +#define ETHASH_REVISION "23" + +#define ETHASH_EPOCH_LENGTH 30000 +#define ETHASH_LIGHT_CACHE_ITEM_SIZE 64 +#define ETHASH_FULL_DATASET_ITEM_SIZE 128 +#define ETHASH_NUM_DATASET_ACCESSES 64 + + +struct ethash_epoch_context +{ + const int epoch_number; + const int light_cache_num_items; + const union ethash_hash512* const light_cache; + const uint32_t* const l1_cache; + const int full_dataset_num_items; +}; + + +struct ethash_epoch_context_full; + + +/** + * Calculates the number of items in the light cache for given epoch. + * + * This function will search for a prime number matching the criteria given + * by the Ethash so the execution time is not constant. It takes ~ 0.01 ms. + * + * @param epoch_number The epoch number. + * @return The number items in the light cache. + */ +int ethash_calculate_light_cache_num_items(int epoch_number) NOEXCEPT; + + +/** + * Calculates the number of items in the full dataset for given epoch. + * + * This function will search for a prime number matching the criteria given + * by the Ethash so the execution time is not constant. It takes ~ 0.05 ms. + * + * @param epoch_number The epoch number. + * @return The number items in the full dataset. + */ +int ethash_calculate_full_dataset_num_items(int epoch_number) NOEXCEPT; + +/** + * Calculates the epoch seed hash. + * @param epoch_number The epoch number. + * @return The epoch seed hash. + */ +union ethash_hash256 ethash_calculate_epoch_seed(int epoch_number) NOEXCEPT; + + +struct ethash_epoch_context* ethash_create_epoch_context(int epoch_number) NOEXCEPT; + +/** + * Creates the epoch context with the full dataset initialized. + * + * The memory for the full dataset is only allocated and marked as "not-generated". + * The items of the full dataset are generated on the fly when hit for the first time. + * + * The memory allocated in the context MUST be freed with ethash_destroy_epoch_context_full(). + * + * @param epoch_number The epoch number. + * @return Pointer to the context or null in case of memory allocation failure. + */ +struct ethash_epoch_context_full* ethash_create_epoch_context_full(int epoch_number) NOEXCEPT; + +void ethash_destroy_epoch_context(struct ethash_epoch_context* context) NOEXCEPT; + +void ethash_destroy_epoch_context_full(struct ethash_epoch_context_full* context) NOEXCEPT; + +#ifdef __cplusplus +} +#endif diff --git a/contrib/ethereum/libethash/ethash/ethash.hpp b/contrib/ethereum/libethash/ethash/ethash.hpp new file mode 100644 index 00000000..03f29afd --- /dev/null +++ b/contrib/ethereum/libethash/ethash/ethash.hpp @@ -0,0 +1,160 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. See the LICENSE file. + +/// @file +/// +/// API design decisions: +/// +/// 1. Signed integer type is used whenever the size of the type is not +/// restricted by the Ethash specification. +/// See http://www.aristeia.com/Papers/C++ReportColumns/sep95.pdf. +/// See https://stackoverflow.com/questions/10168079/why-is-size-t-unsigned/. +/// See https://github.com/Microsoft/GSL/issues/171. + +#pragma once + +#include +#include + +#include +#include +#include + +namespace ethash +{ +constexpr auto revision = ETHASH_REVISION; + +static constexpr int epoch_length = ETHASH_EPOCH_LENGTH; +static constexpr int light_cache_item_size = ETHASH_LIGHT_CACHE_ITEM_SIZE; +static constexpr int full_dataset_item_size = ETHASH_FULL_DATASET_ITEM_SIZE; +static constexpr int num_dataset_accesses = ETHASH_NUM_DATASET_ACCESSES; + +using epoch_context = ethash_epoch_context; +using epoch_context_full = ethash_epoch_context_full; + +/// Constructs a 256-bit hash from an array of bytes. +/// +/// @param bytes A pointer to array of at least 32 bytes. +/// @return The constructed hash. +inline hash256 hash256_from_bytes(const uint8_t bytes[32]) noexcept +{ + hash256 h; + std::memcpy(&h, bytes, sizeof(h)); + return h; +} + +struct result +{ + hash256 final_hash; + hash256 mix_hash; +}; + +struct search_result +{ + bool solution_found = false; + uint64_t nonce = 0; + hash256 final_hash = {}; + hash256 mix_hash = {}; + + search_result() noexcept = default; + + search_result(result res, uint64_t nonce) noexcept + : solution_found(true), nonce(nonce), final_hash(res.final_hash), mix_hash(res.mix_hash) + {} +}; + + +/// Alias for ethash_calculate_light_cache_num_items(). +static constexpr auto calculate_light_cache_num_items = ethash_calculate_light_cache_num_items; + +/// Alias for ethash_calculate_full_dataset_num_items(). +static constexpr auto calculate_full_dataset_num_items = ethash_calculate_full_dataset_num_items; + +/// Alias for ethash_calculate_epoch_seed(). +static constexpr auto calculate_epoch_seed = ethash_calculate_epoch_seed; + + +/// Calculates the epoch number out of the block number. +inline constexpr int get_epoch_number(int block_number) noexcept +{ + return block_number / epoch_length; +} + +/** + * Coverts the number of items of a light cache to size in bytes. + * + * @param num_items The number of items in the light cache. + * @return The size of the light cache in bytes. + */ +inline constexpr size_t get_light_cache_size(int num_items) noexcept +{ + return static_cast(num_items) * light_cache_item_size; +} + +/** + * Coverts the number of items of a full dataset to size in bytes. + * + * @param num_items The number of items in the full dataset. + * @return The size of the full dataset in bytes. + */ +inline constexpr uint64_t get_full_dataset_size(int num_items) noexcept +{ + return static_cast(num_items) * full_dataset_item_size; +} + +/// Owned unique pointer to an epoch context. +using epoch_context_ptr = std::unique_ptr; + +using epoch_context_full_ptr = + std::unique_ptr; + +/// Creates Ethash epoch context. +/// +/// This is a wrapper for ethash_create_epoch_number C function that returns +/// the context as a smart pointer which handles the destruction of the context. +inline epoch_context_ptr create_epoch_context(int epoch_number) noexcept +{ + return {ethash_create_epoch_context(epoch_number), ethash_destroy_epoch_context}; +} + +inline epoch_context_full_ptr create_epoch_context_full(int epoch_number) noexcept +{ + return {ethash_create_epoch_context_full(epoch_number), ethash_destroy_epoch_context_full}; +} + + +result hash(const epoch_context& context, const hash256& header_hash, uint64_t nonce) noexcept; + +result hash(const epoch_context_full& context, const hash256& header_hash, uint64_t nonce) noexcept; + +bool verify_final_hash(const hash256& header_hash, const hash256& mix_hash, uint64_t nonce, + const hash256& boundary) noexcept; + +bool verify(const epoch_context& context, const hash256& header_hash, const hash256& mix_hash, + uint64_t nonce, const hash256& boundary) noexcept; + +search_result search_light(const epoch_context& context, const hash256& header_hash, + const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept; + +search_result search(const epoch_context_full& context, const hash256& header_hash, + const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept; + + +/// Tries to find the epoch number matching the given seed hash. +/// +/// Mining pool protocols (many variants of stratum and "getwork") send out +/// seed hash instead of epoch number to workers. This function tries to recover +/// the epoch number from this seed hash. +/// +/// @param seed Ethash seed hash. +/// @return The epoch number or -1 if not found. +int find_epoch_number(const hash256& seed) noexcept; + + +/// Get global shared epoch context. +const epoch_context& get_global_epoch_context(int epoch_number); + +/// Get global shared epoch context with full dataset initialized. +const epoch_context_full& get_global_epoch_context_full(int epoch_number); +} // namespace ethash diff --git a/contrib/ethereum/libethash/ethash/hash_types.h b/contrib/ethereum/libethash/ethash/hash_types.h new file mode 100644 index 00000000..108e141c --- /dev/null +++ b/contrib/ethereum/libethash/ethash/hash_types.h @@ -0,0 +1,46 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +union ethash_hash256 +{ + uint64_t word64s[4]; + uint32_t word32s[8]; + uint8_t bytes[32]; +}; + +union ethash_hash512 +{ + uint64_t word64s[8]; + uint32_t word32s[16]; + uint8_t bytes[64]; +}; + +union ethash_hash1024 +{ + union ethash_hash512 hash512s[2]; + uint64_t word64s[16]; + uint32_t word32s[32]; + uint8_t bytes[128]; +}; + +union ethash_hash2048 +{ + union ethash_hash512 hash512s[4]; + uint64_t word64s[32]; + uint32_t word32s[64]; + uint8_t bytes[256]; +}; + +#ifdef __cplusplus +} +#endif diff --git a/contrib/ethereum/libethash/ethash/hash_types.hpp b/contrib/ethereum/libethash/ethash/hash_types.hpp new file mode 100644 index 00000000..cb9c3f10 --- /dev/null +++ b/contrib/ethereum/libethash/ethash/hash_types.hpp @@ -0,0 +1,15 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. See the LICENSE file. + +#pragma once + +#include + +namespace ethash +{ +using hash256 = ethash_hash256; +using hash512 = ethash_hash512; +using hash1024 = ethash_hash1024; +using hash2048 = ethash_hash2048; +} // namespace ethash diff --git a/contrib/ethereum/libethash/ethash/keccak.h b/contrib/ethereum/libethash/ethash/keccak.h new file mode 100644 index 00000000..e1414b84 --- /dev/null +++ b/contrib/ethereum/libethash/ethash/keccak.h @@ -0,0 +1,49 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +#pragma once + +#include + +#include + +#ifdef __cplusplus +#define NOEXCEPT noexcept +#else +#define NOEXCEPT +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The Keccak-f[1600] function. + * + * The implementation of the Keccak-f function with 1600-bit width of the permutation (b). + * The size of the state is also 1600 bit what gives 25 64-bit words. + * + * @param state The state of 25 64-bit words on which the permutation is to be performed. + */ +void ethash_keccakf1600(uint64_t state[25]) NOEXCEPT; + +/** + * The Keccak-f[800] function. + * + * The implementation of the Keccak-f function with 800-bit width of the permutation (b). + * The size of the state is also 800 bit what gives 25 32-bit words. + * + * @param state The state of 25 32-bit words on which the permutation is to be performed. + */ +void ethash_keccakf800(uint32_t state[25]) NOEXCEPT; + +union ethash_hash256 ethash_keccak256(const uint8_t* data, size_t size) NOEXCEPT; +union ethash_hash256 ethash_keccak256_32(const uint8_t data[32]) NOEXCEPT; +union ethash_hash512 ethash_keccak512(const uint8_t* data, size_t size) NOEXCEPT; +union ethash_hash512 ethash_keccak512_64(const uint8_t data[64]) NOEXCEPT; + +#ifdef __cplusplus +} +#endif diff --git a/contrib/ethereum/libethash/ethash/keccak.hpp b/contrib/ethereum/libethash/ethash/keccak.hpp new file mode 100644 index 00000000..9dbc6aaa --- /dev/null +++ b/contrib/ethereum/libethash/ethash/keccak.hpp @@ -0,0 +1,35 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. See the LICENSE file. + +#pragma once + +#include +#include + +namespace ethash +{ +inline hash256 keccak256(const uint8_t* data, size_t size) noexcept +{ + return ethash_keccak256(data, size); +} + +inline hash256 keccak256(const hash256& input) noexcept +{ + return ethash_keccak256_32(input.bytes); +} + +inline hash512 keccak512(const uint8_t* data, size_t size) noexcept +{ + return ethash_keccak512(data, size); +} + +inline hash512 keccak512(const hash512& input) noexcept +{ + return ethash_keccak512_64(input.bytes); +} + +static constexpr auto keccak256_32 = ethash_keccak256_32; +static constexpr auto keccak512_64 = ethash_keccak512_64; + +} // namespace ethash diff --git a/contrib/ethereum/libethash/ethash/progpow.hpp b/contrib/ethereum/libethash/ethash/progpow.hpp new file mode 100644 index 00000000..81e6dbaa --- /dev/null +++ b/contrib/ethereum/libethash/ethash/progpow.hpp @@ -0,0 +1,47 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. See the LICENSE file. + +/// @file +/// +/// ProgPoW API +/// +/// This file provides the public API for ProgPoW as the Ethash API extension. + +#include + +namespace progpow +{ +using namespace ethash; // Include ethash namespace. + + +/// The ProgPoW algorithm revision implemented as specified in the spec +/// https://github.com/ifdefelse/ProgPOW#change-history. +constexpr auto revision = "0.9.2"; + +constexpr int period_length = 50; +constexpr uint32_t num_regs = 32; +constexpr size_t num_lanes = 16; +constexpr int num_cache_accesses = 12; +constexpr int num_math_operations = 20; +constexpr size_t l1_cache_size = 16 * 1024; +constexpr size_t l1_cache_num_items = l1_cache_size / sizeof(uint32_t); + +result hash(const epoch_context& context, int block_number, const hash256& header_hash, + uint64_t nonce) noexcept; + +result hash(const epoch_context_full& context, int block_number, const hash256& header_hash, + uint64_t nonce) noexcept; + +bool verify(const epoch_context& context, int block_number, const hash256& header_hash, + const hash256& mix_hash, uint64_t nonce, const hash256& boundary) noexcept; + +search_result search_light(const epoch_context& context, int block_number, + const hash256& header_hash, const hash256& boundary, uint64_t start_nonce, + size_t iterations) noexcept; + +search_result search(const epoch_context_full& context, int block_number, + const hash256& header_hash, const hash256& boundary, uint64_t start_nonce, + size_t iterations) noexcept; + +} // namespace progpow diff --git a/contrib/ethereum/libethash/ethash/version.h b/contrib/ethereum/libethash/ethash/version.h new file mode 100644 index 00000000..f0372b0d --- /dev/null +++ b/contrib/ethereum/libethash/ethash/version.h @@ -0,0 +1,18 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2019 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. + */ + +#pragma once + +/** The ethash library version. */ +#define ETHASH_VERSION "0.4.3" + +#ifdef __cplusplus +namespace ethash +{ +/// The ethash library version. +constexpr auto version = ETHASH_VERSION; + +} // namespace ethash +#endif diff --git a/contrib/ethereum/libethash/keccak.c b/contrib/ethereum/libethash/keccak.c new file mode 100644 index 00000000..4c0b4caa --- /dev/null +++ b/contrib/ethereum/libethash/keccak.c @@ -0,0 +1,123 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +#include + +#include "support/attributes.h" +#include + +#if _WIN32 +/* On Windows assume little endian. */ +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#define __BYTE_ORDER __LITTLE_ENDIAN +#elif __APPLE__ +#include +#else +#include +#endif + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define to_le64(X) X +#else +#define to_le64(X) __builtin_bswap64(X) +#endif + + +/** Loads 64-bit integer from given memory location as little-endian number. */ +static INLINE ALWAYS_INLINE uint64_t load_le(const uint8_t* data) +{ + /* memcpy is the best way of expressing the intention. Every compiler will + optimize is to single load instruction if the target architecture + supports unaligned memory access (GCC and clang even in O0). + This is great trick because we are violating C/C++ memory alignment + restrictions with no performance penalty. */ + uint64_t word; + memcpy(&word, data, sizeof(word)); + return to_le64(word); +} + +static INLINE ALWAYS_INLINE void keccak( + uint64_t* out, size_t bits, const uint8_t* data, size_t size) +{ + static const size_t word_size = sizeof(uint64_t); + const size_t hash_size = bits / 8; + const size_t block_size = (1600 - bits * 2) / 8; + + size_t i; + uint64_t* state_iter; + uint64_t last_word = 0; + uint8_t* last_word_iter = (uint8_t*)&last_word; + + uint64_t state[25] = {0}; + + while (size >= block_size) + { + for (i = 0; i < (block_size / word_size); ++i) + { + state[i] ^= load_le(data); + data += word_size; + } + + ethash_keccakf1600(state); + + size -= block_size; + } + + state_iter = state; + + while (size >= word_size) + { + *state_iter ^= load_le(data); + ++state_iter; + data += word_size; + size -= word_size; + } + + while (size > 0) + { + *last_word_iter = *data; + ++last_word_iter; + ++data; + --size; + } + *last_word_iter = 0x01; + *state_iter ^= to_le64(last_word); + + state[(block_size / word_size) - 1] ^= 0x8000000000000000; + + ethash_keccakf1600(state); + + for (i = 0; i < (hash_size / word_size); ++i) + out[i] = to_le64(state[i]); +} + +union ethash_hash256 ethash_keccak256(const uint8_t* data, size_t size) +{ + union ethash_hash256 hash; + keccak(hash.word64s, 256, data, size); + return hash; +} + +union ethash_hash256 ethash_keccak256_32(const uint8_t data[32]) +{ + union ethash_hash256 hash; + keccak(hash.word64s, 256, data, 32); + return hash; +} + +union ethash_hash512 ethash_keccak512(const uint8_t* data, size_t size) +{ + union ethash_hash512 hash; + keccak(hash.word64s, 512, data, size); + return hash; +} + +union ethash_hash512 ethash_keccak512_64(const uint8_t data[64]) +{ + union ethash_hash512 hash; + keccak(hash.word64s, 512, data, 64); + return hash; +} diff --git a/contrib/ethereum/libethash/keccakf1600.c b/contrib/ethereum/libethash/keccakf1600.c new file mode 100644 index 00000000..271fe76d --- /dev/null +++ b/contrib/ethereum/libethash/keccakf1600.c @@ -0,0 +1,255 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +#include + +static uint64_t rol(uint64_t x, unsigned s) +{ + return (x << s) | (x >> (64 - s)); +} + +static const uint64_t round_constants[24] = { + 0x0000000000000001, + 0x0000000000008082, + 0x800000000000808a, + 0x8000000080008000, + 0x000000000000808b, + 0x0000000080000001, + 0x8000000080008081, + 0x8000000000008009, + 0x000000000000008a, + 0x0000000000000088, + 0x0000000080008009, + 0x000000008000000a, + 0x000000008000808b, + 0x800000000000008b, + 0x8000000000008089, + 0x8000000000008003, + 0x8000000000008002, + 0x8000000000000080, + 0x000000000000800a, + 0x800000008000000a, + 0x8000000080008081, + 0x8000000000008080, + 0x0000000080000001, + 0x8000000080008008, +}; + +void ethash_keccakf1600(uint64_t state[25]) +{ + /* The implementation based on the "simple" implementation by Ronny Van Keer. */ + + int round; + + uint64_t Aba, Abe, Abi, Abo, Abu; + uint64_t Aga, Age, Agi, Ago, Agu; + uint64_t Aka, Ake, Aki, Ako, Aku; + uint64_t Ama, Ame, Ami, Amo, Amu; + uint64_t Asa, Ase, Asi, Aso, Asu; + + uint64_t Eba, Ebe, Ebi, Ebo, Ebu; + uint64_t Ega, Ege, Egi, Ego, Egu; + uint64_t Eka, Eke, Eki, Eko, Eku; + uint64_t Ema, Eme, Emi, Emo, Emu; + uint64_t Esa, Ese, Esi, Eso, Esu; + + uint64_t Ba, Be, Bi, Bo, Bu; + + uint64_t Da, De, Di, Do, Du; + + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < 24; round += 2) + { + /* Round (round + 0): Axx -> Exx */ + + Ba = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + Be = Abe ^ Age ^ Ake ^ Ame ^ Ase; + Bi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + Bo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + Bu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + Da = Bu ^ rol(Be, 1); + De = Ba ^ rol(Bi, 1); + Di = Be ^ rol(Bo, 1); + Do = Bi ^ rol(Bu, 1); + Du = Bo ^ rol(Ba, 1); + + Ba = Aba ^ Da; + Be = rol(Age ^ De, 44); + Bi = rol(Aki ^ Di, 43); + Bo = rol(Amo ^ Do, 21); + Bu = rol(Asu ^ Du, 14); + Eba = Ba ^ (~Be & Bi) ^ round_constants[round]; + Ebe = Be ^ (~Bi & Bo); + Ebi = Bi ^ (~Bo & Bu); + Ebo = Bo ^ (~Bu & Ba); + Ebu = Bu ^ (~Ba & Be); + + Ba = rol(Abo ^ Do, 28); + Be = rol(Agu ^ Du, 20); + Bi = rol(Aka ^ Da, 3); + Bo = rol(Ame ^ De, 45); + Bu = rol(Asi ^ Di, 61); + Ega = Ba ^ (~Be & Bi); + Ege = Be ^ (~Bi & Bo); + Egi = Bi ^ (~Bo & Bu); + Ego = Bo ^ (~Bu & Ba); + Egu = Bu ^ (~Ba & Be); + + Ba = rol(Abe ^ De, 1); + Be = rol(Agi ^ Di, 6); + Bi = rol(Ako ^ Do, 25); + Bo = rol(Amu ^ Du, 8); + Bu = rol(Asa ^ Da, 18); + Eka = Ba ^ (~Be & Bi); + Eke = Be ^ (~Bi & Bo); + Eki = Bi ^ (~Bo & Bu); + Eko = Bo ^ (~Bu & Ba); + Eku = Bu ^ (~Ba & Be); + + Ba = rol(Abu ^ Du, 27); + Be = rol(Aga ^ Da, 36); + Bi = rol(Ake ^ De, 10); + Bo = rol(Ami ^ Di, 15); + Bu = rol(Aso ^ Do, 56); + Ema = Ba ^ (~Be & Bi); + Eme = Be ^ (~Bi & Bo); + Emi = Bi ^ (~Bo & Bu); + Emo = Bo ^ (~Bu & Ba); + Emu = Bu ^ (~Ba & Be); + + Ba = rol(Abi ^ Di, 62); + Be = rol(Ago ^ Do, 55); + Bi = rol(Aku ^ Du, 39); + Bo = rol(Ama ^ Da, 41); + Bu = rol(Ase ^ De, 2); + Esa = Ba ^ (~Be & Bi); + Ese = Be ^ (~Bi & Bo); + Esi = Bi ^ (~Bo & Bu); + Eso = Bo ^ (~Bu & Ba); + Esu = Bu ^ (~Ba & Be); + + + /* Round (round + 1): Exx -> Axx */ + + Ba = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + Be = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + Bi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + Bo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + Bu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + Da = Bu ^ rol(Be, 1); + De = Ba ^ rol(Bi, 1); + Di = Be ^ rol(Bo, 1); + Do = Bi ^ rol(Bu, 1); + Du = Bo ^ rol(Ba, 1); + + Ba = Eba ^ Da; + Be = rol(Ege ^ De, 44); + Bi = rol(Eki ^ Di, 43); + Bo = rol(Emo ^ Do, 21); + Bu = rol(Esu ^ Du, 14); + Aba = Ba ^ (~Be & Bi) ^ round_constants[round + 1]; + Abe = Be ^ (~Bi & Bo); + Abi = Bi ^ (~Bo & Bu); + Abo = Bo ^ (~Bu & Ba); + Abu = Bu ^ (~Ba & Be); + + Ba = rol(Ebo ^ Do, 28); + Be = rol(Egu ^ Du, 20); + Bi = rol(Eka ^ Da, 3); + Bo = rol(Eme ^ De, 45); + Bu = rol(Esi ^ Di, 61); + Aga = Ba ^ (~Be & Bi); + Age = Be ^ (~Bi & Bo); + Agi = Bi ^ (~Bo & Bu); + Ago = Bo ^ (~Bu & Ba); + Agu = Bu ^ (~Ba & Be); + + Ba = rol(Ebe ^ De, 1); + Be = rol(Egi ^ Di, 6); + Bi = rol(Eko ^ Do, 25); + Bo = rol(Emu ^ Du, 8); + Bu = rol(Esa ^ Da, 18); + Aka = Ba ^ (~Be & Bi); + Ake = Be ^ (~Bi & Bo); + Aki = Bi ^ (~Bo & Bu); + Ako = Bo ^ (~Bu & Ba); + Aku = Bu ^ (~Ba & Be); + + Ba = rol(Ebu ^ Du, 27); + Be = rol(Ega ^ Da, 36); + Bi = rol(Eke ^ De, 10); + Bo = rol(Emi ^ Di, 15); + Bu = rol(Eso ^ Do, 56); + Ama = Ba ^ (~Be & Bi); + Ame = Be ^ (~Bi & Bo); + Ami = Bi ^ (~Bo & Bu); + Amo = Bo ^ (~Bu & Ba); + Amu = Bu ^ (~Ba & Be); + + Ba = rol(Ebi ^ Di, 62); + Be = rol(Ego ^ Do, 55); + Bi = rol(Eku ^ Du, 39); + Bo = rol(Ema ^ Da, 41); + Bu = rol(Ese ^ De, 2); + Asa = Ba ^ (~Be & Bi); + Ase = Be ^ (~Bi & Bo); + Asi = Bi ^ (~Bo & Bu); + Aso = Bo ^ (~Bu & Ba); + Asu = Bu ^ (~Ba & Be); + } + + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} diff --git a/contrib/ethereum/libethash/keccakf800.c b/contrib/ethereum/libethash/keccakf800.c new file mode 100644 index 00000000..aa7cceef --- /dev/null +++ b/contrib/ethereum/libethash/keccakf800.c @@ -0,0 +1,253 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +#include + +static uint32_t rol(uint32_t x, unsigned s) +{ + return (x << s) | (x >> (32 - s)); +} + +static const uint32_t round_constants[22] = { + 0x00000001, + 0x00008082, + 0x0000808A, + 0x80008000, + 0x0000808B, + 0x80000001, + 0x80008081, + 0x00008009, + 0x0000008A, + 0x00000088, + 0x80008009, + 0x8000000A, + 0x8000808B, + 0x0000008B, + 0x00008089, + 0x00008003, + 0x00008002, + 0x00000080, + 0x0000800A, + 0x8000000A, + 0x80008081, + 0x00008080, +}; + +void ethash_keccakf800(uint32_t state[25]) +{ + /* The implementation directly translated from ethash_keccakf1600. */ + + int round; + + uint32_t Aba, Abe, Abi, Abo, Abu; + uint32_t Aga, Age, Agi, Ago, Agu; + uint32_t Aka, Ake, Aki, Ako, Aku; + uint32_t Ama, Ame, Ami, Amo, Amu; + uint32_t Asa, Ase, Asi, Aso, Asu; + + uint32_t Eba, Ebe, Ebi, Ebo, Ebu; + uint32_t Ega, Ege, Egi, Ego, Egu; + uint32_t Eka, Eke, Eki, Eko, Eku; + uint32_t Ema, Eme, Emi, Emo, Emu; + uint32_t Esa, Ese, Esi, Eso, Esu; + + uint32_t Ba, Be, Bi, Bo, Bu; + + uint32_t Da, De, Di, Do, Du; + + Aba = state[0]; + Abe = state[1]; + Abi = state[2]; + Abo = state[3]; + Abu = state[4]; + Aga = state[5]; + Age = state[6]; + Agi = state[7]; + Ago = state[8]; + Agu = state[9]; + Aka = state[10]; + Ake = state[11]; + Aki = state[12]; + Ako = state[13]; + Aku = state[14]; + Ama = state[15]; + Ame = state[16]; + Ami = state[17]; + Amo = state[18]; + Amu = state[19]; + Asa = state[20]; + Ase = state[21]; + Asi = state[22]; + Aso = state[23]; + Asu = state[24]; + + for (round = 0; round < 22; round += 2) + { + /* Round (round + 0): Axx -> Exx */ + + Ba = Aba ^ Aga ^ Aka ^ Ama ^ Asa; + Be = Abe ^ Age ^ Ake ^ Ame ^ Ase; + Bi = Abi ^ Agi ^ Aki ^ Ami ^ Asi; + Bo = Abo ^ Ago ^ Ako ^ Amo ^ Aso; + Bu = Abu ^ Agu ^ Aku ^ Amu ^ Asu; + + Da = Bu ^ rol(Be, 1); + De = Ba ^ rol(Bi, 1); + Di = Be ^ rol(Bo, 1); + Do = Bi ^ rol(Bu, 1); + Du = Bo ^ rol(Ba, 1); + + Ba = Aba ^ Da; + Be = rol(Age ^ De, 12); + Bi = rol(Aki ^ Di, 11); + Bo = rol(Amo ^ Do, 21); + Bu = rol(Asu ^ Du, 14); + Eba = Ba ^ (~Be & Bi) ^ round_constants[round]; + Ebe = Be ^ (~Bi & Bo); + Ebi = Bi ^ (~Bo & Bu); + Ebo = Bo ^ (~Bu & Ba); + Ebu = Bu ^ (~Ba & Be); + + Ba = rol(Abo ^ Do, 28); + Be = rol(Agu ^ Du, 20); + Bi = rol(Aka ^ Da, 3); + Bo = rol(Ame ^ De, 13); + Bu = rol(Asi ^ Di, 29); + Ega = Ba ^ (~Be & Bi); + Ege = Be ^ (~Bi & Bo); + Egi = Bi ^ (~Bo & Bu); + Ego = Bo ^ (~Bu & Ba); + Egu = Bu ^ (~Ba & Be); + + Ba = rol(Abe ^ De, 1); + Be = rol(Agi ^ Di, 6); + Bi = rol(Ako ^ Do, 25); + Bo = rol(Amu ^ Du, 8); + Bu = rol(Asa ^ Da, 18); + Eka = Ba ^ (~Be & Bi); + Eke = Be ^ (~Bi & Bo); + Eki = Bi ^ (~Bo & Bu); + Eko = Bo ^ (~Bu & Ba); + Eku = Bu ^ (~Ba & Be); + + Ba = rol(Abu ^ Du, 27); + Be = rol(Aga ^ Da, 4); + Bi = rol(Ake ^ De, 10); + Bo = rol(Ami ^ Di, 15); + Bu = rol(Aso ^ Do, 24); + Ema = Ba ^ (~Be & Bi); + Eme = Be ^ (~Bi & Bo); + Emi = Bi ^ (~Bo & Bu); + Emo = Bo ^ (~Bu & Ba); + Emu = Bu ^ (~Ba & Be); + + Ba = rol(Abi ^ Di, 30); + Be = rol(Ago ^ Do, 23); + Bi = rol(Aku ^ Du, 7); + Bo = rol(Ama ^ Da, 9); + Bu = rol(Ase ^ De, 2); + Esa = Ba ^ (~Be & Bi); + Ese = Be ^ (~Bi & Bo); + Esi = Bi ^ (~Bo & Bu); + Eso = Bo ^ (~Bu & Ba); + Esu = Bu ^ (~Ba & Be); + + + /* Round (round + 1): Exx -> Axx */ + + Ba = Eba ^ Ega ^ Eka ^ Ema ^ Esa; + Be = Ebe ^ Ege ^ Eke ^ Eme ^ Ese; + Bi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi; + Bo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso; + Bu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu; + + Da = Bu ^ rol(Be, 1); + De = Ba ^ rol(Bi, 1); + Di = Be ^ rol(Bo, 1); + Do = Bi ^ rol(Bu, 1); + Du = Bo ^ rol(Ba, 1); + + Ba = Eba ^ Da; + Be = rol(Ege ^ De, 12); + Bi = rol(Eki ^ Di, 11); + Bo = rol(Emo ^ Do, 21); + Bu = rol(Esu ^ Du, 14); + Aba = Ba ^ (~Be & Bi) ^ round_constants[round + 1]; + Abe = Be ^ (~Bi & Bo); + Abi = Bi ^ (~Bo & Bu); + Abo = Bo ^ (~Bu & Ba); + Abu = Bu ^ (~Ba & Be); + + Ba = rol(Ebo ^ Do, 28); + Be = rol(Egu ^ Du, 20); + Bi = rol(Eka ^ Da, 3); + Bo = rol(Eme ^ De, 13); + Bu = rol(Esi ^ Di, 29); + Aga = Ba ^ (~Be & Bi); + Age = Be ^ (~Bi & Bo); + Agi = Bi ^ (~Bo & Bu); + Ago = Bo ^ (~Bu & Ba); + Agu = Bu ^ (~Ba & Be); + + Ba = rol(Ebe ^ De, 1); + Be = rol(Egi ^ Di, 6); + Bi = rol(Eko ^ Do, 25); + Bo = rol(Emu ^ Du, 8); + Bu = rol(Esa ^ Da, 18); + Aka = Ba ^ (~Be & Bi); + Ake = Be ^ (~Bi & Bo); + Aki = Bi ^ (~Bo & Bu); + Ako = Bo ^ (~Bu & Ba); + Aku = Bu ^ (~Ba & Be); + + Ba = rol(Ebu ^ Du, 27); + Be = rol(Ega ^ Da, 4); + Bi = rol(Eke ^ De, 10); + Bo = rol(Emi ^ Di, 15); + Bu = rol(Eso ^ Do, 24); + Ama = Ba ^ (~Be & Bi); + Ame = Be ^ (~Bi & Bo); + Ami = Bi ^ (~Bo & Bu); + Amo = Bo ^ (~Bu & Ba); + Amu = Bu ^ (~Ba & Be); + + Ba = rol(Ebi ^ Di, 30); + Be = rol(Ego ^ Do, 23); + Bi = rol(Eku ^ Du, 7); + Bo = rol(Ema ^ Da, 9); + Bu = rol(Ese ^ De, 2); + Asa = Ba ^ (~Be & Bi); + Ase = Be ^ (~Bi & Bo); + Asi = Bi ^ (~Bo & Bu); + Aso = Bo ^ (~Bu & Ba); + Asu = Bu ^ (~Ba & Be); + } + + state[0] = Aba; + state[1] = Abe; + state[2] = Abi; + state[3] = Abo; + state[4] = Abu; + state[5] = Aga; + state[6] = Age; + state[7] = Agi; + state[8] = Ago; + state[9] = Agu; + state[10] = Aka; + state[11] = Ake; + state[12] = Aki; + state[13] = Ako; + state[14] = Aku; + state[15] = Ama; + state[16] = Ame; + state[17] = Ami; + state[18] = Amo; + state[19] = Amu; + state[20] = Asa; + state[21] = Ase; + state[22] = Asi; + state[23] = Aso; + state[24] = Asu; +} diff --git a/contrib/ethereum/libethash/kiss99.hpp b/contrib/ethereum/libethash/kiss99.hpp new file mode 100644 index 00000000..8550b82e --- /dev/null +++ b/contrib/ethereum/libethash/kiss99.hpp @@ -0,0 +1,64 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +#pragma once + +#include "support/attributes.h" +#include + +/** + * KISS PRNG by the spec from 1999. + * + * The implementation of KISS pseudo-random number generator + * by the specification published on 21 Jan 1999 in + * http://www.cse.yorku.ca/~oz/marsaglia-rng.html. + * The KISS is not versioned so here we are using `kiss99` prefix to indicate + * the version from 1999. + * + * The specification uses `unsigned long` type with the intention for 32-bit + * values. Because in GCC/clang for 64-bit architectures `unsigned long` is + * 64-bit size type, here the explicit `uint32_t` type is used. + * + * @defgroup kiss99 KISS99 + * @{ + */ + +/** + * The KISS generator. + */ +class kiss99 +{ + uint32_t z = 362436069; + uint32_t w = 521288629; + uint32_t jsr = 123456789; + uint32_t jcong = 380116160; + +public: + /** Creates KISS generator state with default values provided by the specification. */ + kiss99() noexcept = default; + + /** Creates KISS generator state with provided init values.*/ + kiss99(uint32_t z, uint32_t w, uint32_t jsr, uint32_t jcong) noexcept + : z{z}, w{w}, jsr{jsr}, jcong{jcong} + {} + + /** Generates next number from the KISS generator. */ + NO_SANITIZE("unsigned-integer-overflow") + uint32_t operator()() noexcept + { + z = 36969 * (z & 0xffff) + (z >> 16); + w = 18000 * (w & 0xffff) + (w >> 16); + + jcong = 69069 * jcong + 1234567; + + jsr ^= (jsr << 17); + jsr ^= (jsr >> 13); + jsr ^= (jsr << 5); + + return (((z << 16) + w) ^ jcong) + jsr; + } +}; + +/** @} */ diff --git a/contrib/ethereum/libethash/managed.cpp b/contrib/ethereum/libethash/managed.cpp new file mode 100644 index 00000000..900da7e7 --- /dev/null +++ b/contrib/ethereum/libethash/managed.cpp @@ -0,0 +1,100 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. See the LICENSE file. + +#include "ethash-internal.hpp" + +#include +#include + +#if !defined(__has_cpp_attribute) +#define __has_cpp_attribute(x) 0 +#endif + +#if __has_cpp_attribute(gnu::noinline) +#define ATTRIBUTE_NOINLINE [[gnu::noinline]] +#elif _MSC_VER +#define ATTRIBUTE_NOINLINE __declspec(noinline) +#else +#define ATTRIBUTE_NOINLINE +#endif + +namespace ethash +{ +namespace +{ +std::mutex shared_context_mutex; +std::shared_ptr shared_context; +thread_local std::shared_ptr thread_local_context; + +std::mutex shared_context_full_mutex; +std::shared_ptr shared_context_full; +thread_local std::shared_ptr thread_local_context_full; + +/// Update thread local epoch context. +/// +/// This function is on the slow path. It's separated to allow inlining the fast +/// path. +/// +/// @todo: Redesign to guarantee deallocation before new allocation. +ATTRIBUTE_NOINLINE +void update_local_context(int epoch_number) +{ + // Release the shared pointer of the obsoleted context. + thread_local_context.reset(); + + // Local context invalid, check the shared context. + std::lock_guard lock{shared_context_mutex}; + + if (!shared_context || shared_context->epoch_number != epoch_number) + { + // Release the shared pointer of the obsoleted context. + shared_context.reset(); + + // Build new context. + shared_context = create_epoch_context(epoch_number); + } + + thread_local_context = shared_context; +} + +ATTRIBUTE_NOINLINE +void update_local_context_full(int epoch_number) +{ + // Release the shared pointer of the obsoleted context. + thread_local_context_full.reset(); + + // Local context invalid, check the shared context. + std::lock_guard lock{shared_context_full_mutex}; + + if (!shared_context_full || shared_context_full->epoch_number != epoch_number) + { + // Release the shared pointer of the obsoleted context. + shared_context_full.reset(); + + // Build new context. + shared_context_full = create_epoch_context_full(epoch_number); + } + + thread_local_context_full = shared_context_full; +} +} // namespace + +const epoch_context& get_global_epoch_context(int epoch_number) +{ + // Check if local context matches epoch number. + if (!thread_local_context || thread_local_context->epoch_number != epoch_number) + update_local_context(epoch_number); + + return *thread_local_context; +} + +const epoch_context_full& get_global_epoch_context_full(int epoch_number) +{ + // Check if local context matches epoch number. + if (!thread_local_context_full || thread_local_context_full->epoch_number != epoch_number) + update_local_context_full(epoch_number); + + return *thread_local_context_full; +} +} // namespace ethash diff --git a/contrib/ethereum/libethash/primes.c b/contrib/ethereum/libethash/primes.c new file mode 100644 index 00000000..2d58874b --- /dev/null +++ b/contrib/ethereum/libethash/primes.c @@ -0,0 +1,43 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +#include "primes.h" + +/** Checks if the number is prime. Requires the number to be > 2 and odd. */ +static int is_odd_prime(int number) +{ + int d; + + /* Check factors up to sqrt(number). + To avoid computing sqrt, compare d*d <= number with 64-bit precision. */ + for (d = 3; (int64_t)d * (int64_t)d <= (int64_t)number; d += 2) + { + if (number % d == 0) + return 0; + } + + return 1; +} + +int ethash_find_largest_prime(int upper_bound) +{ + int n = upper_bound; + + if (n < 2) + return 0; + + if (n == 2) + return 2; + + /* If even number, skip it. */ + if (n % 2 == 0) + --n; + + /* Test descending odd numbers. */ + while (!is_odd_prime(n)) + n -= 2; + + return n; +} diff --git a/contrib/ethereum/libethash/primes.h b/contrib/ethereum/libethash/primes.h new file mode 100644 index 00000000..cf923b01 --- /dev/null +++ b/contrib/ethereum/libethash/primes.h @@ -0,0 +1,25 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Finds the largest prime number not greater than the provided upper bound. + * + * @param upper_bound The upper bound. SHOULD be greater than 1. + * @return The largest prime number `p` such `p <= upper_bound`. + * In case `upper_bound <= 1`, returns 0. + */ +int ethash_find_largest_prime(int upper_bound) NOEXCEPT; + +#ifdef __cplusplus +} +#endif diff --git a/contrib/ethereum/libethash/progpow.cpp b/contrib/ethereum/libethash/progpow.cpp new file mode 100644 index 00000000..fd709e8f --- /dev/null +++ b/contrib/ethereum/libethash/progpow.cpp @@ -0,0 +1,360 @@ +// ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. +// Copyright 2018 Pawel Bylica. +// Licensed under the Apache License, Version 2.0. See the LICENSE file. + +#include + +#include "bit_manipulation.h" +#include "endianness.hpp" +#include "ethash-internal.hpp" +#include "kiss99.hpp" +#include + +#include + +namespace progpow +{ +namespace +{ +/// A variant of Keccak hash function for ProgPoW. +/// +/// This Keccak hash function uses 800-bit permutation (Keccak-f[800]) with 576 bitrate. +/// It take exactly 576 bits of input (split across 3 arguments) and adds no padding. +/// +/// @param header_hash The 256-bit header hash. +/// @param nonce The 64-bit nonce. +/// @param mix_hash Additional 256-bits of data. +/// @return The 256-bit output of the hash function. +hash256 keccak_progpow_256( + const hash256& header_hash, uint64_t nonce, const hash256& mix_hash) noexcept +{ + static constexpr size_t num_words = + sizeof(header_hash.word32s) / sizeof(header_hash.word32s[0]); + + uint32_t state[25] = {}; + + size_t i; + for (i = 0; i < num_words; ++i) + state[i] = le::uint32(header_hash.word32s[i]); + + state[i++] = static_cast(nonce); + state[i++] = static_cast(nonce >> 32); + + for (uint32_t mix_word : mix_hash.word32s) + state[i++] = le::uint32(mix_word); + + ethash_keccakf800(state); + + hash256 output; + for (i = 0; i < num_words; ++i) + output.word32s[i] = le::uint32(state[i]); + return output; +} + +/// The same as keccak_progpow_256() but uses null mix +/// and returns top 64 bits of the output being a big-endian prefix of the 256-bit hash. +inline uint64_t keccak_progpow_64(const hash256& header_hash, uint64_t nonce) noexcept +{ + const hash256 h = keccak_progpow_256(header_hash, nonce, {}); + return be::uint64(h.word64s[0]); +} + + +/// ProgPoW mix RNG state. +/// +/// Encapsulates the state of the random number generator used in computing ProgPoW mix. +/// This includes the state of the KISS99 RNG and the precomputed random permutation of the +/// sequence of mix item indexes. +class mix_rng_state +{ +public: + inline explicit mix_rng_state(uint64_t seed) noexcept; + + uint32_t next_dst() noexcept { return dst_seq[(dst_counter++) % num_regs]; } + uint32_t next_src() noexcept { return src_seq[(src_counter++) % num_regs]; } + + kiss99 rng; + +private: + size_t dst_counter = 0; + std::array dst_seq; + size_t src_counter = 0; + std::array src_seq; +}; + +mix_rng_state::mix_rng_state(uint64_t seed) noexcept +{ + const auto seed_lo = static_cast(seed); + const auto seed_hi = static_cast(seed >> 32); + + const auto z = fnv1a(fnv_offset_basis, seed_lo); + const auto w = fnv1a(z, seed_hi); + const auto jsr = fnv1a(w, seed_lo); + const auto jcong = fnv1a(jsr, seed_hi); + + rng = kiss99{z, w, jsr, jcong}; + + // Create random permutations of mix destinations / sources. + // Uses Fisher-Yates shuffle. + for (uint32_t i = 0; i < num_regs; ++i) + { + dst_seq[i] = i; + src_seq[i] = i; + } + + for (uint32_t i = num_regs; i > 1; --i) + { + std::swap(dst_seq[i - 1], dst_seq[rng() % i]); + std::swap(src_seq[i - 1], src_seq[rng() % i]); + } +} + + +NO_SANITIZE("unsigned-integer-overflow") +inline uint32_t random_math(uint32_t a, uint32_t b, uint32_t selector) noexcept +{ + switch (selector % 11) + { + default: + case 0: + return a + b; + case 1: + return a * b; + case 2: + return mul_hi32(a, b); + case 3: + return std::min(a, b); + case 4: + return rotl32(a, b); + case 5: + return rotr32(a, b); + case 6: + return a & b; + case 7: + return a | b; + case 8: + return a ^ b; + case 9: + return clz32(a) + clz32(b); + case 10: + return popcount32(a) + popcount32(b); + } +} + +/// Merge data from `b` and `a`. +/// Assuming `a` has high entropy, only do ops that retain entropy even if `b` +/// has low entropy (i.e. do not do `a & b`). +NO_SANITIZE("unsigned-integer-overflow") +inline void random_merge(uint32_t& a, uint32_t b, uint32_t selector) noexcept +{ + const auto x = (selector >> 16) % 31 + 1; // Additional non-zero selector from higher bits. + switch (selector % 4) + { + case 0: + a = (a * 33) + b; + break; + case 1: + a = (a ^ b) * 33; + break; + case 2: + a = rotl32(a, x) ^ b; + break; + case 3: + a = rotr32(a, x) ^ b; + break; + } +} + +using lookup_fn = hash2048 (*)(const epoch_context&, uint32_t); + +using mix_array = std::array, num_lanes>; + +void round( + const epoch_context& context, uint32_t r, mix_array& mix, mix_rng_state state, lookup_fn lookup) +{ + const uint32_t num_items = static_cast(context.full_dataset_num_items / 2); + const uint32_t item_index = mix[r % num_lanes][0] % num_items; + const hash2048 item = lookup(context, item_index); + + constexpr size_t num_words_per_lane = sizeof(item) / (sizeof(uint32_t) * num_lanes); + constexpr int max_operations = + num_cache_accesses > num_math_operations ? num_cache_accesses : num_math_operations; + + // Process lanes. + for (int i = 0; i < max_operations; ++i) + { + if (i < num_cache_accesses) // Random access to cached memory. + { + const auto src = state.next_src(); + const auto dst = state.next_dst(); + const auto sel = state.rng(); + + for (size_t l = 0; l < num_lanes; ++l) + { + const size_t offset = mix[l][src] % l1_cache_num_items; + random_merge(mix[l][dst], le::uint32(context.l1_cache[offset]), sel); + } + } + if (i < num_math_operations) // Random math. + { + // Generate 2 unique source indexes. + const auto src_rnd = state.rng() % (num_regs * (num_regs - 1)); + const auto src1 = src_rnd % num_regs; // O <= src1 < num_regs + auto src2 = src_rnd / num_regs; // 0 <= src2 < num_regs - 1 + if (src2 >= src1) + ++src2; + + const auto sel1 = state.rng(); + const auto dst = state.next_dst(); + const auto sel2 = state.rng(); + + for (size_t l = 0; l < num_lanes; ++l) + { + const uint32_t data = random_math(mix[l][src1], mix[l][src2], sel1); + random_merge(mix[l][dst], data, sel2); + } + } + } + + // DAG access pattern. + uint32_t dsts[num_words_per_lane]; + uint32_t sels[num_words_per_lane]; + for (size_t i = 0; i < num_words_per_lane; ++i) + { + dsts[i] = i == 0 ? 0 : state.next_dst(); + sels[i] = state.rng(); + } + + // DAG access. + for (size_t l = 0; l < num_lanes; ++l) + { + const auto offset = ((l ^ r) % num_lanes) * num_words_per_lane; + for (size_t i = 0; i < num_words_per_lane; ++i) + { + const auto word = le::uint32(item.word32s[offset + i]); + random_merge(mix[l][dsts[i]], word, sels[i]); + } + } +} + +mix_array init_mix(uint64_t seed) +{ + const uint32_t z = fnv1a(fnv_offset_basis, static_cast(seed)); + const uint32_t w = fnv1a(z, static_cast(seed >> 32)); + + mix_array mix; + for (uint32_t l = 0; l < mix.size(); ++l) + { + const uint32_t jsr = fnv1a(w, l); + const uint32_t jcong = fnv1a(jsr, l); + kiss99 rng{z, w, jsr, jcong}; + + for (auto& row : mix[l]) + row = rng(); + } + return mix; +} + +hash256 hash_mix( + const epoch_context& context, int block_number, uint64_t seed, lookup_fn lookup) noexcept +{ + auto mix = init_mix(seed); + mix_rng_state state{uint64_t(block_number / period_length)}; + + for (uint32_t i = 0; i < 64; ++i) + round(context, i, mix, state, lookup); + + // Reduce mix data to a single per-lane result. + uint32_t lane_hash[num_lanes]; + for (size_t l = 0; l < num_lanes; ++l) + { + lane_hash[l] = fnv_offset_basis; + for (uint32_t i = 0; i < num_regs; ++i) + lane_hash[l] = fnv1a(lane_hash[l], mix[l][i]); + } + + // Reduce all lanes to a single 256-bit result. + static constexpr size_t num_words = sizeof(hash256) / sizeof(uint32_t); + hash256 mix_hash; + for (uint32_t& w : mix_hash.word32s) + w = fnv_offset_basis; + for (size_t l = 0; l < num_lanes; ++l) + mix_hash.word32s[l % num_words] = fnv1a(mix_hash.word32s[l % num_words], lane_hash[l]); + return le::uint32s(mix_hash); +} +} // namespace + +result hash(const epoch_context& context, int block_number, const hash256& header_hash, + uint64_t nonce) noexcept +{ + const uint64_t seed = keccak_progpow_64(header_hash, nonce); + const hash256 mix_hash = hash_mix(context, block_number, seed, calculate_dataset_item_2048); + const hash256 final_hash = keccak_progpow_256(header_hash, seed, mix_hash); + return {final_hash, mix_hash}; +} + +result hash(const epoch_context_full& context, int block_number, const hash256& header_hash, + uint64_t nonce) noexcept +{ + static const auto lazy_lookup = [](const epoch_context& context, uint32_t index) noexcept + { + auto* full_dataset_1024 = static_cast(context).full_dataset; + auto* full_dataset_2048 = reinterpret_cast(full_dataset_1024); + hash2048& item = full_dataset_2048[index]; + if (item.word64s[0] == 0) + { + // TODO: Copy elision here makes it thread-safe? + item = calculate_dataset_item_2048(context, index); + } + + return item; + }; + + const uint64_t seed = keccak_progpow_64(header_hash, nonce); + const hash256 mix_hash = hash_mix(context, block_number, seed, lazy_lookup); + const hash256 final_hash = keccak_progpow_256(header_hash, seed, mix_hash); + return {final_hash, mix_hash}; +} + +bool verify(const epoch_context& context, int block_number, const hash256& header_hash, + const hash256& mix_hash, uint64_t nonce, const hash256& boundary) noexcept +{ + const uint64_t seed = keccak_progpow_64(header_hash, nonce); + const hash256 final_hash = keccak_progpow_256(header_hash, seed, mix_hash); + if (!is_less_or_equal(final_hash, boundary)) + return false; + + const hash256 expected_mix_hash = + hash_mix(context, block_number, seed, calculate_dataset_item_2048); + return is_equal(expected_mix_hash, mix_hash); +} + +search_result search_light(const epoch_context& context, int block_number, + const hash256& header_hash, const hash256& boundary, uint64_t start_nonce, + size_t iterations) noexcept +{ + const uint64_t end_nonce = start_nonce + iterations; + for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) + { + result r = hash(context, block_number, header_hash, nonce); + if (is_less_or_equal(r.final_hash, boundary)) + return {r, nonce}; + } + return {}; +} + +search_result search(const epoch_context_full& context, int block_number, + const hash256& header_hash, const hash256& boundary, uint64_t start_nonce, + size_t iterations) noexcept +{ + const uint64_t end_nonce = start_nonce + iterations; + for (uint64_t nonce = start_nonce; nonce < end_nonce; ++nonce) + { + result r = hash(context, block_number, header_hash, nonce); + if (is_less_or_equal(r.final_hash, boundary)) + return {r, nonce}; + } + return {}; +} + +} // namespace progpow diff --git a/contrib/ethereum/libethash/support/attributes.h b/contrib/ethereum/libethash/support/attributes.h new file mode 100644 index 00000000..bb62b8d4 --- /dev/null +++ b/contrib/ethereum/libethash/support/attributes.h @@ -0,0 +1,33 @@ +/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm. + * Copyright 2018 Pawel Bylica. + * Licensed under the Apache License, Version 2.0. See the LICENSE file. + */ + +#pragma once + +/** inline */ +#if _MSC_VER || __STDC_VERSION__ +#define INLINE inline +#else +#define INLINE +#endif + +/** [[always_inline]] */ +#if _MSC_VER +#define ALWAYS_INLINE __forceinline +#elif defined(__has_attribute) && __STDC_VERSION__ +#if __has_attribute(always_inline) +#define ALWAYS_INLINE __attribute__((always_inline)) +#endif +#endif +#if !defined(ALWAYS_INLINE) +#define ALWAYS_INLINE +#endif + +/** [[no_sanitize()]] */ +#if __clang__ +#define NO_SANITIZE(sanitizer) \ + __attribute__((no_sanitize(sanitizer))) +#else +#define NO_SANITIZE(sanitizer) +#endif diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 20901607..dc39942a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -49,6 +49,7 @@ file(GLOB_RECURSE DAEMON daemon/*) file(GLOB_RECURSE P2P p2p/*) file(GLOB_RECURSE RPC rpc/*) +file(GLOB_RECURSE STRATUM stratum/*) file(GLOB_RECURSE SIMPLEWALLET simplewallet/*) file(GLOB_RECURSE CONN_TOOL connectivity_tool/*) file(GLOB_RECURSE WALLET wallet/*) @@ -73,6 +74,7 @@ source_group(currency_protocol FILES ${CURRENCY_PROTOCOL}) source_group(daemon FILES ${DAEMON}) source_group(p2p FILES ${P2P}) source_group(rpc FILES ${RPC}) +source_group(stratum FILES ${STRATUM}) source_group(simplewallet FILES ${SIMPLEWALLET}) source_group(connectivity-tool FILES ${CONN_TOOL}) source_group(wallet FILES ${WALLET}) @@ -106,6 +108,10 @@ add_library(rpc ${RPC}) add_dependencies(rpc version ${PCH_LIB_NAME}) ENABLE_SHARED_PCH(RPC) +add_library(stratum ${STRATUM}) +add_dependencies(stratum version ${PCH_LIB_NAME}) +ENABLE_SHARED_PCH(STRATUM) + add_library(wallet ${WALLET}) add_dependencies(wallet version ${PCH_LIB_NAME}) ENABLE_SHARED_PCH(WALLET) @@ -114,23 +120,23 @@ target_link_libraries(currency_core lmdb) add_executable(daemon ${DAEMON} ${P2P} ${CURRENCY_PROTOCOL}) add_dependencies(daemon version) -target_link_libraries(daemon rpc currency_core crypto common upnpc-static zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(daemon rpc stratum currency_core crypto common upnpc-static zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) ENABLE_SHARED_PCH(DAEMON) ENABLE_SHARED_PCH_EXECUTABLE(daemon) add_executable(connectivity_tool ${CONN_TOOL}) add_dependencies(connectivity_tool version) -target_link_libraries(connectivity_tool currency_core crypto common zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(connectivity_tool currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) ENABLE_SHARED_PCH(CONN_TOOL) ENABLE_SHARED_PCH_EXECUTABLE(connectivity_tool) add_executable(simplewallet ${SIMPLEWALLET}) add_dependencies(simplewallet version) -target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) ENABLE_SHARED_PCH(SIMPLEWALLET) ENABLE_SHARED_PCH_EXECUTABLE(simplewallet) -set_property(TARGET common crypto currency_core rpc wallet PROPERTY FOLDER "libs") +set_property(TARGET common crypto currency_core rpc stratum wallet PROPERTY FOLDER "libs") set_property(TARGET daemon simplewallet connectivity_tool PROPERTY FOLDER "prog") set_property(TARGET daemon PROPERTY OUTPUT_NAME "zanod") @@ -150,7 +156,7 @@ if(BUILD_GUI) QT5_USE_MODULES(Zano WebEngineWidgets WebChannel) find_package(Qt5PrintSupport REQUIRED) - target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic ethash Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) if(APPLE) target_link_libraries(Zano ${COCOA_LIBRARY}) diff --git a/src/crypto/wild_keccak.cpp b/src/crypto/wild_keccak.cpp deleted file mode 100644 index fa49c539..00000000 --- a/src/crypto/wild_keccak.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// keccak.c -// 19-Nov-11 Markku-Juhani O. Saarinen -// A baseline Keccak (3rd round) implementation. - -// Memory-hard extension of keccak for PoW -// Copyright (c) 2014 The Boolberry developers -// Copyright (c) 2019 The Hyle Team -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - - -#include "wild_keccak.h" -#include "include_base_utils.h" -namespace crypto -{ - - const uint64_t keccakf_rndc[24] = - { - 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, - 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, - 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, - 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, - 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, - 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, - 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, - 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 - }; - - const int keccakf_rotc[24] = - { - 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, - 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44 - }; - - const int keccakf_piln[24] = - { - 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, - 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1 - }; - - // update the state with given number of rounds - void regular_f::keccakf(uint64_t st[25], int rounds) - { - int i, j, round; - uint64_t t, bc[5]; - - for (round = 0; round < rounds; round++) { - - // Theta - for (i = 0; i < 5; i++) - bc[i] = st[i] ^ st[i + 5] ^ st[i + 10] ^ st[i + 15] ^ st[i + 20]; - - for (i = 0; i < 5; i++) { - t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1); - for (j = 0; j < 25; j += 5) - st[j + i] ^= t; - } - - // Rho Pi - t = st[1]; - for (i = 0; i < 24; i++) { - j = keccakf_piln[i]; - bc[0] = st[j]; - st[j] = ROTL64(t, keccakf_rotc[i]); - t = bc[0]; - } - - // Chi - for (j = 0; j < 25; j += 5) { - for (i = 0; i < 5; i++) - bc[i] = st[j + i]; - for (i = 0; i < 5; i++) - st[j + i] ^= (~bc[(i + 1) % 5]) & bc[(i + 2) % 5]; - } - - // Iota - st[0] ^= keccakf_rndc[round]; - } - } - - bool generate_scratchpad(const crypto::hash& seed_data, std::vector& result_data, uint64_t target_size) - { - result_data.resize(target_size); - result_data[0] = crypto::cn_fast_hash(&seed_data, sizeof(seed_data)); - for (size_t i = 1; i < target_size; i++) - { - result_data[i] = crypto::cn_fast_hash(&result_data[i - 1], sizeof(result_data[i - 1])); - } - return true; - } - - bool generate_scratchpad_light(const crypto::hash& seed_data, std::vector& result_data, uint64_t target_size) - { - CHECK_AND_ASSERT_THROW_MES(target_size % 10 == 0, "wrong target_size = " << target_size); - result_data.reserve(target_size/10); - result_data.push_back(crypto::cn_fast_hash(&seed_data, sizeof(seed_data))); - crypto::hash prev_hash = result_data[0]; - for (size_t i = 1; i < target_size; i++) - { - prev_hash = crypto::cn_fast_hash(&prev_hash, sizeof(prev_hash)); - if (!(i % 10)) - { - result_data.push_back(prev_hash); - } - } - return true; - } - - - bool get_wild_keccak_light(const std::string& bd, crypto::hash& res, const std::vector& scratchpad_light) - { - if (!scratchpad_light.size()) - return false; - auto light_scr_accessor = [&](uint64_t i) - { - //get index of int64 item in scratchpad from i, where is is random number in whole uint64_t range - uint64_t int64_mod_index = i%(scratchpad_light.size() * 10 * 4); - //get related hash index - uint64_t hash_index = int64_mod_index / 4; - //get_in hash index (from 0 to 3) - uint64_t in_hash_index = int64_mod_index % 4; - - //get index of primary hash in scratchpad_light - uint64_t primary_item_index = (hash_index - (hash_index % 10)) / 10; - uint64_t sha_count = hash_index % 10; - crypto::hash res = scratchpad_light[primary_item_index]; - for (uint64_t i = 0; i != sha_count; i++) - { - res = cn_fast_hash(&res, sizeof(res)); - } - return ((uint64_t*)&res)[in_hash_index]; - }; - return get_wild_keccak_light(bd, res, light_scr_accessor); - } -} - diff --git a/src/crypto/wild_keccak.h b/src/crypto/wild_keccak.h deleted file mode 100644 index dc842b02..00000000 --- a/src/crypto/wild_keccak.h +++ /dev/null @@ -1,169 +0,0 @@ -// keccak.h -// 19-Nov-11 Markku-Juhani O. Saarinen - -// Copyright (c) 2014 The Boolberry developers -// Copyright (c) 2019 The Hyle Team -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - - -#pragma once - -#include -#include -#include "crypto.h" - -extern "C" { -//#include "crypto/alt/KeccakNISTInterface.h" - } - -#ifndef KECCAK_ROUNDS -#define KECCAK_ROUNDS 24 -#endif - -#ifndef ROTL64 -#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y)))) -#endif - - -#define KK_MIXIN_SIZE 24 - -namespace crypto -{ - typedef uint64_t state_t_m[25]; - typedef uint64_t mixin_t[KK_MIXIN_SIZE]; - - template - int wild_keccak2(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, callback_t cb) - { - state_t_m st; - uint8_t temp[144]; - uint64_t rsiz, rsizw; - - rsiz = sizeof(state_t_m) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen; - rsizw = rsiz / 8; - memset(&st[0], 0, 25 * sizeof(st[0])); - - - for (; inlen >= rsiz; inlen -= rsiz, in += rsiz) - { - for (size_t i = 0; i < rsizw; i++) - st[i] ^= ((uint64_t *)in)[i]; - - for (int keccak_round = 0; keccak_round != KECCAK_ROUNDS; keccak_round++) - { - f_traits::keccakf(st, keccak_round); - cb(st); - } - } - - // last block and padding - memcpy(temp, in, inlen); - temp[inlen++] = 1; - memset(temp + inlen, 0, rsiz - inlen); - temp[rsiz - 1] |= 0x80; - - for (size_t i = 0; i < rsizw; i++) - st[i] ^= ((uint64_t *)temp)[i]; - - for (int keccak_round = 0; keccak_round != KECCAK_ROUNDS; keccak_round++) - { - f_traits::keccakf(st, keccak_round); - cb(st); - } - - memcpy(md, st, mdlen); - - return 0; - } - - template - int wild_keccak2_dbl(const uint8_t *in, size_t inlen, uint8_t *md, size_t mdlen, callback_t cb) - { - //Satoshi's classic - wild_keccak2(in, inlen, md, mdlen, cb); - wild_keccak2(md, mdlen, md, mdlen, cb); - return 0; - } - - class regular_f - { - public: - static void keccakf(uint64_t st[25], int rounds); - }; - - - - //------------------------------------------------------------------ - inline - bool get_wild_keccak2(const std::string& bd, crypto::hash& res, const uint64_t* int_array_ptr_scratch, uint64_t int64_sz) - { - uint64_t count_access = 0; - crypto::wild_keccak2_dbl(reinterpret_cast(bd.data()), bd.size(), reinterpret_cast(&res), sizeof(res), [&](crypto::state_t_m& st) - { - ++count_access; - if (!int64_sz) - { - return; - } - - for (size_t i = 0; i != sizeof(st) / sizeof(st[0]); i++) - { - size_t depend_index = 0; - if (i == 0) - { - depend_index = sizeof(st) / sizeof(st[0]) - 1; - } - else - { - depend_index = i - 1; - } - st[i] ^= int_array_ptr_scratch[int_array_ptr_scratch[int_array_ptr_scratch[st[depend_index] % int64_sz] % int64_sz] % int64_sz]; - } - }); - return true; - } - //------------------------------------------------------------------ - inline - bool get_wild_keccak2(const std::string& bd, crypto::hash& res, const std::vector& scratchpad, uint64_t sz) - { - - const uint64_t* int_array_ptr = (const uint64_t*)&scratchpad[0]; - size_t int64_sz = sz * 4; - return get_wild_keccak2(bd, res, int_array_ptr, int64_sz); - } - //------------------------------------------------------------------ - template - bool get_wild_keccak_light(const std::string& bd, crypto::hash& res, t_items_accessor cb_get_item) - { - crypto::wild_keccak2_dbl(reinterpret_cast(bd.data()), bd.size(), reinterpret_cast(&res), sizeof(res), [&](crypto::state_t_m& st) - { - for (size_t i = 0; i != sizeof(st) / sizeof(st[0]); i++) - { - size_t depend_index = 0; - if (i == 0) - { - depend_index = sizeof(st) / sizeof(st[0]) - 1; - } - else - { - depend_index = i - 1; - } - st[i] ^= cb_get_item(cb_get_item(cb_get_item(st[depend_index]))); - } - }); - return true; - } - //------------------------------------------------------------------ - bool get_wild_keccak_light(const std::string& bd, crypto::hash& res, const std::vector& scratchpad_light); - //------------------------------------------------------------------ - inline - bool get_wild_keccak2(const std::string& bd, crypto::hash& res, const std::vector& scratchpad) - { - return get_wild_keccak2(bd, res, scratchpad, scratchpad.size()); - } - //------------------------------------------------------------------ - bool generate_scratchpad(const crypto::hash& source_data, std::vector& result_data, uint64_t target_size); - bool generate_scratchpad_light(const crypto::hash& seed_data, std::vector& result_data, uint64_t target_size); -} - diff --git a/src/currency_core/account.cpp b/src/currency_core/account.cpp index 37f5aab9..a291feb8 100644 --- a/src/currency_core/account.cpp +++ b/src/currency_core/account.cpp @@ -98,7 +98,7 @@ namespace currency //cut the last timestamp word from restore_dats std::list words; boost::split(words, restore_data_, boost::is_space()); - CHECK_AND_ASSERT_THROW_MES(words.size() == BRAINWALLET_DEFAULT_WORDS_COUNT, "Words count missmatch: " << words.size()); + CHECK_AND_ASSERT_MES(words.size() == BRAINWALLET_DEFAULT_WORDS_COUNT, false, "Words count missmatch: " << words.size()); std::string timestamp_word = words.back(); words.erase(--words.end()); diff --git a/src/currency_core/basic_pow_helpers.cpp b/src/currency_core/basic_pow_helpers.cpp new file mode 100644 index 00000000..95ed6dfd --- /dev/null +++ b/src/currency_core/basic_pow_helpers.cpp @@ -0,0 +1,74 @@ +// Copyright (c) 2018-2019 Zano Project +// Copyright (c) 2018-2019 Hyle Team +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + +#include "include_base_utils.h" +using namespace epee; + +#include "basic_pow_helpers.h" +#include "currency_format_utils.h" +#include "serialization/binary_utils.h" +#include "serialization/stl_containers.h" +#include "currency_core/currency_config.h" +#include "crypto/crypto.h" +#include "crypto/hash.h" +#include "common/int-util.h" +#include "ethereum/libethash/ethash/ethash.hpp" +#include "ethereum/libethash/ethash/progpow.hpp" + +namespace currency +{ + + //-------------------------------------------------------------- + //global object +// crypto::ethash::cache_manager cache; +// void ethash_set_use_dag(bool use_dag) +// { +// cache.set_use_dag(use_dag); +// } +// //------------------------------------------------------------------ +// const uint8_t* ethash_get_dag(uint64_t epoch, uint64_t& dag_size) +// { +// return cache.get_dag(epoch, dag_size); +// } + //------------------------------------------------------------------ + int ethash_height_to_epoch(uint64_t height) + { + return height / ETHASH_EPOCH_LENGTH; + } + //-------------------------------------------------------------- + crypto::hash get_block_longhash(uint64_t height, const crypto::hash& block_long_ash, uint64_t nonce) + { + int epoch = ethash_height_to_epoch(height); + const auto& context = progpow::get_global_epoch_context_full(static_cast(epoch)); + auto res_eth = progpow::hash(context, height, *(ethash::hash256*)&block_long_ash, nonce); + crypto::hash result = currency::null_hash; + memcpy(&result.data, &res_eth.final_hash, sizeof(res_eth.final_hash)); + return result; + } + //--------------------------------------------------------------- + void get_block_longhash(const block& b, crypto::hash& res) + { + /* + Since etherium hash has a bit different approach in minig, to adopt our code we made little hack: + etherium hash calculates from block's hash and(!) nonce, both passed into PoW hash function. + To achieve the same effect we make blob of data from block in normal way, but then set to zerro nonce + inside serialized buffer, and then pass this nonce to ethash algo as a second argument, as it expected. + */ + blobdata bd = get_block_hashing_blob(b); + + access_nonce_in_block_blob(bd) = 0; + crypto::hash bl_hash = crypto::cn_fast_hash(bd.data(), bd.size()); + + res = get_block_longhash(get_block_height(b), bl_hash, b.nonce); + } + //--------------------------------------------------------------- + crypto::hash get_block_longhash(const block& b) + { + crypto::hash p = null_hash; + get_block_longhash(b, p); + return p; + } +} \ No newline at end of file diff --git a/src/currency_core/basic_pow_helpers.h b/src/currency_core/basic_pow_helpers.h new file mode 100644 index 00000000..ccc1a132 --- /dev/null +++ b/src/currency_core/basic_pow_helpers.h @@ -0,0 +1,44 @@ +// Copyright (c) 2014-2018 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include +#include + +#include "account.h" +#include "include_base_utils.h" + +#include "currency_format_utils_abstract.h" +#include "common/crypto_stream_operators.h" +#include "currency_protocol/currency_protocol_defs.h" +#include "crypto/crypto.h" +#include "crypto/hash.h" +#include "difficulty.h" +//#include "offers_services_helpers.h" +#include "rpc/core_rpc_server_commands_defs.h" +#include "bc_payments_id_service.h" +#include "bc_attachments_helpers_basic.h" +#include "blockchain_storage_basic.h" + +#define CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET 1 + +namespace currency +{ + int ethash_height_to_epoch(uint64_t height); + crypto::hash get_block_longhash(uint64_t h, const crypto::hash& block_long_ash, uint64_t nonce); + void get_block_longhash(const block& b, crypto::hash& res); + crypto::hash get_block_longhash(const block& b); + + inline uint64_t& access_nonce_in_block_blob(blobdata& bd) + { + return *reinterpret_cast(&bd[CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET]); + } + + inline const uint64_t& access_nonce_in_block_blob(const blobdata& bd) + { + return *reinterpret_cast(&bd[CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET]); + } +} \ No newline at end of file diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 7c2d6cb5..19b29ebb 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -31,6 +31,7 @@ #include "miner_common.h" #include "storages/portable_storage_template_helper.h" #include "common/db_backend_lmdb.h" +#include "basic_pow_helpers.h" #include "version.h" #undef LOG_DEFAULT_CHANNEL @@ -99,9 +100,7 @@ blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(std::share m_current_fee_median(0), m_current_fee_median_effective_index(0), m_is_reorganize_in_process(false), - m_deinit_is_done(false), - m_current_scratchpad_seed(currency::null_hash), - m_current_scratchpad_seed_height(0) + m_deinit_is_done(false) { @@ -291,9 +290,6 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro initialize_db_solo_options_values(); - get_seed_for_scratchpad(m_db_blocks.size(), m_current_scratchpad_seed); - m_current_scratchpad_seed_height = m_db_blocks.size(); - m_services_mgr.init(config_folder, vm); @@ -1112,16 +1108,16 @@ uint64_t blockchain_storage::get_current_comulative_blocksize_limit() const return m_db_current_block_cumul_sz_limit; } //------------------------------------------------------------------ -bool blockchain_storage::create_block_template(block& b, crypto::hash& seed, +bool blockchain_storage::create_block_template(block& b, const account_public_address& miner_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce) const { - return create_block_template(b, seed, miner_address, miner_address, diffic, height, ex_nonce, false, pos_entry()); + return create_block_template(b, miner_address, miner_address, diffic, height, ex_nonce, false, pos_entry()); } //------------------------------------------------------------------ -bool blockchain_storage::create_block_template(block& b, crypto::hash& seed, +bool blockchain_storage::create_block_template(block& b, const account_public_address& miner_address, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, @@ -1131,7 +1127,6 @@ bool blockchain_storage::create_block_template(block& b, crypto::hash& seed, const pos_entry& pe, fill_block_template_func_t custom_fill_block_template_func /* = nullptr */) const { - seed = m_current_scratchpad_seed; size_t median_size; uint64_t already_generated_coins; CRITICAL_REGION_BEGIN(m_read_lock); @@ -1456,10 +1451,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto:: } else { - crypto::hash seed = null_hash; - get_seed_for_scratchpad_alt_chain(abei.height, seed, alt_chain); - - proof_of_work = m_scratchpad.get_pow_hash(abei.bl, seed); + proof_of_work = get_block_longhash(abei.bl); if (!check_hash(proof_of_work, current_diff)) { @@ -1613,7 +1605,7 @@ bool blockchain_storage::pre_validate_relayed_block(block& bl, block_verificatio } else { - proof_hash = m_scratchpad.get_pow_hash(bl, m_current_scratchpad_seed); //get_block_longhash(bl); + proof_hash = get_block_longhash(bl); //get_block_longhash(bl); if (!check_hash(proof_hash, current_diffic)) { @@ -1738,9 +1730,6 @@ bool blockchain_storage::get_main_block_rpc_details(uint64_t i, block_rpc_extend CRITICAL_REGION_LOCAL(m_read_lock); auto core_bei_ptr = m_db_blocks[i]; crypto::hash id = get_block_hash(core_bei_ptr->bl); - crypto::hash pow_seed = null_hash; - get_seed_for_scratchpad(i, pow_seed); - bei.pow_seed = epee::string_tools::pod_to_hex(pow_seed); bei.is_orphan = false; bei.total_fee = 0; bei.total_txs_size = 0; @@ -2763,7 +2752,6 @@ bool blockchain_storage::pop_transaction_from_global_index(const transaction& tx CHECK_AND_ASSERT_MES(back_item->tx_id == tx_id, false, "transactions outs global index consistency broken: tx id missmatch"); CHECK_AND_ASSERT_MES(back_item->out_no == i, false, "transactions outs global index consistency broken: in transaction index missmatch"); m_db_outputs.pop_back_item(ot.amount); - //do not let to exist empty m_outputs entries - this will broke scratchpad selector //if (!it->second.size()) // m_db_outputs.erase(it); } @@ -4301,18 +4289,13 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt } else { - //++++++++++++++++++++++++++++++++++++++++++++++++++++++ - //precaution(do we really need this check?) - check_scratchpad(); - //++++++++++++++++++++++++++++++++++++++++++++++++++++++ - proof_hash = m_scratchpad.get_pow_hash(bl, m_current_scratchpad_seed); + proof_hash = get_block_longhash(bl); if (!check_hash(proof_hash, current_diffic)) { LOG_ERROR("Block with id: " << id << ENDL << "PoW hash: " << proof_hash << ENDL - << "PoW seed: " << m_current_scratchpad_seed << ENDL << "unexpected difficulty: " << current_diffic); bvc.m_verification_failed = true; return false; @@ -4575,28 +4558,16 @@ void blockchain_storage::on_block_added(const block_extended_info& bei, const cr { update_next_comulative_size_limit(); m_timestamps_median_cache.clear(); - check_scratchpad(); m_tx_pool.on_blockchain_inc(bei.height, id); TIME_MEASURE_START_PD(raise_block_core_event); rise_core_event(CORE_EVENT_BLOCK_ADDED, void_struct()); TIME_MEASURE_FINISH_PD(raise_block_core_event); } -//------------------------------------------------------------------ - bool blockchain_storage::check_scratchpad() -{ - if(get_scratchpad_last_update_rebuild_height(m_db_blocks.size()) != m_current_scratchpad_seed_height) - { - get_seed_for_scratchpad(m_db_blocks.size(), m_current_scratchpad_seed); - m_current_scratchpad_seed_height = get_scratchpad_last_update_rebuild_height(m_db_blocks.size()); - } - return true; -} //------------------------------------------------------------------ void blockchain_storage::on_block_removed(const block_extended_info& bei) { m_tx_pool.on_blockchain_dec(m_db_blocks.size() - 1, get_top_block_id()); m_timestamps_median_cache.clear(); - check_scratchpad(); LOG_PRINT_L2("block at height " << bei.height << " was removed from the blockchain"); } //------------------------------------------------------------------ @@ -5330,42 +5301,6 @@ bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx return false; } //------------------------------------------------------------------ -bool blockchain_storage::get_seed_for_scratchpad(uint64_t height, crypto::hash& seed)const -{ - CRITICAL_REGION_LOCAL(m_read_lock); - LOG_PRINT_MAGENTA("Get seed for scratchpad [main_chain] on height " << height, LOG_LEVEL_0); - return get_seed_for_scratchpad_cb(height, seed, [&](uint64_t index) -> crypto::hash - { - return get_block_hash(m_db_blocks[index]->bl); - }); -} -//------------------------------------------------------------------ -bool blockchain_storage::get_seed_for_scratchpad_alt_chain(uint64_t height, crypto::hash& seed, const alt_chain_type& alt_chain)const -{ - CRITICAL_REGION_LOCAL(m_read_lock); - //alt_chain: front -> mainchain, back -> alternative head - uint64_t connection_to_main_chain = height; - if (alt_chain.size()) - connection_to_main_chain = alt_chain.front()->second.height; - - return get_seed_for_scratchpad_cb(height, seed, [&](uint64_t index) -> crypto::hash - { - if (index < connection_to_main_chain) - { - //addressed to main chain - return get_block_hash(m_db_blocks[index]->bl); - } - else - { - //addressed to alt chain - uint64_t offset = index - connection_to_main_chain; - CHECK_AND_ASSERT_THROW_MES(offset < alt_chain.size(), "Internal error: failed to validate offset(" << offset << ") < alt_chain.size()("<< alt_chain.size() <<")"); - CHECK_AND_ASSERT_THROW_MES(alt_chain[offset]->second.height == index, "Internal error: failed to validate offset(" << offset << ") < alt_chain.size()(" << alt_chain.size() << ")"); - return get_block_hash(alt_chain[offset]->second.bl); - } - }); -} -//------------------------------------------------------------------ bool blockchain_storage::get_transaction_from_pool_or_db(const crypto::hash& tx_id, std::shared_ptr& tx_ptr, uint64_t min_allowed_block_height /* = 0 */) const { tx_ptr.reset(new transaction()); diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index 5312a4c2..adfddb91 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -39,7 +39,7 @@ #include "dispatch_core_events.h" #include "bc_attachments_service_manager.h" #include "common/median_db_cache.h" -#include "scratchpad_helper.h" + MARK_AS_POD_C11(crypto::key_image); @@ -231,8 +231,8 @@ namespace currency wide_difficulty_type get_cached_next_difficulty(bool pos) const; typedef bool fill_block_template_func_t(block &bl, bool pos, size_t median_size, uint64_t already_generated_coins, size_t &total_size, uint64_t &fee, uint64_t height); - bool create_block_template(block& b, crypto::hash& seed, const account_public_address& miner_address, const account_public_address& stakeholder_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe, fill_block_template_func_t custom_fill_block_template_func = nullptr) const; - bool create_block_template(block& b, crypto::hash& seed, const account_public_address& miner_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce) const; + bool create_block_template(block& b, const account_public_address& miner_address, const account_public_address& stakeholder_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe, fill_block_template_func_t custom_fill_block_template_func = nullptr) const; + bool create_block_template(block& b, const account_public_address& miner_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce) const; bool have_block(const crypto::hash& id) const; size_t get_total_transactions()const; @@ -510,10 +510,7 @@ namespace currency //work like a cache to avoid mutable uint64_t m_current_fee_median; mutable uint64_t m_current_fee_median_effective_index; - bool m_is_reorganize_in_process; - mutable scratchpad_light_pool m_scratchpad; //TODO: optimization for using full scratchpad in mainchain - crypto::hash m_current_scratchpad_seed; - uint64_t m_current_scratchpad_seed_height; + bool m_is_reorganize_in_process; mutable std::atomic m_deinit_is_done; @@ -542,10 +539,6 @@ namespace currency bool validate_alt_block_txs(const block& b, const crypto::hash& id, std::set& collected_keyimages, alt_block_extended_info& abei, const alt_chain_type& alt_chain, uint64_t split_height, uint64_t& ki_lookup_time_total) const; bool update_alt_out_indexes_for_tx_in_block(const transaction& tx, alt_block_extended_info& abei)const; bool get_transaction_from_pool_or_db(const crypto::hash& tx_id, std::shared_ptr& tx_ptr, uint64_t min_allowed_block_height = 0) const; - bool get_seed_for_scratchpad(uint64_t height, crypto::hash& seed)const ; - bool get_seed_for_scratchpad_alt_chain(uint64_t height, crypto::hash& seed, const alt_chain_type& alt_chain) const ; - - bool check_scratchpad(); bool prevalidate_miner_transaction(const block& b, uint64_t height, bool pos)const; bool validate_transaction(const block& b, uint64_t height, const transaction& tx)const; @@ -572,7 +565,6 @@ namespace currency uint64_t get_adjusted_time()const; bool complete_timestamps_vector(uint64_t start_height, std::vector& timestamps); bool update_next_comulative_size_limit(); - //bool get_block_for_scratchpad_alt(uint64_t connection_height, uint64_t block_index, std::list& alt_chain, block & b); bool process_blockchain_tx_extra(const transaction& tx); bool unprocess_blockchain_tx_extra(const transaction& tx); bool process_blockchain_tx_attachments(const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp); diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 71608c76..86e04f95 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -7,7 +7,7 @@ #pragma once -#define CURRENCY_FORMATION_VERSION 76 +#define CURRENCY_FORMATION_VERSION 78 #define CURRENCY_MAX_BLOCK_NUMBER 500000000 @@ -46,12 +46,6 @@ #define BASE_REWARD_DUST_THRESHOLD ((uint64_t)1000000) // pow(10, 6) - change this will cause hard-fork! #define DEFAULT_DUST_THRESHOLD ((uint64_t)0)//((uint64_t)100000) // pow(10, 5) -#define CURRENCY_SCRATCHPAD_BASE_SIZE 16777210 //count in crypto::hash, to get size in bytes x32 -#define CURRENCY_SCRATCHPAD_REBUILD_INTERVAL 720 //once a day if block goes once in 2 minute -#define CURRENCY_SCRATCHPAD_BASE_INDEX_ID_OFFSET 20 //offset down from last rebuild height to block id, that used for indexing seed blocks in CURRENCY_SCRATCHPAD_SEED_BLOCKS_WINDOW -#define CURRENCY_SCRATCHPAD_SEED_BLOCKS_WINDOW 700 //window for addressing seed block ids -#define CURRENCY_SCRATCHPAD_GENESIS_SEED "4c98962ddce32c7763bb9326933a4692975ca29a76349ae7a139faa3430cc5ab" - #define TX_DEFAULT_FEE ((uint64_t)100000) // pow(10, 5) #define TX_MINIMUM_FEE ((uint64_t)100000) // pow(10, 5) diff --git a/src/currency_core/currency_core.cpp b/src/currency_core/currency_core.cpp index 555df8ae..c4b785f4 100644 --- a/src/currency_core/currency_core.cpp +++ b/src/currency_core/currency_core.cpp @@ -401,14 +401,9 @@ namespace currency return m_mempool.add_tx(tx, tx_hash, blob_size, tvc, kept_by_block); } //----------------------------------------------------------------------------------------------- - bool core::get_block_template(block& b, crypto::hash& seed, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe) - { - return m_blockchain_storage.create_block_template(b, seed, adr, stakeholder_address, diffic, height, ex_nonce, pos, pe); - } bool core::get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe) { - crypto::hash seed_subst = currency::null_hash; - return m_blockchain_storage.create_block_template(b, seed_subst, adr, stakeholder_address, diffic, height, ex_nonce, pos, pe); + return m_blockchain_storage.create_block_template(b, adr, stakeholder_address, diffic, height, ex_nonce, pos, pe); } //----------------------------------------------------------------------------------------------- bool core::find_blockchain_supplement(const std::list& qblock_ids, NOTIFY_RESPONSE_CHAIN_ENTRY::request& resp) const diff --git a/src/currency_core/currency_core.h b/src/currency_core/currency_core.h index 1f178268..84b2e821 100644 --- a/src/currency_core/currency_core.h +++ b/src/currency_core/currency_core.h @@ -51,9 +51,7 @@ namespace currency //-------------------- i_miner_handler ----------------------- virtual bool handle_block_found(const block& b, block_verification_context* p_verification_result = nullptr); - virtual bool get_block_template(block& b, crypto::hash& seed, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry()); - - bool get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry()); + virtual bool get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry()); miner& get_miner(){ return m_miner; } static void init_options(boost::program_options::options_description& desc); diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 20cb55ce..b644fc56 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -1212,7 +1212,7 @@ namespace currency //--------------------------------------------------------------- std::string get_word_from_timstamp(uint64_t timestamp) { - uint64_t date_offset = timestamp ? timestamp - WALLET_BRAIN_DATE_OFFSET : 0; + uint64_t date_offset = timestamp > WALLET_BRAIN_DATE_OFFSET ? timestamp - WALLET_BRAIN_DATE_OFFSET : 0; uint64_t weeks_count = date_offset / WALLET_BRAIN_DATE_QUANTUM; CHECK_AND_ASSERT_THROW_MES(weeks_count < std::numeric_limits::max(), "internal error: unable to converto to uint32, val = " << weeks_count); uint32_t weeks_count_32 = static_cast(weeks_count); @@ -1664,24 +1664,7 @@ namespace currency } return true; } -// //-------------------------------------------------------------- -// crypto::hash get_block_longhash(uint64_t height, const crypto::hash& block_long_ash, uint64_t nonce) -// { -// //TODO: add wild keccak 2 -// return null_hash;//TODO; -// } -// //--------------------------------------------------------------- -// void get_block_longhash(const block& b, crypto::hash& res) -// { -// //TODO: add wild keccak 2 -// } -// //--------------------------------------------------------------- -// crypto::hash get_block_longhash(const block& b) -// { -// crypto::hash p = null_hash; -// get_block_longhash(b, p); -// return p; -// } + //--------------------------------------------------------------- uint64_t get_alias_coast_from_fee(const std::string& alias, uint64_t median_fee) { @@ -2405,21 +2388,6 @@ namespace currency return CURRENCY_TESTNET_CONST_REWARD; } //----------------------------------------------------------------------------------------------- - uint64_t get_scratchpad_last_update_rebuild_height(uint64_t h) - { - return h - (h%CURRENCY_SCRATCHPAD_REBUILD_INTERVAL); - } - //----------------------------------------------------------------------------------------------- - uint64_t get_scratchpad_size_for_height(uint64_t h) - { - if (h < CURRENCY_BLOCKS_PER_DAY * 7) - { - return 100; - } - //let's have ~250MB/year if block interval is 2 minutes - return CURRENCY_SCRATCHPAD_BASE_SIZE + get_scratchpad_last_update_rebuild_height(h)*30; - } - //----------------------------------------------------------------------------------------------- bool get_block_reward(bool is_pos, size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward, uint64_t height) { uint64_t base_reward = get_base_block_reward(is_pos, already_generated_coins, height); diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 263e258c..a984233f 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -295,11 +295,6 @@ namespace currency bool parse_amount(uint64_t& amount, const std::string& str_amount); - -// crypto::hash get_block_longhash(uint64_t h, const crypto::hash& block_long_ash, uint64_t nonce); -// void get_block_longhash(const block& b, crypto::hash& res); -// crypto::hash get_block_longhash(const block& b); - bool unserialize_block_complete_entry(const COMMAND_RPC_GET_BLOCKS_FAST::response& serialized, COMMAND_RPC_GET_BLOCKS_DIRECT::response& unserialized); @@ -389,8 +384,6 @@ namespace currency size_t get_max_tx_size(); bool get_block_reward(bool is_pos, size_t median_size, size_t current_block_size, uint64_t already_generated_coins, uint64_t &reward, uint64_t height); uint64_t get_base_block_reward(bool is_pos, uint64_t already_generated_coins, uint64_t height); - uint64_t get_scratchpad_last_update_rebuild_height(uint64_t h); - uint64_t get_scratchpad_size_for_height(uint64_t h); bool is_payment_id_size_ok(const std::string& payment_id); std::string get_account_address_as_str(const account_public_address& addr); std::string get_account_address_and_payment_id_as_str(const account_public_address& addr, const std::string& payment_id); @@ -520,41 +513,6 @@ namespace currency } return false; } - //--------------------------------------------------------------- - template - bool get_seed_for_scratchpad_cb(uint64_t height, crypto::hash& seed, block_chain_accessor_t cb) - { - //CHECK_AND_ASSERT_THROW_MES(m_db_blocks.size() > height, "Internal error: m_db_blocks.size()=" << m_db_blocks.size() << " > height=" << height); - uint64_t last_upd_h = get_scratchpad_last_update_rebuild_height(height); - std::vector seed_data; - if (last_upd_h == 0) - { - crypto::hash genesis_seed = null_hash; - bool r = epee::string_tools::hex_to_pod(CURRENCY_SCRATCHPAD_GENESIS_SEED, genesis_seed); - CHECK_AND_ASSERT_THROW_MES(r, "Unable to parse CURRENCY_SCRATCHPAD_GENESIS_SEED " << CURRENCY_SCRATCHPAD_GENESIS_SEED); - LOG_PRINT_MAGENTA("[SCRATCHPAD] GENESIS SEED SELECTED: " << genesis_seed, LOG_LEVEL_0); - seed = genesis_seed; - return true; - } - uint64_t low_bound_window = 0; - CHECK_AND_ASSERT_THROW_MES(last_upd_h >= CURRENCY_SCRATCHPAD_SEED_BLOCKS_WINDOW, "Internal error: last_upd_h(" << last_upd_h << ") < CURRENCY_SCRATCHPAD_SEED_BLOCKS_WINDOW(" << CURRENCY_SCRATCHPAD_SEED_BLOCKS_WINDOW << ")"); - low_bound_window = last_upd_h - CURRENCY_SCRATCHPAD_SEED_BLOCKS_WINDOW; - - crypto::hash selector_id = cb(last_upd_h - CURRENCY_SCRATCHPAD_BASE_INDEX_ID_OFFSET); - - const uint64_t* pselectors = (const uint64_t*)&selector_id; - std::stringstream ss; - for (size_t i = 0; i != 4; i++) - { - seed_data.push_back(cb(low_bound_window + pselectors[i] % CURRENCY_SCRATCHPAD_SEED_BLOCKS_WINDOW)); - ss << "[" << std::setw(8) << std::hex << pselectors[i] << "->" << low_bound_window + pselectors[i] % CURRENCY_SCRATCHPAD_SEED_BLOCKS_WINDOW << "]" << seed_data.back() << ENDL; - } - seed = crypto::cn_fast_hash(&seed_data[0], sizeof(seed_data[0]) * seed_data.size()); - - LOG_PRINT_MAGENTA("[SCRATCHPAD] SEED SELECTED: h = " << last_upd_h << ", selector: " << selector_id << ENDL << ss.str() << "SEED: " << seed, LOG_LEVEL_0); - - return true; - } //--------------------------------------------------------------- // 62387455827 -> 455827 + 7000000 + 80000000 + 300000000 + 2000000000 + 60000000000, where 455827 <= dust_threshold diff --git a/src/currency_core/difficulty.cpp b/src/currency_core/difficulty.cpp index 518b59dd..21d7d339 100644 --- a/src/currency_core/difficulty.cpp +++ b/src/currency_core/difficulty.cpp @@ -114,12 +114,12 @@ namespace currency { return false; // usual slow check boost::multiprecision::uint512_t hashVal = 0; - for (int i = 1; i < 4; i++) - { // highest word is zero - hashVal |= swap64le(((const uint64_t *)&h)[3 - i]); - hashVal << 64; + for(int i = 0; i < 4; i++) + { + hashVal <<= 64; + hashVal |= swap64le(((const uint64_t *) &h)[3-i]); } - return (hashVal * difficulty > max256bit); + return (hashVal * difficulty <= max256bit); } uint64_t difficulty_to_boundary(wide_difficulty_type difficulty) diff --git a/src/currency_core/miner.cpp b/src/currency_core/miner.cpp index 1a451d83..afb77055 100644 --- a/src/currency_core/miner.cpp +++ b/src/currency_core/miner.cpp @@ -20,6 +20,7 @@ #include "string_coding.h" #include "version.h" #include "storages/portable_storage_template_helper.h" +#include "basic_pow_helpers.h" using namespace epee; @@ -64,16 +65,14 @@ namespace currency stop(); } //----------------------------------------------------------------------------------------------------- - bool miner::set_block_template(const block& bl, const wide_difficulty_type& di, uint64_t height, const crypto::hash& seed) + bool miner::set_block_template(const block& bl, const wide_difficulty_type& di, uint64_t height) { CRITICAL_REGION_LOCAL(m_template_lock); m_template = bl; m_diffic = di; m_height = height; - m_seed = seed; ++m_template_no; m_starter_nonce = crypto::rand(); - m_scratchpad.generate(m_seed, height); return true; } //----------------------------------------------------------------------------------------------------- @@ -96,13 +95,12 @@ namespace currency { extra_nonce += std::string("|") + m_extra_messages[m_config.current_extra_message_index]; } - crypto::hash seed = null_hash; - if(!m_phandler->get_block_template(bl, seed, m_mine_address, m_mine_address, di, height, extra_nonce)) + if(!m_phandler->get_block_template(bl, m_mine_address, m_mine_address, di, height, extra_nonce)) { LOG_ERROR("Failed to get_block_template()"); return false; } - set_block_template(bl, di, height, seed); + set_block_template(bl, di, height); return true; } //----------------------------------------------------------------------------------------------------- @@ -309,8 +307,8 @@ namespace currency wide_difficulty_type local_diff = 0; uint32_t local_template_ver = 0; blobdata local_blob_data; - crypto::hash local_seed = null_hash; uint64_t local_height = 0; + crypto::hash local_blob_data_hash = null_hash; //uint64_t local_template_height = 0; block b; @@ -327,14 +325,15 @@ namespace currency { CRITICAL_REGION_BEGIN(m_template_lock); b = m_template; + b.nonce = 0; local_diff = m_diffic; - local_seed = m_seed; local_height = m_height; CRITICAL_REGION_END(); //local_template_height = get_block_height(b); local_template_ver = m_template_no; nonce = m_starter_nonce + th_local_index; local_blob_data = get_block_hashing_blob(b); + local_blob_data_hash = crypto::cn_fast_hash(local_blob_data.data(), local_blob_data.size()); } if(!local_template_ver)//no any set_block_template call @@ -343,14 +342,15 @@ namespace currency epee::misc_utils::sleep_no_w(1000); continue; } - b.nonce = nonce; - access_nonce_in_block_blob(local_blob_data) = b.nonce; - crypto::hash h = m_scratchpad.get_pow_hash_from_blob(local_blob_data, local_height, local_seed); + //b.nonce = nonce; + //access_nonce_in_block_blob(local_blob_data) = b.nonce; + crypto::hash h = get_block_longhash(local_height, local_blob_data_hash, nonce); if(check_hash(h, local_diff)) { + b.nonce = nonce; ++m_config.current_extra_message_index; - LOG_PRINT_GREEN("Found block for difficulty: " << local_diff, LOG_LEVEL_0); + LOG_PRINT_GREEN("Found block for difficulty: " << local_diff << ", height: " << local_height << ", PoW hash: " << h << ", local_blob_data_hash: " << local_blob_data_hash << ", nonce: " << std::hex << nonce, LOG_LEVEL_0); if(!m_phandler->handle_block_found(b)) { --m_config.current_extra_message_index; diff --git a/src/currency_core/miner.h b/src/currency_core/miner.h index 21799172..1e9d030e 100644 --- a/src/currency_core/miner.h +++ b/src/currency_core/miner.h @@ -14,26 +14,17 @@ #include "difficulty.h" #include "math_helper.h" #include "blockchain_storage.h" +#include "basic_pow_helpers.h" + -#define CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET 1 namespace currency { - inline uint64_t& access_nonce_in_block_blob(blobdata& bd) - { - return *reinterpret_cast(&bd[CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET]); - } - - inline const uint64_t& access_nonce_in_block_blob(const blobdata& bd) - { - return *reinterpret_cast(&bd[CURRENCY_MINER_BLOCK_BLOB_NONCE_OFFSET]); - } - struct i_miner_handler { virtual bool handle_block_found(const block& b, block_verification_context* p_verification_result = nullptr) = 0; - virtual bool get_block_template(block& b, crypto::hash& seed, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry()) = 0; + virtual bool get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos = false, const pos_entry& pe = pos_entry()) = 0; protected: ~i_miner_handler(){}; }; @@ -63,17 +54,17 @@ namespace currency void do_print_hashrate(bool do_hr); inline - static bool find_nonce_for_given_block(block& bl, const wide_difficulty_type& diffic, uint64_t height, const crypto::hash& seed, scratchpad_keeper& sk) + static bool find_nonce_for_given_block(block& bl, const wide_difficulty_type& diffic, uint64_t height) { + bl.nonce = 0; blobdata bd = get_block_hashing_blob(bl); - uint64_t& nonce_ref = access_nonce_in_block_blob(bd); - nonce_ref = 0; + crypto::hash bd_hash = crypto::cn_fast_hash(bd.data(), bd.size()); + //uint64_t& nonce_ref = access_nonce_in_block_blob(bd); + //nonce_ref = 0; for(; bl.nonce != std::numeric_limits::max(); bl.nonce++) { - nonce_ref = bl.nonce; - - crypto::hash h = sk.get_pow_hash_from_blob(bd, height, seed); + crypto::hash h = get_block_longhash(height, bd_hash, bl.nonce); if(check_hash(h, diffic)) { LOG_PRINT_L0("Found nonce for block: " << get_block_hash(bl) << "[" << height << "]: PoW:" << h << "(diff:" << diffic << "), ts: " << bl.timestamp); @@ -84,7 +75,7 @@ namespace currency } private: - bool set_block_template(const block& bl, const wide_difficulty_type& diffic, uint64_t height, const crypto::hash& seed); + bool set_block_template(const block& bl, const wide_difficulty_type& diffic, uint64_t height); bool worker_thread(); bool request_block_template(); void merge_hr(); @@ -106,8 +97,6 @@ namespace currency std::atomic m_starter_nonce; wide_difficulty_type m_diffic; std::atomic m_height; - scratchpad_keeper m_scratchpad; - crypto::hash m_seed; volatile uint32_t m_thread_index; volatile uint32_t m_threads_total; std::atomic m_pausers_count; diff --git a/src/currency_core/miner_common.h b/src/currency_core/miner_common.h index 4c49e173..9c6db391 100644 --- a/src/currency_core/miner_common.h +++ b/src/currency_core/miner_common.h @@ -6,25 +6,3 @@ #pragma once -#define SCRATCHPAD_DEFAULT_FILENAME "scratchpad.bin" -#define WILD_KECCAK_ADDENDUMS_ARRAY_SIZE 10 - -#pragma pack (push, 1) - -struct export_scratchpad_hi -{ - crypto::hash prevhash; - uint64_t height; -}; -struct export_addendums_array_entry -{ - export_scratchpad_hi prev_hi; - uint64_t add_size; -}; -struct export_scratchpad_file_header -{ - export_scratchpad_hi current_hi; - export_addendums_array_entry add_arr[WILD_KECCAK_ADDENDUMS_ARRAY_SIZE]; - uint64_t scratchpad_size; -}; -#pragma pack(pop) diff --git a/src/currency_core/scratchpad_helper.cpp b/src/currency_core/scratchpad_helper.cpp deleted file mode 100644 index b52e967a..00000000 --- a/src/currency_core/scratchpad_helper.cpp +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2018-2019 Zano Project - -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - - -#include "scratchpad_helper.h" -#include "currency_format_utils.h" - - - -namespace currency -{ - scratchpad_keeper::scratchpad_keeper():m_seed(null_hash) - { - - } - //------------------------------------------------------------------------------------ - bool scratchpad_keeper::generate(const crypto::hash& scr_seed, uint64_t height) - { - bool r = false; - CRITICAL_REGION_BEGIN(m_lock); - r = crypto::generate_scratchpad(scr_seed, m_scratchpad, get_scratchpad_size_for_height(height)); - if (r) - m_seed = scr_seed; - CRITICAL_REGION_END(); - return r; - } - //------------------------------------------------------------------------------------ - crypto::hash scratchpad_keeper::get_pow_hash_from_blob(const blobdata& bd, uint64_t height, const crypto::hash& scr_seed) - { - CRITICAL_REGION_LOCAL(m_lock); - crypto::hash res_hash = null_hash; - if (scr_seed != m_seed || get_scratchpad_size_for_height(height) != this->size()) - { - bool r = generate(scr_seed, height); - CHECK_AND_ASSERT_THROW_MES(r, "Unable to generate scratchpad"); - } - CHECK_AND_ASSERT_THROW_MES(get_scratchpad_size_for_height(height) == this->size(), "Fatal error on hash calculation: scratchpad_size=" << m_scratchpad.size() << " at height=" << height << ", scr_seed=" << scr_seed << ", m_seed=" << m_seed); - CHECK_AND_ASSERT_THROW_MES(scr_seed == m_seed, "Fatal error on hash calculation: scratchpad_seed missmatch scr_seed=" << scr_seed << ", m_seed=" << m_seed); - - bool res = get_wild_keccak2(bd, res_hash, m_scratchpad); - CHECK_AND_ASSERT_THROW_MES(res, "Fatal error on hash calculation: scratchpad_size=" << m_scratchpad.size()); - return res_hash; - } - //------------------------------------------------------------------------------------ - - //------------------------------------------------------------------------------------ - uint64_t scratchpad_keeper::size() - { - return m_scratchpad.size(); - } - //------------------------------------------------------------------------------------ - crypto::hash scratchpad_light_pool::get_pow_hash_from_blob(const blobdata& bd, uint64_t height, const crypto::hash& seed) - { - CRITICAL_REGION_LOCAL(m_lock); - std::shared_ptr> pscr_light; - if (!m_scratchpad_pools.get(seed, pscr_light)) - { - LOG_PRINT_MAGENTA("Generating scratchpad light for " << seed << "["<< height <<"]", LOG_LEVEL_0); - pscr_light.reset(new std::vector()); - bool r = crypto::generate_scratchpad_light(seed, *pscr_light, currency::get_scratchpad_size_for_height(height)); - CHECK_AND_ASSERT_THROW_MES(r, "Failed to generate_scratchpad_light"); - m_scratchpad_pools.set(seed, pscr_light); - LOG_PRINT_MAGENTA("Generated ok", LOG_LEVEL_0); - } - CHECK_AND_ASSERT_THROW_MES(pscr_light->size()*10 == currency::get_scratchpad_size_for_height(height), - "Wrong size of cached scratchpad = " << pscr_light->size() << ", expected " << currency::get_scratchpad_size_for_height(height) << " for height " << height); - crypto::hash res = currency::null_hash; - bool r = crypto::get_wild_keccak_light(bd, res, *pscr_light); - CHECK_AND_ASSERT_THROW_MES(r, "Failed to get_wild_keccak_light"); - return res; - } - //------------------------------------------------------------------------------------ -} - diff --git a/src/currency_core/scratchpad_helper.h b/src/currency_core/scratchpad_helper.h deleted file mode 100644 index 515acd56..00000000 --- a/src/currency_core/scratchpad_helper.h +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) 2014-2018 Zano Project -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#pragma once -#include "crypto/wild_keccak.h" -#include "currency_protocol/blobdatatype.h" -#include "currency_core/currency_basic.h" -#include "cache_helper.h" -#include "currency_core/currency_format_utils.h" -#include "currency_core/currency_format_utils_blocks.h" - -namespace currency -{ - template - class scratchpad_keeper_base - { - public: - crypto::hash get_pow_hash(const block& b, const crypto::hash& scr_seed) - { - blobdata bl = get_block_hashing_blob(b); - return static_cast(this)->get_pow_hash_from_blob(bl, get_block_height(b), scr_seed); - } - }; - - - class scratchpad_keeper: public scratchpad_keeper_base - { - public: - scratchpad_keeper(); - bool generate(const crypto::hash& seed, uint64_t height); - crypto::hash get_pow_hash_from_blob(const blobdata& bd, uint64_t height, const crypto::hash& seed); - uint64_t size(); - private: - scratchpad_keeper(const scratchpad_keeper&) {} - crypto::hash m_seed; - std::vector m_scratchpad; - std::recursive_mutex m_lock; - }; - - - class scratchpad_light_pool : public scratchpad_keeper_base - { - public: - scratchpad_light_pool() {} - crypto::hash get_pow_hash_from_blob(const blobdata& bd, uint64_t height, const crypto::hash& seed); - private: - //map of seed to - epee::misc_utils::cache_base>, 4> m_scratchpad_pools; - std::recursive_mutex m_lock; - }; - -} \ No newline at end of file diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 6adef318..8272a08d 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -20,6 +20,7 @@ using namespace epee; #include "currency_core/checkpoints_create.h" #include "currency_core/currency_core.h" #include "rpc/core_rpc_server.h" +#include "stratum/stratum_server.h" #include "currency_protocol/currency_protocol_handler.h" #include "daemon_commands_handler.h" #include "common/miniupnp_helper.h" @@ -85,6 +86,7 @@ int main(int argc, char* argv[]) nodetool::node_server >::init_options(desc_cmd_sett); currency::miner::init_options(desc_cmd_sett); bc_services::bc_offers_service::init_options(desc_cmd_sett); + currency::stratum_server::init_options(desc_cmd_sett); po::options_description desc_options("Allowed options"); @@ -146,8 +148,8 @@ int main(int argc, char* argv[]) } - - + // stratum server is enabled if any of its options present + bool stratum_enabled = currency::stratum_server::should_start(vm); LOG_PRINT("Module folder: " << argv[0], LOG_LEVEL_0); //create objects and link them @@ -162,6 +164,9 @@ int main(int argc, char* argv[]) daemon_cmmands_handler dch(p2psrv, rpc_server); tools::miniupnp_helper upnp_helper; //ccore.get_blockchain_storage().get_attachment_services_manager().add_service(&offers_service); + std::shared_ptr stratum_server_ptr; + if (stratum_enabled) + stratum_server_ptr = std::make_shared(&ccore); if (command_line::get_arg(vm, command_line::arg_show_rpc_autodoc)) { @@ -206,6 +211,15 @@ int main(int argc, char* argv[]) res = ccore.init(vm); CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core"); LOG_PRINT_L0("Core initialized OK"); + + if (stratum_enabled) + { + LOG_PRINT_L0("Initializing stratum server..."); + res = stratum_server_ptr->init(vm); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize stratum server."); + } + + auto& bcs = ccore.get_blockchain_storage(); if (!offers_service.is_disabled() && bcs.get_current_blockchain_size() > 1 && bcs.get_top_block_id() != offers_service.get_last_seen_block_id()) @@ -231,16 +245,35 @@ int main(int argc, char* argv[]) CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core rpc server."); LOG_PRINT_L0("Core rpc server started ok"); + //start stratum only after core got initialized + if (stratum_enabled) + { + LOG_PRINT_L0("Starting stratum server..."); + res = stratum_server_ptr->run(false); + CHECK_AND_ASSERT_MES(res, 1, "Failed to start stratum server."); + LOG_PRINT_L0("Stratum server started ok"); + } - tools::signal_handler::install([&dch, &p2psrv] { + tools::signal_handler::install([&dch, &p2psrv, &stratum_server_ptr] { dch.stop_handling(); p2psrv.send_stop_signal(); + if (stratum_server_ptr) + stratum_server_ptr->send_stop_signal(); }); LOG_PRINT_L0("Starting p2p net loop..."); p2psrv.run(); LOG_PRINT_L0("p2p net loop stopped"); + //stop components + if (stratum_enabled) + { + LOG_PRINT_L0("Stopping stratum server..."); + stratum_server_ptr->send_stop_signal(); + stratum_server_ptr->timed_wait_server_stop(1000); + LOG_PRINT_L0("Stratum server stopped"); + } + LOG_PRINT_L0("Stopping core rpc server..."); rpc_server.send_stop_signal(); rpc_server.timed_wait_server_stop(5000); @@ -253,6 +286,9 @@ int main(int argc, char* argv[]) LOG_PRINT_L0("Deinitializing market..."); (static_cast(offers_service)).deinit(); + LOG_PRINT_L0("Deinitializing stratum server ..."); + stratum_server_ptr.reset(); + LOG_PRINT_L0("Deinitializing rpc server ..."); rpc_server.deinit(); LOG_PRINT_L0("Deinitializing currency_protocol..."); diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index 32a4c764..b06714e1 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -17,7 +17,7 @@ arg_type var_name = AUTO_VAL_INIT(var_name); \ view::api_response default_ar = AUTO_VAL_INIT(default_ar); \ if (!epee::serialization::load_t_from_json(var_name, param.toStdString())) \ -{ \ +{ \ default_ar.error_code = API_RETURN_CODE_BAD_ARG; \ return MAKE_RESPONSE(default_ar); \ } @@ -32,6 +32,20 @@ if (!epee::serialization::load_t_from_json(var_name, param.toStdString())) \ #define LOG_API_PARAMS(log_level) LOG_PRINT_BLUE(LOCAL_FUNCTION_DEF__ << "(" << param.toStdString() << ")", log_level) +#define CATCH_ENTRY_FAIL_API_RESPONCE() } \ + catch (const std::exception& ex) \ + { \ + LOG_ERROR("Exception catched, ERROR:" << ex.what()); \ + PREPARE_RESPONSE(view::api_void, err_resp); \ + err_resp.error_code = API_RETURN_CODE_INTERNAL_ERROR; \ + return MAKE_RESPONSE(err_resp); \ + } \ + catch(...) \ + { \ + PREPARE_RESPONSE(view::api_void, err_resp); \ + err_resp.error_code = API_RETURN_CODE_INTERNAL_ERROR; \ + return MAKE_RESPONSE(err_resp); \ + } #include "mainwindow.h" // @@ -107,7 +121,6 @@ MainWindow::MainWindow(): //workaround for macos broken tolower from std, very dirty hack bc_services::set_external_to_low_converter(convert_to_lower_via_qt); #endif - } MainWindow::~MainWindow() @@ -120,7 +133,9 @@ MainWindow::~MainWindow() void MainWindow::on_load_finished(bool ok) { + TRY_ENTRY(); LOG_PRINT("MainWindow::on_load_finished(ok = " << (ok ? "true" : "false") << ")", LOG_LEVEL_0); + CATCH_ENTRY2(void()); } @@ -128,26 +143,34 @@ void MainWindow::on_load_finished(bool ok) //------------- QString MainWindow::get_default_user_dir(const QString& param) { + TRY_ENTRY(); return tools::get_default_user_dir().c_str(); + CATCH_ENTRY_FAIL_API_RESPONCE(); } bool MainWindow::toggle_mining() { + TRY_ENTRY(); m_backend.toggle_pos_mining(); return true; + CATCH_ENTRY2(false); } QString MainWindow::get_exchange_last_top(const QString& params) { + TRY_ENTRY(); return QString(); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_tx_pool_info() { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_RESPONSE(currency::COMMAND_RPC_GET_POOL_INFO::response, ar); ar.error_code = m_backend.get_tx_pool_info(ar.response_data); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } // bool MainWindow::store_config() // { @@ -156,26 +179,33 @@ QString MainWindow::get_tx_pool_info() QString MainWindow::get_default_fee() { + TRY_ENTRY(); return QString(std::to_string(m_backend.get_default_fee()).c_str()); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_options() { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_RESPONSE(view::gui_options, ar); m_backend.get_gui_options(ar.response_data); ar.error_code = API_RETURN_CODE_OK; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } void MainWindow::tray_quit_requested() { + TRY_ENTRY(); LOG_PRINT_MAGENTA("[GUI]->[HTML] tray_quit_requested", LOG_LEVEL_0); emit quit_requested("{}"); + CATCH_ENTRY2(void()); } void MainWindow::closeEvent(QCloseEvent *event) { + TRY_ENTRY(); LOG_PRINT_L0("[GUI] CLOSE EVENT"); CHECK_AND_ASSERT_MES(m_gui_deinitialize_done_1 == m_backend_stopped_2, void(), "m_gui_deinitialize_done_1 != m_backend_stopped_2, m_gui_deinitialize_done_1 = " << m_gui_deinitialize_done_1 << "m_backend_stopped_2 = " << m_backend_stopped_2); @@ -201,10 +231,12 @@ void MainWindow::closeEvent(QCloseEvent *event) emit quit_requested("{}"); event->ignore(); } + CATCH_ENTRY2(void()); } std::string state_to_text(int s) { + TRY_ENTRY(); std::string res = epee::string_tools::int_to_hex(s); res += "("; if (s & Qt::WindowMinimized) @@ -218,10 +250,12 @@ std::string state_to_text(int s) res += ")"; return res; + CATCH_ENTRY2(""); } void MainWindow::changeEvent(QEvent *e) { + TRY_ENTRY(); switch (e->type()) { case QEvent::WindowStateChange: @@ -263,28 +297,32 @@ void MainWindow::changeEvent(QEvent *e) } QWidget::changeEvent(e); + CATCH_ENTRY2(void()); } bool MainWindow::store_app_config() { + TRY_ENTRY(); std::string conf_path = m_backend.get_config_folder() + "/" + GUI_INTERNAL_CONFIG; return tools::serialize_obj_to_file(m_config, conf_path); + CATCH_ENTRY2(false); } bool MainWindow::load_app_config() { + TRY_ENTRY(); std::string conf_path = m_backend.get_config_folder() + "/" + GUI_INTERNAL_CONFIG; return tools::unserialize_obj_from_file(m_config, conf_path); + CATCH_ENTRY2(false); } bool MainWindow::init(const std::string& htmlPath) { + TRY_ENTRY(); //QtWebEngine::initialize(); init_tray_icon(htmlPath); set_html_path(htmlPath); - - m_backend.subscribe_to_core_events(this); bool r = QSslSocket::supportsSsl(); @@ -304,17 +342,21 @@ bool MainWindow::init(const std::string& htmlPath) m_view->setContextMenuPolicy(Qt::ContextMenuPolicy::NoContextMenu); return true; + CATCH_ENTRY2(false); } void MainWindow::on_menu_show() { + TRY_ENTRY(); qDebug() << "Context menu: show()"; this->show(); this->activateWindow(); + CATCH_ENTRY2(void()); } void MainWindow::init_tray_icon(const std::string& htmlPath) { + TRY_ENTRY(); if (!QSystemTrayIcon::isSystemTrayAvailable()) { LOG_PRINT_L0("System tray is unavailable"); @@ -356,10 +398,12 @@ void MainWindow::init_tray_icon(const std::string& htmlPath) connect(m_tray_icon.get(), SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayIconActivated(QSystemTrayIcon::ActivationReason))); m_tray_icon->show(); + CATCH_ENTRY2(void()); } void MainWindow::bool_toggle_icon(const QString& param) { + TRY_ENTRY(); std::string path; if (param == "blocked") @@ -370,17 +414,21 @@ void MainWindow::bool_toggle_icon(const QString& param) QIcon qi(path.c_str()); qi.setIsMask(true); m_tray_icon->setIcon(qi); + CATCH_ENTRY2(void()); } QString MainWindow::get_log_file() { + TRY_ENTRY(); std::string buff; epee::file_io_utils::load_last_n_from_file_to_string(log_space::log_singletone::get_actual_log_file_path(), 1000000, buff); return QString::fromStdString(buff); + CATCH_ENTRY2(""); } void MainWindow::store_window_pos() { + TRY_ENTRY(); QPoint pos = this->pos(); QSize sz = this->size(); m_config.m_window_position.first = pos.x(); @@ -388,9 +436,11 @@ void MainWindow::store_window_pos() m_config.m_window_size.first = sz.height(); m_config.m_window_size.second = sz.width(); + CATCH_ENTRY2(void()); } void MainWindow::store_pos(bool consider_showed) { + TRY_ENTRY(); m_config.is_maximazed = this->isMaximized(); //here position supposed to be filled from last unserialize or filled on maximize handler if (!m_config.is_maximazed) @@ -398,9 +448,11 @@ void MainWindow::store_pos(bool consider_showed) if (consider_showed) m_config.is_showed = this->isVisible(); + CATCH_ENTRY2(void()); } void MainWindow::restore_pos(bool consider_showed) { + TRY_ENTRY(); if (m_config.is_maximazed) { this->setWindowState(windowState() | Qt::WindowMaximized); @@ -426,9 +478,11 @@ void MainWindow::restore_pos(bool consider_showed) this->showMinimized(); } + CATCH_ENTRY2(void()); } void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason) { + TRY_ENTRY(); if (reason == QSystemTrayIcon::ActivationReason::Trigger) { if ( !(this->windowState() & Qt::WindowMinimized)) @@ -443,46 +497,58 @@ void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason) } + CATCH_ENTRY2(void()); } void MainWindow::load_file(const QString &fileName) { + TRY_ENTRY(); LOG_PRINT_L0("Loading html from path: " << fileName.toStdString()); m_view->load(QUrl::fromLocalFile(QFileInfo(fileName).absoluteFilePath())); + CATCH_ENTRY2(void()); } QString MainWindow::set_clipboard(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(param); - return "OK"; + return API_RETURN_CODE_OK; + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } QString MainWindow::get_clipboard() { + TRY_ENTRY(); LOG_API_TIMING(); QClipboard *clipboard = QApplication::clipboard(); return clipboard->text(); + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } QString MainWindow::on_request_quit() { + TRY_ENTRY(); LOG_PRINT_MAGENTA("[HTML]->[GUI] on_request_quit", LOG_LEVEL_0); m_gui_deinitialize_done_1 = true; m_backend.send_stop_signal(); - return "OK"; + return API_RETURN_CODE_OK; + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } bool MainWindow::do_close() { + TRY_ENTRY(); this->close(); return true; + CATCH_ENTRY2(false); } bool MainWindow::show_inital() { + TRY_ENTRY(); if (load_app_config()) restore_pos(true); else @@ -497,10 +563,12 @@ bool MainWindow::show_inital() m_config.is_showed = true; } return true; + CATCH_ENTRY2(false); } bool MainWindow::on_backend_stopped() { + TRY_ENTRY(); LOG_PRINT_L0("[BACKEND]->[GUI] on_backend_stopped"); m_backend_stopped_2 = true; //m_deinitialize_done = true; @@ -510,10 +578,12 @@ bool MainWindow::on_backend_stopped() /*bool r = */QMetaObject::invokeMethod(this, "do_close", Qt::QueuedConnection); // } return true; + CATCH_ENTRY2(false); } bool MainWindow::update_daemon_status(const view::daemon_status_info& info) { + TRY_ENTRY(); //this->update_daemon_state(info); std::string json_str; epee::serialization::store_t_to_json(info, json_str); @@ -527,26 +597,34 @@ bool MainWindow::update_daemon_status(const view::daemon_status_info& info) QMetaObject::invokeMethod(this, "update_daemon_state", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str())); m_last_update_daemon_status_json = json_str; return true; + CATCH_ENTRY2(false); } bool MainWindow::show_msg_box(const std::string& message) { + TRY_ENTRY(); QMessageBox::information(this, "Error", message.c_str(), QMessageBox::Ok); return true; + CATCH_ENTRY2(false); } bool MainWindow::init_backend(int argc, char* argv[]) { + TRY_ENTRY(); return m_backend.init(argc, argv, this); + CATCH_ENTRY2(false); } QString MainWindow::is_remnotenode_mode_preconfigured() { - return "FALSE"; + TRY_ENTRY(); + return API_RETURN_CODE_FALSE; + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } QString MainWindow::start_backend(const QString& params) { + TRY_ENTRY(); view::start_backend_params sbp = AUTO_VAL_INIT(sbp); view::api_response ar = AUTO_VAL_INIT(ar); @@ -564,28 +642,34 @@ QString MainWindow::start_backend(const QString& params) } ar.error_code = API_RETURN_CODE_OK; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } bool MainWindow::update_wallet_status(const view::wallet_status_info& wsi) { + TRY_ENTRY(); m_wallet_states->operator [](wsi.wallet_id) = wsi.wallet_state; std::string json_str; epee::serialization::store_t_to_json(wsi, json_str); LOG_PRINT_L0(get_wallet_log_prefix(wsi.wallet_id) + "SENDING SIGNAL -> [update_wallet_status]:" << std::endl << json_str ); QMetaObject::invokeMethod(this, "update_wallet_status", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str())); return true; + CATCH_ENTRY2(false); } bool MainWindow::set_options(const view::gui_options& opt) { + TRY_ENTRY(); std::string json_str; epee::serialization::store_t_to_json(opt, json_str); LOG_PRINT_L0("SENDING SIGNAL -> [set_options]:" << std::endl << json_str); QMetaObject::invokeMethod(this, "set_options", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str())); return true; + CATCH_ENTRY2(false); } bool MainWindow::nativeEventFilter(const QByteArray &eventType, void *message, long *result) { + TRY_ENTRY(); #ifdef WIN32 MSG *msg = static_cast< MSG * >(message); if (msg->message == WM_QUERYENDSESSION) @@ -595,22 +679,26 @@ bool MainWindow::nativeEventFilter(const QByteArray &eventType, void *message, l } #endif return false; + CATCH_ENTRY2(false); } bool MainWindow::update_wallets_info(const view::wallets_summary_info& wsi) { + TRY_ENTRY(); std::string json_str; epee::serialization::store_t_to_json(wsi, json_str); LOG_PRINT_L0("SENDING SIGNAL -> [update_wallets_info]"<< std::endl << json_str ); QMetaObject::invokeMethod(this, "update_wallets_info", Qt::QueuedConnection, Q_ARG(QString, json_str.c_str())); return true; + CATCH_ENTRY2(false); } bool MainWindow::money_transfer(const view::transfer_event_info& tei) { + TRY_ENTRY(); std::string json_str; epee::serialization::store_t_to_json(tei, json_str); @@ -650,10 +738,12 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei) show_notification(title, msg); return true; + CATCH_ENTRY2(false); } bool MainWindow::money_transfer_cancel(const view::transfer_event_info& tei) { + TRY_ENTRY(); std::string json_str; epee::serialization::store_t_to_json(tei, json_str); @@ -663,17 +753,21 @@ bool MainWindow::money_transfer_cancel(const view::transfer_event_info& tei) return true; + CATCH_ENTRY2(false); } bool MainWindow::wallet_sync_progress(const view::wallet_sync_progres_param& p) { + TRY_ENTRY(); LOG_PRINT_L2(get_wallet_log_prefix(p.wallet_id) + "SENDING SIGNAL -> [wallet_sync_progress]" << " wallet_id: " << p.wallet_id << ": " << p.progress << "%"); //this->wallet_sync_progress(epee::serialization::store_t_to_json(p).c_str()); QMetaObject::invokeMethod(this, "wallet_sync_progress", Qt::QueuedConnection, Q_ARG(QString, epee::serialization::store_t_to_json(p).c_str())); return true; + CATCH_ENTRY2(false); } bool MainWindow::set_html_path(const std::string& path) { + TRY_ENTRY(); //init_tray_icon(path); #ifdef _MSC_VER load_file(std::string(path + "/index.html").c_str()); @@ -682,38 +776,48 @@ bool MainWindow::set_html_path(const std::string& path) load_file(QString((std::string("") + path + "/index.html").c_str())); #endif return true; + CATCH_ENTRY2(false); } bool MainWindow::pos_block_found(const currency::block& block_found) { + TRY_ENTRY(); std::stringstream ss; ss << "Found Block h = " << currency::get_block_height(block_found); LOG_PRINT_L0("SENDING SIGNAL -> [update_pos_mining_text]"); //this->update_pos_mining_text(ss.str().c_str()); QMetaObject::invokeMethod(this, "update_pos_mining_text", Qt::QueuedConnection, Q_ARG(QString, ss.str().c_str())); return true; + CATCH_ENTRY2(false); } QString MainWindow::get_version() { + TRY_ENTRY(); return PROJECT_VERSION_LONG; + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_os_version() { + TRY_ENTRY(); return tools::get_os_version_string().c_str(); + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } QString MainWindow::get_alias_coast(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::struct_with_one_t_type, lvl); view::get_alias_coast_response resp; resp.error_code = m_backend.get_alias_coast(lvl.v, resp.coast); return epee::serialization::store_t_to_json(resp).c_str(); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::set_localization_strings(const QString param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::set_localization_request, lr); view::api_response resp; @@ -733,10 +837,12 @@ QString MainWindow::set_localization_strings(const QString param) LOG_PRINT_L0("New localization set, language title: " << lr.language_title << ", strings " << lr.strings.size()); } return epee::serialization::store_t_to_json(resp).c_str(); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::request_alias_registration(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); //return que_call2("request_alias_registration", param, [this](const view::request_alias_param& tp, view::api_response& ar){ PREPARE_ARG_FROM_JSON(view::request_alias_param, tp); @@ -754,9 +860,11 @@ QString MainWindow::request_alias_registration(const QString& param) ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); ar.error_code = API_RETURN_CODE_OK; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::request_alias_update(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::request_alias_param, tp); PREPARE_RESPONSE(view::transfer_response, ar); @@ -773,9 +881,11 @@ QString MainWindow::request_alias_update(const QString& param) ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); ar.error_code = API_RETURN_CODE_OK; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::transfer(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); //return que_call2("transfer", json_transfer_object, [this](const view::transfer_params& tp, view::api_response& ar){ PREPARE_ARG_FROM_JSON(view::transfer_params, tp); @@ -796,11 +906,14 @@ QString MainWindow::transfer(const QString& param) ar.response_data.tx_hash = string_tools::pod_to_hex(currency::get_transaction_hash(res_tx)); ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } void MainWindow::message_box(const QString& msg) { + TRY_ENTRY(); show_msg_box(msg.toStdString()); + CATCH_ENTRY2(void()); } struct serialize_variant_visitor : public boost::static_visitor @@ -815,12 +928,15 @@ struct serialize_variant_visitor : public boost::static_visitor template std::string serialize_variant(const t_variant& v) { + TRY_ENTRY(); return boost::apply_visitor(serialize_variant_visitor(), v); + CATCH_ENTRY2(""); } void MainWindow::on_core_event(const std::string event_name, const currency::core_event_v& e) { + TRY_ENTRY(); //at the moment we don't forward CORE_EVENT_BLOCK_ADDEDevent to GUI if (CORE_EVENT_BLOCK_ADDED == event_name) return; @@ -828,10 +944,12 @@ void MainWindow::on_core_event(const std::string event_name, const currency::cor m_events.m_que.push_back(currency::core_event()); m_events.m_que.back().details = currency::core_event_v(e); m_events.m_que.back().method = event_name; + CATCH_ENTRY2(void()); } std::string get_events_que_json_string(const std::list& eq, std::string& methods_list) { + TRY_ENTRY(); //t the moment portable_storage is not supporting polymorphic objects lists, so //there is no hope to make serialization with variant list, lets handle it manual std::stringstream ss; @@ -851,10 +969,12 @@ std::string get_events_que_json_string(const std::list& eq } ss << "]}"; return ss.str(); + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } void MainWindow::on_complete_events() { + TRY_ENTRY(); if (m_events.m_que.size()) { std::string methods_list; @@ -874,14 +994,18 @@ void MainWindow::on_complete_events() m_events.m_que.clear(); } + CATCH_ENTRY2(void()); } void MainWindow::on_clear_events() { + TRY_ENTRY(); m_events.m_que.clear(); + CATCH_ENTRY2(void()); } QString MainWindow::get_secure_app_data(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); view::password_data pwd = AUTO_VAL_INIT(pwd); @@ -917,10 +1041,12 @@ QString MainWindow::get_secure_app_data(const QString& param) } return app_data_buff.substr(sizeof(app_data_file_binary_header)).c_str(); + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } QString MainWindow::store_app_data(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); view::api_response ar; ar.error_code = API_RETURN_CODE_FAIL; @@ -940,9 +1066,11 @@ QString MainWindow::store_app_data(const QString& param) //ar.error_code = store_to_file((m_backend.get_config_folder() + "/" + GUI_CONFIG_FILENAME).c_str(), param).toStdString(); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::is_file_exist(const QString& path) { + TRY_ENTRY(); try{ bool r = file_io_utils::is_file_exist(path.toStdWString()); if (r) @@ -960,9 +1088,11 @@ QString MainWindow::is_file_exist(const QString& path) { return API_RETURN_CODE_ALREADY_EXISTS; } + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } QString MainWindow::store_to_file(const QString& path, const QString& buff) { + TRY_ENTRY(); try{ bool r = file_io_utils::save_string_to_file_throw(path.toStdWString(), buff.toStdString()); if (r) @@ -982,18 +1112,22 @@ QString MainWindow::store_to_file(const QString& path, const QString& buff) } + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } QString MainWindow::get_app_data() { + TRY_ENTRY(); LOG_API_TIMING(); std::string app_data_buff; file_io_utils::load_file_to_string(m_backend.get_config_folder() + "/" + GUI_CONFIG_FILENAME, app_data_buff); return app_data_buff.c_str(); + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } QString MainWindow::store_secure_app_data(const QString& param, const QString& pass) { + TRY_ENTRY(); LOG_API_TIMING(); if (!tools::create_directories_if_necessary(m_backend.get_config_folder())) { @@ -1018,10 +1152,12 @@ QString MainWindow::store_secure_app_data(const QString& param, const QString& p ar.error_code = API_RETURN_CODE_FAIL; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::have_secure_app_data() { + TRY_ENTRY(); LOG_API_TIMING(); view::api_response ar = AUTO_VAL_INIT(ar); @@ -1032,9 +1168,11 @@ QString MainWindow::have_secure_app_data() ar.error_code = API_RETURN_CODE_FALSE; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::drop_secure_app_data() { + TRY_ENTRY(); LOG_API_TIMING(); view::api_response ar = AUTO_VAL_INIT(ar); @@ -1044,9 +1182,11 @@ QString MainWindow::drop_secure_app_data() else ar.error_code = API_RETURN_CODE_FALSE; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_all_aliases() { + TRY_ENTRY(); LOG_API_TIMING(); //PREPARE_ARG_FROM_JSON(view::struct_with_one_t_type, param); PREPARE_RESPONSE(view::alias_set, rsp); @@ -1055,30 +1195,38 @@ QString MainWindow::get_all_aliases() QString res = MAKE_RESPONSE(rsp); LOG_PRINT_GREEN("GET_ALL_ALIASES: res: " << rsp.error_code << ", count: " << rsp.response_data.aliases.size() << ", string buff size: " << res.size(), LOG_LEVEL_1); return res; + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_alias_info_by_address(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_RESPONSE(currency::alias_rpc_details, rsp); rsp.error_code = m_backend.get_alias_info_by_address(param.toStdString(), rsp.response_data); return MAKE_RESPONSE(rsp); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_alias_info_by_name(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_RESPONSE(currency::alias_rpc_details, rsp); rsp.error_code = m_backend.get_alias_info_by_name(param.toStdString(), rsp.response_data); return MAKE_RESPONSE(rsp); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::validate_address(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); view::address_validation_response ar = AUTO_VAL_INIT(ar); ar.error_code = m_backend.validate_address(param.toStdString(), ar.payment_id); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::set_log_level(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::struct_with_one_t_type, lvl); epee::log_space::get_set_log_detalisation_level(true, lvl.v); @@ -1086,14 +1234,17 @@ QString MainWindow::set_log_level(const QString& param) LOG_PRINT("[LOG LEVEL]: set to " << lvl.v, LOG_LEVEL_MIN); return MAKE_RESPONSE(default_ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_log_level(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_RESPONSE(view::struct_with_one_t_type, ar); ar.response_data.v = epee::log_space::get_set_log_detalisation_level(); ar.error_code = API_RETURN_CODE_OK; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } // QString MainWindow::dump_all_offers() @@ -1127,12 +1278,15 @@ QString MainWindow::get_log_level(const QString& param) QString MainWindow::webkit_launched_script() { + TRY_ENTRY(); m_last_update_daemon_status_json.clear(); return ""; + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } //////////////////// QString MainWindow::show_openfile_dialog(const QString& param) { + TRY_ENTRY(); view::system_filedialog_request ofdr = AUTO_VAL_INIT(ofdr); view::system_filedialog_response ofdres = AUTO_VAL_INIT(ofdres); if (!epee::serialization::load_t_from_json(ofdr, param.toStdString())) @@ -1154,11 +1308,13 @@ QString MainWindow::show_openfile_dialog(const QString& param) ofdres.error_code = API_RETURN_CODE_OK; ofdres.path = path.toStdString(); return MAKE_RESPONSE(ofdres); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::show_savefile_dialog(const QString& param) { + TRY_ENTRY(); PREPARE_ARG_FROM_JSON(view::system_filedialog_request, ofdr); view::system_filedialog_response ofdres = AUTO_VAL_INIT(ofdres); @@ -1175,10 +1331,12 @@ QString MainWindow::show_savefile_dialog(const QString& param) ofdres.error_code = API_RETURN_CODE_OK; ofdres.path = path.toStdString(); return MAKE_RESPONSE(ofdres); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::close_wallet(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); //return que_call2("close_wallet", param, [this](const view::wallet_id_obj& owd, view::api_response& ar){ PREPARE_ARG_FROM_JSON(view::wallet_id_obj, owd); @@ -1186,25 +1344,30 @@ QString MainWindow::close_wallet(const QString& param) ar.error_code = m_backend.close_wallet(owd.wallet_id); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_contracts(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::wallet_id_obj, owd); PREPARE_RESPONSE(view::contracts_array, ar); ar.error_code = m_backend.get_contracts(owd.wallet_id, ar.response_data.contracts); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::create_proposal(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::create_proposal_param, cpp); PREPARE_RESPONSE(view::contracts_array, ar); ar.error_code = m_backend.create_proposal(cpp.wallet_id, cpp.details, cpp.payment_id, cpp.expiration_period, cpp.fee, cpp.b_fee); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } @@ -1212,16 +1375,19 @@ QString MainWindow::create_proposal(const QString& param) QString MainWindow::accept_proposal(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::wallet_and_contract_id_param, waip); PREPARE_RESPONSE(view::api_void, ar); ar.error_code = m_backend.accept_proposal(waip.wallet_id, waip.contract_id); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::release_contract(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::accept_proposal_param, rcp); PREPARE_RESPONSE(view::api_void, ar); @@ -1229,10 +1395,12 @@ QString MainWindow::release_contract(const QString& param) ar.error_code = m_backend.release_contract(rcp.wallet_id, rcp.contract_id, rcp.release_type); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::request_cancel_contract(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::crequest_cancel_contract_param, rcp); PREPARE_RESPONSE(view::api_void, ar); @@ -1240,10 +1408,12 @@ QString MainWindow::request_cancel_contract(const QString& param) ar.error_code = m_backend.request_cancel_contract(rcp.wallet_id, rcp.contract_id, rcp.fee, rcp.expiration_period); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::accept_cancel_contract(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::wallet_and_contract_id_param, wci); PREPARE_RESPONSE(view::api_void, ar); @@ -1251,31 +1421,36 @@ QString MainWindow::accept_cancel_contract(const QString& param) ar.error_code = m_backend.accept_cancel_contract(wci.wallet_id, wci.contract_id); return MAKE_RESPONSE(ar); - + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::generate_wallet(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); //return que_call2("generate_wallet", param, [this](const view::open_wallet_request& owd, view::api_response& ar){ PREPARE_ARG_FROM_JSON(view::open_wallet_request, owd); PREPARE_RESPONSE(view::open_wallet_response, ar); ar.error_code = m_backend.generate_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, ar.response_data); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::restore_wallet(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); //return que_call2("restore_wallet", param, [this](const view::restore_wallet_request& owd, view::api_response& ar){ PREPARE_ARG_FROM_JSON(view::restore_wallet_request, owd); PREPARE_RESPONSE(view::open_wallet_response, ar); ar.error_code = m_backend.restore_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, owd.restore_key, ar.response_data); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::open_wallet(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); //return que_call2("open_wallet", param, [this](const view::open_wallet_request& owd, view::api_response& ar){ @@ -1283,42 +1458,51 @@ QString MainWindow::open_wallet(const QString& param) PREPARE_RESPONSE(view::open_wallet_response, ar); ar.error_code = m_backend.open_wallet(epee::string_encoding::utf8_to_wstring(owd.path), owd.pass, ar.response_data); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_my_offers(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); //return que_call2("open_wallet", param, [this](const view::open_wallet_request& owd, view::api_response& ar){ PREPARE_ARG_FROM_JSON(bc_services::core_offers_filter, f); PREPARE_RESPONSE(currency::COMMAND_RPC_GET_ALL_OFFERS::response, ar); ar.error_code = m_backend.get_my_offers(f, ar.response_data.offers); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_fav_offers(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::get_fav_offers_request, f); PREPARE_RESPONSE(currency::COMMAND_RPC_GET_ALL_OFFERS::response, ar); ar.error_code = m_backend.get_fav_offers(f.ids, f.filter, ar.response_data.offers); return MAKE_RESPONSE(ar); - + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::is_pos_allowed() { + TRY_ENTRY(); LOG_API_TIMING(); return m_backend.is_pos_allowed().c_str(); + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } QString MainWindow::run_wallet(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::wallet_id_obj, wio); default_ar.error_code = m_backend.run_wallet(wio.wallet_id); return MAKE_RESPONSE(default_ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::resync_wallet(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); //return que_call2("get_wallet_info", param, [this](const view::wallet_id_obj& a, view::api_response& ar){ PREPARE_ARG_FROM_JSON(view::wallet_id_obj, a); @@ -1326,31 +1510,24 @@ QString MainWindow::resync_wallet(const QString& param) ar.error_code = m_backend.resync_wallet(a.wallet_id); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } -// QString MainWindow::get_all_offers(const QString& param) -// { -// LOG_API_TIMING(); -// //return que_call2("get_all_offers", param, [this](const view::api_void& a, view::api_response& ar){ -// // PREPARE_ARG_FROM_JSON(view::api_void, a); -// PREPARE_RESPONSE(currency::COMMAND_RPC_GET_ALL_OFFERS::response, ar); -// ar.error_code = m_backend.get_all_offers(ar.response_data); -// return MAKE_RESPONSE(ar); -// } - - QString MainWindow::get_offers_ex(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); //return que_call2("get_offers_ex", param, [this](const bc_services::core_offers_filter& f, view::api_response& ar){ PREPARE_ARG_FROM_JSON(bc_services::core_offers_filter, f); PREPARE_RESPONSE(currency::COMMAND_RPC_GET_ALL_OFFERS::response, ar); ar.error_code = m_backend.get_offers_ex(f, ar.response_data.offers, ar.response_data.total_offers); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::push_offer(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); LOG_API_PARAMS(LOG_LEVEL_2); //return que_call2("push_offer", param, [this](const view::push_offer_param& a, view::api_response& ar){ @@ -1369,10 +1546,12 @@ QString MainWindow::push_offer(const QString& param) ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); ar.error_code = API_RETURN_CODE_OK; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::cancel_offer(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); LOG_API_PARAMS(LOG_LEVEL_2); // return que_call2("cancel_offer", param, [this](const view::cancel_offer_param& a, view::api_response& ar){ @@ -1390,10 +1569,12 @@ QString MainWindow::cancel_offer(const QString& param) ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); ar.error_code = API_RETURN_CODE_OK; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::push_update_offer(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); LOG_API_PARAMS(LOG_LEVEL_2); //return que_call2("cancel_offer", param, [this](const bc_services::update_offer_details& a, view::api_response& ar){ @@ -1411,20 +1592,24 @@ QString MainWindow::push_update_offer(const QString& param) ar.response_data.tx_blob_size = currency::get_object_blobsize(res_tx); ar.error_code = API_RETURN_CODE_OK; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_recent_transfers(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::get_recent_transfers_request, a); PREPARE_RESPONSE(view::transfers_array, ar); ar.error_code = m_backend.get_recent_transfers(a.wallet_id, a.offest, a.count, ar.response_data); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_mining_history(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); //return prepare_call("get_mining_history", param, [this](const view::wallet_id_obj& a, view::api_response& ar) { PREPARE_ARG_FROM_JSON(view::wallet_id_obj, a); @@ -1436,62 +1621,78 @@ QString MainWindow::get_mining_history(const QString& param) ar.error_code = API_RETURN_CODE_OK; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::start_pos_mining(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::wallet_id_obj, wo); default_ar.error_code = m_backend.start_pos_mining(wo.wallet_id); return MAKE_RESPONSE(default_ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::stop_pos_mining(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::wallet_id_obj, wo); default_ar.error_code = m_backend.stop_pos_mining(wo.wallet_id); return MAKE_RESPONSE(default_ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_smart_wallet_info(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::wallet_id_obj, wo); PREPARE_RESPONSE(view::get_restore_info_response, ar); ar.error_code = m_backend.get_wallet_restore_info(wo.wallet_id, ar.response_data.restore_key); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::get_mining_estimate(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::request_mining_estimate, me); PREPARE_RESPONSE(view::response_mining_estimate, ar); ar.error_code = m_backend.get_mining_estimate(me.amount_coins, me.time, ar.response_data.final_amount, ar.response_data.all_coins_and_pos_diff_rate, ar.response_data.days_estimate); return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::backup_wallet_keys(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::backup_keys_request, me); default_ar.error_code = m_backend.backup_wallet(me.wallet_id, epee::string_encoding::utf8_to_wstring(me.path)); return MAKE_RESPONSE(default_ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::reset_wallet_password(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::reset_pass_request, me); default_ar.error_code = m_backend.reset_wallet_password(me.wallet_id, me.pass); return MAKE_RESPONSE(default_ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::is_wallet_password_valid(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::reset_pass_request, me); default_ar.error_code = m_backend.is_wallet_password_valid(me.wallet_id, me.pass); return MAKE_RESPONSE(default_ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::is_autostart_enabled() { + TRY_ENTRY(); LOG_API_TIMING(); view::api_response ar; @@ -1501,10 +1702,12 @@ QString MainWindow::is_autostart_enabled() ar.error_code = API_RETURN_CODE_FALSE; return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::toggle_autostart(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::struct_with_one_t_type, as); @@ -1514,16 +1717,20 @@ QString MainWindow::toggle_autostart(const QString& param) default_ar.error_code = API_RETURN_CODE_FAIL; return MAKE_RESPONSE(default_ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::check_available_sources(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::api_request_t >, sources); return m_backend.check_available_sources(sources.wallet_id, sources.req_data).c_str(); + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } QString MainWindow::open_url_in_browser(const QString& param) { + TRY_ENTRY(); QString prefix = "https://"; if (!QDesktopServices::openUrl(QUrl(prefix + param))) { @@ -1532,20 +1739,26 @@ QString MainWindow::open_url_in_browser(const QString& param) } LOG_PRINT_L0("[Open URL]: " << param.toStdString()); return API_RETURN_CODE_OK; + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } QString MainWindow::is_valid_restore_wallet_text(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); return m_backend.is_valid_brain_restore_data(param.toStdString()).c_str(); + CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } void MainWindow::contextMenuEvent(QContextMenuEvent * event) { + TRY_ENTRY(); + CATCH_ENTRY2(void()); } QString MainWindow::print_text(const QString& param) { + TRY_ENTRY(); LOG_API_TIMING(); PREPARE_ARG_FROM_JSON(view::print_text_param, ptp); @@ -1572,20 +1785,24 @@ QString MainWindow::print_text(const QString& param) default_ar.error_code = API_RETURN_CODE_OK; LOG_PRINT_L0("[PRINT_TEXT] default_ar.error_code = " << default_ar.error_code); return MAKE_RESPONSE(default_ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } QString MainWindow::print_log(const QString& param) { + TRY_ENTRY(); PREPARE_ARG_FROM_JSON(view::print_log_params, plp); LOG_PRINT("[GUI_LOG]" << plp.msg, plp.log_level); default_ar.error_code = API_RETURN_CODE_OK; return MAKE_RESPONSE(default_ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); } void MainWindow::show_notification(const std::string& title, const std::string& message) { + TRY_ENTRY(); LOG_PRINT_L1("system notification: \"" << title << "\", \"" << message << "\""); // it's expected that title and message are utf-8 encoded! @@ -1598,6 +1815,7 @@ void MainWindow::show_notification(const std::string& title, const std::string& // use native notification system on macOS notification_helper::show(title, message); #endif + CATCH_ENTRY2(void()); } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 4ba2bbf3..bf9c8994 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -783,7 +783,7 @@ namespace currency //pe.keyimage key image will be set in the wallet //pe.wallet_index is not included in serialization map, TODO: refactoring here - if (!m_core.get_block_template(b, res.seed, miner_address, stakeholder_address, dt, res.height, req.extra_text, req.pos_block, pe)) + if (!m_core.get_block_template(b, miner_address, stakeholder_address, dt, res.height, req.extra_text, req.pos_block, pe)) { error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; error_resp.message = "Internal error: failed to create block template"; diff --git a/src/rpc/mining_protocol_defs.h b/src/rpc/mining_protocol_defs.h index 14665583..4a2c0f23 100644 --- a/src/rpc/mining_protocol_defs.h +++ b/src/rpc/mining_protocol_defs.h @@ -120,34 +120,6 @@ namespace mining }; }; - struct COMMAND_RPC_GET_FULLSCRATCHPAD - { - RPC_METHOD_NAME("getfullscratchpad"); - - struct request - { - std::string id; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(id) - END_KV_SERIALIZE_MAP() - }; - - struct response - { - height_info hi; - std::string scratchpad_hex; - std::string status; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(hi) - KV_SERIALIZE(scratchpad_hex) - KV_SERIALIZE(status) - END_KV_SERIALIZE_MAP() - }; - }; - - struct COMMAND_RPC_SUBMITSHARE { RPC_METHOD_NAME("submit"); @@ -177,31 +149,5 @@ namespace mining }; }; - - struct COMMAND_RPC_STORE_SCRATCHPAD - { - RPC_METHOD_NAME("store_scratchpad"); - - struct request - { - std::string local_file_path; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(local_file_path) - END_KV_SERIALIZE_MAP() - }; - - struct response - { - std::string status; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(status) - END_KV_SERIALIZE_MAP() - }; - }; - - - } diff --git a/src/stratum/stratum_helpers.h b/src/stratum/stratum_helpers.h new file mode 100644 index 00000000..fc4e680a --- /dev/null +++ b/src/stratum/stratum_helpers.h @@ -0,0 +1,248 @@ +// Copyright (c) 2018-2019 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once +#include +#include "epee/include/misc_language.h" +#include "epee/include/storages/parserse_base_utils.h" +#include "epee/include/storages/portable_storage.h" +#include "ethereum/libethash/ethash/ethash.h" +#include "ethereum/libethash/ethash/keccak.h" +#include "currency_core/currency_format_utils.h" + +namespace stratum +{ +//------------------------------------------------------------------------------------------------------------------------------ + + // Small helper for extracting separate JSON-RPC requests from input buffer. + // TODO: currently it does not handle curly brackets within strings to make things simplier + struct json_helper + { + void feed(const std::string& s) + { + feed(s.c_str(), s.size()); + } + + void feed(const char* str, size_t size) + { + m_buffer.append(str, size); + + int b_count = 0; + for(size_t i = 0; i < m_buffer.size(); ) + { + char c = m_buffer[i]; + if (c == '{') + ++b_count; + else if (c == '}') + { + if (--b_count == 0) + { + m_objects.push_back(m_buffer.substr(0, i + 1)); + m_buffer.erase(0, i + 1); + i = 0; + continue; + } + } + ++i; + } + } + + bool has_objects() const + { + return !m_objects.empty(); + } + + bool pop_object(std::string &destination) + { + if (m_objects.empty()) + return false; + + destination = m_objects.front(); + m_objects.pop_front(); + return true; + } + + std::string m_buffer; + std::list m_objects; + }; + + template + bool ps_get_value_noexcept(epee::serialization::portable_storage& ps, const std::string& value_name, t_value& val, epee::serialization::portable_storage::hsection hparent_section) + { + try + { + return ps.get_value(value_name, val, hparent_section); + } + catch (...) + { + return false; + } + } + + std::string trim_0x(const std::string& s) + { + if (s.length() >= 2 && s[0] == '0' && s[1] == 'x') + return s.substr(2); + return s; + } + + constexpr char hexmap[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + constexpr char hexmap_backward[] = + { //0 1 2 3 4 5 6 7 8 9 A B C D E F + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 0 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 1 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 2 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 20, 20, 20, 20, 20, // 3 + 20, 10, 11, 12, 13, 14, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 4 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 5 + 20, 10, 11, 12, 13, 14, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 6 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 7 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 8 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // 9 + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // A + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // B + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // C + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // D + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, // E + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 // F + }; + + template + std::string pod_to_net_format(const pod_t &h) + { + const char* data = reinterpret_cast(&h); + size_t len = sizeof h; + + std::string s(len * 2, ' '); + for (size_t i = 0; i < len; ++i) { + s[2 * i] = hexmap[(data[i] & 0xF0) >> 4]; + s[2 * i + 1] = hexmap[(data[i] & 0x0F)]; + } + + return "0x" + s; + } + + template + std::string pod_to_net_format_reverse(const pod_t &h) + { + const char* data = reinterpret_cast(&h); + size_t len = sizeof h; + + std::string s(len * 2, ' '); + for (size_t i = 0; i < len; ++i) { + s[2 * i] = hexmap[(data[len - i - 1] & 0xF0) >> 4]; // reverse bytes order in data + s[2 * i + 1] = hexmap[(data[len - i - 1] & 0x0F)]; + } + + return "0x" + s; + } + template + bool pod_from_net_format(const std::string& str, pod_t& result, bool assume_following_zeroes = false) + { + std::string s = trim_0x(str); + if (s.size() != sizeof(pod_t) * 2) + { + if (!assume_following_zeroes || s.size() > sizeof(pod_t) * 2) + return false; // invalid string length + s.insert(s.size() - 1, sizeof(pod_t) * 2 - s.size(), '0'); // add zeroes at the end + } + + const unsigned char* hex_str = reinterpret_cast(s.c_str()); + char* pod_data = reinterpret_cast(&result); + + for (size_t i = 0; i < sizeof(pod_t); ++i) + { + char a = hexmap_backward[hex_str[2 * i + 1]]; + char b = hexmap_backward[hex_str[2 * i + 0]]; + if (a > 15 || b > 15) + return false; // invalid character + pod_data[i] = a | (b << 4); + } + return true; + } + + template + bool pod_from_net_format_reverse(const std::string& str, pod_t& result, bool assume_leading_zeroes = false) + { + std::string s = trim_0x(str); + if (s.size() != sizeof(pod_t) * 2) + { + if (!assume_leading_zeroes || s.size() > sizeof(pod_t) * 2) + return false; // invalid string length + s.insert(0, sizeof(pod_t) * 2 - s.size(), '0'); // add zeroes at the beginning + } + + const unsigned char* hex_str = reinterpret_cast(s.c_str()); + char* pod_data = reinterpret_cast(&result); + + for (size_t i = 0; i < sizeof(pod_t); ++i) + { + char a = hexmap_backward[hex_str[2 * i + 1]]; + char b = hexmap_backward[hex_str[2 * i + 0]]; + if (a > 15 || b > 15) + return false; // invalid character + pod_data[sizeof(pod_t) - i - 1] = a | (b << 4); // reverse byte order + } + return true; + } + + uint64_t epoch_by_seedhash(const ethash_hash256& seed_hash) + { + ethash_hash256 epoch_seed = {}; + for (uint32_t i = 0; i < 2016; ++i) // 2016 epoches will be enough until 2038 + { + if (memcmp(&seed_hash, &epoch_seed, sizeof seed_hash) == 0) + return i; + epoch_seed = ethash_keccak256_32(epoch_seed.bytes); + } + return UINT64_MAX; + } + + //------------------------------------------------------------------------------------------------------------------------------ + + // http://www.jsonrpc.org/specification + // 'id' -- an identifier established by the Client that MUST contain a String, Number, or NULL value if included. + // The Server MUST reply with the same value in the Response object if included. + struct jsonrpc_id_null_t {}; + typedef boost::variant jsonrpc_id_t; + + std::string jsonrpc_id_to_value_str(const jsonrpc_id_t& id) + { + if (id.type() == typeid(int64_t)) + return boost::to_string(boost::get(id)); + if (id.type() == typeid(std::string)) + return '"' + boost::to_string(boost::get(id)) + '"'; + return "null"; + } + + namespace details + { + struct jsonrpc_id_visitor : public boost::static_visitor<> + { + explicit jsonrpc_id_visitor(jsonrpc_id_t &value) : m_value(value) {} + void operator()(const uint64_t id) { m_value = id; } + void operator()(const int64_t id) { m_value = id; } + void operator()(const std::string& id) { m_value = id; } + template + void operator()(const T&) { /* nothing */ } + + jsonrpc_id_t &m_value; + }; + } + + bool read_jsonrpc_id(epee::serialization::portable_storage& ps, jsonrpc_id_t& result) + { + epee::serialization::storage_entry se; + if (!ps.get_value("id", se, nullptr)) + return false; + + details::jsonrpc_id_visitor vis(result); + boost::apply_visitor(vis, se); + return true; + } + +} // namespace stratum + +inline std::ostream &operator <<(std::ostream &o, const ethash_hash256 &v) { return print256(o, v); } diff --git a/src/stratum/stratum_server.cpp b/src/stratum/stratum_server.cpp new file mode 100644 index 00000000..58de4622 --- /dev/null +++ b/src/stratum/stratum_server.cpp @@ -0,0 +1,1207 @@ +// Copyright (c) 2018-2019 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "stratum_server.h" +#include "stratum_helpers.h" +#include "net/abstract_tcp_server2.h" +#include "currency_core/currency_config.h" +#include "currency_core/currency_core.h" +#include "common/command_line.h" +#include "common/int-util.h" +#include "version.h" +#include "currency_protocol/currency_protocol_handler.h" + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "stratum" +ENABLE_CHANNEL_BY_DEFAULT("stratum"); + +using namespace stratum; + +namespace currency +{ + +namespace +{ +// This username should be used by stratum clients to log in IN CASE stratum server was started with "stratum-miner-address" option. +// Alternatevly, valid and the very same wallet address should be user among all the workers. +#define WORKER_ALLOWED_USERNAME "miner" + +#define STRATUM_BIND_IP_DEFAULT "0.0.0.0" +#define STRATUM_THREADS_COUNT_DEFAULT 2 +#define STRATUM_BLOCK_TEMPLATE_UPD_PERIOD_DEFAULT 30 // sec +#define STRATUM_TOTAL_HR_PRINT_INTERVAL_S_DEFAULT 60 // sec +#define VDIFF_TARGET_MIN_DEFAULT 100000000ull // = 100 Mh +#define VDIFF_TARGET_MAX_DEFAULT 100000000000ull // = 100 Gh +#define VDIFF_TARGET_TIME_DEFAULT 30 // sec +#define VDIFF_RETARGET_TIME_DEFAULT 240 // sec +#define VDIFF_RETARGET_SHARES_COUNT 12 // enforce retargeting if this many shares are be received (huge performace comparing to current difficulty) +#define VDIFF_VARIANCE_PERCENT_DEFAULT 25 // % + + const command_line::arg_descriptor arg_stratum = {"stratum", "Stratum server: enable" }; + const command_line::arg_descriptor arg_stratum_bind_ip = {"stratum-bind-ip", "Stratum server: IP to bind", STRATUM_BIND_IP_DEFAULT }; + const command_line::arg_descriptor arg_stratum_bind_port = {"stratum-bind-port", "Stratum server: port to listen at", std::to_string(STRATUM_DEFAULT_PORT) }; + const command_line::arg_descriptor arg_stratum_threads = {"stratum-threads-count", "Stratum server: number of server threads", STRATUM_THREADS_COUNT_DEFAULT }; + const command_line::arg_descriptor arg_stratum_miner_address = {"stratum-miner-address", "Stratum server: miner address. All workers" + " will mine to this address. If not set here, ALL workers should use the very same wallet address as username." + " If set here - they're allowed to log in with username '" WORKER_ALLOWED_USERNAME "' instead of address.", "", true }; + + const command_line::arg_descriptor arg_stratum_block_template_update_period = {"stratum-template-update-period", + "Stratum server: if there are no new blocks, update block template this often (sec.)", STRATUM_BLOCK_TEMPLATE_UPD_PERIOD_DEFAULT }; + const command_line::arg_descriptor arg_stratum_hr_print_interval = {"stratum-hr-print-interval", "Stratum server: how often to print hashrate stats (sec.)", STRATUM_TOTAL_HR_PRINT_INTERVAL_S_DEFAULT }; + + const command_line::arg_descriptor arg_stratum_vdiff_target_min = {"stratum-vdiff-target-min", "Stratum server: minimum worker difficulty", VDIFF_TARGET_MIN_DEFAULT }; + const command_line::arg_descriptor arg_stratum_vdiff_target_max = {"stratum-vdiff-target-max", "Stratum server: maximum worker difficulty", VDIFF_TARGET_MAX_DEFAULT }; + const command_line::arg_descriptor arg_stratum_vdiff_target_time = {"stratum-vdiff-target-time", "Stratum server: target time per share (i.e. try to get one share per this many seconds)", VDIFF_TARGET_TIME_DEFAULT }; + const command_line::arg_descriptor arg_stratum_vdiff_retarget_time = {"stratum-vdiff-retarget-time", "Stratum server: check to see if we should retarget this often (sec.)", VDIFF_RETARGET_TIME_DEFAULT }; + const command_line::arg_descriptor arg_stratum_vdiff_retarget_shares = {"stratum-vdiff-retarget-shares", "Stratum server: enforce retargeting if got this many shares", VDIFF_RETARGET_SHARES_COUNT }; + const command_line::arg_descriptor arg_stratum_vdiff_variance_percent = {"stratum-vdiff-variance-percent", "Stratum server: allow average time to very this % from target without retarget", VDIFF_VARIANCE_PERCENT_DEFAULT }; + const command_line::arg_descriptor arg_stratum_always_online = { "stratum-always-online", "Stratum server consider core as always online, useful for debugging with --offline-mode" }; + +//============================================================================================================================== + + static jsonrpc_id_null_t jsonrpc_id_null; // object of jsonrpc_id_null_t for convenience + +// JSON-RPC error codes +#define JSONRPC_ERROR_CODE_DEFAULT -32000 // -32000 to -32099 : Reserved for implementation-defined server-errors. +#define JSONRPC_ERROR_CODE_PARSE -32700 +#define JSONRPC_ERROR_CODE_METHOD_NOT_FOUND -32601 + +#define LP_CC_WORKER( ct, message, log_level) LOG_PRINT_CC( ct, "WORKER " << ct.m_worker_name << ": " << message, log_level) +#define LP_CC_WORKER_GREEN( ct, message, log_level) LOG_PRINT_CC_GREEN( ct, "WORKER " << ct.m_worker_name << ": " << message, log_level) +#define LP_CC_WORKER_RED( ct, message, log_level) LOG_PRINT_CC_RED( ct, "WORKER " << ct.m_worker_name << ": " << message, log_level) +#define LP_CC_WORKER_BLUE( ct, message, log_level) LOG_PRINT_CC_BLUE( ct, "WORKER " << ct.m_worker_name << ": " << message, log_level) +#define LP_CC_WORKER_YELLOW( ct, message, log_level) LOG_PRINT_CC_YELLOW( ct, "WORKER " << ct.m_worker_name << ": " << message, log_level) +#define LP_CC_WORKER_CYAN( ct, message, log_level) LOG_PRINT_CC_CYAN( ct, "WORKER " << ct.m_worker_name << ": " << message, log_level) +#define LP_CC_WORKER_MAGENTA( ct, message, log_level) LOG_PRINT_CC_MAGENTA( ct, "WORKER " << ct.m_worker_name << ": " << message, log_level) + +#define HR_TO_STREAM_IN_MHS_1P(hr) std::fixed << std::setprecision(1) << hr / 1000000.0 +#define HR_TO_STREAM_IN_MHS_3P(hr) std::fixed << std::setprecision(3) << hr / 1000000.0 + +// debug stuff +#define DBG_NETWORK_DIFFICULTY 0 // if non-zero: use this value as net difficulty when checking shares (useful for debugging on testnet, recommended value is 160000000000ull) +#define DBG_CORE_ALWAYS_SYNCRONIZED 0 // if set to 1: allows the server to start even if the core is not syncronized, useful for debugging with --offline-mode +#define STRINGIZE_DETAIL(x) #x +#define STRINGIZE(x) STRINGIZE_DETAIL(x) +#define DP(x) LOG_PRINT_L0("LINE " STRINGIZE(__LINE__) ": " #x " = " << x) + +//============================================================================================================================== + struct vdiff_params_t + { + explicit vdiff_params_t() + : target_min(0) + , target_max(0) + , target_time_ms(0) + , retarget_time_ms(0) + , retarget_shares_count(0) + , variance_percent(0) + {} + + vdiff_params_t(uint64_t target_min, uint64_t target_max, uint64_t target_time_s, uint64_t retarget_time_s, uint64_t retarget_shares_count, uint64_t variance_percent) + : target_min(target_min) + , target_max(target_max) + , target_time_ms(target_time_s * 1000) + , retarget_time_ms(retarget_time_s * 1000) + , retarget_shares_count(retarget_shares_count) + , variance_percent(variance_percent) + {} + + uint64_t target_min; + uint64_t target_max; + uint64_t target_time_ms; + uint64_t retarget_time_ms; + uint64_t retarget_shares_count; + uint64_t variance_percent; + }; + + struct stratum_connection_context : public epee::net_utils::connection_context_base + { + explicit stratum_connection_context() + : m_worker_name("?") + , m_worker_difficulty(1) + , m_ts_started(0) + , m_ts_share_period_timer(0) + , m_ts_difficulty_updated(0) + , m_valid_shares_count(0) + , m_wrong_shares_count(0) + , m_hashes_calculated(0) + , m_blocks_count(0) + {} + + void set_worker_name(const std::string& worker_name) + { + CRITICAL_REGION_LOCAL(m_lock); + m_worker_name = worker_name; + } + + uint64_t get_hr_estimate_duration() + { + CRITICAL_REGION_LOCAL(m_lock); + return (epee::misc_utils::get_tick_count() - m_ts_started) / 1000; + } + + uint64_t estimate_worker_hashrate() + { + CRITICAL_REGION_LOCAL(m_lock); + if (m_ts_started == 0) + return 0; + uint64_t duration = (epee::misc_utils::get_tick_count() - m_ts_started) / 1000; + if (duration == 0) + return 0; + return (m_hashes_calculated / duration).convert_to(); + } + + uint64_t get_average_share_period_ms() + { + CRITICAL_REGION_LOCAL(m_lock); + if (m_ts_share_period_timer == 0) + return 0; + uint64_t duration_ms = (epee::misc_utils::get_tick_count() - m_ts_share_period_timer); + if (m_valid_shares_count == 0) + return 0; + return duration_ms / m_valid_shares_count; + } + + void reset_average_share_period_ms() + { + CRITICAL_REGION_LOCAL(m_lock); + m_ts_share_period_timer = epee::misc_utils::get_tick_count(); + m_valid_shares_count = 0; + } + + void set_worker_difficulty(const wide_difficulty_type& d) + { + CRITICAL_REGION_LOCAL(m_lock); + m_worker_difficulty = d; + m_ts_difficulty_updated = epee::misc_utils::get_tick_count(); + } + + void init_and_start_timers(const vdiff_params_t& vd_params) + { + CRITICAL_REGION_LOCAL(m_lock); + m_ts_started = epee::misc_utils::get_tick_count(); + m_vd_params = vd_params; + set_worker_difficulty(m_vd_params.target_min); + reset_average_share_period_ms(); + } + + wide_difficulty_type get_worker_difficulty() + { + CRITICAL_REGION_LOCAL(m_lock); + return m_worker_difficulty; + } + + // returns true if worker difficulty has just been changed + bool adjust_worker_difficulty_if_needed() + { + CRITICAL_REGION_LOCAL(m_lock); + + // check retarget condition if 1) there're too many shares received; 2) difficulty was updated long enough time ago + if (m_valid_shares_count >= m_vd_params.retarget_shares_count || + epee::misc_utils::get_tick_count() - m_ts_difficulty_updated > m_vd_params.retarget_time_ms) + { + int64_t average_share_period_ms = 0; + wide_difficulty_type new_d = 0; + if (m_valid_shares_count != 0) + { + // there were shares, calculate using average share period + average_share_period_ms = static_cast(get_average_share_period_ms()); + if (average_share_period_ms != 0 && + uint64_t(llabs(average_share_period_ms - int64_t(m_vd_params.target_time_ms))) > m_vd_params.target_time_ms * m_vd_params.variance_percent / 100) + { + new_d = m_worker_difficulty * m_vd_params.target_time_ms / average_share_period_ms; + } + } + else + { + // no shares are found during retarget_time_ms, perhaps the difficulty is too high, lower it significantly + new_d = (m_vd_params.target_min + m_worker_difficulty) / 4; + } + + if (new_d != 0) + { + if (new_d < m_vd_params.target_min) + new_d = m_vd_params.target_min; + if (new_d > m_vd_params.target_max) + new_d = m_vd_params.target_max; + + if (new_d != m_worker_difficulty) + { + LP_CC_WORKER_YELLOW((*this), "difficulty update: " << m_worker_difficulty << " -> " << new_d << + " (av. share pediod was: " << average_share_period_ms << ", target: " << m_vd_params.target_time_ms << + ", shares: " << m_valid_shares_count << ", variance: " << int64_t(100 * average_share_period_ms / m_vd_params.target_time_ms - 100) << "%)", LOG_LEVEL_2); + set_worker_difficulty(new_d); + reset_average_share_period_ms(); + return true; + } + } + } + return false; + } + + void increment_normal_shares_count() + { + CRITICAL_REGION_LOCAL(m_lock); + ++m_valid_shares_count; + m_hashes_calculated += m_worker_difficulty; + } + + void increment_stale_shares_count() + { + CRITICAL_REGION_LOCAL(m_lock); + ++m_valid_shares_count; + m_hashes_calculated += m_worker_difficulty; + } + + void increment_wrong_shares_count() + { + //++m_wrong_shares_count; not implemented yet + } + + void increment_blocks_count() + { + CRITICAL_REGION_LOCAL(m_lock); + ++m_blocks_count; + } + + size_t get_blocks_count() + { + CRITICAL_REGION_LOCAL(m_lock); + return m_blocks_count; + } + + uint64_t get_current_valid_shares_count() + { + CRITICAL_REGION_LOCAL(m_lock); + return m_valid_shares_count; + } + + mutable epee::critical_section m_lock; + std::string m_worker_name; + wide_difficulty_type m_worker_difficulty; + uint64_t m_ts_started; + uint64_t m_ts_share_period_timer; + uint64_t m_ts_difficulty_updated; + size_t m_valid_shares_count; // number of shares that satisfy worker's difficulty (valid + stale) + size_t m_wrong_shares_count; + size_t m_blocks_count; + wide_difficulty_type m_hashes_calculated; + vdiff_params_t m_vd_params; + }; // struct stratum_connection_context + +//============================================================================================================================== + template + class stratum_protocol_handler; + + template + struct stratum_protocol_handler_config : public i_blockchain_update_listener + { + typedef stratum_protocol_handler_config this_t; + typedef stratum_protocol_handler protocol_handler_t; + + stratum_protocol_handler_config() + : m_max_packet_size(10240) + , m_p_core(nullptr) + , m_network_difficulty(0) + , m_miner_addr(null_pub_addr) + , m_block_template_ethash(null_hash) + , m_blockchain_last_block_id(null_hash) + , m_block_template_height(0) + , m_block_template_update_ts(0) + , m_last_ts_total_hr_was_printed(epee::misc_utils::get_tick_count()) + , m_total_hr_print_interval_ms(STRATUM_TOTAL_HR_PRINT_INTERVAL_S_DEFAULT * 1000) + , m_block_template_update_pediod_ms(STRATUM_BLOCK_TEMPLATE_UPD_PERIOD_DEFAULT * 1000) + , m_nameless_worker_id(0) + , m_total_blocks_found(0) + , m_stop_flag(false) + , m_blocktemplate_update_thread(&this_t::block_template_update_thread, this) + , m_is_core_always_online(false) + { + LOG_PRINT_L4("stratum_protocol_handler_config::ctor()"); + } + + ~stratum_protocol_handler_config() + { + LOG_PRINT_L4("stratum_protocol_handler_config::dtor()"); + + m_stop_flag = true; + m_blocktemplate_update_thread.join(); + + if (m_p_core) + m_p_core->remove_blockchain_update_listener(this); + } + + void add_protocol_handler(protocol_handler_t* p_ph) + { + CRITICAL_REGION_BEGIN(m_ph_map_lock); + m_protocol_handlers[p_ph->get_context().m_connection_id] = p_ph; + CRITICAL_REGION_END(); + LOG_PRINT_CC(p_ph->get_context(), "stratum_protocol_handler_config: protocol handler added", LOG_LEVEL_4); + //m_pcommands_handler->on_connection_new(pconn->m_connection_context); + } + + void remove_protocol_handler(protocol_handler_t* p_ph) + { + CRITICAL_REGION_BEGIN(m_ph_map_lock); + m_protocol_handlers.erase(p_ph->get_context().m_connection_id); + CRITICAL_REGION_END(); + LOG_PRINT_CC(p_ph->get_context(), "stratum_protocol_handler_config: protocol handler removed", LOG_LEVEL_4); + //m_pcommands_handler->on_connection_close(pconn->m_connection_context); + } + + void test() + { + //protocol_handler_t* p_ph = m_protocol_handlers.begin()->second; + //std::string test = " \t { \n \"{ \\\\ \":\"}\", \"id\":1,\"jsonrpc\":\"2.0\",\"result\":[\"0x63de85850f7e02baba2dc0765ebfb01040e56354729be70358ff341b48c608ad\",\"0xa92afa474bb50595e467a1722ed7a74fc00b3307de5022d5b76cf979490f2222\",\"0x00000000dbe6fecebdedd5beb573440e5a884d1b2fbf06fcce912adcb8d8422e\"]}"; + //std::string test = "{\"error\": [0], \"id\" : 555, \"result\" : \"AAA!\"}"; + //std::string test = "{\"id\":10,\"method\":\"eth_submitWork\",\"params\":[\"0x899624c0078e824f\",\"0xb98617aec14a2872fb45ab755f6273a1ae719d0ff0d441a25bb8235d82cb4123\",\"0x30f599f39276df17656727f16c3230c072dd8f2dd780161625479d352e8b2a97\"]}"; + //std::string test = "{\"id\":10,\"method\":\"eth_submitWork\",\"parasms\":[\"0x899624c0078e824f\"]}"; + //std::string test = R"({"worker": "", "jsonrpc": "2.0", "params": [], "id": 3, "method": "eth_getWork"})"; + //std::string test = R"({"worker": "eth1.0", "jsonrpc": "2.0", "params": ["HeyPnNRKwWzPF3JQMi1dcTJBRr3anA3iEMyY5vokAusYj73grFg8VhiYgWXJ4S31oT5ZV7rCjXn3QgZxQ9xr6DQJ1LThkj3", "x"], "id": 2, "method": "eth_submitLogin"})"; + //p_ph->handle_recv(test.c_str(), test.size()); + } + + void block_template_update_thread() + { + log_space::log_singletone::set_thread_log_prefix("[ST]"); + while (!m_stop_flag) + { + if (is_core_syncronized() && epee::misc_utils::get_tick_count() - m_block_template_update_ts >= m_block_template_update_pediod_ms) + { + update_block_template(); + } + print_total_hashrate_if_needed(); + epee::misc_utils::sleep_no_w(200); + } + } + + bool update_block_template(bool enforce_update = false) + { + CRITICAL_REGION_LOCAL(m_work_change_lock); + uint64_t stub; + crypto::hash top_block_id = null_hash; + m_p_core->get_blockchain_top(stub, top_block_id); + if (!enforce_update && top_block_id == m_blockchain_last_block_id && epee::misc_utils::get_tick_count() - m_block_template_update_ts < m_block_template_update_pediod_ms) + return false;// no new blocks since last update, keep the same work + + LOG_PRINT("stratum_protocol_handler_config::update_block_template(" << (enforce_update ? "true" : "false") << ")", LOG_LEVEL_4); + m_block_template = AUTO_VAL_INIT(m_block_template); + wide_difficulty_type block_template_difficulty; + blobdata extra = AUTO_VAL_INIT(extra); + bool r = m_p_core->get_block_template(m_block_template, m_miner_addr, m_miner_addr, block_template_difficulty, m_block_template_height, extra); + CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); +#if DBG_NETWORK_DIFFICULTY == 0 + m_network_difficulty = block_template_difficulty; +#else + m_network_difficulty = DBG_NETWORK_DIFFICULTY; // for debug purpose only +#endif + m_blockchain_last_block_id = top_block_id; + + m_block_template_hash_blob = get_block_hashing_blob(m_block_template); + if (access_nonce_in_block_blob(m_block_template_hash_blob) != 0) + { + LOG_PRINT_RED("non-zero nonce in generated block template", LOG_LEVEL_0); + access_nonce_in_block_blob(m_block_template_hash_blob) = 0; + } + m_prev_block_template_ethash = m_block_template_ethash; + m_block_template_ethash = crypto::cn_fast_hash(m_block_template_hash_blob.data(), m_block_template_hash_blob.size()); + m_block_template_update_ts = epee::misc_utils::get_tick_count(); + + set_work_for_all_workers(); // notify all workers of updated work + + return true; + } + + void set_work_for_all_workers(protocol_handler_t* ph_to_skip = nullptr) + { + LOG_PRINT("stratum_protocol_handler_config::set_work_for_all_workers()", LOG_LEVEL_4); + CRITICAL_REGION_LOCAL(m_ph_map_lock); + for (auto& ph : m_protocol_handlers) + { + if (ph.second == ph_to_skip) + continue; + ph.second->get_context().adjust_worker_difficulty_if_needed(); // some miners seem to not give a f*ck about updated job taget if the block hash wasn't changed, so change difficulty only on work update + std::string new_work_json = get_work_json(ph.second->get_context().get_worker_difficulty()); + ph.second->set_work(new_work_json); + ph.second->send_notification(new_work_json); + } + } + + std::string get_work_json(const wide_difficulty_type& worker_difficulty) + { + CRITICAL_REGION_LOCAL(m_work_change_lock); + if (!is_core_syncronized()) + return R"("result":[])"; + + crypto::hash target_boundary = null_hash; + difficulty_to_boundary_long(worker_difficulty, target_boundary); + + ethash_hash256 seed_hash = ethash_calculate_epoch_seed(ethash_height_to_epoch(m_block_template_height)); + return R"("result":[")" + pod_to_net_format(m_block_template_ethash) + R"(",")" + pod_to_net_format(seed_hash) + R"(",")" + pod_to_net_format_reverse(target_boundary) + R"(",")" + pod_to_net_format_reverse(m_block_template_height) + R"("])"; + } + + void update_work(protocol_handler_t* p_ph) + { + LOG_PRINT_CC(p_ph->get_context(), "stratum_protocol_handler_config::update_work()", LOG_LEVEL_4); + bool updated = false; + if (is_core_syncronized()) + { + updated = update_block_template(); + } + else + { + LP_CC_WORKER_YELLOW(p_ph->get_context(), "core is NOT synchronized, respond with empty job package", LOG_LEVEL_2); + } + + if (!updated) + p_ph->set_work(get_work_json(p_ph->get_context().get_worker_difficulty())); + } + + bool handle_work(protocol_handler_t* p_ph, const jsonrpc_id_t& id, const std::string& worker, uint64_t nonce, const crypto::hash& block_ethash) + { + CRITICAL_REGION_LOCAL(m_work_change_lock); + bool r = false; + + if (!is_core_syncronized()) + { + // TODO: make an option for more aggressive mining in case there's a little difference in blockchain size (1..2) + LP_CC_WORKER_BLUE(p_ph->get_context(), "Work received, but the core is NOT syncronized. Skip...", LOG_LEVEL_1); + p_ph->send_response_default(id); + return true; + } + + const uint64_t height = get_block_height(m_block_template); + + // make sure worker sent work with correct block ethash + if (block_ethash != m_block_template_ethash) + { + if (block_ethash == m_prev_block_template_ethash) + { + // Got stale share, do nothing. In future it can be used for more aggressive mining strategies + LP_CC_WORKER_BLUE(p_ph->get_context(), "got stale share, skip it", LOG_LEVEL_1); + p_ph->send_response_default(id); + p_ph->get_context().increment_stale_shares_count(); + return true; + } + + LP_CC_WORKER_RED(p_ph->get_context(), "wrong work submitted, ethhash " << block_ethash << ", expected: " << m_block_template_ethash, LOG_LEVEL_0); + p_ph->send_response_error(id, JSONRPC_ERROR_CODE_DEFAULT, "wrong work"); + p_ph->get_context().increment_wrong_shares_count(); + return false; + } + + crypto::hash block_pow_hash = get_block_longhash(height, m_block_template_ethash, nonce); + wide_difficulty_type worker_difficulty = p_ph->get_context().get_worker_difficulty(); + + if (!check_hash(block_pow_hash, worker_difficulty)) + { + LP_CC_WORKER_RED(p_ph->get_context(), "block pow hash " << block_pow_hash << " doesn't meet worker difficulty: " << worker_difficulty << ENDL << + "nonce: " << nonce << " (0x" << epee::string_tools::pod_to_hex(nonce) << ")", LOG_LEVEL_0); + p_ph->send_response_error(id, JSONRPC_ERROR_CODE_DEFAULT, "not enough work was done"); + p_ph->get_context().increment_wrong_shares_count(); + return false; + } + + p_ph->send_response_default(id); + p_ph->get_context().increment_normal_shares_count(); + m_shares_per_minute.chick(); + + if (!check_hash(block_pow_hash, m_network_difficulty)) + { + // work is enough for worker difficulty, but not enough for network difficulty -- it's okay, move on! + LP_CC_WORKER_GREEN(p_ph->get_context(), "share found for difficulty " << worker_difficulty << ", nonce: 0x" << epee::string_tools::pod_to_hex(nonce), LOG_LEVEL_1); + LP_CC_WORKER_GREEN(p_ph->get_context(), "shares: " << p_ph->get_context().get_current_valid_shares_count() << ", share period av: " << p_ph->get_context().get_average_share_period_ms() << ", target: " << p_ph->get_context().m_vd_params.target_time_ms + << ", variance: " << int64_t(100 * p_ph->get_context().get_average_share_period_ms() / p_ph->get_context().m_vd_params.target_time_ms - 100) << " %", LOG_LEVEL_3); + return true; + } + + // seems we've just found a block! + // create a block template and push it to the core + m_block_template.nonce = nonce; + crypto::hash block_hash = get_block_hash(m_block_template); + + LP_CC_WORKER_GREEN(p_ph->get_context(), "block found " << block_hash << " at height " << height << " for difficulty " << m_network_difficulty << " pow: " << block_pow_hash << ENDL << + "nonce: " << nonce << " (0x" << epee::string_tools::pod_to_hex(nonce) << ")", LOG_LEVEL_1); + + block_verification_context bvc = AUTO_VAL_INIT(bvc); + r = m_p_core->handle_incoming_block(m_block_template, bvc, false); + if (r) + { + if (!bvc.m_verification_failed && !bvc.added_to_altchain && bvc.m_added_to_main_chain && !bvc.m_already_exists && !bvc.m_marked_as_orphaned) + { + LP_CC_WORKER_GREEN(p_ph->get_context(), "found block " << block_hash << " at height " << height << " was successfully added to the blockchain, difficulty " << m_network_difficulty, LOG_LEVEL_0); + r = update_block_template(); + CHECK_AND_ASSERT_MES_NO_RET(r, "Stratum: internal error. Block template wasn't updated as expected after handling found block."); + p_ph->get_context().increment_blocks_count(); + ++m_total_blocks_found; + } + else + { + LP_CC_WORKER_RED(p_ph->get_context(), "block " << block_hash << " at height " << height << " was NOT added to the blockchain:" << ENDL << + " verification_failed: " << bvc.m_verification_failed << ENDL << + " added_to_altchain: " << bvc.added_to_altchain << ENDL << + " added_to_main_chain: " << bvc.m_added_to_main_chain << ENDL << + " already_exists: " << bvc.m_already_exists << ENDL << + " marked_as_orphaned: " << bvc.m_marked_as_orphaned, LOG_LEVEL_0); + } + } + else + { + LP_CC_WORKER_RED(p_ph->get_context(), "block " << block_hash << " was rejected by the core", LOG_LEVEL_0); + } + + return true; + } + + bool handle_login(protocol_handler_t* p_ph, const jsonrpc_id_t& id, const std::string& user_str, const std::string& pass_str, const std::string& worker_str, uint64_t start_difficulty) + { + CRITICAL_REGION_LOCAL(m_work_change_lock); + bool r = false, error = false; + std::stringstream error_str; + + if (user_str == WORKER_ALLOWED_USERNAME) + { + // it's a valid login only in case miner address was already set + if (m_miner_addr == null_pub_addr) + { + error = true; + error_str << "trying to log in with '" WORKER_ALLOWED_USERNAME "' username, while mining address WAS NOT previously set in daemon. Set mining address in daemon OR use it as a username."; + } + } + else + { + // mining address is used as username, make sure it's correct and match with previously set + account_public_address address = null_pub_addr; + r = get_account_address_from_str(address, user_str); + if (!r) + { + error = true; + error_str << "can't parse wallet address from username: " << user_str << "."; + } + + if (m_miner_addr != null_pub_addr && address != m_miner_addr) + { + error = true; + error_str << "wallet address " << user_str << " doesn't match the address previously set in daemon and/or other workers."; + } + + set_miner_address(address); + } + + if (error) + { + LP_CC_WORKER_RED(p_ph->get_context(), error_str.str() << " Connection will be dropped.", LOG_LEVEL_0); + p_ph->send_response_error(id, JSONRPC_ERROR_CODE_DEFAULT, error_str.str()); + return false; + } + + p_ph->get_context().set_worker_name(worker_str); + if (start_difficulty != 0) + p_ph->get_context().set_worker_difficulty(start_difficulty); + + LP_CC_WORKER_GREEN(p_ph->get_context(), "logged in with username " << user_str << ", start difficulty: " << (start_difficulty != 0 ? std::to_string(start_difficulty) : "default"), LOG_LEVEL_0); + p_ph->send_response_default(id); + + // send initial work + update_work(p_ph); + + return true; + } + + bool handle_submit_hashrate(protocol_handler_t* p_ph, uint64_t rate, const crypto::hash& rate_submit_id) + { + LP_CC_WORKER_CYAN(p_ph->get_context(), "reported hashrate: " << HR_TO_STREAM_IN_MHS_3P(rate) << " Mh/s" << + ", estimated hashrate: " << HR_TO_STREAM_IN_MHS_3P(p_ph->get_context().estimate_worker_hashrate()) << " Mh/s, run time: " << + epee::misc_utils::get_time_interval_string(p_ph->get_context().get_hr_estimate_duration()), LOG_LEVEL_3); + return true; + } + + // required member for epee::net_utils::boosted_tcp_server concept + void on_send_stop_signal() + { + LOG_PRINT_L4("stratum_protocol_handler_config::on_send_stop_signal()"); + CRITICAL_REGION_LOCAL(m_ph_map_lock); + m_protocol_handlers.clear(); + } + + // i_blockchain_update_listener member + virtual void on_blockchain_update() override + { + LOG_PRINT_L3("stratum_protocol_handler_config::on_blockchain_update()"); + + if (!is_core_syncronized()) + return; // don't notify workers when blockchain is synchronizing + + update_block_template(); + } + + void set_core(currency::core* c) + { + m_p_core = c; + m_p_core->add_blockchain_update_listener(this); + } + + void set_is_core_always_online(bool is_core_always_online) + { + m_is_core_always_online = is_core_always_online; + } + + void set_miner_address(const account_public_address& miner_addr) + { + m_miner_addr = miner_addr; + } + + bool is_core_syncronized() + { + if (!m_p_core) + return false; + +#if DBG_CORE_ALWAYS_SYNCRONIZED == 1 + return true; // standalone mode, usefull for debugging WITH --offline-mode option +#endif + if (m_is_core_always_online) + return true; + + // TODO!!! Bad design, need more correct way of getting this information + currency::i_currency_protocol* proto = m_p_core->get_protocol(); + currency::t_currency_protocol_handler* protocol = dynamic_cast*>(proto); + if (!protocol) + return false; + return protocol->is_synchronized(); + } + + void set_vdiff_params(const vdiff_params_t& p) + { + m_vdiff_params = p; + } + + const vdiff_params_t& get_vdiff_params() const + { + return m_vdiff_params; + } + + void print_total_hashrate_if_needed() + { + if (epee::misc_utils::get_tick_count() - m_last_ts_total_hr_was_printed < m_total_hr_print_interval_ms) + return; + + if (!is_core_syncronized()) + { + LOG_PRINT_L0("Blockchain is synchronizing..."); + } + + CRITICAL_REGION_LOCAL(m_ph_map_lock); + if (m_protocol_handlers.empty()) + { + LOG_PRINT_CYAN("Blocks found: [" << m_total_blocks_found << "], no miners connected", LOG_LEVEL_0); + } + else + { + std::stringstream ss; + uint64_t total_reported_hr = 0, total_estimated_hr = 0; + for (auto& ph : m_protocol_handlers) + { + uint64_t reported_hr = 0, estimated_hr = 0; + ph.second->get_hashrate(reported_hr, estimated_hr); + total_reported_hr += reported_hr; + total_estimated_hr += estimated_hr; + ss << ph.second->get_context().m_worker_name << ": [" << ph.second->get_context().get_blocks_count() << "] " << HR_TO_STREAM_IN_MHS_1P(reported_hr) << " (" << HR_TO_STREAM_IN_MHS_1P(estimated_hr) << "), "; + } + auto s = ss.str(); + LOG_PRINT_CYAN("Blocks found: [" << m_total_blocks_found << "], total speed: " << HR_TO_STREAM_IN_MHS_3P(total_reported_hr) << " Mh/s as reported by miners (" << HR_TO_STREAM_IN_MHS_3P(total_estimated_hr) << " Mh/s estimated by the server), current shares/min: " << m_shares_per_minute.get_speed() << ENDL << + m_protocol_handlers.size() << " worker(s): " << s.substr(0, s.length() > 2 ? s.length() - 2 : 0), LOG_LEVEL_0); + } + + m_last_ts_total_hr_was_printed = epee::misc_utils::get_tick_count(); + } + + void set_total_hr_print_interval_s(uint64_t s) + { + m_total_hr_print_interval_ms = s * 1000; + } + + void set_block_template_update_period(uint64_t s) + { + m_block_template_update_pediod_ms = s * 1000; + } + + size_t get_number_id_for_nameless_worker() + { + CRITICAL_REGION_LOCAL(m_generic_lock); + return m_nameless_worker_id++; + } + + + size_t m_max_packet_size; + + private: + typedef std::unordered_map > protocol_handlers_map; + typedef epee::math_helper::speed<60 * 1000 /* ms */> shares_per_minute_rate_t; + + protocol_handlers_map m_protocol_handlers; + mutable epee::critical_section m_ph_map_lock; + mutable epee::critical_section m_work_change_lock; + mutable epee::critical_section m_generic_lock; + + // job data + block m_block_template; + std::string m_block_template_hash_blob; + crypto::hash m_block_template_ethash; + crypto::hash m_blockchain_last_block_id; + uint64_t m_block_template_height; + std::atomic m_block_template_update_ts; + + // previous job (for handling stale shares) + crypto::hash m_prev_block_template_ethash; + + vdiff_params_t m_vdiff_params; + wide_difficulty_type m_network_difficulty; + + core* m_p_core; + account_public_address m_miner_addr; // all workers will share the same miner address + std::atomic m_last_ts_total_hr_was_printed; + uint64_t m_total_hr_print_interval_ms; + uint64_t m_block_template_update_pediod_ms; + size_t m_nameless_worker_id; + size_t m_total_blocks_found; + shares_per_minute_rate_t m_shares_per_minute; + bool m_is_core_always_online; + + std::atomic m_stop_flag; + std::thread m_blocktemplate_update_thread; + }; // struct stratum_protocol_handler_config + + //============================================================================================================================== + + template + class stratum_protocol_handler + { + public: + typedef stratum_protocol_handler this_t; + typedef epee::net_utils::connection connection_t; + + typedef connection_context_t connection_context; // required type for epee::net_utils::boosted_tcp_server concept + typedef stratum_protocol_handler_config config_type; // required type for epee::net_utils::boosted_tcp_server concept + + // required member for epee::net_utils::boosted_tcp_server concept + stratum_protocol_handler(connection_t* p_connection, config_type& config, connection_context_t& context) + : m_p_connection(p_connection) + , m_config(config) + , m_context(context) + , m_connection_initialized(false) + , m_last_reported_hashrate(0) + { + LOG_PRINT_CC(m_context, "stratum_protocol_handler::ctor()", LOG_LEVEL_4); + } + + ~stratum_protocol_handler() + { + if (m_connection_initialized) + { + m_config.remove_protocol_handler(this); + m_connection_initialized = false; + } + + LOG_PRINT_CC(m_context, "stratum_protocol_handler::dtor()", LOG_LEVEL_4); + } + + // required member for epee::net_utils::boosted_tcp_server concept + bool handle_recv(const void* p_data, size_t data_size) + { + const char* str = static_cast(p_data); + + if (!m_connection_initialized) + return false; + + if (data_size > m_config.m_max_packet_size) + { + LP_CC_WORKER_RED(m_context, "Maximum packet size exceeded! maximum: " << m_config.m_max_packet_size << ", received: " << data_size << ". Connection will be closed.", LOG_LEVEL_0); + return false; + } + + m_json_helper.feed(str, data_size); + LP_CC_WORKER(m_context, "data received: " << data_size << " bytes:" << ENDL << std::string(str, data_size), LOG_LEVEL_4); + + if (m_json_helper.has_objects()) + { + std::string json; + while (m_json_helper.pop_object(json)) + { + epee::serialization::portable_storage ps; + if (ps.load_from_json(json)) + { + if (!handle_json_request(ps, json)) + { + LP_CC_WORKER_RED(m_context, "JSON request handling failed. JSON:" << ENDL << json << ENDL, LOG_LEVEL_1); + } + } + else + { + LP_CC_WORKER_RED(m_context, "JSON object detected, but can't be parsed. JSON:" << ENDL << json << ENDL, LOG_LEVEL_1); + } + } + } + + return true; + } + + bool handle_json_request(epee::serialization::portable_storage& ps, const std::string& json) + { + std::stringstream error_stream; + jsonrpc_id_t id = jsonrpc_id_null; + read_jsonrpc_id(ps, id); + + std::string method; + if (ps_get_value_noexcept(ps, "method", method, nullptr)) + { + epee::serialization::portable_storage::hsection params_section = ps.open_section("params", nullptr); + auto handler_it = m_methods_handlers.find(method); + if (handler_it == m_methods_handlers.end()) + { + error_stream << "unknown method is requested: " << method << ENDL << "JSON request: " << json; + LP_CC_WORKER_RED(m_context, error_stream.str(), LOG_LEVEL_1); + send_response_error(id, JSONRPC_ERROR_CODE_METHOD_NOT_FOUND, error_stream.str()); + return false; + } + + return (this->*(handler_it->second))(id, ps, params_section); + } + + // if it's no a method call -- it should be result + std::string result; + if (ps_get_value_noexcept(ps, "result", result, nullptr)) + { + std::string error; + ps_get_value_noexcept(ps, "error", error, nullptr); + epee::serialization::portable_storage::hsection error_section = ps.open_section("error", nullptr); + if (error_section != nullptr || !error.empty()) + { + LP_CC_WORKER_RED(m_context, "received an error: " << json, LOG_LEVEL_1); + return true; // means it is handled ok + } + } + + LP_CC_WORKER_YELLOW(m_context, "Unrecongized request received: " << json, LOG_LEVEL_2); + return true; // means it handled ok + } + + static void init() + { + if (m_methods_handlers.empty()) + { + m_methods_handlers.insert(std::make_pair("eth_submitLogin", &this_t::handle_method_eth_submitLogin)); + m_methods_handlers.insert(std::make_pair("eth_getWork", &this_t::handle_method_eth_getWork)); + m_methods_handlers.insert(std::make_pair("eth_submitHashrate", &this_t::handle_method_eth_submitHashrate)); + m_methods_handlers.insert(std::make_pair("eth_submitWork", &this_t::handle_method_eth_submitWork)); + } + } + + bool handle_method_eth_submitLogin(const jsonrpc_id_t& id, epee::serialization::portable_storage& ps, epee::serialization::portable_storage::hsection params_section) + { + std::string user_str, pass_str; + epee::serialization::harray params_array = ps.get_first_value("params", user_str, nullptr); + if (params_array != nullptr) + ps.get_next_value(params_array, pass_str); + + std::string worker_str; + ps_get_value_noexcept(ps, "worker", worker_str, nullptr); + if (worker_str.empty()) + worker_str = std::to_string(m_config.get_number_id_for_nameless_worker()); + + uint64_t start_difficulty = 0; // default + size_t start_diff_delim_pos = user_str.find('-'); + if (start_diff_delim_pos != std::string::npos) + { + // extract start difficulty from username presuming it complies format "username.difficulty" + std::string start_difficulty_str = user_str.substr(start_diff_delim_pos + 1); + TRY_ENTRY() + start_difficulty = std::stoull(start_difficulty_str); + CATCH_ENTRY_CUSTOM("submitLogin", { LOG_PRINT_L0(worker_str << ": Can't parse start difficulty from " << start_difficulty_str); }, false); + user_str = user_str.substr(0, start_diff_delim_pos); + } + + LOG_PRINT_CC(m_context, "Stratum [submitLogin] USER: " << user_str << ", pass: " << pass_str << ", worker: " << worker_str << ", start diff.: " << (start_difficulty == 0 ? std::string("default") : std::to_string(start_difficulty)), LOG_LEVEL_3); + return m_config.handle_login(this, id, user_str, pass_str, worker_str, start_difficulty); + } + + bool handle_method_eth_getWork(const jsonrpc_id_t& id, epee::serialization::portable_storage& ps, epee::serialization::portable_storage::hsection params_section) + { + m_config.update_work(this); + + CRITICAL_REGION_LOCAL(m_work_change_lock); + if (!m_cached_work_json.empty()) + send_response(id, m_cached_work_json); + + return true; + } + + bool handle_method_eth_submitHashrate(const jsonrpc_id_t& id, epee::serialization::portable_storage& ps, epee::serialization::portable_storage::hsection params_section) + { + std::string rate_str, rate_submit_id_str; + epee::serialization::harray params_array = ps.get_first_value("params", rate_str, nullptr); + bool r = params_array != nullptr && ps.get_next_value(params_array, rate_submit_id_str); + CHECK_AND_ASSERT_MES(r, false, "Incorrect parameters"); + + uint64_t rate = 0; + CHECK_AND_ASSERT_MES(pod_from_net_format_reverse(rate_str, rate, true), false, "Can't parse rate from " << rate_str); + crypto::hash rate_submit_id = null_hash; + CHECK_AND_ASSERT_MES(pod_from_net_format(rate_submit_id_str, rate_submit_id), false, "Can't parse rate_submit_id from " << rate_submit_id_str); + + m_last_reported_hashrate = rate; + return m_config.handle_submit_hashrate(this, rate, rate_submit_id); + } + + bool handle_method_eth_submitWork(const jsonrpc_id_t& id, epee::serialization::portable_storage& ps, epee::serialization::portable_storage::hsection params_section) + { + bool r = true; + std::string nonce_str, header_str, mixhash_str; + epee::serialization::harray params_array = ps.get_first_value("params", nonce_str, nullptr); + r = params_array != nullptr && ps.get_next_value(params_array, header_str); + r = params_array != nullptr && ps.get_next_value(params_array, mixhash_str); + CHECK_AND_ASSERT_MES(r, false, "Incorrect parameters"); + + std::string worker; + ps_get_value_noexcept(ps, "worker", worker, nullptr); + + uint64_t nonce = 0; + CHECK_AND_ASSERT_MES(pod_from_net_format_reverse(nonce_str, nonce, true), false, "Can't parse nonce from " << nonce_str); + crypto::hash header_hash = null_hash; + CHECK_AND_ASSERT_MES(pod_from_net_format(header_str, header_hash), false, "Can't parse header hash from " << header_str); + + return m_config.handle_work(this, id, worker, nonce, header_hash); + } + + void send(const std::string& data) + { + static_cast(m_p_connection)->do_send(data.c_str(), data.size()); + LOG_PRINT_CC(m_context, "DATA sent >>>>>>>>>>>>> " << ENDL << data, LOG_LEVEL_4); + } + + void send_notification(const std::string& json) + { + // JSON-RPC 2.0 spec: "A Notification is a Request object without an "id" member." + send(R"({"jsonrpc":"2.0",)" + json + "}" "\n"); // LF character is not specified by JSON-RPC standard, but it is REQUIRED by ethminer 0.12 to work + } + + void send_response_method(const jsonrpc_id_t& id, const std::string& method, const std::string& response) + { + send_response(id, std::string(R"("method":")") + method + R"(",)" + response); + } + + void send_response(const jsonrpc_id_t& id, const std::string& response) + { + send(R"({"jsonrpc":"2.0","id":)" + jsonrpc_id_to_value_str(id) + "," + response + "}" "\n"); // LF character is not specified by JSON-RPC standard, but it is REQUIRED by ethminer 0.12 to work + } + + void send_response_default(const jsonrpc_id_t& id) + { + send_response(id, R"("result":true)"); + } + + void send_response_error(const jsonrpc_id_t& id, int64_t error_code, const std::string& error_message) + { + send_response(id, R"("error":{"code":)" + std::to_string(error_code) + R"(,"message":")" + error_message + R"("})"); + } + + void set_work(const std::string& json) + { + CRITICAL_REGION_LOCAL(m_work_change_lock); + if (m_cached_work_json != json) + { + LP_CC_WORKER(m_context, "work updated: " << json, LOG_LEVEL_2); + } + m_cached_work_json = json; + } + + // required member for epee::net_utils::boosted_tcp_server concept + void handle_qued_callback() + { + } + + // required member for epee::net_utils::boosted_tcp_server concept + bool after_init_connection() + { + LOG_PRINT_CC(m_context, "stratum_protocol_handler::after_init_connection()", LOG_LEVEL_4); + if (!m_connection_initialized) + { + m_connection_initialized = true; + m_config.add_protocol_handler(this); + m_context.init_and_start_timers(m_config.get_vdiff_params()); + } + LP_CC_WORKER_CYAN(m_context, "connected", LOG_LEVEL_1); + return true; + } + + // required member for epee::net_utils::boosted_tcp_server concept + bool release_protocol() + { + LOG_PRINT_CC(m_context, "stratum_protocol_handler::release_protocol()", LOG_LEVEL_4); + LP_CC_WORKER(m_context, "disconnected", LOG_LEVEL_0); + return true; + } + + connection_context_t& get_context() { return m_context; } + const connection_context_t& get_context() const { return m_context; } + + void get_hashrate(uint64_t& last_reported_hr, uint64_t& estimated_hr) + { + last_reported_hr = m_last_reported_hashrate; + estimated_hr = m_context.estimate_worker_hashrate(); + } + + + private: + connection_t* m_p_connection; // m_p_connection owns this protocol handler as data member, so back link is a simple pointer + config_type& m_config; + connection_context_t& m_context; + + json_helper m_json_helper; + std::string m_cached_work_json; + + epee::critical_section m_work_change_lock; + uint64_t m_last_reported_hashrate; + + typedef bool (this_t::*method_handler_func_t)(const jsonrpc_id_t& id, epee::serialization::portable_storage& ps, epee::serialization::portable_storage::hsection params_section); + static std::unordered_map m_methods_handlers; + + std::atomic m_connection_initialized; + }; // class stratum_protocol_handler +//============================================================================================================================== + typedef stratum_protocol_handler protocol_handler_t; + typedef epee::net_utils::boosted_tcp_server tcp_server_t; + + // static memeber definition + template + std::unordered_map::method_handler_func_t> stratum_protocol_handler::m_methods_handlers; +} // anonumous namespace + +//------------------------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------------------------ +//------------------------------------------------------------------------------------------------------------------------------ +struct stratum_server_impl +{ + tcp_server_t server; +}; +//------------------------------------------------------------------------------------------------------------------------------ +stratum_server::stratum_server(core* c) + : m_p_core(c) +{ + m_impl = new stratum_server_impl(); +} +//------------------------------------------------------------------------------------------------------------------------------ +stratum_server::~stratum_server() +{ + delete m_impl; + m_impl = nullptr; +} +//------------------------------------------------------------------------------------------------------------------------------ +void stratum_server::init_options(boost::program_options::options_description& desc) +{ + stratum_protocol_handler::init(); + + command_line::add_arg(desc, arg_stratum); + command_line::add_arg(desc, arg_stratum_bind_ip); + command_line::add_arg(desc, arg_stratum_bind_port); + command_line::add_arg(desc, arg_stratum_threads); + command_line::add_arg(desc, arg_stratum_miner_address); + command_line::add_arg(desc, arg_stratum_vdiff_target_min); + command_line::add_arg(desc, arg_stratum_vdiff_target_max); + command_line::add_arg(desc, arg_stratum_vdiff_target_time); + command_line::add_arg(desc, arg_stratum_vdiff_retarget_time); + command_line::add_arg(desc, arg_stratum_vdiff_retarget_shares); + command_line::add_arg(desc, arg_stratum_vdiff_variance_percent); + command_line::add_arg(desc, arg_stratum_block_template_update_period); + command_line::add_arg(desc, arg_stratum_hr_print_interval); + command_line::add_arg(desc, arg_stratum_always_online); + +} +//------------------------------------------------------------------------------------------------------------------------------ +bool stratum_server::should_start(const boost::program_options::variables_map& vm) +{ + return command_line::get_arg(vm, arg_stratum); +} +//------------------------------------------------------------------------------------------------------------------------------ +bool stratum_server::init(const boost::program_options::variables_map& vm) +{ + bool r = false; + m_impl->server.set_threads_prefix("ST"); + + std::string bind_ip_str = command_line::get_arg(vm, arg_stratum_bind_ip); + std::string bind_port_str = command_line::get_arg(vm, arg_stratum_bind_port); + m_threads_count = command_line::get_arg(vm, arg_stratum_threads); + + auto& config = m_impl->server.get_config_object(); + config.set_core(m_p_core); + + if (command_line::has_arg(vm, arg_stratum_always_online)) + { + config.set_is_core_always_online(command_line::get_arg(vm, arg_stratum_always_online)); + } + + + if (command_line::has_arg(vm, arg_stratum_miner_address)) + { + std::string miner_address_str = command_line::get_arg(vm, arg_stratum_miner_address); + account_public_address miner_address = null_pub_addr; + r = get_account_address_from_str(miner_address, miner_address_str); + CHECK_AND_ASSERT_MES(r, false, "Stratum server: invalid miner address given: " << miner_address_str); + config.set_miner_address(miner_address); + } + + config.set_vdiff_params( + vdiff_params_t( + command_line::get_arg(vm, arg_stratum_vdiff_target_min), + command_line::get_arg(vm, arg_stratum_vdiff_target_max), + command_line::get_arg(vm, arg_stratum_vdiff_target_time), + command_line::get_arg(vm, arg_stratum_vdiff_retarget_time), + command_line::get_arg(vm, arg_stratum_vdiff_retarget_shares), + command_line::get_arg(vm, arg_stratum_vdiff_variance_percent) + ) + ); + + config.set_block_template_update_period(command_line::get_arg(vm, arg_stratum_block_template_update_period)); + + config.set_total_hr_print_interval_s(command_line::get_arg(vm, arg_stratum_hr_print_interval)); + + LOG_PRINT_L0("Stratum server: start listening at " << bind_ip_str << ":" << bind_port_str << "..."); + r = m_impl->server.init_server(bind_port_str, bind_ip_str); + CHECK_AND_ASSERT_MES(r, false, "Stratum server: initialization failure"); + + return true; +} +//------------------------------------------------------------------------------------------------------------------------------ +bool stratum_server::run(bool wait /* = true */) +{ + //m_impl->server.get_config_object().test(); + + LOG_PRINT("Stratum server: start net server with " << m_threads_count << " threads...", LOG_LEVEL_0); + if (!m_impl->server.run_server(m_threads_count, wait)) + { + LOG_ERROR("Stratum server: net server failure"); + return false; + } + + if (wait) + LOG_PRINT("Stratum server: net server stopped", LOG_LEVEL_0); + return true; +} +//------------------------------------------------------------------------------------------------------------------------------ +bool stratum_server::deinit() +{ + return m_impl->server.deinit_server(); +} +//------------------------------------------------------------------------------------------------------------------------------ +bool stratum_server::timed_wait_server_stop(uint64_t ms) +{ + return m_impl->server.timed_wait_server_stop(ms); +} +//------------------------------------------------------------------------------------------------------------------------------ +bool stratum_server::send_stop_signal() +{ + m_impl->server.send_stop_signal(); + return true; +} +//------------------------------------------------------------------------------------------------------------------------------ + +} // namespace currency diff --git a/src/stratum/stratum_server.h b/src/stratum/stratum_server.h new file mode 100644 index 00000000..7647e34e --- /dev/null +++ b/src/stratum/stratum_server.h @@ -0,0 +1,42 @@ +// Copyright (c) 2018-2019 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include +#include + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL "stratum" + +namespace currency +{ + class core; + struct stratum_server_impl; + + class stratum_server + { + public: + static void init_options(boost::program_options::options_description& desc); + static bool should_start(const boost::program_options::variables_map& vm); + + stratum_server(core* c); + ~stratum_server(); + bool init(const boost::program_options::variables_map& vm); + bool run(bool wait = true); + bool deinit(); + bool timed_wait_server_stop(uint64_t ms); + bool send_stop_signal(); + + private: + size_t m_threads_count; + + stratum_server_impl* m_impl; + core* m_p_core; + }; +} + +#undef LOG_DEFAULT_CHANNEL +#define LOG_DEFAULT_CHANNEL NULL diff --git a/src/version.h.in b/src/version.h.in index 974320d3..500e3e80 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -2,6 +2,6 @@ #define BUILD_COMMIT_ID "@VERSION@" #define PROJECT_VERSION "1.0" -#define PROJECT_VERSION_BUILD_NO 9 +#define PROJECT_VERSION_BUILD_NO 12 #define PROJECT_VERSION_BUILD_NO_STR STRINGIFY_EXPAND(PROJECT_VERSION_BUILD_NO) #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO_STR "[" BUILD_COMMIT_ID "]" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index fe608853..99d17fd8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -29,13 +29,13 @@ add_executable(net_load_tests_srv net_load_tests/srv.cpp) add_dependencies(coretests version) -target_link_libraries(coretests currency_core common crypto wallet rpc zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(difficulty-tests currency_core ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(functional_tests wallet currency_core crypto common rpc zlibstatic upnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(hash-tests crypto) -target_link_libraries(hash-target-tests crypto currency_core ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(performance_tests currency_core common crypto zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) -target_link_libraries(unit_tests wallet currency_core crypto common gtest_main zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(coretests currency_core common crypto wallet rpc zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(difficulty-tests currency_core ${CMAKE_THREAD_LIBS_INIT} ethash ${Boost_LIBRARIES}) +target_link_libraries(functional_tests wallet currency_core crypto common rpc zlibstatic ethash upnpc-static ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(hash-tests crypto ethash) +target_link_libraries(hash-target-tests crypto currency_core ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(performance_tests currency_core common crypto zlibstatic ethash${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(unit_tests wallet currency_core crypto common gtest_main zlibstatic ethash${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(net_load_tests_clt currency_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) target_link_libraries(net_load_tests_srv currency_core common crypto gtest_main ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) diff --git a/tests/core_tests/alias_tests.cpp b/tests/core_tests/alias_tests.cpp index 8996b88f..498287ac 100644 --- a/tests/core_tests/alias_tests.cpp +++ b/tests/core_tests/alias_tests.cpp @@ -381,8 +381,7 @@ bool gen_alias_tests::check_too_many_aliases_registration(currency::core& c, siz wide_difficulty_type diff; uint64_t height; blobdata extra = AUTO_VAL_INIT(extra); - crypto::hash seed = currency::null_hash; - bool r = c.get_block_template(b, seed, ai.m_address, ai.m_address, diff, height, extra); + bool r = c.get_block_template(b, ai.m_address, ai.m_address, diff, height, extra); CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); CHECK_AND_ASSERT_MES(b.tx_hashes.empty(), false, "block template has some txs, expected--none"); @@ -413,7 +412,7 @@ bool gen_alias_tests::check_too_many_aliases_registration(currency::core& c, siz CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == total_alias_to_gen, false, "Unexpected number of txs in the pool: " << c.get_pool_transactions_count() << ", expected: " << total_alias_to_gen); // complete block template and try to process it - r = miner::find_nonce_for_given_block(b, diff, height, seed, m_scratchpad_keeper); + r = miner::find_nonce_for_given_block(b, diff, height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); @@ -1289,12 +1288,11 @@ bool gen_alias_switch_and_check_block_template::add_block_from_template(currency currency::block b; wide_difficulty_type diff; uint64_t height; - crypto::hash seed = currency::null_hash; blobdata extra = AUTO_VAL_INIT(extra); - bool r = c.get_block_template(b, seed, acc.get_public_address(), acc.get_public_address(), diff, height, extra); + bool r = c.get_block_template(b, acc.get_public_address(), acc.get_public_address(), diff, height, extra); CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); - r = miner::find_nonce_for_given_block(b, diff, height, seed, m_scratchpad_keeper); + r = miner::find_nonce_for_given_block(b, diff, height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); @@ -1409,12 +1407,11 @@ bool gen_alias_too_many_regs_in_block_template::add_block_from_template(currency currency::block b; wide_difficulty_type diff; uint64_t height; - crypto::hash seed = currency::null_hash; blobdata extra = AUTO_VAL_INIT(extra); - bool r = c.get_block_template(b, seed, acc.get_public_address(), acc.get_public_address(), diff, height, extra); + bool r = c.get_block_template(b, acc.get_public_address(), acc.get_public_address(), diff, height, extra); CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); - r = miner::find_nonce_for_given_block(b, diff, height, seed, m_scratchpad_keeper); + r = miner::find_nonce_for_given_block(b, diff, height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); diff --git a/tests/core_tests/block_reward.cpp b/tests/core_tests/block_reward.cpp index 3fdf7d3b..a7d01fd8 100644 --- a/tests/core_tests/block_reward.cpp +++ b/tests/core_tests/block_reward.cpp @@ -87,8 +87,7 @@ bool block_template_against_txs_size::c1(currency::core& c, size_t ev_index, con wide_difficulty_type diff = 0; uint64_t height = 0; g_block_txs_total_size = txs_total_size; // passing an argument to custom_fill_block_template_func via global variable (not perfect but works well) - crypto::hash seed = currency::null_hash; - r = bcs.create_block_template(b, seed, miner_addr, miner_addr, diff, height, ex_nonce, is_pos != 0, pe, &custom_fill_block_template_func); + r = bcs.create_block_template(b, miner_addr, miner_addr, diff, height, ex_nonce, is_pos != 0, pe, &custom_fill_block_template_func); CHECK_AND_ASSERT_MES(r, false, "create_block_template failed, txs_total_size = " << txs_total_size); CHECK_AND_ASSERT_MES(height == top_block_height + 1, false, "Incorrect height: " << height << ", expected: " << top_block_height + 1 << ", txs_total_size = " << txs_total_size); diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 97c420db..944ffd77 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -693,15 +693,8 @@ bool test_generator::find_nounce(currency::block& blk, std::vector crypto::hash - { - return currency::get_block_hash(blocks[index]->b); - }); - - return miner::find_nonce_for_given_block(blk, dif, height, seed, m_scratchpad); + return miner::find_nonce_for_given_block(blk, dif, height); } bool test_generator::construct_genesis_block(currency::block& blk, const currency::account_base& miner_acc, uint64_t timestamp) diff --git a/tests/core_tests/chaingen.h b/tests/core_tests/chaingen.h index 321e9882..c91d0cea 100644 --- a/tests/core_tests/chaingen.h +++ b/tests/core_tests/chaingen.h @@ -14,7 +14,6 @@ #include "wallet/wallet2.h" #include "test_core_time.h" #include "chaingen_helpers.h" -#include "currency_core/scratchpad_helper.h" #define TESTS_DEFAULT_FEE ((uint64_t)TX_DEFAULT_FEE) #define MK_TEST_COINS(amount) (static_cast(amount) * TESTS_DEFAULT_FEE) @@ -306,7 +305,6 @@ protected: uint64_t height; crypto::hash hash; }; - currency::scratchpad_keeper m_scratchpad_keeper; size_t m_invalid_block_index; size_t m_invalid_tx_index; size_t m_orphan_block_index; @@ -507,7 +505,6 @@ private: std::unordered_map m_blocks_info; static test_gentime_settings m_test_gentime_settings; static test_gentime_settings m_test_gentime_settings_default; - mutable currency::scratchpad_keeper m_scratchpad; }; extern const crypto::signature invalid_signature; // invalid non-null signature for test purpose @@ -872,7 +869,6 @@ namespace crypto { return o << "account: " << std::endl << " addr: " << get_account_address_as_str(acc.get_public_address()) << std::endl << - " seed: " << epee::string_tools::buff_to_hex_nodelimer(acc.get_restore_data()) << std::endl << " spend secret key: " << acc.get_keys().m_spend_secret_key << std::endl << " spend public key: " << acc.get_public_address().m_spend_public_key << std::endl << " view secret key: " << acc.get_keys().m_view_secret_key << std::endl << diff --git a/tests/core_tests/chaingen_helpers.h b/tests/core_tests/chaingen_helpers.h index 69216e7d..00b193dd 100644 --- a/tests/core_tests/chaingen_helpers.h +++ b/tests/core_tests/chaingen_helpers.h @@ -11,14 +11,13 @@ // chaingen-independent helpers that may be used outside of core_tests (for ex. in functional_tests) -inline bool mine_next_pow_block_in_playtime(currency::scratchpad_keeper& scr_keeper, const currency::account_public_address& miner_addr, currency::core& c, currency::block* output = nullptr) +inline bool mine_next_pow_block_in_playtime(const currency::account_public_address& miner_addr, currency::core& c, currency::block* output = nullptr) { currency::block b = AUTO_VAL_INIT(b); currency::wide_difficulty_type diff; uint64_t height; currency::blobdata extra = AUTO_VAL_INIT(extra); - crypto::hash seed = currency::null_hash; - bool r = c.get_block_template(b, seed, miner_addr, miner_addr, diff, height, extra); + bool r = c.get_block_template(b, miner_addr, miner_addr, diff, height, extra); CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); // adjust block's timestamp to keep difficulty low @@ -28,7 +27,7 @@ inline bool mine_next_pow_block_in_playtime(currency::scratchpad_keeper& scr_kee // keep global time up with blocks' timestamps test_core_time::adjust(b.timestamp); - r = currency::miner::find_nonce_for_given_block(b, diff, height, seed, scr_keeper); + r = currency::miner::find_nonce_for_given_block(b, diff, height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); @@ -41,7 +40,7 @@ inline bool mine_next_pow_block_in_playtime(currency::scratchpad_keeper& scr_kee return true; } -inline bool mine_next_pow_block_in_playtime_with_given_txs(currency::scratchpad_keeper& scr_keeper, const currency::account_public_address& miner_addr, currency::core& c, const std::vector& txs, const crypto::hash& prev_id, uint64_t height, currency::block* output = nullptr) +inline bool mine_next_pow_block_in_playtime_with_given_txs(const currency::account_public_address& miner_addr, currency::core& c, const std::vector& txs, const crypto::hash& prev_id, uint64_t height, currency::block* output = nullptr) { struct loc_helper { @@ -73,12 +72,11 @@ inline bool mine_next_pow_block_in_playtime_with_given_txs(currency::scratchpad_ uint64_t height_from_template = 0; currency::blobdata extra = AUTO_VAL_INIT(extra); currency::pos_entry pe = AUTO_VAL_INIT(pe); - crypto::hash seed; bool r = false; { CRITICAL_REGION_LOCAL(s_locker); loc_helper::txs_accessor() = &txs; - r = c.get_blockchain_storage().create_block_template(b, seed, miner_addr, miner_addr, diff, height_from_template, extra, false, pe, loc_helper::fill_block_template_func); + r = c.get_blockchain_storage().create_block_template(b, miner_addr, miner_addr, diff, height_from_template, extra, false, pe, loc_helper::fill_block_template_func); } CHECK_AND_ASSERT_MES(r, false, "get_block_template failed"); @@ -106,7 +104,7 @@ inline bool mine_next_pow_block_in_playtime_with_given_txs(currency::scratchpad_ height = height_from_template; } - r = currency::miner::find_nonce_for_given_block(b, diff, height, seed, scr_keeper); + r = currency::miner::find_nonce_for_given_block(b, diff, height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); @@ -119,15 +117,15 @@ inline bool mine_next_pow_block_in_playtime_with_given_txs(currency::scratchpad_ return true; } -inline bool mine_next_pow_block_in_playtime_with_given_txs(currency::scratchpad_keeper& scr_keeper, const currency::account_public_address& miner_addr, currency::core& c, const std::vector& txs, currency::block* output = nullptr) +inline bool mine_next_pow_block_in_playtime_with_given_txs(const currency::account_public_address& miner_addr, currency::core& c, const std::vector& txs, currency::block* output = nullptr) { - return mine_next_pow_block_in_playtime_with_given_txs(scr_keeper, miner_addr, c, txs, currency::null_hash, SIZE_MAX, output); + return mine_next_pow_block_in_playtime_with_given_txs(miner_addr, c, txs, currency::null_hash, SIZE_MAX, output); } -inline bool mine_next_pow_blocks_in_playtime(currency::scratchpad_keeper& scr_keeper, const currency::account_public_address& miner_addr, currency::core& c, size_t blocks_count) +inline bool mine_next_pow_blocks_in_playtime(const currency::account_public_address& miner_addr, currency::core& c, size_t blocks_count) { for (size_t i = 0; i != blocks_count; i++) - if (!mine_next_pow_block_in_playtime(scr_keeper, miner_addr, c)) + if (!mine_next_pow_block_in_playtime(miner_addr, c)) return false; return true; diff --git a/tests/core_tests/checkpoints_tests.cpp b/tests/core_tests/checkpoints_tests.cpp index a2688df7..2275b884 100644 --- a/tests/core_tests/checkpoints_tests.cpp +++ b/tests/core_tests/checkpoints_tests.cpp @@ -628,7 +628,7 @@ bool gen_no_attchments_in_coinbase::init_config_set_cp(currency::core& c, size_t crc.pos_minimum_heigh = 1; c.get_blockchain_storage().set_core_runtime_config(crc); - m_checkpoints.add_checkpoint(12, "4ba98ca9d92e99e28a30bd5395a305213be2fc18372bbf94ef216ba017640e56"); + m_checkpoints.add_checkpoint(12, "b28d40aa02b30d1f0e807147151b5073dc8dc930414cbbdbde11a9502f9c6936"); c.set_checkpoints(currency::checkpoints(m_checkpoints)); return true; @@ -683,19 +683,19 @@ bool gen_no_attchments_in_coinbase::c1(currency::core& c, size_t ev_index, const test_core_time::adjust(blk_0r.timestamp + DIFFICULTY_TOTAL_TARGET); block blk_a; - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_miner_acc.get_public_address(), c, &blk_a); + r = mine_next_pow_block_in_playtime(m_miner_acc.get_public_address(), c, &blk_a); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); test_core_time::adjust(blk_a.timestamp + DIFFICULTY_TOTAL_TARGET); block blk_b; - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_miner_acc.get_public_address(), c, &blk_b); + r = mine_next_pow_block_in_playtime(m_miner_acc.get_public_address(), c, &blk_b); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); test_core_time::adjust(blk_b.timestamp + DIFFICULTY_TOTAL_TARGET); block blk_c; - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_miner_acc.get_public_address(), c, &blk_c); + r = mine_next_pow_block_in_playtime(m_miner_acc.get_public_address(), c, &blk_c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); // make sure the checkpoint zone is successfully left behind diff --git a/tests/core_tests/emission_test.cpp b/tests/core_tests/emission_test.cpp index 590524f7..33de91e6 100644 --- a/tests/core_tests/emission_test.cpp +++ b/tests/core_tests/emission_test.cpp @@ -66,10 +66,9 @@ bool emission_test::c1(currency::core& c, size_t ev_index, const std::vector& events) bool escrow_altchain_meta_impl::mine_next_block_with_tx(currency::core& c, const currency::transaction& tx) { block b = AUTO_VAL_INIT(b); - bool r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({ tx }), m_last_block_hash, m_last_block_height + 1, &b); + bool r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({ tx }), m_last_block_hash, m_last_block_height + 1, &b); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed"); m_last_block_hash = get_block_hash(b); m_last_block_height = get_block_height(b); @@ -95,7 +95,7 @@ bool escrow_altchain_meta_impl::mine_next_block_with_tx(currency::core& c, const bool escrow_altchain_meta_impl::mine_next_block_with_no_tx(currency::core& c) { block b = AUTO_VAL_INIT(b); - bool r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector(), m_last_block_hash, m_last_block_height + 1, &b); + bool r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector(), m_last_block_hash, m_last_block_height + 1, &b); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed"); m_last_block_hash = get_block_hash(b); m_last_block_height = get_block_height(b); diff --git a/tests/core_tests/escrow_wallet_tests.cpp b/tests/core_tests/escrow_wallet_tests.cpp index f0d02778..a0045d0d 100644 --- a/tests/core_tests/escrow_wallet_tests.cpp +++ b/tests/core_tests/escrow_wallet_tests.cpp @@ -80,7 +80,7 @@ bool escrow_wallet_test::prepare_proposal_accepted_test(currency::core& c, const miner_wlt->transfer(AMOUNT_TO_TRANSFER_ESCROW + TX_DEFAULT_FEE * 2, accunt_seller.get_public_address()); LOG_PRINT_MAGENTA("Transaction sent to seller_account: " << AMOUNT_TO_TRANSFER_ESCROW + TX_DEFAULT_FEE * 2, LOG_LEVEL_0); - bool r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + bool r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); @@ -121,7 +121,7 @@ bool escrow_wallet_test::prepare_proposal_accepted_test(currency::core& c, const LOG_PRINT_MAGENTA("Escrow proposal sent bseller_account: escrow_proposal_tx id: " << currency::get_transaction_hash(escrow_proposal_tx) << ", multisig_id: " << multisig_id, LOG_LEVEL_0); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_mining_accunt.get_public_address(), c, 2); + r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, 2); wallet_buyer->refresh(); wallet_seller->refresh(); @@ -147,7 +147,7 @@ bool escrow_wallet_test::prepare_proposal_accepted_test(currency::core& c, const //---------------------- wallet_seller->accept_proposal(multisig_id, TX_DEFAULT_FEE); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); wallet_buyer->refresh(); wallet_seller->refresh(); @@ -197,7 +197,7 @@ bool escrow_wallet_test::exec_test_with_specific_release_type(currency::core& c, tools::wallet2::escrow_contracts_container contracts_buyer, contracts_seller; wallet_buyer->finish_contract(multisig_id, release_instruction); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_mining_accunt.get_public_address(), c, 2); + r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, 2); wallet_buyer->refresh(); wallet_seller->refresh(); wallet_buyer->get_contracts(contracts_buyer); @@ -230,11 +230,11 @@ bool escrow_wallet_test::exec_test_with_cancel_release_type(currency::core& c, c wallet_miner = init_playtime_test_wallet(events, c, m_mining_accunt); wallet_miner->refresh(); wallet_miner->transfer(TX_DEFAULT_FEE, wallet_buyer->get_account().get_public_address()); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_mining_accunt.get_public_address(), c, 10); + r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, 10); wallet_buyer->refresh(); tools::wallet2::escrow_contracts_container contracts_buyer, contracts_seller; wallet_buyer->request_cancel_contract(multisig_id, TX_DEFAULT_FEE, 60 * 60); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_mining_accunt.get_public_address(), c, 2); + r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, 2); wallet_buyer->refresh(); wallet_seller->refresh(); wallet_buyer->get_contracts(contracts_buyer); @@ -252,7 +252,7 @@ bool escrow_wallet_test::exec_test_with_cancel_release_type(currency::core& c, c //cancel contract wallet_seller->accept_cancel_contract(multisig_id); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_mining_accunt.get_public_address(), c, 2); + r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, 2); wallet_buyer->refresh(); wallet_seller->refresh(); wallet_buyer->get_contracts(contracts_buyer); @@ -396,7 +396,7 @@ bool escrow_w_and_fake_outputs::c1(currency::core& c, size_t ev_index, const std CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -406,7 +406,7 @@ bool escrow_w_and_fake_outputs::c1(currency::core& c, size_t ev_index, const std CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -416,7 +416,7 @@ bool escrow_w_and_fake_outputs::c1(currency::core& c, size_t ev_index, const std CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, WALLET_DEFAULT_TX_SPENDABLE_AGE); + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, WALLET_DEFAULT_TX_SPENDABLE_AGE); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -441,7 +441,7 @@ bool escrow_w_and_fake_outputs::c1(currency::core& c, size_t ev_index, const std CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -651,7 +651,7 @@ bool escrow_incorrect_proposal::check_normal_proposal(currency::core& c, size_t alice_wlt->accept_proposal(contract_id, TX_DEFAULT_FEE); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -661,7 +661,7 @@ bool escrow_incorrect_proposal::check_normal_proposal(currency::core& c, size_t miner_wlt->finish_contract(contract_id, BC_ESCROW_SERVICE_INSTRUCTION_RELEASE_NORMAL); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -788,7 +788,7 @@ bool escrow_proposal_expiration::c1(currency::core& c, size_t ev_index, const st CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); // mine a block with proposal transport tx - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -797,7 +797,7 @@ bool escrow_proposal_expiration::c1(currency::core& c, size_t ev_index, const st CHECK_AND_ASSERT_MES(refresh_wallet_and_check_contract_state("Bob", bob_wlt, tools::wallet_rpc::escrow_contract_details::proposal_sent, ms_id, 1), false, ""); // mine few block to shift the timestamp median far enough - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW); + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); // check Alice's balance @@ -866,7 +866,7 @@ bool escrow_proposal_expiration::c2(currency::core& c, size_t ev_index, const st // mine a few blocks with no txs for (size_t i = 0; i < TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW + 1; ++i) { - r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector()); + r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector()); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); } @@ -896,7 +896,7 @@ bool escrow_proposal_expiration::c2(currency::core& c, size_t ev_index, const st CHECK_AND_ASSERT_MES(r, false, "Bob tried to accept an expired proposal, but wallet exception was not caught"); // mine a block with proposal transport tx - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); // check it has left tx pool @@ -1022,7 +1022,7 @@ bool escrow_proposal_and_accept_expiration::c1(currency::core& c, size_t ev_inde // mine a few blocks with no txs for (size_t i = 0; i < TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW + 1; ++i) { - r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector()); + r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector()); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); } @@ -1057,7 +1057,7 @@ bool escrow_proposal_and_accept_expiration::c1(currency::core& c, size_t ev_inde CHECK_AND_ASSERT_MES(r, false, "Bob tried to accept an expired proposal, but wallet exception was not caught"); LOG_PRINT_CYAN("%%%%% mine a block with proposal transport tx", LOG_LEVEL_0); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); // check it has left tx pool @@ -1336,7 +1336,7 @@ bool escrow_incorrect_proposal_acceptance::check_normal_acceptance(currency::cor CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -1673,7 +1673,7 @@ bool escrow_custom_test::do_custom_test(currency::core& c, size_t ev_index, cons CHECK_AND_ASSERT_MES(check_wallet_balance_blocked_for_escrow(*alice_wlt.get(), "Alice", cd.cpd.amount_a_pledge + cd.cpd.amount_to_pay), false, ""); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -1712,7 +1712,7 @@ bool escrow_custom_test::do_custom_test(currency::core& c, size_t ev_index, cons false, ""); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -1751,7 +1751,7 @@ bool escrow_custom_test::do_custom_test(currency::core& c, size_t ev_index, cons CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", bob_expected_balance, 0, INVALID_BALANCE_VAL, 0, 0), false, ""); // should not change CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -1795,7 +1795,7 @@ bool escrow_custom_test::do_custom_test(currency::core& c, size_t ev_index, cons CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", bob_expected_balance, 0, INVALID_BALANCE_VAL, cd.is_release_normal() ? cd.cpd.amount_b_pledge + cd.cpd.amount_to_pay : 0, cd.is_release_normal() ? 0 : ms_amount - cd.b_release_fee), false, ""); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -1842,7 +1842,7 @@ bool escrow_custom_test::do_custom_test(currency::core& c, size_t ev_index, cons CHECK_AND_ASSERT_MES(check_balance_via_wallet(*bob_wlt.get(), "Bob", bob_expected_balance, 0, INVALID_BALANCE_VAL, bob_expected_aw_in_balance, 0), false, ""); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -2096,7 +2096,7 @@ bool escrow_incorrect_cancel_proposal::check_normal_cancel_proposal(currency::co bob_wlt->accept_cancel_contract(ms_id); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -2273,7 +2273,7 @@ bool escrow_proposal_not_enough_money::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(check_balance_via_wallet(*alice_wlt.get(), "Alice", MK_TEST_COINS(30), 0, MK_TEST_COINS(30), 0, 0), false, ""); // mine few blocks to make sure there's no problem - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, 5); + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 5); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); // and check balance again @@ -2359,7 +2359,7 @@ bool escrow_cancellation_and_tx_order::c1(currency::core& c, size_t ev_index, co // mine a block, containing escrow proposal tx CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2377,7 +2377,7 @@ bool escrow_cancellation_and_tx_order::c1(currency::core& c, size_t ev_index, co // mine a block containing contract acceptance CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2437,8 +2437,8 @@ bool escrow_cancellation_and_tx_order::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(contracts.begin()->second.state == tools::wallet_rpc::escrow_contract_details::contract_released_cancelled, false, "Bob has invalid contract state: " << tools::wallet_rpc::get_escrow_contract_state_name(contracts.begin()->second.state)); // mine a block containing only cancel_request_acceptance_tx (this should trigger contracts' states swtiching into contract_released_cancelled) - LOG_PRINT_GREEN("\n" "mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, cancel_request_acceptance_tx)", LOG_LEVEL_0); - r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({cancel_request_acceptance_tx})); + LOG_PRINT_GREEN("\n" "mine_next_pow_block_in_playtime_with_given_txs(cancel_request_acceptance_tx)", LOG_LEVEL_0); + r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({cancel_request_acceptance_tx})); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2458,8 +2458,8 @@ bool escrow_cancellation_and_tx_order::c1(currency::core& c, size_t ev_index, co // mine a block containing only cancel_request_tx (this SHOULD NOT trigger contracts' states swtiching into contract_cancel_proposal_sent or anything) - LOG_PRINT_GREEN("\n" "mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, cancel_request_tx)", LOG_LEVEL_0); - r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({cancel_request_tx})); + LOG_PRINT_GREEN("\n" "mine_next_pow_block_in_playtime_with_given_txs(cancel_request_tx)", LOG_LEVEL_0); + r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({cancel_request_tx})); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2563,7 +2563,7 @@ bool escrow_cancellation_proposal_expiration::c1(currency::core& c, size_t ev_in // mine a block, containing escrow proposal tx CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2584,7 +2584,7 @@ bool escrow_cancellation_proposal_expiration::c1(currency::core& c, size_t ev_in // mine a block containing contract acceptance CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2621,7 +2621,7 @@ bool escrow_cancellation_proposal_expiration::c1(currency::core& c, size_t ev_in // mine a few blocks with no txs to shift expiration median for(size_t i = 0; i < 7; ++i) { - r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector()); + r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector()); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed"); } // cancellation request is still in the pool @@ -2649,8 +2649,8 @@ bool escrow_cancellation_proposal_expiration::c1(currency::core& c, size_t ev_in CHECK_AND_ASSERT_MES(refresh_wallet_and_check_1_contract_state("Bob", bob_wlt, tools::wallet_rpc::escrow_contract_details::contract_accepted, 7), false, ""); // mine a block containing cancel_request_tx (already expired) -- should be okay - LOG_PRINT_GREEN("\n\n\n" "mine_next_pow_block_in_playtime(m_scratchpad_keeper, ) -- including expires contract cancellation request" "\n\n", LOG_LEVEL_0); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + LOG_PRINT_GREEN("\n\n\n" "mine_next_pow_block_in_playtime() -- including expires contract cancellation request" "\n\n", LOG_LEVEL_0); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2684,8 +2684,8 @@ bool escrow_cancellation_proposal_expiration::c1(currency::core& c, size_t ev_in CHECK_AND_ASSERT_MES(refresh_wallet_and_check_1_contract_state("Bob", bob_wlt, tools::wallet_rpc::escrow_contract_details::contract_cancel_proposal_sent, 0), false, ""); // mine a block containing cancel_request_tx - LOG_PRINT_GREEN("\n" "mine_next_pow_block_in_playtime(m_scratchpad_keeper, )", LOG_LEVEL_0); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + LOG_PRINT_GREEN("\n" "mine_next_pow_block_in_playtime()", LOG_LEVEL_0); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2694,8 +2694,8 @@ bool escrow_cancellation_proposal_expiration::c1(currency::core& c, size_t ev_in CHECK_AND_ASSERT_MES(refresh_wallet_and_check_1_contract_state("Bob", bob_wlt, tools::wallet_rpc::escrow_contract_details::contract_cancel_proposal_sent, 1), false, ""); // mine one more block (it's necessary for triggering expiration checks in wallets and shifting an expiration ts median) - LOG_PRINT_GREEN("\n" "mine_next_pow_block_in_playtime(m_scratchpad_keeper, )", LOG_LEVEL_0); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, 7); + LOG_PRINT_GREEN("\n" "mine_next_pow_block_in_playtime()", LOG_LEVEL_0); + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, 7); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2810,7 +2810,7 @@ bool escrow_cancellation_acceptance_expiration::c1(currency::core& c, size_t ev_ // mine a block, containing escrow proposal tx CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2825,7 +2825,7 @@ bool escrow_cancellation_acceptance_expiration::c1(currency::core& c, size_t ev_ // mine a block containing contract acceptance CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2838,7 +2838,7 @@ bool escrow_cancellation_acceptance_expiration::c1(currency::core& c, size_t ev_ // confirm cancellation request in blockchain CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c), false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c), false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); // contract state in wallets should be cancel_proposal_sent for both parties @@ -2862,7 +2862,7 @@ bool escrow_cancellation_acceptance_expiration::c1(currency::core& c, size_t ev_ // mine a few blocks with no txs to shift expiration median, cancellation acceptance is still in the pool for(size_t i = 0; i < 7; ++i) { - r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector()); + r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector()); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed"); } CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -2886,7 +2886,7 @@ bool escrow_cancellation_acceptance_expiration::c1(currency::core& c, size_t ev_ CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); // mine a block with cancel_accept_tx (already expired). It should be rejected - r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({ cancel_accept_tx })); + r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({ cancel_accept_tx })); CHECK_AND_ASSERT_MES(!r, false, "mine_next_pow_block_in_playtime_with_given_txs should have been failed as block contains expired tx"); // no changes with contract state expected @@ -2968,6 +2968,6 @@ bool escrow_proposal_acceptance_in_alt_chain::generate(std::vector& events) { - //mine_next_pow_block_in_playtime(m_scratchpad_keeper, ) + //mine_next_pow_block_in_playtime() return true; } diff --git a/tests/core_tests/misc_tests.cpp b/tests/core_tests/misc_tests.cpp index 80c800ca..ac4feddd 100644 --- a/tests/core_tests/misc_tests.cpp +++ b/tests/core_tests/misc_tests.cpp @@ -347,7 +347,7 @@ bool block_template_vs_invalid_txs_from_pool::check_block_template(currency::cor bool r = false; currency::block b = AUTO_VAL_INIT(b); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, addr, c, &b); + r = mine_next_pow_block_in_playtime(addr, c, &b); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); return true; diff --git a/tests/core_tests/mixin_attr.cpp b/tests/core_tests/mixin_attr.cpp index 3d68039b..ac4fec15 100644 --- a/tests/core_tests/mixin_attr.cpp +++ b/tests/core_tests/mixin_attr.cpp @@ -289,7 +289,7 @@ bool mix_in_spent_outs::c1(currency::core& c, size_t ev_index, const std::vector CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect number of txs in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "There are txs in the pool"); diff --git a/tests/core_tests/multisig_wallet_tests.cpp b/tests/core_tests/multisig_wallet_tests.cpp index 73bd4162..fee3ea47 100644 --- a/tests/core_tests/multisig_wallet_tests.cpp +++ b/tests/core_tests/multisig_wallet_tests.cpp @@ -160,7 +160,7 @@ bool multisig_wallet_test::c1(currency::core& c, size_t ev_index, const std::vec transaction result_tx = AUTO_VAL_INIT(result_tx); miner_wlt->transfer(dst, 0, 0, TX_DEFAULT_FEE, extra, attachments, tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), result_tx); - bool r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + bool r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); //findout multisig out intex @@ -175,7 +175,7 @@ bool multisig_wallet_test::c1(currency::core& c, size_t ev_index, const std::vec crypto::hash multisig_id = get_multisig_out_id(result_tx, i); CHECK_AND_ASSERT_MES(multisig_id != null_hash, false, "Multisig failed: failed to get get_multisig_out_id"); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); std::shared_ptr wallet_a = init_playtime_test_wallet(events, c, m_accunt_a); @@ -208,7 +208,7 @@ bool multisig_wallet_test::c1(currency::core& c, size_t ev_index, const std::vec tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), result_tx); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + r = mine_next_pow_blocks_in_playtime(m_mining_accunt.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); wallet_a->refresh(); @@ -300,7 +300,7 @@ bool multisig_wallet_test_many_dst::c1(currency::core& c, size_t ev_index, const CHECK_AND_ASSERT_MES(it != result_tx.vout.end(), false, "Can't find output txout_multisig"); size_t multisig_index = it - result_tx.vout.begin(); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); std::shared_ptr w = init_playtime_test_wallet(events, c, addresses[0]); @@ -317,7 +317,7 @@ bool multisig_wallet_test_many_dst::c1(currency::core& c, size_t ev_index, const transfer_multisig(*w.get(), owner_keys, get_multisig_out_id(result_tx, multisig_index), std::vector({ de2 }), 0, TESTS_DEFAULT_FEE, std::vector(), std::vector(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx); TMP_LOG_RESTORE; - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, m_accounts[ALICE_ACC_IDX]); @@ -428,7 +428,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co // Mine a block and make sure tx was put into it CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -487,7 +487,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co 0, TX_DEFAULT_FEE, std::vector(), std::vector(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); // Once Bob refreshes his wallet he should see that Alice has already spent they shared multisig @@ -549,7 +549,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co 0, TX_DEFAULT_FEE, std::vector(), std::vector(), tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "There are txs in the pool."); @@ -584,7 +584,7 @@ bool multisig_wallet_heterogenous_dst::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(caught, false, "Dan was able to make multisig tx for alreadly spent output"); // Miner mines the next PoW block, confirming Alice's transaction. - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "There are txs in the pool."); @@ -689,7 +689,7 @@ bool multisig_wallet_same_dst_addr::c1(currency::core& c, size_t ev_index, const // mine the next PoW and make sure everythig is allright CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect number of tx in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "There are transactions in the pool"); @@ -707,7 +707,7 @@ bool multisig_wallet_same_dst_addr::c1(currency::core& c, size_t ev_index, const 0, TX_DEFAULT_FEE, empty_extra, empty_attachment, tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect number of tx in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "There are transactions in the pool"); @@ -778,7 +778,7 @@ bool multisig_wallet_ms_to_ms::c1(currency::core& c, size_t ev_index, const std: // mine the next PoW and make sure everythig is allright CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect number of tx in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "There are transactions in the pool"); @@ -802,7 +802,7 @@ bool multisig_wallet_ms_to_ms::c1(currency::core& c, size_t ev_index, const std: // check the pool and mine a block CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect number of tx in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "There are transactions in the pool"); @@ -818,7 +818,7 @@ bool multisig_wallet_ms_to_ms::c1(currency::core& c, size_t ev_index, const std: 0, TX_DEFAULT_FEE, empty_extra, empty_attachment, tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), tx); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect number of tx in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "There are transactions in the pool"); @@ -1625,7 +1625,7 @@ multisig_and_checkpoints::multisig_and_checkpoints() bool multisig_and_checkpoints::set_cp(currency::core& c, size_t ev_index, const std::vector& events) { currency::checkpoints checkpoints; - checkpoints.add_checkpoint(15, "816f96e8a0e259491ed7e03ef0f2eea69762276152f4990d71f657b1e37d8764"); + checkpoints.add_checkpoint(15, "b9adef016fc8de02ad6d0db526e536a3c2211ee23a2d906f56989465c3e38602"); c.set_checkpoints(std::move(checkpoints)); return true; @@ -2490,14 +2490,14 @@ bool multisig_unconfirmed_transfer_and_multiple_scan_pool_calls::c1(currency::co transaction key_to_ms_tx = AUTO_VAL_INIT(key_to_ms_tx); miner_wlt->transfer(dst, 0, 0, TX_DEFAULT_FEE, extra, attachments, tools::detail::digit_split_strategy, tools::tx_dust_policy(DEFAULT_DUST_THRESHOLD), key_to_ms_tx); - bool r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, miner_acc.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + bool r = mine_next_pow_blocks_in_playtime(miner_acc.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); size_t ms_out_idx = get_multisig_out_index(key_to_ms_tx.vout); crypto::hash multisig_id = get_multisig_out_id(key_to_ms_tx, ms_out_idx); CHECK_AND_ASSERT_MES(multisig_id != null_hash, false, "Multisig failed: failed to get get_multisig_out_id"); - //r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, miner_acc.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + //r = mine_next_pow_blocks_in_playtime(miner_acc.get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); //CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); std::shared_ptr alice_wlt = init_playtime_test_wallet(events, c, alice_acc); diff --git a/tests/core_tests/offers_test.cpp b/tests/core_tests/offers_test.cpp index 8a24e711..ca72b906 100644 --- a/tests/core_tests/offers_test.cpp +++ b/tests/core_tests/offers_test.cpp @@ -567,7 +567,7 @@ bool offers_handling_on_chain_switching::c1(currency::core& c, size_t ev_index, uint64_t blk_1r_height = c.get_current_blockchain_size() - 2; crypto::hash blk_1r_id = c.get_block_id_by_height(blk_1r_height); block blk_2a = AUTO_VAL_INIT(blk_2a); - r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector(), blk_1r_id, blk_1r_height + 1, &blk_2a); + r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector(), blk_1r_id, blk_1r_height + 1, &blk_2a); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -577,7 +577,7 @@ bool offers_handling_on_chain_switching::c1(currency::core& c, size_t ev_index, // mine second alt block (include offer tx) -- this should trigger chain switching block blk_3a = AUTO_VAL_INIT(blk_3a); - r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({tx_1}), get_block_hash(blk_2a), blk_1r_height + 2, &blk_3a); + r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({tx_1}), get_block_hash(blk_2a), blk_1r_height + 2, &blk_3a); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); @@ -673,7 +673,7 @@ bool offer_removing_and_selected_output::check_offers(currency::core& c, size_t crypto::hash create_offer_tx_id = get_transaction_hash(create_offer_tx); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c), false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c), false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); refresh_wallet_and_check_balance("offer's put into the blockchain", "Alice", alice_wlt, alice_start_balance - od.fee, true, 1); @@ -699,7 +699,7 @@ bool offer_removing_and_selected_output::check_offers(currency::core& c, size_t // add it to the blockchain CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c), false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c), false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); // Alice's banace should not change @@ -937,7 +937,7 @@ bool offers_updating_hack::update_foreign_offer(currency::core& c, size_t ev_ind // put in a block 'tx', leave Alice's tx in the pool CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({ tx })), false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({ tx })), false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); LOG_PRINT_L0(ENDL << c.get_tx_pool().print_pool(true)); @@ -1005,7 +1005,7 @@ bool offers_updating_hack::delete_foreign_offer(currency::core& c, size_t ev_ind // put in a block 'tx', leave Alice's tx in the pool CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); - CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({ tx_c })), false, "mine_next_pow_block_in_playtime failed"); + CHECK_AND_ASSERT_MES(mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector({ tx_c })), false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool: " << c.get_pool_transactions_count()); LOG_PRINT_L0(ENDL << c.get_tx_pool().print_pool(true)); @@ -1264,7 +1264,7 @@ bool offer_lifecycle_via_tx_pool::c1(currency::core& c, size_t ev_index, const s CATCH_ENTRY2(false); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true)); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, some_addr, c); + r = mine_next_pow_block_in_playtime(some_addr, c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true)); @@ -1280,7 +1280,7 @@ bool offer_lifecycle_via_tx_pool::c1(currency::core& c, size_t ev_index, const s CATCH_ENTRY2(false); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true)); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, some_addr, c); + r = mine_next_pow_block_in_playtime(some_addr, c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true)); @@ -1297,7 +1297,7 @@ bool offer_lifecycle_via_tx_pool::c1(currency::core& c, size_t ev_index, const s CATCH_ENTRY2(false); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true)); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, some_addr, c); + r = mine_next_pow_block_in_playtime(some_addr, c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true)); @@ -1313,7 +1313,7 @@ bool offer_lifecycle_via_tx_pool::c1(currency::core& c, size_t ev_index, const s CATCH_ENTRY2(false); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true)); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, some_addr, c); + r = mine_next_pow_block_in_playtime(some_addr, c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Invalid tx pool count: " << c.get_pool_transactions_count() << ENDL << "tx pool:" << ENDL << c.get_tx_pool().print_pool(true)); diff --git a/tests/core_tests/pos_validation.cpp b/tests/core_tests/pos_validation.cpp index a137fc8f..7d8af42a 100644 --- a/tests/core_tests/pos_validation.cpp +++ b/tests/core_tests/pos_validation.cpp @@ -495,7 +495,7 @@ bool pos_wallet_minting_same_amount_diff_outs::prepare_wallets_0(currency::core& r = populate_wallet_with_stake_coins(w.w, alice_wlt, w.pos_entries_count, m_wallet_stake_amount, pos_amounts); CHECK_AND_ASSERT_MES(r, false, "populate_wallet_with_stake_coins failed"); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, alice_wlt->get_account().get_public_address(), c, WALLET_DEFAULT_TX_SPENDABLE_AGE + 1); // to preventing run out of the money for Alice + r = mine_next_pow_blocks_in_playtime(alice_wlt->get_account().get_public_address(), c, WALLET_DEFAULT_TX_SPENDABLE_AGE + 1); // to preventing run out of the money for Alice CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); c.get_blockchain_storage().get_top_block(b); uint64_t ts = b.timestamp; @@ -552,7 +552,7 @@ bool pos_wallet_minting_same_amount_diff_outs::prepare_wallets_1(currency::core& r = populate_wallet_with_stake_coins(w.w, alice_wlt, w.pos_entries_count, m_wallet_stake_amount, pos_amounts); CHECK_AND_ASSERT_MES(r, false, "populate_wallet_with_stake_coins failed"); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, alice_wlt->get_account().get_public_address(), c, WALLET_DEFAULT_TX_SPENDABLE_AGE + 1); // to preventing run out of the money for Alice + r = mine_next_pow_blocks_in_playtime(alice_wlt->get_account().get_public_address(), c, WALLET_DEFAULT_TX_SPENDABLE_AGE + 1); // to preventing run out of the money for Alice CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); c.get_blockchain_storage().get_top_block(b); uint64_t ts = b.timestamp; @@ -662,7 +662,7 @@ bool pos_wallet_minting_same_amount_diff_outs::c1(currency::core& c, size_t ev_i ts = ideal_next_pow_block_ts; // "wait" until ideal_next_pow_block_ts if it was not already happened (fast forward but don't wayback the time) test_core_time::adjust(ts); size_t tx_count_before = c.get_pool_transactions_count(); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(tx_count_before == 0 || c.get_pool_transactions_count() < tx_count_before, false, "invalid number of txs in tx pool: " << c.get_pool_transactions_count() << ", was: " << tx_count_before); last_pow_block_ts = ts; diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index 5062d752..b8af35f7 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -1309,7 +1309,7 @@ bool tx_expiration_time_and_block_template::c1(currency::core& c, size_t ev_inde CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect tx count in the pool: " << c.get_pool_transactions_count()); account_public_address addr = AUTO_VAL_INIT(addr); - bool r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, addr, c); + bool r = mine_next_pow_block_in_playtime(addr, c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); // tx MAY stay in the pool, check it as forced condition (may change in future) diff --git a/tests/core_tests/wallet_rpc_tests.cpp b/tests/core_tests/wallet_rpc_tests.cpp index 34293b18..c4ee2e51 100644 --- a/tests/core_tests/wallet_rpc_tests.cpp +++ b/tests/core_tests/wallet_rpc_tests.cpp @@ -137,7 +137,7 @@ bool wallet_rpc_integrated_address_transfer::c1(currency::core& c, size_t ev_ind CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "enexpected pool txs count: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count()); @@ -171,7 +171,7 @@ bool wallet_rpc_integrated_address_transfer::c1(currency::core& c, size_t ev_ind CHECK_AND_ASSERT_MES(r, false, "RPC call failed, code: " << je.code << ", msg: " << je.message); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "enexpected pool txs count: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count()); diff --git a/tests/core_tests/wallet_tests.cpp b/tests/core_tests/wallet_tests.cpp index 71427959..0cbc7551 100644 --- a/tests/core_tests/wallet_tests.cpp +++ b/tests/core_tests/wallet_tests.cpp @@ -1179,7 +1179,7 @@ bool gen_wallet_oversized_payment_id::c1(currency::core& c, size_t ev_index, con CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Tx pool has incorrect number of txs: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count()); @@ -1215,7 +1215,7 @@ bool gen_wallet_oversized_payment_id::c1(currency::core& c, size_t ev_index, con CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Tx pool has incorrect number of txs: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Tx pool is not empty: " << c.get_pool_transactions_count()); @@ -1769,7 +1769,7 @@ bool gen_wallet_alias_via_special_wallet_funcs::c1(currency::core& c, size_t ev_ CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - bool r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + bool r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -1790,7 +1790,7 @@ bool gen_wallet_alias_via_special_wallet_funcs::c1(currency::core& c, size_t ev_ CHECK_AND_ASSERT_MES(l->m_result, false, "Wrong wti received via callback"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); CHECK_AND_ASSERT_MES(c.get_current_blockchain_size() == 2 + CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE + 2, false, "Incorrect blockchain size"); @@ -1803,7 +1803,7 @@ bool gen_wallet_alias_via_special_wallet_funcs::c1(currency::core& c, size_t ev_ alice_wlt->request_alias_update(ai, res_tx, TX_DEFAULT_FEE, 0); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); CHECK_AND_ASSERT_MES(c.get_current_blockchain_size() == 2 + CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE + 3, false, "Incorrect blockchain size"); @@ -2072,7 +2072,7 @@ bool gen_wallet_offers_basic::c1(currency::core& c, size_t ev_index, const std:: CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 2, false, "Incorrect txs count in the pool"); - bool r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + bool r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -2123,7 +2123,7 @@ bool gen_wallet_offers_basic::c1(currency::core& c, size_t ev_index, const std:: CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -2154,7 +2154,7 @@ bool gen_wallet_offers_basic::c1(currency::core& c, size_t ev_index, const std:: CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Incorrect txs count in the pool"); @@ -2274,7 +2274,7 @@ bool gen_wallet_offers_size_limit::c1(currency::core& c, size_t ev_index, const log_space::get_set_log_detalisation_level(true, log_level); // restore CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); miner_wlt->refresh(blocks_fetched, received_money, atomic_false); CHECK_AND_ASSERT_MES(blocks_fetched == 1, false, "Incorrect numbers of blocks fetched"); @@ -2373,7 +2373,7 @@ bool gen_wallet_dust_to_account::c1(currency::core& c, size_t ev_index, const st CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - bool r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + bool r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); miner_wlt->refresh(blocks_fetched, received_money, atomic_false); @@ -2473,7 +2473,7 @@ bool gen_wallet_selecting_pos_entries::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(c.get_current_blockchain_size() == CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 3 + 1 + WALLET_DEFAULT_TX_SPENDABLE_AGE - 1, false, "Incorrect current blockchain height"); // this block should unlock the money and PoS-entries should become available - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); alice_wlt->refresh(blocks_fetched, received_money, atomic_false); CHECK_AND_ASSERT_MES(blocks_fetched == 1, false, "Incorrect number of blocks fetched"); @@ -2497,7 +2497,7 @@ bool gen_wallet_selecting_pos_entries::c1(currency::core& c, size_t ev_index, co alice_wlt->transfer(dst, 0, 0, TX_DEFAULT_FEE, std::vector(), std::vector()); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); alice_wlt->refresh(blocks_fetched, received_money, atomic_false); CHECK_AND_ASSERT_MES(blocks_fetched == 1, false, "Incorrect number of blocks fetched"); @@ -2571,7 +2571,7 @@ bool gen_wallet_spending_coinstake_after_minting::c1(currency::core& c, size_t e CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "Incorrect txs count in the pool"); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); alice_wlt->refresh(blocks_fetched, received_money, atomic_false); CHECK_AND_ASSERT_MES(blocks_fetched == 1, false, "Incorrect number of blocks fetched"); @@ -2878,7 +2878,7 @@ bool mined_balance_wallet_test::c1(currency::core& c, size_t ev_index, const std std::list blocks; size_t n = CURRENCY_MINED_MONEY_UNLOCK_WINDOW; - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, n); + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, n); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); r = bcs.get_blocks(bcs.get_current_blockchain_size() - n, n, blocks); CHECK_AND_ASSERT_MES(r, false, "get_blocks failed"); @@ -2994,11 +2994,11 @@ bool wallet_outputs_with_same_key_image::c1(currency::core& c, size_t ev_index, bool r = refresh_wallet_and_check_balance("before tx_1 and tx_2 added", "Alice", alice_wlt, MK_TEST_COINS(3) * 2, true, CURRENCY_MINED_MONEY_UNLOCK_WINDOW + 2, 0); CHECK_AND_ASSERT_MES(r, false, ""); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "there are txs in the pool!"); - r = mine_next_pow_blocks_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + r = mine_next_pow_blocks_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c, CURRENCY_MINED_MONEY_UNLOCK_WINDOW); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_blocks_in_playtime failed"); // only one tx_1 output is counted as the tx_2 output has the very same key image @@ -3017,7 +3017,7 @@ bool wallet_outputs_with_same_key_image::c1(currency::core& c, size_t ev_index, } CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 1, false, "wrong tx count in the pool: " << c.get_pool_transactions_count()); - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "there are txs in the pool!"); @@ -3097,7 +3097,7 @@ bool wallet_unconfirmed_tx_expiration::c1(currency::core& c, size_t ev_index, co // mine a few block with no tx, so Alice's tx is expired in the pool for (size_t i = 0; i < 5; ++i) { - r = mine_next_pow_block_in_playtime_with_given_txs(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector()); + r = mine_next_pow_block_in_playtime_with_given_txs(m_accounts[MINER_ACC_IDX].get_public_address(), c, std::vector()); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime_with_given_txs failed"); } @@ -3114,7 +3114,7 @@ bool wallet_unconfirmed_tx_expiration::c1(currency::core& c, size_t ev_index, co CHECK_AND_ASSERT_MES(c.get_pool_transactions_count() == 0, false, "Invalid txs count in the pool: " << c.get_pool_transactions_count()); // mine one more block to trigger wallet's on_idle() and outdated tx clearing - r = mine_next_pow_block_in_playtime(m_scratchpad_keeper, m_accounts[MINER_ACC_IDX].get_public_address(), c); + r = mine_next_pow_block_in_playtime(m_accounts[MINER_ACC_IDX].get_public_address(), c); CHECK_AND_ASSERT_MES(r, false, "mine_next_pow_block_in_playtime failed"); // make sure all Alice's money are unlocked and no coins were actually spent diff --git a/tests/functional_tests/core_concurrency_test.cpp b/tests/functional_tests/core_concurrency_test.cpp index 11594763..23bb8885 100644 --- a/tests/functional_tests/core_concurrency_test.cpp +++ b/tests/functional_tests/core_concurrency_test.cpp @@ -101,17 +101,14 @@ bool generate_events(currency::core& c, cct_events_t& events, const cct_wallets_ const currency::account_public_address& miner_addr = wallets[random_in_range(0, wallets.size() - 1)]->get_account().get_public_address(); currency::block b = AUTO_VAL_INIT(b); - currency::scratchpad_keeper sk; - crypto::hash seed = currency::null_hash; - sk.generate(seed, height); if (is_in_main_chain) { blobdata ex_nonce; wide_difficulty_type diff = 0; if (prev_block.height != 0) test_core_time::adjust(prev_block.bl.timestamp + DIFFICULTY_POW_TARGET); - r = bcs.create_block_template(b, seed, miner_addr, diff, height, ex_nonce); + r = bcs.create_block_template(b, miner_addr, diff, height, ex_nonce); CHECK_AND_ASSERT_MES(r, false, "create_block_template failed"); } else @@ -145,7 +142,7 @@ bool generate_events(currency::core& c, cct_events_t& events, const cct_wallets_ test_core_time::adjust(b.timestamp); currency::wide_difficulty_type diff = 0; - r = currency::miner::find_nonce_for_given_block(b, diff, height, seed, sk); + r = currency::miner::find_nonce_for_given_block(b, diff, height); CHECK_AND_ASSERT_MES(r, false, "find_nonce_for_given_block failed"); currency::block_verification_context bvc = AUTO_VAL_INIT(bvc); diff --git a/tests/performance_tests/keccak_test.h b/tests/performance_tests/keccak_test.h index 3553ec1a..e6579cb2 100644 --- a/tests/performance_tests/keccak_test.h +++ b/tests/performance_tests/keccak_test.h @@ -4,126 +4,92 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #pragma once - -#include "crypto/crypto.h" -#include "currency_core/currency_basic.h" -#include "profile_tools.h" - -extern "C" { -#include "crypto/keccak.h" -//#include "crypto/alt/KeccakNISTInterface.h" -} - - -#include "crypto/wild_keccak.h" -//#include "crypto/wild_keccak2.h" -#include "../core_tests/random_helper.h" -#include "crypto/hash.h" - - - - -#define TEST_BUFF_LEN 200 - -class test_keccak_base -{ -public: - static const size_t loop_count = 100000; - - bool init() - { - currency::block b; - m_buff = currency::get_block_hashing_blob(b); - m_buff.append(32 * 4, 0); - return true; - } - - bool pretest() - { - ++m_buff[0]; - if (!m_buff[0]) - ++m_buff[0]; - return true; - } -protected: - std::string m_buff; -}; - -// class test_keccak : public test_keccak_base +// +// #include "crypto/crypto.h" +// #include "currency_core/currency_basic.h" +// #include "profile_tools.h" +// +// extern "C" { +// #include "crypto/keccak.h" +// //#include "crypto/alt/KeccakNISTInterface.h" +// } +// +// +// #include "crypto/wild_keccak.h" +// //#include "crypto/wild_keccak2.h" +// #include "../core_tests/random_helper.h" +// #include "crypto/hash.h" +// +// +// +// +// #define TEST_BUFF_LEN 200 +// +// class test_keccak_base +// { +// public: +// static const size_t loop_count = 100000; +// +// bool init() +// { +// currency::block b; +// m_buff = currency::get_block_hashing_blob(b); +// m_buff.append(32 * 4, 0); +// return true; +// } +// +// bool pretest() +// { +// ++m_buff[0]; +// if (!m_buff[0]) +// ++m_buff[0]; +// return true; +// } +// protected: +// std::string m_buff; +// }; +// +// // class test_keccak : public test_keccak_base +// // { +// // public: +// // bool test() +// // { +// // pretest(); +// // crypto::hash h; +// // keccak(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h)); +// // LOG_PRINT_L4(h); +// // return true; +// // } +// // }; +// +// +// class test_keccak_generic : public test_keccak_base // { // public: // bool test() // { // pretest(); // crypto::hash h; -// keccak(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h)); +// crypto::keccak_generic(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h)); // LOG_PRINT_L4(h); // return true; // } // }; - - -class test_keccak_generic : public test_keccak_base -{ -public: - bool test() - { - pretest(); - crypto::hash h; - crypto::keccak_generic(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h)); - LOG_PRINT_L4(h); - return true; - } -}; - -class test_keccak_generic_with_mul : public test_keccak_base -{ -public: - bool test() - { - pretest(); - crypto::hash h; - crypto::keccak_generic(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h)); - return true; - } -}; - -template -class test_wild_keccak : public test_keccak_base -{ -public: - bool init() - { - m_scratchpad_vec.resize(scratchpad_size / sizeof(crypto::hash)); - for (auto& h : m_scratchpad_vec) - h = crypto::rand(); - - return test_keccak_base::init(); - } - - bool test() - { - pretest(); - - crypto::hash h; - crypto::wild_keccak_dbl(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h), [&](crypto::state_t_m& st, crypto::mixin_t& mix) - { -#define SCR_I(i) m_scratchpad_vec[st[i]%m_scratchpad_vec.size()] - for (size_t i = 0; i != 6; i++) - { - OPT_XOR_4_RES(SCR_I(i * 4), SCR_I(i * 4 + 1), SCR_I(i * 4 + 2), SCR_I(i * 4 + 3), *(crypto::hash*)&mix[i * 4]); - } - }); - - return true; - } -protected: - std::vector m_scratchpad_vec; -}; - +// +// class test_keccak_generic_with_mul : public test_keccak_base +// { +// public: +// bool test() +// { +// pretest(); +// crypto::hash h; +// crypto::keccak_generic(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h)); +// return true; +// } +// }; // // template -// class test_wild_keccak2 : public test_keccak_base +// class test_wild_keccak : public test_keccak_base // { // public: // bool init() @@ -139,102 +105,136 @@ protected: // { // pretest(); // -// crypto::hash h2; -// crypto::wild_keccak_dbl_opt(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h2), sizeof(h2), (const UINT64*)&m_scratchpad_vec[0], m_scratchpad_vec.size() * 4); -// LOG_PRINT_L4("HASH:" << h2); +// crypto::hash h; +// crypto::wild_keccak_dbl(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h), sizeof(h), [&](crypto::state_t_m& st, crypto::mixin_t& mix) +// { +// #define SCR_I(i) m_scratchpad_vec[st[i]%m_scratchpad_vec.size()] +// for (size_t i = 0; i != 6; i++) +// { +// OPT_XOR_4_RES(SCR_I(i * 4), SCR_I(i * 4 + 1), SCR_I(i * 4 + 2), SCR_I(i * 4 + 3), *(crypto::hash*)&mix[i * 4]); +// } +// }); +// // return true; // } // protected: // std::vector m_scratchpad_vec; // }; - -#ifdef _DEBUG - #define max_measere_scratchpad 100000 -#else - #define max_measere_scratchpad 50000000 -#endif -#define measere_rounds 10000 - -void generate_scratchpad() -{ - crypto::hash seed = crypto::cn_fast_hash("sdssdsffdss", 10); - std::vector scratchpad; - size_t count = 500000000 / 32; - TIME_MEASURE_START_MS(gen_time); - LOG_PRINT_L0("Generating...."); - crypto::generate_scratchpad2(seed, scratchpad, count); - TIME_MEASURE_FINISH_MS(gen_time); - LOG_PRINT_L0("Generated scratchpad " << (scratchpad.size() * 32) / (1024 * 1024) << "MB in " << gen_time << "ms"); -} - -void generate_light_scratchpad() -{ - crypto::hash seed = crypto::cn_fast_hash("sdssdsffdss", 10); - std::vector scratchpad; - size_t count = 500000000 / 32; - TIME_MEASURE_START_MS(gen_time); - LOG_PRINT_L0("Generating...."); - crypto::generate_scratchpad_light(seed, scratchpad, count); - TIME_MEASURE_FINISH_MS(gen_time); - LOG_PRINT_L0("Generated scratchpad " << (scratchpad.size() * 32) / (1024 * 1024) << "MB in " << gen_time << "ms"); -} - - -void measure_keccak_over_scratchpad(uint64_t start_scratchpad_size, uint64_t step_size) -{ -// std::cout << std::setw(20) << std::left << "sz\t" << - //std::setw(10) << "original\t" << -// std::setw(10) << "original opt\t" << -// std::setw(10) << "w2\t" << -// std::setw(10) << "w2_opt" << ENDL; - - std::vector scratchpad_vec; - scratchpad_vec.resize(max_measere_scratchpad); - std::string has_str = "Keccak is a family of sponge functions. The sponge function is a generalization of the concept of cryptographic hash function with infinite output and can perform quasi all symmetric cryptographic functions, from hashing to pseudo-random number generation to authenticated encryption"; - - for (size_t j = 0; j != scratchpad_vec.size(); j++) - scratchpad_vec[j] = crypto::rand(); - - for (uint64_t i = start_scratchpad_size; i < max_measere_scratchpad; i += i/10) - { - - crypto::hash res_h = currency::null_hash; - uint64_t ticks_a = epee::misc_utils::get_tick_count(); - *(uint64_t*)(&has_str[8]) = i; - - uint64_t ticks_b = epee::misc_utils::get_tick_count(); - for (size_t r = 0; r != measere_rounds; r++) - { - *(size_t*)(&has_str[1]) = r; - crypto::get_wild_keccak(has_str, res_h, 1, scratchpad_vec, i); - } - - //wild keccak 2 - uint64_t ticks_c = epee::misc_utils::get_tick_count(); - for (size_t r = 0; r != measere_rounds; r++) - { - *(size_t*)(&has_str[1]) = r; - res_h = crypto::cn_fast_hash(has_str.data(), has_str.size()); - } - //wild keccak 2 opt - uint64_t ticks_d = epee::misc_utils::get_tick_count(); - for (size_t r = 0; r != measere_rounds; r++) - { - crypto::get_wild_keccak2(has_str, res_h, scratchpad_vec, i); - } - - uint64_t ticks_e = epee::misc_utils::get_tick_count(); - std::cout << std::setw(20) << std::left << i * sizeof(crypto::hash) << "\t" << - //std::setw(10) << ticks_b - ticks_a << "\t" << - //std::setw(10) << ticks_c - ticks_b << "\t" << - std::setw(10) << ticks_d - ticks_c << "\t" << - std::setw(10) << ticks_e - ticks_d << ENDL; - } -} - -void measure_keccak_over_scratchpad() -{ - //measure_keccak_over_scratchpad(100/32, 100/32); - //measure_keccak_over_scratchpad(10, max_measere_scratchpad / 10); - measure_keccak_over_scratchpad(max_measere_scratchpad/10, 0); -} +// +// // +// // template +// // class test_wild_keccak2 : public test_keccak_base +// // { +// // public: +// // bool init() +// // { +// // m_scratchpad_vec.resize(scratchpad_size / sizeof(crypto::hash)); +// // for (auto& h : m_scratchpad_vec) +// // h = crypto::rand(); +// // +// // return test_keccak_base::init(); +// // } +// // +// // bool test() +// // { +// // pretest(); +// // +// // crypto::hash h2; +// // crypto::wild_keccak_dbl_opt(reinterpret_cast(&m_buff[0]), m_buff.size(), reinterpret_cast(&h2), sizeof(h2), (const UINT64*)&m_scratchpad_vec[0], m_scratchpad_vec.size() * 4); +// // LOG_PRINT_L4("HASH:" << h2); +// // return true; +// // } +// // protected: +// // std::vector m_scratchpad_vec; +// // }; +// +// #ifdef _DEBUG +// #define max_measere_scratchpad 100000 +// #else +// #define max_measere_scratchpad 50000000 +// #endif +// #define measere_rounds 10000 +// +// void generate_scratchpad() +// { +// crypto::hash seed = crypto::cn_fast_hash("sdssdsffdss", 10); +// std::vector scratchpad; +// size_t count = 500000000 / 32; +// TIME_MEASURE_START_MS(gen_time); +// LOG_PRINT_L0("Generating...."); +// crypto::generate_scratchpad2(seed, scratchpad, count); +// TIME_MEASURE_FINISH_MS(gen_time); +// LOG_PRINT_L0("Generated scratchpad " << (scratchpad.size() * 32) / (1024 * 1024) << "MB in " << gen_time << "ms"); +// } +// +// void generate_light_scratchpad() +// { +// crypto::hash seed = crypto::cn_fast_hash("sdssdsffdss", 10); +// std::vector scratchpad; +// size_t count = 500000000 / 32; +// TIME_MEASURE_START_MS(gen_time); +// LOG_PRINT_L0("Generating...."); +// crypto::generate_scratchpad_light(seed, scratchpad, count); +// TIME_MEASURE_FINISH_MS(gen_time); +// LOG_PRINT_L0("Generated scratchpad " << (scratchpad.size() * 32) / (1024 * 1024) << "MB in " << gen_time << "ms"); +// } +// +// +// void measure_keccak_over_scratchpad(uint64_t start_scratchpad_size, uint64_t step_size) +// { +// // std::cout << std::setw(20) << std::left << "sz\t" << +// //std::setw(10) << "original\t" << +// // std::setw(10) << "original opt\t" << +// // std::setw(10) << "w2\t" << +// // std::setw(10) << "w2_opt" << ENDL; +// +// std::vector scratchpad_vec; +// scratchpad_vec.resize(max_measere_scratchpad); +// std::string has_str = "Keccak is a family of sponge functions. The sponge function is a generalization of the concept of cryptographic hash function with infinite output and can perform quasi all symmetric cryptographic functions, from hashing to pseudo-random number generation to authenticated encryption"; +// +// for (size_t j = 0; j != scratchpad_vec.size(); j++) +// scratchpad_vec[j] = crypto::rand(); +// +// for (uint64_t i = start_scratchpad_size; i < max_measere_scratchpad; i += i/10) +// { +// +// crypto::hash res_h = currency::null_hash; +// uint64_t ticks_a = epee::misc_utils::get_tick_count(); +// *(uint64_t*)(&has_str[8]) = i; +// +// uint64_t ticks_b = epee::misc_utils::get_tick_count(); +// for (size_t r = 0; r != measere_rounds; r++) +// { +// *(size_t*)(&has_str[1]) = r; +// crypto::get_wild_keccak(has_str, res_h, 1, scratchpad_vec, i); +// } +// +// //wild keccak 2 +// uint64_t ticks_c = epee::misc_utils::get_tick_count(); +// for (size_t r = 0; r != measere_rounds; r++) +// { +// *(size_t*)(&has_str[1]) = r; +// res_h = crypto::cn_fast_hash(has_str.data(), has_str.size()); +// } +// //wild keccak 2 opt +// uint64_t ticks_d = epee::misc_utils::get_tick_count(); +// for (size_t r = 0; r != measere_rounds; r++) +// { +// crypto::get_wild_keccak2(has_str, res_h, scratchpad_vec, i); +// } +// +// uint64_t ticks_e = epee::misc_utils::get_tick_count(); +// std::cout << std::setw(20) << std::left << i * sizeof(crypto::hash) << "\t" << +// //std::setw(10) << ticks_b - ticks_a << "\t" << +// //std::setw(10) << ticks_c - ticks_b << "\t" << +// std::setw(10) << ticks_d - ticks_c << "\t" << +// std::setw(10) << ticks_e - ticks_d << ENDL; +// } +// } +// +// void measure_keccak_over_scratchpad() +// { +// //measure_keccak_over_scratchpad(100/32, 100/32); +// //measure_keccak_over_scratchpad(10, max_measere_scratchpad / 10); +// measure_keccak_over_scratchpad(max_measere_scratchpad/10, 0); +// } diff --git a/tests/performance_tests/main.cpp b/tests/performance_tests/main.cpp index c6b88c64..37591d6a 100644 --- a/tests/performance_tests/main.cpp +++ b/tests/performance_tests/main.cpp @@ -38,7 +38,7 @@ int main(int argc, char** argv) //generate_scratchpad(); //generate_light_scratchpad(); //measure_keccak_over_scratchpad(); - test_scratchpad_against_light_scratchpad(); + //test_scratchpad_against_light_scratchpad(); /* TEST_PERFORMANCE2(test_construct_tx, 1, 1); TEST_PERFORMANCE2(test_construct_tx, 1, 2); diff --git a/tests/unit_tests/pow_hash_test.cpp b/tests/unit_tests/pow_hash_test.cpp index 523aeed1..f74c1ad9 100644 --- a/tests/unit_tests/pow_hash_test.cpp +++ b/tests/unit_tests/pow_hash_test.cpp @@ -10,42 +10,42 @@ #include "crypto/crypto.h" #include "currency_core/currency_basic.h" #include "profile_tools.h" -#include "crypto/wild_keccak.h" +//#include "crypto/wild_keccak.h" #include "currency_core/currency_format_utils.h" using namespace currency; - -bool test_scratchpad_against_light_scratchpad() -{ - crypto::hash seed = crypto::cn_fast_hash("sdssdsffdss", 10); - std::vector scratchpad; - size_t count = 400; - TIME_MEASURE_START_MS(gen_time); - LOG_PRINT_L0("Generating full ...."); - crypto::generate_scratchpad2(seed, scratchpad, count); - TIME_MEASURE_FINISH_MS(gen_time); - LOG_PRINT_L0("Generated full scratchpad " << (scratchpad.size() * 32) / (1024 * 1024) << "MB in " << gen_time << "ms"); - std::vector scratchpad_light; - crypto::generate_scratchpad_light(seed, scratchpad_light, count); - - std::string hashing_str = "dsfssfadfada"; - crypto::hash full_h = currency::null_hash; - crypto::hash light_h = currency::null_hash; - crypto::get_wild_keccak2(hashing_str, full_h, scratchpad); - crypto::get_wild_keccak_light(hashing_str, light_h, scratchpad_light); - if (full_h != light_h) - { - LOG_ERROR("Hash missmatch"); - return false; - } - return true; -} - -TEST(pow_tests, test_full_against_light) -{ - bool res = test_scratchpad_against_light_scratchpad(); - ASSERT_TRUE(res); -} +// +// bool test_scratchpad_against_light_scratchpad() +// { +// crypto::hash seed = crypto::cn_fast_hash("sdssdsffdss", 10); +// std::vector scratchpad; +// size_t count = 400; +// TIME_MEASURE_START_MS(gen_time); +// LOG_PRINT_L0("Generating full ...."); +// crypto::generate_scratchpad2(seed, scratchpad, count); +// TIME_MEASURE_FINISH_MS(gen_time); +// LOG_PRINT_L0("Generated full scratchpad " << (scratchpad.size() * 32) / (1024 * 1024) << "MB in " << gen_time << "ms"); +// std::vector scratchpad_light; +// crypto::generate_scratchpad_light(seed, scratchpad_light, count); +// +// std::string hashing_str = "dsfssfadfada"; +// crypto::hash full_h = currency::null_hash; +// crypto::hash light_h = currency::null_hash; +// crypto::get_wild_keccak2(hashing_str, full_h, scratchpad); +// crypto::get_wild_keccak_light(hashing_str, light_h, scratchpad_light); +// if (full_h != light_h) +// { +// LOG_ERROR("Hash missmatch"); +// return false; +// } +// return true; +// } +// +// TEST(pow_tests, test_full_against_light) +// { +// bool res = test_scratchpad_against_light_scratchpad(); +// ASSERT_TRUE(res); +// } diff --git a/utils/configure_win64_msvs2015_gui.cmd b/utils/configure_win64_msvs2015_gui.cmd index 07884551..73e44d17 100644 --- a/utils/configure_win64_msvs2015_gui.cmd +++ b/utils/configure_win64_msvs2015_gui.cmd @@ -4,4 +4,4 @@ cd .. @mkdir build_msvc2015_64 cd build_msvc2015_64 -cmake -D USE_PCH=TRUE -D BUILD_TESTS=TRUE -D CMAKE_PREFIX_PATH="%QT_PREFIX_PATH%"\msvc2015_64 -D BUILD_GUI=TRUE -D USE_OPENCL=TRUE -D STATIC=FALSE -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_ROOT%\lib64-msvc-14.0" -G "Visual Studio 14 2015 Win64" -T host=x64 ".." \ No newline at end of file +cmake -D USE_PCH=TRUE -D BUILD_TESTS=TRUE -D CMAKE_PREFIX_PATH="%QT_PREFIX_PATH%"\msvc2015_64 -D BUILD_GUI=TRUE -D STATIC=FALSE -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_ROOT%\lib64-msvc-14.0" -G "Visual Studio 14 2015 Win64" -T host=x64 ".." \ No newline at end of file diff --git a/utils/configure_win64_msvs2017_gui.cmd b/utils/configure_win64_msvs2017_gui.cmd index a104a1fa..fe6e3eea 100644 --- a/utils/configure_win64_msvs2017_gui.cmd +++ b/utils/configure_win64_msvs2017_gui.cmd @@ -4,4 +4,4 @@ cd .. @mkdir build_msvc2017_64 cd build_msvc2017_64 -cmake -D USE_PCH=TRUE -D BUILD_TESTS=TRUE -D CMAKE_PREFIX_PATH="%QT_PREFIX_PATH%"\msvc2017_64 -D BUILD_GUI=TRUE -D USE_OPENCL=TRUE -D STATIC=FALSE -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_ROOT%\lib64-msvc-14.1" -G "Visual Studio 15 2017 Win64" -T host=x64 ".." \ No newline at end of file +cmake -D USE_PCH=TRUE -D BUILD_TESTS=TRUE -D CMAKE_PREFIX_PATH="%QT_PREFIX_PATH%"\msvc2017_64 -D BUILD_GUI=TRUE -D STATIC=FALSE -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_ROOT%\lib64-msvc-14.1" -G "Visual Studio 15 2017 Win64" -T host=x64 ".." \ No newline at end of file