mirror of
https://github.com/SChernykh/p2pool.git
synced 2024-12-22 11:29:23 +00:00
Unit tests for difficulty_type
This commit is contained in:
parent
b26c4616d7
commit
2d8530798d
7 changed files with 400 additions and 0 deletions
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
[submodule "tests/googletest"]
|
||||
path = tests/googletest
|
||||
url = https://github.com/google/googletest
|
|
@ -234,7 +234,9 @@ private:
|
|||
std::ofstream m_logFile;
|
||||
};
|
||||
|
||||
#ifndef P2POOL_LOG_DISABLE
|
||||
static Worker worker;
|
||||
#endif
|
||||
|
||||
NOINLINE Writer::Writer(Severity severity) : Stream(m_stackBuf)
|
||||
{
|
||||
|
@ -252,7 +254,9 @@ NOINLINE Writer::~Writer()
|
|||
m_buf[1] = static_cast<uint8_t>(size & 255);
|
||||
m_buf[2] = static_cast<uint8_t>(size >> 8);
|
||||
m_buf[m_pos] = '\n';
|
||||
#ifndef P2POOL_LOG_DISABLE
|
||||
worker.write(m_buf, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
void reopen()
|
||||
|
@ -263,7 +267,9 @@ void reopen()
|
|||
|
||||
void stop()
|
||||
{
|
||||
#ifndef P2POOL_LOG_DISABLE
|
||||
worker.stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
NOINLINE void Stream::writeCurrentTime()
|
||||
|
|
10
src/log.h
10
src/log.h
|
@ -384,6 +384,14 @@ namespace {
|
|||
#define CONCAT(a, b) CONCAT2(a, b)
|
||||
#define CONCAT2(a, b) a##b
|
||||
|
||||
#ifdef P2POOL_LOG_DISABLE
|
||||
|
||||
#define LOGINFO(level, ...)
|
||||
#define LOGWARN(level, ...)
|
||||
#define LOGERR(level, ...)
|
||||
|
||||
#else
|
||||
|
||||
#define LOG(level, severity, ...) \
|
||||
do { \
|
||||
if (level <= log::GLOBAL_LOG_LEVEL) { \
|
||||
|
@ -398,6 +406,8 @@ namespace {
|
|||
#define LOGWARN(level, ...) LOG(level, log::Severity::Warning, __VA_ARGS__)
|
||||
#define LOGERR(level, ...) LOG(level, log::Severity::Error, __VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
void reopen();
|
||||
void stop();
|
||||
|
||||
|
|
108
tests/CMakeLists.txt
Normal file
108
tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,108 @@
|
|||
cmake_minimum_required(VERSION 2.8.12)
|
||||
project(p2pool_tests)
|
||||
|
||||
add_subdirectory(googletest)
|
||||
set(LIBS gtest)
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES GNU)
|
||||
set(WARNING_FLAGS "")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -s")
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS}")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
|
||||
if (WIN32)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
|
||||
else()
|
||||
if (STATIC_LINUX_BINARY)
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static")
|
||||
else()
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libgcc -static-libstdc++")
|
||||
endif()
|
||||
endif()
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
set(WARNING_FLAGS "")
|
||||
set(SECURITY_FLAGS "/GS /guard:cf")
|
||||
set(OPTIMIZATION_FLAGS "/O2 /Oi /Ob2 /Ot /DNDEBUG /GL")
|
||||
|
||||
set(CMAKE_C_FLAGS_DEBUG "${WARNING_FLAGS} ${SECURITY_FLAGS} /Od /Ob0 /Zi /MTd /fsanitize=address")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${WARNING_FLAGS} ${SECURITY_FLAGS} /Od /Ob0 /Zi /MTd /fsanitize=address")
|
||||
|
||||
set(CMAKE_C_FLAGS_RELEASE "${WARNING_FLAGS} ${SECURITY_FLAGS} ${OPTIMIZATION_FLAGS} /MT")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${WARNING_FLAGS} ${SECURITY_FLAGS} ${OPTIMIZATION_FLAGS} /MT")
|
||||
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${WARNING_FLAGS} ${SECURITY_FLAGS} /Ob1 /Ot /Zi /MT")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
|
||||
set(WARNING_FLAGS "")
|
||||
set(OPTIMIZATION_FLAGS "-Ofast -funroll-loops -fmerge-all-constants")
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WARNING_FLAGS}")
|
||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARNING_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${WARNING_FLAGS} ${OPTIMIZATION_FLAGS}")
|
||||
endif()
|
||||
|
||||
set(HEADERS
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
src/difficulty_type.cpp
|
||||
src/tests.cpp
|
||||
../src/log.cpp
|
||||
../src/util.cpp
|
||||
)
|
||||
|
||||
include_directories(../src)
|
||||
include_directories(../external/src)
|
||||
include_directories(../external/src/cryptonote)
|
||||
include_directories(../external/src/libuv/include)
|
||||
include_directories(../external/src/cppzmq)
|
||||
include_directories(../external/src/libzmq/include)
|
||||
include_directories(../external/src/llhttp)
|
||||
include_directories(../external/src/randomx/src)
|
||||
include_directories(src)
|
||||
include_directories(googletest/googletest/include)
|
||||
|
||||
if (WIN32)
|
||||
set(LIBS ${LIBS} ws2_32 iphlpapi userenv psapi)
|
||||
elseif (NOT APPLE)
|
||||
set(LIBS ${LIBS} pthread gss dl)
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
find_library(ZMQ_LIBRARY_DEBUG NAMES libzmq-v142-mt-sgd-4_3_5 PATHS "../external/lib/libzmq/Debug")
|
||||
find_library(ZMQ_LIBRARY NAMES libzmq-v142-mt-s-4_3_5 PATHS "../external/lib/libzmq/Release")
|
||||
find_library(UV_LIBRARY_DEBUG NAMES uv_a PATHS "../external/lib/libuv/Debug")
|
||||
find_library(UV_LIBRARY NAMES uv_a PATHS "../external/lib/libuv/Release")
|
||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES GNU OR CMAKE_CXX_COMPILER_ID MATCHES Clang)
|
||||
find_library(ZMQ_LIBRARY_DEBUG NAMES zmq libzmq.a)
|
||||
find_library(ZMQ_LIBRARY NAMES zmq libzmq.a)
|
||||
find_library(UV_LIBRARY_DEBUG NAMES uv libuv.a)
|
||||
find_library(UV_LIBRARY NAMES uv libuv.a)
|
||||
find_library(SODIUM_LIBRARY sodium)
|
||||
endif()
|
||||
|
||||
find_library(PGM_LIBRARY pgm)
|
||||
find_library(NORM_LIBRARY norm)
|
||||
|
||||
if (PGM_LIBRARY)
|
||||
set(LIBS ${LIBS} ${PGM_LIBRARY})
|
||||
endif()
|
||||
|
||||
if (NORM_LIBRARY)
|
||||
set(LIBS ${LIBS} ${NORM_LIBRARY})
|
||||
endif()
|
||||
|
||||
if (SODIUM_LIBRARY)
|
||||
set(LIBS ${LIBS} ${SODIUM_LIBRARY})
|
||||
endif()
|
||||
|
||||
add_definitions(/DZMQ_STATIC /DP2POOL_LOG_DISABLE)
|
||||
|
||||
add_executable(${CMAKE_PROJECT_NAME} ${HEADERS} ${SOURCES})
|
||||
target_link_libraries(${CMAKE_PROJECT_NAME} debug ${ZMQ_LIBRARY_DEBUG} debug ${UV_LIBRARY_DEBUG} optimized ${ZMQ_LIBRARY} optimized ${UV_LIBRARY} ${LIBS})
|
1
tests/googletest
Submodule
1
tests/googletest
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 955c7f837efad184ec63e771c42542d37545eaef
|
248
tests/src/difficulty_type.cpp
Normal file
248
tests/src/difficulty_type.cpp
Normal file
|
@ -0,0 +1,248 @@
|
|||
/*
|
||||
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
|
||||
* Copyright (c) 2021 SChernykh <https://github.com/SChernykh>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <random>
|
||||
|
||||
namespace p2pool {
|
||||
|
||||
TEST(difficulty_type, target)
|
||||
{
|
||||
// diff = 0
|
||||
{
|
||||
difficulty_type d(0, 0);
|
||||
ASSERT_EQ(d.target(), std::numeric_limits<uint64_t>::max());
|
||||
}
|
||||
|
||||
// diff = 1
|
||||
{
|
||||
difficulty_type d(1, 0);
|
||||
ASSERT_EQ(d.target(), std::numeric_limits<uint64_t>::max());
|
||||
}
|
||||
|
||||
// diff = 2^64
|
||||
{
|
||||
difficulty_type d(0, 1);
|
||||
ASSERT_EQ(d.target(), 1);
|
||||
}
|
||||
|
||||
// diff = 2^32
|
||||
{
|
||||
difficulty_type d(1ull << 32, 0);
|
||||
ASSERT_EQ(d.target(), 1ull << 32);
|
||||
}
|
||||
|
||||
// diff from block 2440918
|
||||
{
|
||||
difficulty_type d(334654765825ull, 0);
|
||||
ASSERT_EQ(d.target(), 55121714);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(difficulty_type, sum)
|
||||
{
|
||||
// No carry
|
||||
{
|
||||
difficulty_type diff[4] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
|
||||
|
||||
for (int i = 0; i <= 3; ++i) {
|
||||
for (int j = 0; j <= 3; ++j) {
|
||||
difficulty_type a = diff[i];
|
||||
a += diff[j];
|
||||
ASSERT_EQ(a.lo, diff[i].lo + diff[j].lo);
|
||||
ASSERT_EQ(a.hi, diff[i].hi + diff[j].hi);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Carry
|
||||
{
|
||||
difficulty_type a(11400714819323198485ull, 0);
|
||||
difficulty_type b(15975348984942515101ull, 0);
|
||||
a += b;
|
||||
ASSERT_EQ(a.lo, 8929319730556161970ull);
|
||||
ASSERT_EQ(a.hi, 1);
|
||||
}
|
||||
|
||||
// Carry (edge case)
|
||||
{
|
||||
difficulty_type a(std::numeric_limits<uint64_t>::max(), 0);
|
||||
difficulty_type b(1, 0);
|
||||
a += b;
|
||||
ASSERT_EQ(a.lo, 0);
|
||||
ASSERT_EQ(a.hi, 1);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(difficulty_type, compare)
|
||||
{
|
||||
const difficulty_type diff[4] = { { 0, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
|
||||
|
||||
for (int i = 0; i <= 3; ++i) {
|
||||
for (int j = 0; j <= 3; ++j) {
|
||||
ASSERT_EQ(diff[i] < diff[j], i < j);
|
||||
ASSERT_EQ(diff[i] >= diff[j], i >= j);
|
||||
ASSERT_EQ(diff[i] == diff[j], i == j);
|
||||
ASSERT_EQ(diff[i] != diff[j], i != j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(difficulty_type, check_pow)
|
||||
{
|
||||
hash h;
|
||||
|
||||
// Power of 2 close to the current Monero network difficulty
|
||||
difficulty_type diff = { 1ull << 38, 0 };
|
||||
{
|
||||
// 2^256 / 2^38 = 2^218
|
||||
// diff.check_pow() will get 2^256 as a multiplication result = lowest possible value that fails the test
|
||||
uint64_t data[4] = { 0, 0, 0, 1ull << 26 };
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
ASSERT_EQ(diff.check_pow(h), false);
|
||||
|
||||
// Now decrease the hash by 1. It should pass the test now
|
||||
data[0] = data[1] = data[2] = std::numeric_limits<uint64_t>::max();
|
||||
--data[3];
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
ASSERT_EQ(diff.check_pow(h), true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Factors of 2^256 - 1:
|
||||
* P1 = 3
|
||||
* P1 = 5
|
||||
* P2 = 17
|
||||
* P3 = 257
|
||||
* P3 = 641
|
||||
* P5 = 65537
|
||||
* P6 = 274177
|
||||
* P7 = 6700417
|
||||
* P14 = 67280421310721
|
||||
* P17 = 59649589127497217
|
||||
* P22 = 5704689200685129054721
|
||||
*/
|
||||
diff = { 67280421310721ull, 0 };
|
||||
{
|
||||
// (2^256 - 1) / 67280421310721 = 1721036922503113971692907638171526209875755521904893141463060735
|
||||
// diff.check_pow() will get 2^256-1 as a multiplication result = highest possible value that still passes the test
|
||||
uint64_t data[4] = { 0xfffffffffffbd0ffull, 0x0000000000042f00ull, 0xfffffffffffbd0ffull, 0x42f00ull };
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
ASSERT_EQ(diff.check_pow(h), true);
|
||||
|
||||
// Now increase the hash by 1. It should not pass the test anymore
|
||||
++data[0];
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
ASSERT_EQ(diff.check_pow(h), false);
|
||||
}
|
||||
|
||||
// diff = 5704689200685129054721
|
||||
diff = { 4645281908877605377ull, 309ull };
|
||||
{
|
||||
// (2^256 - 1) / 5704689200685129054721 = 20297703374166229616474325006177763232573806344580020735
|
||||
// diff.check_pow() will get 2^256-1 as a multiplication result = highest possible value that still passes the test
|
||||
uint64_t data[4] = { 0xff2c1503c50eb9ffull, 0xffffffffffffffffull, 0xd3eafc3af14600ull, 0 };
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
ASSERT_EQ(diff.check_pow(h), true);
|
||||
|
||||
// Now increase the hash by 1. It should not pass the test anymore
|
||||
++data[0];
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
ASSERT_EQ(diff.check_pow(h), false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Factors of 2^256 + 1:
|
||||
* P16 = 1238926361552897
|
||||
* P62 = 93461639715357977769163558199606896584051237541638188580280321
|
||||
*/
|
||||
diff = { 1238926361552897ull, 0 };
|
||||
{
|
||||
// (2^256 + 1) / 1238926361552897 = 93461639715357977769163558199606896584051237541638188580280321
|
||||
// diff.check_pow() will get 2^256+1 as a multiplication result = lowest possible non-power of 2 that fails the test
|
||||
uint64_t data[4] = { 0x49baa0ba2c911801ull, 0x6ee3637cab2586d0ull, 0x4c585a8f5c7073e3, 0x3a29ull };
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
ASSERT_EQ(diff.check_pow(h), false);
|
||||
|
||||
// Now decrease the hash by 1. It should pass the test now
|
||||
--data[0];
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
ASSERT_EQ(diff.check_pow(h), true);
|
||||
}
|
||||
|
||||
// Randomized tests with fixed seed
|
||||
std::mt19937_64 r(0);
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
// Random difficulty between 300G and 400G
|
||||
difficulty_type diff{ 300000000000ull + (r() % 100000000000ull), 0 };
|
||||
hash h;
|
||||
|
||||
// All zeros
|
||||
memset(h.h, 0, HASH_SIZE);
|
||||
ASSERT_EQ(diff.check_pow(h), true);
|
||||
|
||||
// All ones
|
||||
memset(h.h, -1, HASH_SIZE);
|
||||
ASSERT_EQ(diff.check_pow(h), false);
|
||||
|
||||
{
|
||||
uint64_t data[4];
|
||||
uint64_t rem;
|
||||
data[3] = udiv128(1, 0, diff.lo, &rem);
|
||||
data[2] = udiv128(rem, 0, diff.lo, &rem);
|
||||
data[1] = udiv128(rem, 0, diff.lo, &rem);
|
||||
data[0] = udiv128(rem, 0, diff.lo, &rem);
|
||||
|
||||
// Max hash value that passes this difficulty
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
EXPECT_EQ(diff.check_pow(h), true);
|
||||
|
||||
// Add 1 to data (256-bit number)
|
||||
for (int j = 0; j <= 3; ++j) {
|
||||
++data[j];
|
||||
if (data[j]) {
|
||||
// No carry, exit the loop
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Min hash value that fails this difficulty
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
EXPECT_EQ(diff.check_pow(h), false);
|
||||
}
|
||||
|
||||
const uint64_t target = diff.target();
|
||||
|
||||
// Random values that pass
|
||||
for (int j = 0; j < 10000; ++j) {
|
||||
const uint64_t data[4] = { r(), r(), r(), r() % target };
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
EXPECT_EQ(diff.check_pow(h), true);
|
||||
}
|
||||
|
||||
// Random values that fail
|
||||
for (int j = 0; j < 10000; ++j) {
|
||||
const uint64_t data[4] = { r(), r(), r(), target + (r() % (std::numeric_limits<uint64_t>::max() - target + 1)) };
|
||||
memcpy(h.h, data, HASH_SIZE);
|
||||
EXPECT_EQ(diff.check_pow(h), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
24
tests/src/tests.cpp
Normal file
24
tests/src/tests.cpp
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* This file is part of the Monero P2Pool <https://github.com/SChernykh/p2pool>
|
||||
* Copyright (c) 2021 SChernykh <https://github.com/SChernykh>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
Loading…
Reference in a new issue