Commit 95711bc2 authored by obscuren's avatar obscuren

Updated ethash

parent 387f6bba
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
}, },
{ {
"ImportPath": "github.com/ethereum/ethash", "ImportPath": "github.com/ethereum/ethash",
"Comment": "v17-64-ga323708", "Comment": "v23-11-g5376ec8",
"Rev": "a323708b8c4d253b8567bf6c72727d1aec302225" "Rev": "5376ec8816d6bf787d4fc91a08b4527bc5e1f469"
}, },
{ {
"ImportPath": "github.com/ethereum/serpent-go", "ImportPath": "github.com/ethereum/serpent-go",
......
...@@ -8,3 +8,5 @@ pyethash.egg-info/ ...@@ -8,3 +8,5 @@ pyethash.egg-info/
*.so *.so
*~ *~
*.swp *.swp
MANIFEST
dist/
cmake_minimum_required(VERSION 2.8.7) cmake_minimum_required(VERSION 2.8.7)
project(ethash) project(ethash)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules/")
set(ETHHASH_LIBS ethash) set(ETHHASH_LIBS ethash)
if (WIN32 AND WANT_CRYPTOPP) if (WIN32 AND WANT_CRYPTOPP)
...@@ -10,6 +10,12 @@ endif() ...@@ -10,6 +10,12 @@ endif()
add_subdirectory(src/libethash) add_subdirectory(src/libethash)
# bin2h.cmake doesn't work # bin2h.cmake doesn't work
#add_subdirectory(src/libethash-cl EXCLUDE_FROM_ALL) if (NOT OpenCL_FOUND)
find_package(OpenCL)
endif()
if (OpenCL_FOUND)
add_subdirectory(src/libethash-cl)
endif()
add_subdirectory(src/benchmark EXCLUDE_FROM_ALL) add_subdirectory(src/benchmark EXCLUDE_FROM_ALL)
add_subdirectory(test/c EXCLUDE_FROM_ALL) add_subdirectory(test/c EXCLUDE_FROM_ALL)
include setup.py
# C sources
include src/libethash/internal.c
include src/libethash/sha3.c
include src/libethash/util.c
include src/python/core.c
# Headers
include src/libethash/compiler.h
include src/libethash/data_sizes.h
include src/libethash/endian.h
include src/libethash/ethash.h
include src/libethash/fnv.h
include src/libethash/internal.h
include src/libethash/sha3.h
include src/libethash/util.h
.PHONY: clean .PHONY: clean test
test:
./test/test.sh
clean: clean:
rm -rf *.so pyethash.egg-info/ build/ test/python/python-virtual-env/ test/c/build/ pyethash/*.{so,pyc} rm -rf *.so pyethash.egg-info/ build/ test/python/python-virtual-env/ test/c/build/ pyethash.so test/python/*.pyc dist/ MANIFEST
...@@ -8,6 +8,6 @@ file(GLOB SOURCE "../../cryptopp/*.cpp") ...@@ -8,6 +8,6 @@ file(GLOB SOURCE "../../cryptopp/*.cpp")
add_library(${LIBRARY} ${HEADERS} ${SOURCE}) add_library(${LIBRARY} ${HEADERS} ${SOURCE})
set(CRYPTOPP_INCLUDE_DIRS "../.." PARENT_SCOPE) set(CRYPTOPP_INCLUDE_DIRS "../.." "../../../" PARENT_SCOPE)
set(CRYPTOPP_LIBRARIES ${LIBRARY} PARENT_SCOPE) set(CRYPTOPP_LIBRARIES ${LIBRARY} PARENT_SCOPE)
set(CRYPTOPP_FOUND TRUE PARENT_SCOPE) set(CRYPTOPP_FOUND TRUE PARENT_SCOPE)
import pyethash.core
core = pyethash.core
EPOCH_LENGTH = 30000
#!/usr/bin/env python #!/usr/bin/env python
from distutils.core import setup, Extension from distutils.core import setup, Extension
pyethash_core = Extension('pyethash.core', pyethash = Extension('pyethash',
sources = [ sources = [
'src/python/core.c', 'src/python/core.c',
'src/libethash/util.c', 'src/libethash/util.c',
'src/libethash/internal.c', 'src/libethash/internal.c',
'src/libethash/sha3.c' 'src/libethash/sha3.c'],
depends = [
'src/libethash/ethash.h',
'src/libethash/compiler.h',
'src/libethash/data_sizes.h',
'src/libethash/endian.h',
'src/libethash/ethash.h',
'src/libethash/fnv.h',
'src/libethash/internal.h',
'src/libethash/sha3.h',
'src/libethash/util.h'
], ],
extra_compile_args = ["-std=gnu99"]) extra_compile_args = ["-Isrc/", "-std=gnu99", "-Wall"])
setup ( setup (
name = 'pyethash', name = 'pyethash',
author = "Matthew Wampler-Doty", author = "Matthew Wampler-Doty",
author_email = "matthew.wampler.doty@gmail.com", author_email = "matthew.wampler.doty@gmail.com",
license = 'GPL', license = 'GPL',
version = '1.0', version = '23',
url = 'https://github.com/ethereum/ethash',
download_url = 'https://github.com/ethereum/ethash/tarball/v23',
description = 'Python wrappers for ethash, the ethereum proof of work hashing function', description = 'Python wrappers for ethash, the ethereum proof of work hashing function',
ext_modules = [pyethash_core], ext_modules = [pyethash],
) )
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#include <algorithm> #include <algorithm>
#ifdef WITH_CRYPTOPP #ifdef WITH_CRYPTOPP
#include <libethash/SHA3_cryptopp.h> #include <libethash/sha3_cryptopp.h>
#include <string> #include <string>
#else #else
......
...@@ -2,14 +2,39 @@ set(LIBRARY ethash-cl) ...@@ -2,14 +2,39 @@ set(LIBRARY ethash-cl)
set(CMAKE_BUILD_TYPE Release) set(CMAKE_BUILD_TYPE Release)
include(bin2h.cmake) include(bin2h.cmake)
bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl VARIABLE_NAME ethash_cl_miner_kernel HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h) bin2h(SOURCE_FILE ethash_cl_miner_kernel.cl
VARIABLE_NAME ethash_cl_miner_kernel
HEADER_FILE ${CMAKE_CURRENT_BINARY_DIR}/ethash_cl_miner_kernel.h)
if (NOT MSVC)
# Initialize CXXFLAGS for c++11
set(CMAKE_CXX_FLAGS "-Wall -std=c++11")
set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O4 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g")
# Compiler-specific C++11 activation.
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
execute_process(
COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE GCC_VERSION)
if (NOT (GCC_VERSION VERSION_GREATER 4.7 OR GCC_VERSION VERSION_EQUAL 4.7))
message(FATAL_ERROR "${PROJECT_NAME} requires g++ 4.7 or greater.")
endif ()
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
else ()
message(FATAL_ERROR "Your C++ compiler does not support C++11.")
endif ()
endif()
if (NOT OpenCL_FOUND) if (NOT OpenCL_FOUND)
find_package(OpenCL) find_package(OpenCL)
endif() endif()
if (OpenCL_FOUND) if (OpenCL_FOUND)
include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR}) include_directories(${OpenCL_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
include_directories(..) include_directories(..)
add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h) add_library(${LIBRARY} ethash_cl_miner.cpp ethash_cl_miner.h cl.hpp)
TARGET_LINK_LIBRARIES(${LIBRARY} ${OpenCL_LIBRARIES} ethash) TARGET_LINK_LIBRARIES(${LIBRARY} ${OpenCL_LIBRARIES} ethash)
endif() endif()
...@@ -68,8 +68,7 @@ function(BIN2H) ...@@ -68,8 +68,7 @@ function(BIN2H)
string(REGEX REPLACE ", $" "" arrayValues ${arrayValues}) string(REGEX REPLACE ", $" "" arrayValues ${arrayValues})
# converts the variable name into proper C identifier # converts the variable name into proper C identifier
# TODO: fix for legacy cmake IF (${CMAKE_VERSION} GREATER 2.8.10) # fix for legacy cmake
IF (${CMAKE_VERSION} GREATER 2.8.10)
string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) string(MAKE_C_IDENTIFIER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
ENDIF() ENDIF()
string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME) string(TOUPPER "${BIN2H_VARIABLE_NAME}" BIN2H_VARIABLE_NAME)
......
...@@ -24,15 +24,22 @@ ...@@ -24,15 +24,22 @@
#include <assert.h> #include <assert.h>
#include <queue> #include <queue>
#include <vector>
#include "ethash_cl_miner.h" #include "ethash_cl_miner.h"
#include "ethash_cl_miner_kernel.h" #include "ethash_cl_miner_kernel.h"
#include <libethash/util.h> #include <libethash/util.h>
#define ETHASH_BYTES 32
// workaround lame platforms
#if !CL_VERSION_1_2
#define CL_MAP_WRITE_INVALIDATE_REGION CL_MAP_WRITE
#define CL_MEM_HOST_READ_ONLY 0
#endif
#undef min #undef min
#undef max #undef max
#define HASH_BYTES 32
static void add_definition(std::string& source, char const* id, unsigned value) static void add_definition(std::string& source, char const* id, unsigned value)
{ {
char buf[256]; char buf[256];
...@@ -41,6 +48,7 @@ static void add_definition(std::string& source, char const* id, unsigned value) ...@@ -41,6 +48,7 @@ static void add_definition(std::string& source, char const* id, unsigned value)
} }
ethash_cl_miner::ethash_cl_miner() ethash_cl_miner::ethash_cl_miner()
: m_opencl_1_1()
{ {
} }
...@@ -71,11 +79,23 @@ bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32], ...@@ -71,11 +79,23 @@ bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32],
} }
// use default device // use default device
cl::Device& device = devices[0]; unsigned device_num = 0;
debugf("Using device: %s\n", device.getInfo<CL_DEVICE_NAME>().c_str()); cl::Device& device = devices[device_num];
std::string device_version = device.getInfo<CL_DEVICE_VERSION>();
debugf("Using device: %s (%s)\n", device.getInfo<CL_DEVICE_NAME>().c_str(),device_version.c_str());
if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0)
{
debugf("OpenCL 1.0 is not supported.\n");
return false;
}
if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0)
{
m_opencl_1_1 = true;
}
// create context // create context
m_context = cl::Context({device}); m_context = cl::Context(std::vector<cl::Device>(&device, &device+1));
m_queue = cl::CommandQueue(m_context, device); m_queue = cl::CommandQueue(m_context, device);
// use requested workgroup size, but we require multiple of 8 // use requested workgroup size, but we require multiple of 8
...@@ -120,7 +140,7 @@ bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32], ...@@ -120,7 +140,7 @@ bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32],
ethash_mkcache(&cache, &params, seed); ethash_mkcache(&cache, &params, seed);
// if this throws then it's because we probably need to subdivide the dag uploads for compatibility // if this throws then it's because we probably need to subdivide the dag uploads for compatibility
void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, CL_MAP_WRITE_INVALIDATE_REGION, 0, params.full_size); void* dag_ptr = m_queue.enqueueMapBuffer(m_dag, true, m_opencl_1_1 ? CL_MAP_WRITE : CL_MAP_WRITE_INVALIDATE_REGION, 0, params.full_size);
ethash_compute_full_data(dag_ptr, &params, &cache); ethash_compute_full_data(dag_ptr, &params, &cache);
m_queue.enqueueUnmapMemObject(m_dag, dag_ptr); m_queue.enqueueUnmapMemObject(m_dag, dag_ptr);
...@@ -130,7 +150,7 @@ bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32], ...@@ -130,7 +150,7 @@ bool ethash_cl_miner::init(ethash_params const& params, const uint8_t seed[32],
// create mining buffers // create mining buffers
for (unsigned i = 0; i != c_num_buffers; ++i) for (unsigned i = 0; i != c_num_buffers; ++i)
{ {
m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | CL_MEM_HOST_READ_ONLY, 32*c_hash_batch_size); m_hash_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY | (!m_opencl_1_1 ? CL_MEM_HOST_READ_ONLY : 0), 32*c_hash_batch_size);
m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t)); m_search_buf[i] = cl::Buffer(m_context, CL_MEM_WRITE_ONLY, (c_max_search_results + 1) * sizeof(uint32_t));
} }
return true; return true;
...@@ -176,7 +196,6 @@ void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, ...@@ -176,7 +196,6 @@ void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce,
m_hash_kernel.setArg(0, m_hash_buf[buf]); m_hash_kernel.setArg(0, m_hash_buf[buf]);
// execute it! // execute it!
clock_t start_time = clock();
m_queue.enqueueNDRangeKernel( m_queue.enqueueNDRangeKernel(
m_hash_kernel, m_hash_kernel,
cl::NullRange, cl::NullRange,
...@@ -196,8 +215,8 @@ void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce, ...@@ -196,8 +215,8 @@ void ethash_cl_miner::hash(uint8_t* ret, uint8_t const* header, uint64_t nonce,
pending_batch const& batch = pending.front(); pending_batch const& batch = pending.front();
// could use pinned host pointer instead, but this path isn't that important. // could use pinned host pointer instead, but this path isn't that important.
uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * HASH_BYTES); uint8_t* hashes = (uint8_t*)m_queue.enqueueMapBuffer(m_hash_buf[batch.buf], true, CL_MAP_READ, 0, batch.count * ETHASH_BYTES);
memcpy(ret + batch.base*HASH_BYTES, hashes, batch.count*HASH_BYTES); memcpy(ret + batch.base*ETHASH_BYTES, hashes, batch.count*ETHASH_BYTES);
m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes); m_queue.enqueueUnmapMemObject(m_hash_buf[batch.buf], hashes);
pending.pop(); pending.pop();
...@@ -223,8 +242,19 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook ...@@ -223,8 +242,19 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
{ {
m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero); m_queue.enqueueWriteBuffer(m_search_buf[i], false, 0, 4, &c_zero);
} }
#if CL_VERSION_1_2
cl::Event pre_return_event; cl::Event pre_return_event;
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event); if (!m_opencl_1_1)
{
m_queue.enqueueBarrierWithWaitList(NULL, &pre_return_event);
}
else
#else
{
m_queue.finish();
}
#endif
/* /*
__kernel void ethash_combined_search( __kernel void ethash_combined_search(
...@@ -284,6 +314,11 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook ...@@ -284,6 +314,11 @@ void ethash_cl_miner::search(uint8_t const* header, uint64_t target, search_hook
} }
// not safe to return until this is ready // not safe to return until this is ready
pre_return_event.wait(); #if CL_VERSION_1_2
if (!m_opencl_1_1)
{
pre_return_event.wait();
}
#endif
} }
...@@ -40,4 +40,5 @@ private: ...@@ -40,4 +40,5 @@ private:
cl::Buffer m_hash_buf[c_num_buffers]; cl::Buffer m_hash_buf[c_num_buffers];
cl::Buffer m_search_buf[c_num_buffers]; cl::Buffer m_search_buf[c_num_buffers];
unsigned m_workgroup_size; unsigned m_workgroup_size;
bool m_opencl_1_1;
}; };
\ No newline at end of file
...@@ -2,7 +2,6 @@ set(LIBRARY ethash) ...@@ -2,7 +2,6 @@ set(LIBRARY ethash)
if (CPPETHEREUM) if (CPPETHEREUM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
#else ()
endif () endif ()
set(CMAKE_BUILD_TYPE Release) set(CMAKE_BUILD_TYPE Release)
......
/* /*
This file is part of cpp-ethereum. This file is part of ethash.
cpp-ethereum is free software: you can redistribute it and/or modify ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful, ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with ethash. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file ethash.h /** @file ethash.h
...@@ -26,13 +26,15 @@ ...@@ -26,13 +26,15 @@
#include <stddef.h> #include <stddef.h>
#include "compiler.h" #include "compiler.h"
#define REVISION 20 #define REVISION 23
#define DAGSIZE_BYTES_INIT 1073741824U // 2**30 #define DATASET_BYTES_INIT 1073741824U // 2**30
#define DAG_GROWTH 8388608U // 2**23 #define DATASET_BYTES_GROWTH 8388608U // 2**23
#define CACHE_MULTIPLIER 1024 #define CACHE_BYTES_INIT 1073741824U // 2**24
#define CACHE_BYTES_GROWTH 131072U // 2**17
#define EPOCH_LENGTH 30000U #define EPOCH_LENGTH 30000U
#define MIX_BYTES 128 #define MIX_BYTES 128
#define DAG_PARENTS 256 #define HASH_BYTES 64
#define DATASET_PARENTS 256
#define CACHE_ROUNDS 3 #define CACHE_ROUNDS 3
#define ACCESSES 64 #define ACCESSES 64
...@@ -60,19 +62,38 @@ static inline void ethash_params_init(ethash_params *params, const uint32_t bloc ...@@ -60,19 +62,38 @@ static inline void ethash_params_init(ethash_params *params, const uint32_t bloc
} }
typedef struct ethash_cache { typedef struct ethash_cache {
void *mem; void *mem;
} ethash_cache; } ethash_cache;
void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]); void ethash_mkcache(ethash_cache *cache, ethash_params const *params, const uint8_t seed[32]);
void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache); void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache);
void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce); void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce);
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number);
static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) { ethash_cache c; c.mem = cache; ethash_mkcache(&c, params, seed); } static inline void ethash_prep_light(void *cache, ethash_params const *params, const uint8_t seed[32]) {
static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_cache c; c.mem = (void*)cache; ethash_light(ret, &c, params, header_hash, nonce); } ethash_cache c;
static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) { ethash_cache c; c.mem = (void*)cache; ethash_compute_full_data(full, params, &c); } c.mem = cache;
static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) { ethash_full(ret, full, params, header_hash, nonce); } ethash_mkcache(&c, params, seed);
}
static inline void ethash_compute_light(ethash_return_value *ret, void const *cache, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) {
ethash_cache c;
c.mem = (void *) cache;
ethash_light(ret, &c, params, header_hash, nonce);
}
static inline void ethash_prep_full(void *full, ethash_params const *params, void const *cache) {
ethash_cache c;
c.mem = (void *) cache;
ethash_compute_full_data(full, params, &c);
}
static inline void ethash_compute_full(ethash_return_value *ret, void const *full, ethash_params const *params, const uint8_t header_hash[32], const uint64_t nonce) {
ethash_full(ret, full, params, header_hash, nonce);
}
// Returns if hash is less than or equal to difficulty
static inline int ethash_check_difficulty( static inline int ethash_check_difficulty(
const uint8_t hash[32], const uint8_t hash[32],
const uint8_t difficulty[32]) { const uint8_t difficulty[32]) {
...@@ -81,7 +102,7 @@ static inline int ethash_check_difficulty( ...@@ -81,7 +102,7 @@ static inline int ethash_check_difficulty(
if (hash[i] == difficulty[i]) continue; if (hash[i] == difficulty[i]) continue;
return hash[i] < difficulty[i]; return hash[i] < difficulty[i];
} }
return 0; return 1;
} }
int ethash_quick_check_difficulty( int ethash_quick_check_difficulty(
......
/* /*
This file is part of cpp-ethereum. This file is part of ethash.
cpp-ethereum is free software: you can redistribute it and/or modify ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful, ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file dash.cpp /** @file internal.c
* @author Tim Hughes <tim@twistedfury.com> * @author Tim Hughes <tim@twistedfury.com>
* @author Matthew Wampler-Doty * @author Matthew Wampler-Doty
* @date 2015 * @date 2015
...@@ -38,12 +38,12 @@ ...@@ -38,12 +38,12 @@
#endif // WITH_CRYPTOPP #endif // WITH_CRYPTOPP
size_t ethash_get_datasize(const uint32_t block_number) { size_t ethash_get_datasize(const uint32_t block_number) {
assert(block_number / EPOCH_LENGTH < 500); assert(block_number / EPOCH_LENGTH < 2048);
return dag_sizes[block_number / EPOCH_LENGTH]; return dag_sizes[block_number / EPOCH_LENGTH];
} }
size_t ethash_get_cachesize(const uint32_t block_number) { size_t ethash_get_cachesize(const uint32_t block_number) {
assert(block_number / EPOCH_LENGTH < 500); assert(block_number / EPOCH_LENGTH < 2048);
return cache_sizes[block_number / EPOCH_LENGTH]; return cache_sizes[block_number / EPOCH_LENGTH];
} }
...@@ -55,7 +55,7 @@ void static ethash_compute_cache_nodes( ...@@ -55,7 +55,7 @@ void static ethash_compute_cache_nodes(
ethash_params const *params, ethash_params const *params,
const uint8_t seed[32]) { const uint8_t seed[32]) {
assert((params->cache_size % sizeof(node)) == 0); assert((params->cache_size % sizeof(node)) == 0);
uint32_t const num_nodes = (uint32_t)(params->cache_size / sizeof(node)); uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node));
SHA3_512(nodes[0].bytes, seed, 32); SHA3_512(nodes[0].bytes, seed, 32);
...@@ -68,10 +68,9 @@ void static ethash_compute_cache_nodes( ...@@ -68,10 +68,9 @@ void static ethash_compute_cache_nodes(
uint32_t const idx = nodes[i].words[0] % num_nodes; uint32_t const idx = nodes[i].words[0] % num_nodes;
node data; node data;
data = nodes[(num_nodes - 1 + i) % num_nodes]; data = nodes[(num_nodes - 1 + i) % num_nodes];
for (unsigned w = 0; w != NODE_WORDS; ++w) for (unsigned w = 0; w != NODE_WORDS; ++w) {
{ data.words[w] ^= nodes[idx].words[w];
data.words[w] ^= nodes[idx].words[w]; }
}
SHA3_512(nodes[i].bytes, data.bytes, sizeof(data)); SHA3_512(nodes[i].bytes, data.bytes, sizeof(data));
} }
} }
...@@ -86,7 +85,7 @@ void static ethash_compute_cache_nodes( ...@@ -86,7 +85,7 @@ void static ethash_compute_cache_nodes(
} }
void ethash_mkcache( void ethash_mkcache(
ethash_cache *cache, ethash_cache *cache,
ethash_params const *params, ethash_params const *params,
const uint8_t seed[32]) { const uint8_t seed[32]) {
node *nodes = (node *) cache->mem; node *nodes = (node *) cache->mem;
...@@ -99,13 +98,13 @@ void ethash_calculate_dag_item( ...@@ -99,13 +98,13 @@ void ethash_calculate_dag_item(
const struct ethash_params *params, const struct ethash_params *params,
const struct ethash_cache *cache) { const struct ethash_cache *cache) {
uint32_t num_parent_nodes = (uint32_t)(params->cache_size / sizeof(node)); uint32_t num_parent_nodes = (uint32_t) (params->cache_size / sizeof(node));
node const *cache_nodes = (node const *) cache->mem; node const *cache_nodes = (node const *) cache->mem;
node const *init = &cache_nodes[node_index % num_parent_nodes]; node const *init = &cache_nodes[node_index % num_parent_nodes];
memcpy(ret, init, sizeof(node)); memcpy(ret, init, sizeof(node));
ret->words[0] ^= node_index; ret->words[0] ^= node_index;
SHA3_512(ret->bytes, ret->bytes, sizeof(node)); SHA3_512(ret->bytes, ret->bytes, sizeof(node));
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
__m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME); __m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME);
...@@ -115,12 +114,11 @@ void ethash_calculate_dag_item( ...@@ -115,12 +114,11 @@ void ethash_calculate_dag_item(
__m128i xmm3 = ret->xmm[3]; __m128i xmm3 = ret->xmm[3];
#endif #endif
for (unsigned i = 0; i != DAG_PARENTS; ++i) for (unsigned i = 0; i != DATASET_PARENTS; ++i) {
{ uint32_t parent_index = ((node_index ^ i) * FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes;
uint32_t parent_index = ((node_index ^ i)*FNV_PRIME ^ ret->words[i % NODE_WORDS]) % num_parent_nodes;
node const *parent = &cache_nodes[parent_index]; node const *parent = &cache_nodes[parent_index];
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
{ {
xmm0 = _mm_mullo_epi32(xmm0, fnv_prime); xmm0 = _mm_mullo_epi32(xmm0, fnv_prime);
xmm1 = _mm_mullo_epi32(xmm1, fnv_prime); xmm1 = _mm_mullo_epi32(xmm1, fnv_prime);
...@@ -143,10 +141,10 @@ void ethash_calculate_dag_item( ...@@ -143,10 +141,10 @@ void ethash_calculate_dag_item(
ret->words[w] = fnv_hash(ret->words[w], parent->words[w]); ret->words[w] = fnv_hash(ret->words[w], parent->words[w]);
} }
} }
#endif #endif
} }
SHA3_512(ret->bytes, ret->bytes, sizeof(node)); SHA3_512(ret->bytes, ret->bytes, sizeof(node));
} }
void ethash_compute_full_data( void ethash_compute_full_data(
...@@ -164,7 +162,7 @@ void ethash_compute_full_data( ...@@ -164,7 +162,7 @@ void ethash_compute_full_data(
} }
static void ethash_hash( static void ethash_hash(
ethash_return_value * ret, ethash_return_value *ret,
node const *full_nodes, node const *full_nodes,
ethash_cache const *cache, ethash_cache const *cache,
ethash_params const *params, ethash_params const *params,
...@@ -174,7 +172,7 @@ static void ethash_hash( ...@@ -174,7 +172,7 @@ static void ethash_hash(
assert((params->full_size % MIX_WORDS) == 0); assert((params->full_size % MIX_WORDS) == 0);
// pack hash and nonce together into first 40 bytes of s_mix // pack hash and nonce together into first 40 bytes of s_mix
assert(sizeof(node)*8 == 512); assert(sizeof(node) * 8 == 512);
node s_mix[MIX_NODES + 1]; node s_mix[MIX_NODES + 1];
memcpy(s_mix[0].bytes, header_hash, 32); memcpy(s_mix[0].bytes, header_hash, 32);
...@@ -193,23 +191,21 @@ static void ethash_hash( ...@@ -193,23 +191,21 @@ static void ethash_hash(
} }
#endif #endif
node* const mix = s_mix + 1; node *const mix = s_mix + 1;
for (unsigned w = 0; w != MIX_WORDS; ++w) { for (unsigned w = 0; w != MIX_WORDS; ++w) {
mix->words[w] = s_mix[0].words[w % NODE_WORDS]; mix->words[w] = s_mix[0].words[w % NODE_WORDS];
} }
unsigned const unsigned const
page_size = sizeof(uint32_t) * MIX_WORDS, page_size = sizeof(uint32_t) * MIX_WORDS,
num_full_pages = (unsigned)(params->full_size / page_size); num_full_pages = (unsigned) (params->full_size / page_size);
for (unsigned i = 0; i != ACCESSES; ++i) for (unsigned i = 0; i != ACCESSES; ++i) {
{ uint32_t const index = ((s_mix->words[0] ^ i) * FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages;
uint32_t const index = ((s_mix->words[0] ^ i)*FNV_PRIME ^ mix->words[i % MIX_WORDS]) % num_full_pages;
for (unsigned n = 0; n != MIX_NODES; ++n) for (unsigned n = 0; n != MIX_NODES; ++n) {
{ const node *dag_node = &full_nodes[MIX_NODES * index + n];
const node * dag_node = &full_nodes[MIX_NODES * index + n];
if (!full_nodes) { if (!full_nodes) {
node tmp_node; node tmp_node;
...@@ -217,7 +213,7 @@ static void ethash_hash( ...@@ -217,7 +213,7 @@ static void ethash_hash(
dag_node = &tmp_node; dag_node = &tmp_node;
} }
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
{ {
__m128i fnv_prime = _mm_set1_epi32(FNV_PRIME); __m128i fnv_prime = _mm_set1_epi32(FNV_PRIME);
__m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]); __m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]);
...@@ -235,20 +231,19 @@ static void ethash_hash( ...@@ -235,20 +231,19 @@ static void ethash_hash(
mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]); mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]);
} }
} }
#endif #endif
} }
} }
// compress mix // compress mix
for (unsigned w = 0; w != MIX_WORDS; w += 4) for (unsigned w = 0; w != MIX_WORDS; w += 4) {
{ uint32_t reduction = mix->words[w + 0];
uint32_t reduction = mix->words[w+0]; reduction = reduction * FNV_PRIME ^ mix->words[w + 1];
reduction = reduction*FNV_PRIME ^ mix->words[w+1]; reduction = reduction * FNV_PRIME ^ mix->words[w + 2];
reduction = reduction*FNV_PRIME ^ mix->words[w+2]; reduction = reduction * FNV_PRIME ^ mix->words[w + 3];
reduction = reduction*FNV_PRIME ^ mix->words[w+3]; mix->words[w / 4] = reduction;
mix->words[w/4] = reduction; }
}
#if BYTE_ORDER != LITTLE_ENDIAN #if BYTE_ORDER != LITTLE_ENDIAN
for (unsigned w = 0; w != MIX_WORDS/4; ++w) { for (unsigned w = 0; w != MIX_WORDS/4; ++w) {
...@@ -258,7 +253,7 @@ static void ethash_hash( ...@@ -258,7 +253,7 @@ static void ethash_hash(
memcpy(ret->mix_hash, mix->bytes, 32); memcpy(ret->mix_hash, mix->bytes, 32);
// final Keccak hash // final Keccak hash
SHA3_256(ret->result, s_mix->bytes, 64+32); // Keccak-256(s + compressed_mix) SHA3_256(ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix)
} }
void ethash_quick_hash( void ethash_quick_hash(
...@@ -267,7 +262,7 @@ void ethash_quick_hash( ...@@ -267,7 +262,7 @@ void ethash_quick_hash(
const uint64_t nonce, const uint64_t nonce,
const uint8_t mix_hash[32]) { const uint8_t mix_hash[32]) {
uint8_t buf[64+32]; uint8_t buf[64 + 32];
memcpy(buf, header_hash, 32); memcpy(buf, header_hash, 32);
#if BYTE_ORDER != LITTLE_ENDIAN #if BYTE_ORDER != LITTLE_ENDIAN
nonce = fix_endian64(nonce); nonce = fix_endian64(nonce);
...@@ -275,7 +270,14 @@ void ethash_quick_hash( ...@@ -275,7 +270,14 @@ void ethash_quick_hash(
memcpy(&(buf[32]), &nonce, 8); memcpy(&(buf[32]), &nonce, 8);
SHA3_512(buf, buf, 40); SHA3_512(buf, buf, 40);
memcpy(&(buf[64]), mix_hash, 32); memcpy(&(buf[64]), mix_hash, 32);
SHA3_256(return_hash, buf, 64+32); SHA3_256(return_hash, buf, 64 + 32);
}
void ethash_get_seedhash(uint8_t seedhash[32], const uint32_t block_number) {
memset(seedhash, 0, 32);
const uint32_t epochs = block_number / EPOCH_LENGTH;
for (uint32_t i = 0; i < epochs; ++i)
SHA3_256(seedhash, seedhash, 32);
} }
int ethash_quick_check_difficulty( int ethash_quick_check_difficulty(
...@@ -289,10 +291,10 @@ int ethash_quick_check_difficulty( ...@@ -289,10 +291,10 @@ int ethash_quick_check_difficulty(
return ethash_check_difficulty(return_hash, difficulty); return ethash_check_difficulty(return_hash, difficulty);
} }
void ethash_full(ethash_return_value * ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { void ethash_full(ethash_return_value *ret, void const *full_mem, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce); ethash_hash(ret, (node const *) full_mem, NULL, params, previous_hash, nonce);
} }
void ethash_light(ethash_return_value * ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) { void ethash_light(ethash_return_value *ret, ethash_cache const *cache, ethash_params const *params, const uint8_t previous_hash[32], const uint64_t nonce) {
ethash_hash(ret, NULL, cache, params, previous_hash, nonce); ethash_hash(ret, NULL, cache, params, previous_hash, nonce);
} }
\ No newline at end of file
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
#include "endian.h" #include "endian.h"
#include "ethash.h" #include "ethash.h"
#define ENABLE_SSE 1 #define ENABLE_SSE 0
#if defined(_M_X64) && ENABLE_SSE #if defined(_M_X64) && ENABLE_SSE
#include <smmintrin.h> #include <smmintrin.h>
......
/* /*
This file is part of cpp-ethereum. This file is part of ethash.
cpp-ethereum is free software: you can redistribute it and/or modify ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful, ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with ethash. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file sha3.cpp /** @file sha3.cpp
......
/* /*
This file is part of cpp-ethereum. This file is part of ethash.
cpp-ethereum is free software: you can redistribute it and/or modify ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
cpp-ethereum is distributed in the hope that it will be useful, ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>. along with ethash. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** @file util.h /** @file util.h
* @author Tim Hughes <tim@twistedfury.com> * @author Tim Hughes <tim@twistedfury.com>
......
...@@ -4,7 +4,9 @@ ...@@ -4,7 +4,9 @@
#include <libethash/internal.h> #include <libethash/internal.h>
#ifdef WITH_CRYPTOPP #ifdef WITH_CRYPTOPP
#include <libethash/sha3_cryptopp.h> #include <libethash/sha3_cryptopp.h>
#else #else
#include <libethash/sha3.h> #include <libethash/sha3.h>
#endif // WITH_CRYPTOPP #endif // WITH_CRYPTOPP
...@@ -28,7 +30,7 @@ BOOST_AUTO_TEST_CASE(fnv_hash_check) { ...@@ -28,7 +30,7 @@ BOOST_AUTO_TEST_CASE(fnv_hash_check) {
uint32_t x = 1235U; uint32_t x = 1235U;
const uint32_t const uint32_t
y = 9999999U, y = 9999999U,
expected = (FNV_PRIME * x) ^ y; expected = (FNV_PRIME * x) ^y;
x = fnv_hash(x, y); x = fnv_hash(x, y);
...@@ -65,43 +67,50 @@ BOOST_AUTO_TEST_CASE(SHA512_check) { ...@@ -65,43 +67,50 @@ BOOST_AUTO_TEST_CASE(SHA512_check) {
BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_check) { BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_check) {
ethash_params params; ethash_params params;
ethash_params_init(&params, 0); ethash_params_init(&params, 0);
BOOST_REQUIRE_MESSAGE(params.full_size < DAGSIZE_BYTES_INIT, BOOST_REQUIRE_MESSAGE(params.full_size < DATASET_BYTES_INIT,
"\nfull size: " << params.full_size << "\n" "\nfull size: " << params.full_size << "\n"
<< "should be less than or equal to: " << DAGSIZE_BYTES_INIT << "\n"); << "should be less than or equal to: " << DATASET_BYTES_INIT << "\n");
BOOST_REQUIRE_MESSAGE(params.full_size + 20*MIX_BYTES >= DAGSIZE_BYTES_INIT, BOOST_REQUIRE_MESSAGE(params.full_size + 20 * MIX_BYTES >= DATASET_BYTES_INIT,
"\nfull size + 20*MIX_BYTES: " << params.full_size + 20*MIX_BYTES << "\n" "\nfull size + 20*MIX_BYTES: " << params.full_size + 20 * MIX_BYTES << "\n"
<< "should be greater than or equal to: " << DAGSIZE_BYTES_INIT << "\n"); << "should be greater than or equal to: " << DATASET_BYTES_INIT << "\n");
BOOST_REQUIRE_MESSAGE(params.cache_size < DAGSIZE_BYTES_INIT / 32, BOOST_REQUIRE_MESSAGE(params.cache_size < DATASET_BYTES_INIT / 32,
"\ncache size: " << params.cache_size << "\n" "\ncache size: " << params.cache_size << "\n"
<< "should be less than or equal to: " << DAGSIZE_BYTES_INIT / 32 << "\n"); << "should be less than or equal to: " << DATASET_BYTES_INIT / 32 << "\n");
} }
BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_calcifide_check) { BOOST_AUTO_TEST_CASE(ethash_params_init_genesis_calcifide_check) {
ethash_params params; ethash_params params;
ethash_params_init(&params, 0); ethash_params_init(&params, 0);
const uint32_t expected_full_size = 1073739904; const uint32_t expected_full_size = 1073739904;
const uint32_t expected_cache_size = 1048384; const uint32_t expected_cache_size = 16776896;
BOOST_REQUIRE_MESSAGE(params.full_size == expected_full_size, BOOST_REQUIRE_MESSAGE(params.full_size == expected_full_size,
"\nexpected: " << expected_cache_size << "\n" "\nexpected: " << expected_cache_size << "\n"
<< "actual: " << params.full_size << "\n"); << "actual: " << params.full_size << "\n");
BOOST_REQUIRE_MESSAGE(params.cache_size == expected_cache_size, BOOST_REQUIRE_MESSAGE(params.cache_size == expected_cache_size,
"\nexpected: " << expected_cache_size << "\n" "\nexpected: " << expected_cache_size << "\n"
<< "actual: " << params.cache_size << "\n"); << "actual: " << params.cache_size << "\n");
} }
BOOST_AUTO_TEST_CASE(light_and_full_client_checks) { BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {
ethash_params params; ethash_params params;
uint8_t seed[32], hash[32]; uint8_t seed[32], hash[32], difficulty[32];
ethash_return_value light_out, full_out; ethash_return_value light_out, full_out;
memcpy(seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); memcpy(seed, "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
memcpy(hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32); memcpy(hash, "~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~~~", 32);
// Set the difficulty
difficulty[0] = 197;
difficulty[1] = 90;
for (int i = 2; i < 32; i++)
difficulty[i] = (uint8_t) 255;
ethash_params_init(&params, 0); ethash_params_init(&params, 0);
params.cache_size = 1024; params.cache_size = 1024;
params.full_size = 1024 * 32; params.full_size = 1024 * 32;
ethash_cache cache; ethash_cache cache;
cache.mem = alloca(params.cache_size); cache.mem = alloca(params.cache_size);
ethash_mkcache(&cache, &params, seed); ethash_mkcache(&cache, &params, seed);
node * full_mem = (node *) alloca(params.full_size); node *full_mem = (node *) alloca(params.full_size);
ethash_compute_full_data(full_mem, &params, &cache); ethash_compute_full_data(full_mem, &params, &cache);
{ {
...@@ -115,7 +124,6 @@ BOOST_AUTO_TEST_CASE(light_and_full_client_checks) { ...@@ -115,7 +124,6 @@ BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {
} }
{ {
node node; node node;
ethash_calculate_dag_item(&node, 0, &params, &cache); ethash_calculate_dag_item(&node, 0, &params, &cache);
...@@ -128,7 +136,7 @@ BOOST_AUTO_TEST_CASE(light_and_full_client_checks) { ...@@ -128,7 +136,7 @@ BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {
} }
{ {
for (int i = 0 ; i < params.full_size / sizeof(node) ; ++i ) { for (int i = 0; i < params.full_size / sizeof(node); ++i) {
for (uint32_t j = 0; j < 32; ++j) { for (uint32_t j = 0; j < 32; ++j) {
node expected_node; node expected_node;
ethash_calculate_dag_item(&expected_node, j, &params, &cache); ethash_calculate_dag_item(&expected_node, j, &params, &cache);
...@@ -187,6 +195,12 @@ BOOST_AUTO_TEST_CASE(light_and_full_client_checks) { ...@@ -187,6 +195,12 @@ BOOST_AUTO_TEST_CASE(light_and_full_client_checks) {
BOOST_REQUIRE_MESSAGE(full_mix_hash_string == light_mix_hash_string, BOOST_REQUIRE_MESSAGE(full_mix_hash_string == light_mix_hash_string,
"\nlight mix hash: " << light_mix_hash_string.c_str() << "\n" "\nlight mix hash: " << light_mix_hash_string.c_str() << "\n"
<< "full mix hash: " << full_mix_hash_string.c_str() << "\n"); << "full mix hash: " << full_mix_hash_string.c_str() << "\n");
BOOST_REQUIRE_MESSAGE(ethash_check_difficulty(full_out.result, difficulty),
"ethash_check_difficulty failed"
);
BOOST_REQUIRE_MESSAGE(ethash_quick_check_difficulty(hash, 5U, full_out.mix_hash, difficulty),
"ethash_quick_check_difficulty failed"
);
} }
} }
...@@ -199,14 +213,14 @@ BOOST_AUTO_TEST_CASE(ethash_check_difficulty_check) { ...@@ -199,14 +213,14 @@ BOOST_AUTO_TEST_CASE(ethash_check_difficulty_check) {
memcpy(target, "22222222222222222222222222222222", 32); memcpy(target, "22222222222222222222222222222222", 32);
BOOST_REQUIRE_MESSAGE( BOOST_REQUIRE_MESSAGE(
ethash_check_difficulty(hash, target), ethash_check_difficulty(hash, target),
"\nexpected \"" << hash << "\" to have less difficulty than \"" << target << "\"\n"); "\nexpected \"" << std::string((char *) hash, 32).c_str() << "\" to have the same or less difficulty than \"" << std::string((char *) target, 32).c_str() << "\"\n");
BOOST_REQUIRE_MESSAGE( BOOST_REQUIRE_MESSAGE(
!ethash_check_difficulty(hash, hash), ethash_check_difficulty(hash, hash),
"\nexpected \"" << hash << "\" to have the same difficulty as \"" << hash << "\"\n"); "\nexpected \"" << hash << "\" to have the same or less difficulty than \"" << hash << "\"\n");
memcpy(target, "11111111111111111111111111111112", 32); memcpy(target, "11111111111111111111111111111112", 32);
BOOST_REQUIRE_MESSAGE( BOOST_REQUIRE_MESSAGE(
ethash_check_difficulty(hash, target), ethash_check_difficulty(hash, target),
"\nexpected \"" << hash << "\" to have less difficulty than \"" << target << "\"\n"); "\nexpected \"" << hash << "\" to have the same or less difficulty than \"" << target << "\"\n");
memcpy(target, "11111111111111111111111111111110", 32); memcpy(target, "11111111111111111111111111111110", 32);
BOOST_REQUIRE_MESSAGE( BOOST_REQUIRE_MESSAGE(
!ethash_check_difficulty(hash, target), !ethash_check_difficulty(hash, target),
......
package ethashTest
import (
"bytes"
"crypto/rand"
"encoding/hex"
"log"
"math/big"
"testing"
"github.com/ethereum/ethash"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/ethdb"
)
func TestEthash(t *testing.T) {
seedHash := make([]byte, 32)
_, err := rand.Read(seedHash)
if err != nil {
panic(err)
}
db, err := ethdb.NewMemDatabase()
if err != nil {
panic(err)
}
blockProcessor, err := core.NewCanonical(5, db)
if err != nil {
panic(err)
}
log.Println("Block Number: ", blockProcessor.ChainManager().CurrentBlock().Number())
e := ethash.New(blockProcessor.ChainManager())
miningHash := make([]byte, 32)
if _, err := rand.Read(miningHash); err != nil {
panic(err)
}
diff := big.NewInt(10000)
log.Println("difficulty", diff)
nonce := uint64(0)
ghash_full := e.FullHash(nonce, miningHash)
log.Printf("ethash full (on nonce): %x %x\n", ghash_full, nonce)
ghash_light := e.LightHash(nonce, miningHash)
log.Printf("ethash light (on nonce): %x %x\n", ghash_light, nonce)
if bytes.Compare(ghash_full, ghash_light) != 0 {
t.Errorf("full: %x, light: %x", ghash_full, ghash_light)
}
}
func TestGetSeedHash(t *testing.T) {
seed0, err := ethash.GetSeedHash(0)
if err != nil {
t.Errorf("Failed to get seedHash for block 0: %v", err)
}
if bytes.Compare(seed0, []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}) != 0 {
log.Printf("seedHash for block 0 should be 0s, was: %v\n", seed0)
}
seed1, err := ethash.GetSeedHash(30000)
if err != nil {
t.Error(err)
}
// From python:
// > from pyethash import get_seedhash
// > get_seedhash(30000)
expectedSeed1, err := hex.DecodeString("290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563")
if err != nil {
t.Error(err)
}
if bytes.Compare(seed1, expectedSeed1) != 0 {
log.Printf("seedHash for block 1 should be: %v,\nactual value: %v\n", expectedSeed1, seed1)
}
}
#!/bin/bash
# Strict mode
set -e
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
done
TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
export GOPATH=${HOME}/.go
export PATH=$PATH:$GOPATH/bin
echo "# getting go dependencies (can take some time)..."
cd ${TEST_DIR}/../.. && go get
cd ${GOPATH}/src/github.com/ethereum/go-ethereum
git checkout poc-9
cd ${TEST_DIR} && go test
pyethereum==0.7.522 pyethereum==0.7.522
nose==1.3.4 nose==1.3.4
pysha3==0.3
\ No newline at end of file
...@@ -14,6 +14,6 @@ TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" ...@@ -14,6 +14,6 @@ TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
[ -d $TEST_DIR/python-virtual-env ] || virtualenv --system-site-packages $TEST_DIR/python-virtual-env [ -d $TEST_DIR/python-virtual-env ] || virtualenv --system-site-packages $TEST_DIR/python-virtual-env
source $TEST_DIR/python-virtual-env/bin/activate source $TEST_DIR/python-virtual-env/bin/activate
pip install -r $TEST_DIR/requirements.txt > /dev/null pip install -r $TEST_DIR/requirements.txt > /dev/null
pip install -e $TEST_DIR/../.. > /dev/null pip install --upgrade --no-deps --force-reinstall -e $TEST_DIR/../..
cd $TEST_DIR cd $TEST_DIR
nosetests --with-doctest -v nosetests --with-doctest -v --nocapture
...@@ -4,42 +4,102 @@ from random import randint ...@@ -4,42 +4,102 @@ from random import randint
def test_get_cache_size_not_None(): def test_get_cache_size_not_None():
for _ in range(100): for _ in range(100):
block_num = randint(0,12456789) block_num = randint(0,12456789)
out = pyethash.core.get_cache_size(block_num) out = pyethash.get_cache_size(block_num)
assert out != None assert out != None
def test_get_full_size_not_None(): def test_get_full_size_not_None():
for _ in range(100): for _ in range(100):
block_num = randint(0,12456789) block_num = randint(0,12456789)
out = pyethash.core.get_full_size(block_num) out = pyethash.get_full_size(block_num)
assert out != None assert out != None
def test_get_cache_size_based_on_EPOCH(): def test_get_cache_size_based_on_EPOCH():
for _ in range(100): for _ in range(100):
block_num = randint(0,12456789) block_num = randint(0,12456789)
out1 = pyethash.core.get_cache_size(block_num) out1 = pyethash.get_cache_size(block_num)
out2 = pyethash.core.get_cache_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH) out2 = pyethash.get_cache_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
assert out1 == out2 assert out1 == out2
def test_get_full_size_based_on_EPOCH(): def test_get_full_size_based_on_EPOCH():
for _ in range(100): for _ in range(100):
block_num = randint(0,12456789) block_num = randint(0,12456789)
out1 = pyethash.core.get_full_size(block_num) out1 = pyethash.get_full_size(block_num)
out2 = pyethash.core.get_full_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH) out2 = pyethash.get_full_size((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH)
assert out1 == out2 assert out1 == out2
#def test_get_params_based_on_EPOCH(): # See light_and_full_client_checks in test.cpp
# block_num = 123456 def test_mkcache_is_as_expected():
# out1 = pyethash.core.get_params(block_num) actual = pyethash.mkcache_bytes(
# out2 = pyethash.core.get_params((block_num // pyethash.EPOCH_LENGTH) * pyethash.EPOCH_LENGTH) 1024,
# assert out1["DAG Size"] == out2["DAG Size"] "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~").encode('hex')
# assert out1["Cache Size"] == out2["Cache Size"] expected = "2da2b506f21070e1143d908e867962486d6b0a02e31d468fd5e3a7143aafa76a14201f63374314e2a6aaf84ad2eb57105dea3378378965a1b3873453bb2b78f9a8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995ca8620b2ebeca41fbc773bb837b5e724d6eb2de570d99858df0d7d97067fb8103b21757873b735097b35d3bea8fd1c359a9e8a63c1540c76c9784cf8d975e995c259440b89fa3481c2c33171477c305c8e1e421f8d8f6d59585449d0034f3e421808d8da6bbd0b6378f567647cc6c4ba6c434592b198ad444e7284905b7c6adaf70bf43ec2daa7bd5e8951aa609ab472c124cf9eba3d38cff5091dc3f58409edcc386c743c3bd66f92408796ee1e82dd149eaefbf52b00ce33014a6eb3e50625413b072a58bc01da28262f42cbe4f87d4abc2bf287d15618405a1fe4e386fcdafbb171064bd99901d8f81dd6789396ce5e364ac944bbbd75a7827291c70b42d26385910cd53ca535ab29433dd5c5714d26e0dce95514c5ef866329c12e958097e84462197c2b32087849dab33e88b11da61d52f9dbc0b92cc61f742c07dbbf751c49d7678624ee60dfbe62e5e8c47a03d8247643f3d16ad8c8e663953bcda1f59d7e2d4a9bf0768e789432212621967a8f41121ad1df6ae1fa78782530695414c6213942865b2730375019105cae91a4c17a558d4b63059661d9f108362143107babe0b848de412e4da59168cce82bfbff3c99e022dd6ac1e559db991f2e3f7bb910cefd173e65ed00a8d5d416534e2c8416ff23977dbf3eb7180b75c71580d08ce95efeb9b0afe904ea12285a392aff0c8561ff79fca67f694a62b9e52377485c57cc3598d84cac0a9d27960de0cc31ff9bbfe455acaa62c8aa5d2cce96f345da9afe843d258a99c4eaf3650fc62efd81c7b81cd0d534d2d71eeda7a6e315d540b4473c80f8730037dc2ae3e47b986240cfc65ccc565f0d8cde0bc68a57e39a271dda57440b3598bee19f799611d25731a96b5dbbbefdff6f4f656161462633030d62560ea4e9c161cf78fc96a2ca5aaa32453a6c5dea206f766244e8c9d9a8dc61185ce37f1fc804459c5f07434f8ecb34141b8dcae7eae704c950b55556c5f40140c3714b45eddb02637513268778cbf937a33e4e33183685f9deb31ef54e90161e76d969587dd782eaa94e289420e7c2ee908517f5893a26fdb5873d68f92d118d4bcf98d7a4916794d6ab290045e30f9ea00ca547c584b8482b0331ba1539a0f2714fddc3a0b06b0cfbb6a607b8339c39bcfd6640b1f653e9d70ef6c985b"
# assert actual == expected
#def test_get_params_returns_different_values_based_on_different_block_input():
# out1 = pyethash.core.get_params(123456) def test_calc_dataset_is_not_None():
# out2 = pyethash.core.get_params(12345) cache = pyethash.mkcache_bytes(
# assert out1["DAG Size"] != out2["DAG Size"] 1024,
# assert out1["Cache Size"] != out2["Cache Size"] "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
# assert pyethash.calc_dataset_bytes(1024 * 32, cache) != None
#def test_get_cache_smoke_test():
# params = pyethash.core.get_params(123456) def test_light_and_full_agree():
# assert pyethash.core.mkcache(params, "~~~~") != None cache = pyethash.mkcache_bytes(
1024,
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
full_size = 1024 * 32
header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~"
light_result = pyethash.hashimoto_light(full_size, cache, header, 0)
dataset = pyethash.calc_dataset_bytes(full_size, cache)
full_result = pyethash.hashimoto_full(dataset, header, 0)
assert light_result["mix digest"] != None
assert len(light_result["mix digest"]) == 32
assert light_result["mix digest"] == full_result["mix digest"]
assert light_result["result"] != None
assert len(light_result["result"]) == 32
assert light_result["result"] == full_result["result"]
def int_to_bytes(i):
b = []
for _ in range(32):
b.append(chr(i & 0xff))
i >>= 8
b.reverse()
return "".join(b)
def test_mining_basic():
easy_difficulty = int_to_bytes(2**256 - 1)
assert easy_difficulty.encode('hex') == 'f' * 64
cache = pyethash.mkcache_bytes(
1024,
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
full_size = 1024 * 32
header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~"
dataset = pyethash.calc_dataset_bytes(full_size, cache)
# Check type of outputs
assert type(pyethash.mine(dataset,header,easy_difficulty)) == dict
assert type(pyethash.mine(dataset,header,easy_difficulty)["nonce"]) == long
assert type(pyethash.mine(dataset,header,easy_difficulty)["mix digest"]) == str
assert type(pyethash.mine(dataset,header,easy_difficulty)["result"]) == str
def test_mining_doesnt_always_return_the_same_value():
easy_difficulty1 = int_to_bytes(int(2**256 * 0.999))
# 1 in 1000 difficulty
easy_difficulty2 = int_to_bytes(int(2**256 * 0.001))
assert easy_difficulty1 != easy_difficulty2
cache = pyethash.mkcache_bytes(
1024,
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
full_size = 1024 * 32
header = "~~~~~X~~~~~~~~~~~~~~~~~~~~~~~~~~"
dataset = pyethash.calc_dataset_bytes(full_size, cache)
# Check type of outputs
assert pyethash.mine(dataset, header, easy_difficulty1)['nonce'] != pyethash.mine(dataset, header, easy_difficulty2)['nonce']
def test_get_seedhash():
assert pyethash.get_seedhash(0).encode('hex') == '0' * 64
import hashlib, sha3
expected = pyethash.get_seedhash(0)
#print "checking seed hashes:",
for i in range(0, 30000*2048, 30000):
#print i // 30000,
assert pyethash.get_seedhash(i) == expected
expected = hashlib.sha3_256(expected).digest()
...@@ -14,7 +14,12 @@ TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" ...@@ -14,7 +14,12 @@ TEST_DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
echo -e "\n################# Testing JS ##################" echo -e "\n################# Testing JS ##################"
# TODO: Use mocha and real testing tools instead of rolling our own # TODO: Use mocha and real testing tools instead of rolling our own
cd $TEST_DIR/../js cd $TEST_DIR/../js
node test.js if [ -x "$(which nodejs)" ] ; then
nodejs test.js
fi
if [ -x "$(which node)" ] ; then
node test.js
fi
echo -e "\n################# Testing C ##################" echo -e "\n################# Testing C ##################"
$TEST_DIR/c/test.sh $TEST_DIR/c/test.sh
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment