Browse Source

Merge branch 'master' into master-davilizh

cl-refactor
Paweł Bylica 8 years ago
parent
commit
4c89e9247b
No known key found for this signature in database GPG Key ID: 7A0C037434FE77EF
  1. 18
      .bumpversion.cfg
  2. 13
      .travis.yml
  3. 29
      CMakeLists.txt
  4. 4
      README.md
  5. 47
      appveyor.yml
  6. 2
      cmake/Hunter/config.cmake
  7. 2
      cmake/variables.ps1.in
  8. 2
      cmake/variables.sh.in
  9. 2363
      doc/Doxyfile
  10. 7
      ethminer/CMakeLists.txt
  11. 64
      ethminer/MinerAux.h
  12. 39
      extdep/getstuff.bat
  13. 6
      libdevcore/Common.h
  14. 19
      libdevcore/Log.cpp
  15. 12
      libdevcore/Log.h
  16. 1
      libethash-cl/ethash_cl_miner.cpp
  17. 40
      libethash-cuda/ethash_cuda_miner.cpp
  18. 2
      libethash-cuda/ethash_cuda_miner.h
  19. 26
      libethash/CMakeLists.txt
  20. 56
      libethash/ethash.h
  21. 219
      libethash/internal.c
  22. 96
      libethash/internal.h
  23. 119
      libethash/io.c
  24. 202
      libethash/io.h
  25. 111
      libethash/io_posix.c
  26. 100
      libethash/io_win32.c
  27. 47
      libethash/mmap.h
  28. 84
      libethash/mmap_win32.c
  29. 37
      libethash/sha3_cryptopp.cpp
  30. 18
      libethash/sha3_cryptopp.h
  31. 41
      libethash/util.c
  32. 47
      libethash/util.h
  33. 38
      libethash/util_win32.c
  34. 50
      libethcore/BlockHeader.cpp
  35. 121
      libethcore/BlockHeader.h
  36. 225
      libethcore/BlockInfo.h
  37. 14
      libethcore/CMakeLists.txt
  38. 66
      libethcore/Common.h
  39. 38
      libethcore/Ethash.cpp
  40. 78
      libethcore/Ethash.h
  41. 151
      libethcore/EthashAux.cpp
  42. 116
      libethcore/EthashAux.h
  43. 4
      libethcore/EthashCUDAMiner.cpp
  44. 8
      libethcore/EthashCUDAMiner.h
  45. 22
      libethcore/EthashGPUMiner.cpp
  46. 9
      libethcore/EthashGPUMiner.h
  47. 54
      libethcore/EthashSealEngine.cpp
  48. 48
      libethcore/EthashSealEngine.h
  49. 1
      libethcore/Exceptions.h
  50. 14
      libethcore/Farm.h
  51. 12
      libethcore/Miner.cpp
  52. 30
      libethcore/Miner.h
  53. 21
      libstratum/EthStratumClient.cpp
  54. 10
      libstratum/EthStratumClient.h
  55. 8
      libstratum/EthStratumClientV2.cpp
  56. 11
      libstratum/EthStratumClientV2.h
  57. 2
      scripts/install-cuda-trusty.sh

18
.bumpversion.cfg

@ -0,0 +1,18 @@
[bumpversion]
current_version = 0.11.0.dev0
commit = True
tag = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)((?P<prerel>rc|\.dev)(?P<prerelver>\d+))?
serialize =
{major}.{minor}.{patch}{prerel}{prerelver}
{major}.{minor}.{patch}
[bumpversion:part:prerel]
optional_value = rel
values =
.dev
rc
rel
[bumpversion:file:CMakeLists.txt]

13
.travis.yml

@ -1,6 +1,7 @@
language: cpp
branches:
only:
- /^v\d+\..+$/
- master
matrix:
include:
@ -14,6 +15,7 @@ matrix:
cache:
directories:
- $HOME/.hunter/_Base/Cache
- $HOME/.local
before_install:
- if [[ "$CUDA" = ON ]]; then source scripts/install-cuda-trusty.sh; fi
- if [ "$TRAVIS_OS_NAME" = linux ]; then scripts/install_cmake.sh; fi
@ -24,3 +26,14 @@ script:
- build/ethminer/ethminer --list-devices -U
- if [ "$TRAVIS_OS_NAME" = linux ]; then ldd -v build/ethminer/ethminer; fi
- if [ "$TRAVIS_OS_NAME" = osx ]; then otool -L build/ethminer/ethminer; fi
- cmake --build build --target package
deploy:
provider: releases
api_key:
secure: "KfYTW8o20BUEZc57vF3H4+qXgpDsMeWk3N4IQtNKkdhFzEUzQaXi1WHRtvcR5kq+rvDiXwy0fELglDZpCSa4wfQvM5fKlb7WPQgkyRZyCpwnXlqvb6dL8KxJekQHZ5fFpzc/ow0dx/UqzJgv+cWDnBEK/gl+9j+vt9oq1nV1LSaxmtO3Qs7y+ffq5Tbzo06q6/CfeyOZi23g+AYtnoEBKwYqa807atWM6cJpudPmyhYHQFgaQZMfzk44z/MnJb7nxtkqcx57KWaY2EHlFj6yrHMcXWyM8j+P0ZBwUbOpHkWvBpgmDKR2J3u0WmiJDDo3E6K0g9QgbAnF5+yqvpBC5kaSHAaicJ3+7ghSgo18Eea0BkLbmb0t93h5NJfRhg0GDjgG3LkHao9ALM35x3OXG38JI6bOLd6jSV2Vkg8qLWAZjP1TUb/4VTIFnyITSv+xrY7ZP9D0XcRybZ5Z0YnaI/J6NFJct9ICAlQ6cHkS0MO6PICTSbZbKhbDZP0Lt6iDDUeje5+uvPAl0uuzuciSqEM77JWYN/edOXurgkfljEny3P96AW70gUUBTVEE+4tjng4DMLHCH/1Jg/WfMPfSVC3AUR0WbvjMki6veMt37fy8Jys8gFpwZbMG3cCSkYXDDFWF/Q+p2v6pX76CZZz+LxO2XcZ7x4bw+c7AGzRWV7c="
file_glob: true
file: build/ethminer-*.tar.gz
skip_cleanup: true
on:
tags: true

29
CMakeLists.txt

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.0)
cmake_minimum_required(VERSION 3.3)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/cmake/toolchain.cmake CACHE FILEPATH "CMake toolchain file")
@ -14,10 +14,8 @@ HunterGate(
)
cmake_policy(SET CMP0042 OLD) # fix MACOSX_RPATH
cmake_policy(SET CMP0048 NEW) # allow VERSION argument in project()
project(ethminer VERSION 0.10.0)
project(ethminer)
set(PROJECT_VERSION 0.11.0.dev0)
# link_directories interprate relative paths with respect to CMAKE_CURRENT_SOURCE_DIR
cmake_policy(SET CMP0015 NEW)
@ -123,3 +121,24 @@ if(ETHSTRATUM)
endif()
add_subdirectory(libethcore)
add_subdirectory(ethminer)
if(WIN32)
set(CPACK_GENERATOR ZIP)
else()
set(CPACK_GENERATOR TGZ)
endif()
set(CPACK_PACKAGE_FILE_NAME ${PROJECT_NAME}-${PROJECT_VERSION}-${CMAKE_SYSTEM_NAME})
set(CPACK_PACKAGE_CHECKSUM SHA256)
set(CPACK_INCLUDE_TOPLEVEL_DIRECTORY FALSE)
include(CPack)
# Export some variables for CIs
if(PROJECT_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$")
set(PROJECT_VERSION_IS_PRERELEASE false)
else()
set(PROJECT_VERSION_IS_PRERELEASE true)
endif()
configure_file(cmake/variables.sh.in variables.sh)
configure_file(cmake/variables.ps1.in variables.ps1)

4
README.md

@ -69,11 +69,11 @@ cmake --build .
### CMake build options
- `-DETHASHCL=ON` - enable OpenCL mining, `ON` by default,
- `-DETHASHCUDA=OFF` - enable CUDA mining, `OFF` by default,
- `-DETHASHCUDA=ON` - enable CUDA mining, `OFF` by default,
- `-DETHSTRATUM=ON` - build with Stratum protocol support, `ON` by default.
[CMake]: https://cmake.org
[cpp-ethereum]: https://github.com/ethereum/cpp-ethereum
[Genoil's fork]: https://github.com/Genoil/cpp-ethereum
[Gitter]: https://gitter.im/ethereum-mining/ethminer
[Hunter]: https://docs.hunter.sh
[Hunter]: https://docs.hunter.sh

47
appveyor.yml

@ -2,18 +2,49 @@ version: "{build}"
branches:
only:
- master
- /v\d+\..+/
shallow_clone: true
os: Visual Studio 2015
configuration:
- Release
- RelWithDebInfo
cache:
- C:/.hunter/_Base/Cache
install:
- C:/.hunter/_Base/Cache -> cmake/Hunter/config.cmake
install: |
appveyor DownloadFile https://github.com/ethereum/cpp-dependencies/releases/download/cache/CUDA-v8.0-WindowsServer2012.zip
7z x CUDA-v8.0-WindowsServer2012.zip -oC:/
set PATH=%PATH%;C:/CUDA/v8.0/bin
nvcc -V
before_build:
- cmake -G "Visual Studio 14 2015 Win64" -H. -Bbuild
build:
project: c:/projects/ethminer/build/ethminer.sln
parallel: true
verbosity: minimal
- cmake -G "Visual Studio 14 2015 Win64" -H. -Bbuild -DETHASHCUDA=ON
build_script:
- cmake --build build --config %CONFIGURATION%
after_build:
ps: |
cmake --build build --config $env:configuration --target package
if ($env:configuration -ne "Release") {
Get-Item build/ethminer-*-Windows.* | Rename-Item -NewName { $_.name -Replace 'ethminer','ethminer-dbg' }
}
artifacts:
- path: build/ethminer/Release/ethminer.exe
- path: build/ethminer-*.zip
name: ethminer
before_deploy:
# Read variables dumped by CMake configuration.
- ps: . build/variables.ps1
deploy:
# Create GitHub release, also set the release name and description.
provider: GitHub
tag: $(appveyor_repo_tag_name)
release: ethminer $(ethminer_version)
description: ''
force_update: true # Force update in case Travis CI created the release before.
prerelease: $(ethminer_version_is_prerelease)
draft: false
artifact: ethminer
auth_token:
secure: uDRcvbW+9GIyKlZ9guJfWOQ6jg0An6eULg6mEkYgdKn/GVNpYSKvO5oHxP0U8a+e
on:
appveyor_repo_tag: true

2
cmake/Hunter/config.cmake

@ -1 +1 @@
hunter_config(CURL VERSION ${HUNTER_CURL_VERSION} CMAKE_ARGS HTTP_ONLY=ON)
hunter_config(CURL VERSION ${HUNTER_CURL_VERSION} CMAKE_ARGS HTTP_ONLY=ON CMAKE_USE_OPENSSL=OFF CMAKE_USE_LIBSSH2=OFF)

2
cmake/variables.ps1.in

@ -0,0 +1,2 @@
$env:ethminer_version="@PROJECT_VERSION@"
$env:ethminer_version_is_prerelease="@PROJECT_VERSION_IS_PRERELEASE@"

2
cmake/variables.sh.in

@ -0,0 +1,2 @@
ETHMINER_VERSION='@PROJECT_VERSION@'
ETHMINER_VERSION_IS_PRERELEASE='@PROJECT_VERSION_IS_PRERELEASE@'

2363
doc/Doxyfile

File diff suppressed because it is too large

7
ethminer/CMakeLists.txt

@ -16,9 +16,12 @@ target_link_libraries(${EXECUTABLE} ethcore)
target_link_libraries(${EXECUTABLE} ethash)
target_link_libraries(${EXECUTABLE} devcore libjson-rpc-cpp::client)
if (ETHSTRATUM)
target_link_libraries(${EXECUTABLE} ethstratum)
if(ETHSTRATUM)
target_link_libraries(${EXECUTABLE} ethstratum)
endif()
include(GNUInstallDirs)
install(TARGETS ethminer DESTINATION ${CMAKE_INSTALL_BINDIR})
if(MSVC)
install(FILES $<TARGET_PDB_FILE:ethminer> DESTINATION ${CMAKE_INSTALL_BINDIR} OPTIONAL)
endif()

64
ethminer/MinerAux.h

@ -596,33 +596,24 @@ public:
MinerType minerType() const { return m_minerType; }
private:
void doInitDAG(unsigned _n)
{
h256 seedHash = EthashAux::seedHash(_n);
cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl;
EthashAux::full(seedHash, true);
exit(0);
}
void doBenchmark(MinerType _m, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5)
{
Ethash::BlockHeader genesis;
BlockHeader genesis;
genesis.setNumber(m_benchmarkBlock);
genesis.setDifficulty(1 << 18);
cdebug << genesis.boundary();
GenericFarm<EthashProofOfWork> f;
map<string, GenericFarm<EthashProofOfWork>::SealerDescriptor> sealers;
Farm f;
map<string, Farm::SealerDescriptor> sealers;
#if ETH_ETHASHCL
sealers["opencl"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashGPUMiner(ci); }};
sealers["opencl"] = Farm::SealerDescriptor{&EthashGPUMiner::instances, [](Miner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }};
#endif
#if ETH_ETHASHCUDA
sealers["cuda"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{ &EthashCUDAMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashCUDAMiner(ci); } };
sealers["cuda"] = Farm::SealerDescriptor{ &EthashCUDAMiner::instances, [](Miner::ConstructionInfo ci){ return new EthashCUDAMiner(ci); } };
#endif
f.setSealers(sealers);
f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; });
f.onSolutionFound([&](Solution) { return false; });
string platformInfo = _m == MinerType::CPU ? "CPU" : (_m == MinerType::CL ? "CL" : "CUDA");
cout << "Benchmarking on platform: " << platformInfo << endl;
@ -674,18 +665,18 @@ private:
void doSimulation(MinerType _m, int difficulty = 20)
{
Ethash::BlockHeader genesis;
BlockHeader genesis;
genesis.setNumber(m_benchmarkBlock);
genesis.setDifficulty(1 << 18);
cdebug << genesis.boundary();
GenericFarm<EthashProofOfWork> f;
map<string, GenericFarm<EthashProofOfWork>::SealerDescriptor> sealers;
Farm f;
map<string, Farm::SealerDescriptor> sealers;
#if ETH_ETHASHCL
sealers["opencl"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{ &EthashGPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashGPUMiner(ci); } };
sealers["opencl"] = Farm::SealerDescriptor{ &EthashGPUMiner::instances, [](Miner::ConstructionInfo ci){ return new EthashGPUMiner(ci); } };
#endif
#if ETH_ETHASHCUDA
sealers["cuda"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{ &EthashCUDAMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashCUDAMiner(ci); } };
sealers["cuda"] = Farm::SealerDescriptor{ &EthashCUDAMiner::instances, [](Miner::ConstructionInfo ci){ return new EthashCUDAMiner(ci); } };
#endif
f.setSealers(sealers);
@ -707,11 +698,11 @@ private:
int time = 0;
EthashProofOfWork::WorkPackage current = EthashProofOfWork::WorkPackage(genesis);
WorkPackage current = WorkPackage(genesis);
while (true) {
bool completed = false;
EthashProofOfWork::Solution solution;
f.onSolutionFound([&](EthashProofOfWork::Solution sol)
Solution solution;
f.onSolutionFound([&](Solution sol)
{
solution = sol;
return completed = true;
@ -759,12 +750,12 @@ private:
void doFarm(MinerType _m, string & _remote, unsigned _recheckPeriod)
{
map<string, GenericFarm<EthashProofOfWork>::SealerDescriptor> sealers;
map<string, Farm::SealerDescriptor> sealers;
#if ETH_ETHASHCL
sealers["opencl"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashGPUMiner(ci); }};
sealers["opencl"] = Farm::SealerDescriptor{&EthashGPUMiner::instances, [](Miner::ConstructionInfo ci){ return new EthashGPUMiner(ci); }};
#endif
#if ETH_ETHASHCUDA
sealers["cuda"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{ &EthashCUDAMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashCUDAMiner(ci); } };
sealers["cuda"] = Farm::SealerDescriptor{ &EthashCUDAMiner::instances, [](Miner::ConstructionInfo ci){ return new EthashCUDAMiner(ci); } };
#endif
(void)_m;
(void)_remote;
@ -777,7 +768,7 @@ private:
FarmClient * prpc = &rpc;
h256 id = h256::random();
GenericFarm<EthashProofOfWork> f;
Farm f;
f.setSealers(sealers);
if (_m == MinerType::CPU)
f.start("cpu", false);
@ -785,15 +776,14 @@ private:
f.start("opencl", false);
else if (_m == MinerType::CUDA)
f.start("cuda", false);
EthashProofOfWork::WorkPackage current, previous;
WorkPackage current, previous;
std::mutex x_current;
EthashAux::FullType dag;
while (m_running)
try
{
bool completed = false;
EthashProofOfWork::Solution solution;
f.onSolutionFound([&](EthashProofOfWork::Solution sol)
Solution solution;
f.onSolutionFound([&](Solution sol)
{
solution = sol;
return completed = true;
@ -912,17 +902,17 @@ private:
#if ETH_STRATUM
void doStratum()
{
map<string, GenericFarm<EthashProofOfWork>::SealerDescriptor> sealers;
map<string, Farm::SealerDescriptor> sealers;
#if ETH_ETHASHCL
sealers["opencl"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{ &EthashGPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashGPUMiner(ci); } };
sealers["opencl"] = Farm::SealerDescriptor{ &EthashGPUMiner::instances, [](Miner::ConstructionInfo ci){ return new EthashGPUMiner(ci); } };
#endif
#if ETH_ETHASHCUDA
sealers["cuda"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{ &EthashCUDAMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashCUDAMiner(ci); } };
sealers["cuda"] = Farm::SealerDescriptor{ &EthashCUDAMiner::instances, [](Miner::ConstructionInfo ci){ return new EthashCUDAMiner(ci); } };
#endif
if (!m_farmRecheckSet)
m_farmRecheckPeriod = m_defaultStratumFarmRecheckPeriod;
GenericFarm<EthashProofOfWork> f;
Farm f;
// this is very ugly, but if Stratum Client V2 tunrs out to be a success, V1 will be completely removed anyway
if (m_stratumClientVersion == 1) {
@ -940,7 +930,7 @@ private:
}
f.setSealers(sealers);
f.onSolutionFound([&](EthashProofOfWork::Solution sol)
f.onSolutionFound([&](Solution sol)
{
if (client.isConnected()) {
client.submit(sol);
@ -984,7 +974,7 @@ private:
}
f.setSealers(sealers);
f.onSolutionFound([&](EthashProofOfWork::Solution sol)
f.onSolutionFound([&](Solution sol)
{
client.submit(sol);
return false;

39
extdep/getstuff.bat

@ -1,39 +0,0 @@
REM get stuff!
if not exist download mkdir download
if not exist install mkdir install
if not exist install\windows mkdir install\windows
set eth_server=https://build.ethdev.com/builds/windows-precompiled
call :download boost 1.55.0
call :download cryptopp 5.6.2
call :download curl 7.4.2
call :download jsoncpp 1.6.2
call :download json-rpc-cpp 0.5.0
call :download leveldb 1.2
call :download microhttpd 0.9.2
call :download OpenCL_ICD 1
goto :EOF
:download
set eth_name=%1
set eth_version=%2
cd download
if not exist %eth_name%-%eth_version%-x64.tar.gz (
for /f "tokens=2 delims={}" %%g in ('bitsadmin /create %eth_name%-%eth_version%-x64.tar.gz') do (
bitsadmin /transfer {%%g} /download /priority normal %eth_server%/%eth_name%-%eth_version%-x64.tar.gz %cd%\%eth_name%-%eth_version%-x64.tar.gz
bitsadmin /cancel {%%g}
)
)
if not exist %eth_name%-%eth_version% cmake -E tar -zxvf %eth_name%-%eth_version%-x64.tar.gz
cmake -E copy_directory %eth_name%-%eth_version% ..\install\windows
cd ..
goto :EOF

6
libdevcore/Common.h

@ -40,14 +40,8 @@
#include <boost/multiprecision/cpp_int.hpp>
#include "vector_ref.h"
// CryptoPP defines byte in the global namespace, so must we.
using byte = uint8_t;
#define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {}
#define DEV_IF_NO_ELSE(X) if(!(X)){}else
#define DEV_IF_THROWS(X) try{X;}catch(...)
namespace dev
{

19
libdevcore/Log.cpp

@ -21,8 +21,6 @@
#include "Log.h"
#include <string>
#include <iostream>
#include <thread>
#ifdef __APPLE__
#include <pthread.h>
@ -42,23 +40,6 @@ mutex x_logOverride;
/// or equal to the currently output verbosity (g_logVerbosity).
static map<type_info const*, bool> s_logOverride;
LogOverrideAux::LogOverrideAux(std::type_info const* _ch, bool _value):
m_ch(_ch)
{
Guard l(x_logOverride);
m_old = s_logOverride.count(_ch) ? (int)s_logOverride[_ch] : c_null;
s_logOverride[m_ch] = _value;
}
LogOverrideAux::~LogOverrideAux()
{
Guard l(x_logOverride);
if (m_old == c_null)
s_logOverride.erase(m_ch);
else
s_logOverride[m_ch] = (bool)m_old;
}
#ifdef _WIN32
const char* LogChannel::name() { return EthGray "..."; }
const char* LeftChannel::name() { return EthNavy "<--"; }

12
libdevcore/Log.h

@ -52,18 +52,6 @@ extern int g_logVerbosity;
/// The current method that the logging system uses to output the log messages. Defaults to simpleDebugOut().
extern std::function<void(std::string const&, char const*)> g_logPost;
class LogOverrideAux
{
protected:
LogOverrideAux(std::type_info const* _ch, bool _value);
~LogOverrideAux();
private:
std::type_info const* m_ch;
static const int c_null = -1;
int m_old;
};
class ThreadContext
{
public:

1
libethash-cl/ethash_cl_miner.cpp

@ -33,7 +33,6 @@
#include <random>
#include <atomic>
#include <sstream>
#include <libethash/util.h>
#include <libethash/ethash.h>
#include <libethash/internal.h>
#include "ethash_cl_miner.h"

40
libethash-cuda/ethash_cuda_miner.cpp

@ -25,15 +25,12 @@
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <assert.h>
#include <queue>
#include <random>
#include <atomic>
#include <sstream>
#include <vector>
#include <chrono>
#include <thread>
#include <libethash/util.h>
#include <libethash/ethash.h>
#include <libethash/internal.h>
#include <cuda_runtime.h>
@ -41,8 +38,6 @@
#include "ethash_cuda_miner_kernel_globals.h"
#define ETHASH_BYTES 32
// workaround lame platforms
#undef min
@ -106,11 +101,23 @@ std::string ethash_cuda_miner::platform_info(unsigned _deviceId)
return "{ \"platform\": \"CUDA " + std::string(platform) + "\", \"device\": \"" + std::string(device_props.name) + "\", \"version\": \"Compute " + std::string(compute) + "\" }";
}
unsigned ethash_cuda_miner::getNumDevices()
int ethash_cuda_miner::getNumDevices()
{
int device_count;
CUDA_SAFE_CALL(cudaGetDeviceCount(&device_count));
return device_count;
int deviceCount = -1;
cudaError_t err = cudaGetDeviceCount(&deviceCount);
if (err == cudaSuccess)
return deviceCount;
if (err == cudaErrorInsufficientDriver)
{
int driverVersion = -1;
cudaDriverGetVersion(&driverVersion);
if (driverVersion == 0)
throw std::runtime_error{"No CUDA driver found"};
throw std::runtime_error{"Insufficient CUDA driver: " + std::to_string(driverVersion)};
}
throw std::runtime_error{cudaGetErrorString(err)};
}
bool ethash_cuda_miner::configureGPU(
@ -138,13 +145,13 @@ bool ethash_cuda_miner::configureGPU(
// by default let's only consider the DAG of the first epoch
uint64_t dagSize = ethash_get_datasize(_currentBlock);
uint64_t requiredSize = dagSize + _extraGPUMemory;
unsigned devicesCount = getNumDevices();
for (unsigned int i = 0; i < devicesCount; i++)
int devicesCount = getNumDevices();
for (int i = 0; i < devicesCount; i++)
{
if (_devices[i] != -1)
{
int deviceId = min((int)devicesCount - 1, _devices[i]);
int deviceId = min(devicesCount - 1, _devices[i]);
cudaDeviceProp props;
CUDA_SAFE_CALL(cudaGetDeviceProperties(&props, deviceId));
if (props.totalGlobalMem >= requiredSize)
@ -184,7 +191,8 @@ void ethash_cuda_miner::listDevices()
try
{
string outString = "\nListing CUDA devices.\nFORMAT: [deviceID] deviceName\n";
for (unsigned int i = 0; i < getNumDevices(); i++)
int numDevices = getNumDevices();
for (int i = 0; i < numDevices; ++i)
{
cudaDeviceProp props;
CUDA_SAFE_CALL(cudaGetDeviceProperties(&props, i));
@ -197,7 +205,7 @@ void ethash_cuda_miner::listDevices()
}
catch(std::runtime_error const& err)
{
std::cerr << err.what();
std::cerr << "CUDA error: " << err.what() << '\n';
}
}
@ -271,8 +279,6 @@ bool ethash_cuda_miner::init(ethash_light_t _light, uint8_t const* _lightData, u
if (_cpyToHost)
{
uint8_t* memoryDAG = new uint8_t[dagSize];
if (!memoryDAG) throw std::runtime_error("Failed to init host memory for DAG, not enough memory?");
cout << "Copying DAG from GPU #" << device_num << " to host" << endl;
CUDA_SAFE_CALL(cudaMemcpy(reinterpret_cast<void*>(memoryDAG), dag, dagSize, cudaMemcpyDeviceToHost));
@ -342,7 +348,7 @@ void ethash_cuda_miner::search(uint8_t const* header, uint64_t target, search_ho
uint64_t batch_size = s_gridSize * s_blockSize;
for (; !exit; m_current_index++, m_current_nonce += batch_size)
{
unsigned int stream_index = m_current_index % s_numStreams;
auto stream_index = m_current_index % s_numStreams;
cudaStream_t stream = m_streams[stream_index];
volatile uint32_t* buffer = m_search_buf[stream_index];
uint32_t found_count = 0;

2
libethash-cuda/ethash_cuda_miner.h

@ -23,7 +23,7 @@ public:
ethash_cuda_miner();
static std::string platform_info(unsigned _deviceId = 0);
static unsigned getNumDevices();
static int getNumDevices();
static void listDevices();
static bool configureGPU(
int * _devices,

26
libethash/CMakeLists.txt

@ -2,22 +2,16 @@ if (NOT MSVC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99")
endif()
set(FILES util.h
io.c
internal.c
ethash.h
endian.h
compiler.h
fnv.h
data_sizes.h)
if (MSVC)
list(APPEND FILES util_win32.c io_win32.c mmap_win32.c)
else()
list(APPEND FILES io_posix.c)
endif()
list(APPEND FILES sha3.c sha3.h)
set(FILES
internal.c
ethash.h
endian.h
compiler.h
fnv.h
data_sizes.h
sha3.c
sha3.h
)
add_library(ethash ${FILES})

56
libethash/ethash.h

@ -37,8 +37,6 @@
#define ETHASH_DATASET_PARENTS 256
#define ETHASH_CACHE_ROUNDS 3
#define ETHASH_ACCESSES 64
#define ETHASH_DAG_MAGIC_NUM_SIZE 8
#define ETHASH_DAG_MAGIC_NUM 0xFEE1DEADBADDCAFE
#ifdef __cplusplus
extern "C" {
@ -47,19 +45,8 @@ extern "C" {
/// Type of a seedhash/blockhash e.t.c.
typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t;
// convenience macro to statically initialize an h256_t
// usage:
// ethash_h256_t a = ethash_h256_static_init(1, 2, 3, ... )
// have to provide all 32 values. If you don't provide all the rest
// will simply be unitialized (not guranteed to be 0)
#define ethash_h256_static_init(...) \
{ {__VA_ARGS__} }
struct ethash_light;
typedef struct ethash_light* ethash_light_t;
struct ethash_full;
typedef struct ethash_full* ethash_full_t;
typedef int(*ethash_callback_t)(unsigned);
typedef struct ethash_return_value {
ethash_h256_t result;
@ -94,49 +81,6 @@ ethash_return_value_t ethash_light_compute(
uint64_t nonce
);
/**
* Allocate and initialize a new ethash_full handler
*
* @param light The light handler containing the cache.
* @param callback A callback function with signature of @ref ethash_callback_t
* It accepts an unsigned with which a progress of DAG calculation
* can be displayed. If all goes well the callback should return 0.
* If a non-zero value is returned then DAG generation will stop.
* Be advised. A progress value of 100 means that DAG creation is
* almost complete and that this function will soon return succesfully.
* It does not mean that the function has already had a succesfull return.
* @return Newly allocated ethash_full handler or NULL in case of
* ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data()
*/
ethash_full_t ethash_full_new(ethash_light_t light, const char * custom_dir_name, ethash_callback_t callback);
/**
* Frees a previously allocated ethash_full handler
* @param full The light handler to free
*/
void ethash_full_delete(ethash_full_t full);
/**
* Calculate the full client data
*
* @param full The full client handler
* @param header_hash The header hash to pack into the mix
* @param nonce The nonce to pack into the mix
* @return An object of ethash_return_value to hold the return value
*/
ethash_return_value_t ethash_full_compute(
ethash_full_t full,
ethash_h256_t const header_hash,
uint64_t nonce
);
/**
* Get a pointer to the full DAG data
*/
void const* ethash_full_dag(ethash_full_t full);
/**
* Get the size of the DAG data
*/
uint64_t ethash_full_dag_size(ethash_full_t full);
/**
* Calculate the seedhash for a given block number
*/

219
libethash/internal.c

@ -23,23 +23,12 @@
#include <assert.h>
#include <inttypes.h>
#include <stddef.h>
#include <errno.h>
#include <math.h>
#include "mmap.h"
#include "ethash.h"
#include "fnv.h"
#include "endian.h"
#include "internal.h"
#include "data_sizes.h"
#include "io.h"
#ifdef WITH_CRYPTOPP
#include "sha3_cryptopp.h"
#else
#include "sha3.h"
#endif // WITH_CRYPTOPP
uint64_t ethash_get_datasize(uint64_t const block_number)
{
@ -142,35 +131,6 @@ void ethash_calculate_dag_item(
SHA3_512(ret->bytes, ret->bytes, sizeof(node));
}
bool ethash_compute_full_data(
void* mem,
uint64_t full_size,
ethash_light_t const light,
ethash_callback_t callback
)
{
if (full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 ||
(full_size % sizeof(node)) != 0) {
return false;
}
uint32_t const max_n = (uint32_t)(full_size / sizeof(node));
node* full_nodes = mem;
double const progress_change = 1.0f / max_n;
double progress = 0.0f;
// now compute full nodes
for (uint32_t n = 0; n != max_n; ++n) {
if (callback &&
n % (max_n / 100) == 0 &&
callback((unsigned int)(ceil(progress * 100.0f))) != 0) {
return false;
}
progress += progress_change;
ethash_calculate_dag_item(&(full_nodes[n]), n, light);
}
return true;
}
static bool ethash_hash(
ethash_return_value_t* ret,
node const* full_nodes,
@ -254,22 +214,6 @@ static bool ethash_hash(
return true;
}
void ethash_quick_hash(
ethash_h256_t* return_hash,
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash
)
{
uint8_t buf[64 + 32];
memcpy(buf, header_hash, 32);
fix_endian64_same(nonce);
memcpy(&(buf[32]), &nonce, 8);
SHA3_512(buf, buf, 40);
memcpy(&(buf[64]), mix_hash, 32);
SHA3_256(return_hash, buf, 64 + 32);
}
ethash_h256_t ethash_get_seedhash(uint64_t block_number)
{
ethash_h256_t ret;
@ -280,19 +224,6 @@ ethash_h256_t ethash_get_seedhash(uint64_t block_number)
return ret;
}
bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
ethash_h256_t const* boundary
)
{
ethash_h256_t return_hash;
ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash);
return ethash_check_difficulty(&return_hash, boundary);
}
ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed)
{
struct ethash_light *ret;
@ -359,153 +290,3 @@ ethash_return_value_t ethash_light_compute(
uint64_t full_size = ethash_get_datasize(light->block_number);
return ethash_light_compute_internal(light, full_size, header_hash, nonce);
}
static bool ethash_mmap(struct ethash_full* ret, FILE* f)
{
int fd;
char* mmapped_data;
errno = 0;
ret->file = f;
if ((fd = ethash_fileno(ret->file)) == -1) {
return false;
}
mmapped_data = mmap(
NULL,
(size_t)ret->file_size + ETHASH_DAG_MAGIC_NUM_SIZE,
PROT_READ | PROT_WRITE,
MAP_SHARED,
fd,
0
);
if (mmapped_data == MAP_FAILED) {
return false;
}
ret->data = (node*)(mmapped_data + ETHASH_DAG_MAGIC_NUM_SIZE);
return true;
}
ethash_full_t ethash_full_new_internal(
char const* dirname,
ethash_h256_t const seed_hash,
uint64_t full_size,
ethash_light_t const light,
ethash_callback_t callback
)
{
struct ethash_full* ret;
FILE *f = NULL;
ret = calloc(sizeof(*ret), 1);
if (!ret) {
return NULL;
}
ret->file_size = (size_t)full_size;
switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) {
case ETHASH_IO_FAIL:
// ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case
goto fail_free_full;
case ETHASH_IO_MEMO_MATCH:
if (!ethash_mmap(ret, f)) {
ETHASH_CRITICAL("mmap failure()");
goto fail_close_file;
}
return ret;
case ETHASH_IO_MEMO_SIZE_MISMATCH:
// if a DAG of same filename but unexpected size is found, silently force new file creation
if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) {
ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size.");
goto fail_free_full;
}
// fallthrough to the mismatch case here, DO NOT go through match
case ETHASH_IO_MEMO_MISMATCH:
if (!ethash_mmap(ret, f)) {
ETHASH_CRITICAL("mmap failure()");
goto fail_close_file;
}
break;
}
if (!ethash_compute_full_data(ret->data, full_size, light, callback)) {
ETHASH_CRITICAL("Failure at computing DAG data.");
goto fail_free_full_data;
}
// after the DAG has been filled then we finalize it by writting the magic number at the beginning
if (fseek(f, 0, SEEK_SET) != 0) {
ETHASH_CRITICAL("Could not seek to DAG file start to write magic number.");
goto fail_free_full_data;
}
uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM;
if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
ETHASH_CRITICAL("Could not write magic number to DAG's beginning.");
goto fail_free_full_data;
}
if (fflush(f) != 0) {// make sure the magic number IS there
ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?");
goto fail_free_full_data;
}
return ret;
fail_free_full_data:
// could check that munmap(..) == 0 but even if it did not can't really do anything here
munmap(ret->data, (size_t)full_size);
fail_close_file:
fclose(ret->file);
fail_free_full:
free(ret);
return NULL;
}
ethash_full_t ethash_full_new(ethash_light_t light, const char * custom_dir_name, ethash_callback_t callback)
{
char strbuf[256];
if (strcmp(custom_dir_name, "") != 0)
strcpy(strbuf, custom_dir_name);
else
if (!ethash_get_default_dirname(strbuf, 256)) {
return NULL;
}
uint64_t full_size = ethash_get_datasize(light->block_number);
ethash_h256_t seedhash = ethash_get_seedhash(light->block_number);
return ethash_full_new_internal(strbuf, seedhash, full_size, light, callback);
}
void ethash_full_delete(ethash_full_t full)
{
// could check that munmap(..) == 0 but even if it did not can't really do anything here
munmap(full->data, (size_t)full->file_size);
if (full->file) {
fclose(full->file);
}
free(full);
}
ethash_return_value_t ethash_full_compute(
ethash_full_t full,
ethash_h256_t const header_hash,
uint64_t nonce
)
{
ethash_return_value_t ret;
ret.success = true;
if (!ethash_hash(
&ret,
(node const*)full->data,
NULL,
full->file_size,
header_hash,
nonce)) {
ret.success = false;
}
return ret;
}
void const* ethash_full_dag(ethash_full_t full)
{
return full->data;
}
uint64_t ethash_full_dag_size(ethash_full_t full)
{
return full->file_size;
}

96
libethash/internal.h

@ -31,53 +31,11 @@ typedef union node {
} node;
static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i)
{
return hash->b[i];
}
static inline void ethash_h256_set(ethash_h256_t* hash, unsigned int i, uint8_t v)
{
hash->b[i] = v;
}
static inline void ethash_h256_reset(ethash_h256_t* hash)
{
memset(hash, 0, 32);
}
// Returns if hash is less than or equal to boundary (2^256/difficulty)
static inline bool ethash_check_difficulty(
ethash_h256_t const* hash,
ethash_h256_t const* boundary
)
{
// Boundary is big endian
for (int i = 0; i < 32; i++) {
if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) {
continue;
}
return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i);
}
return true;
}
/**
* Difficulty quick check for POW preverification
*
* @param header_hash The hash of the header
* @param nonce The block's nonce
* @param mix_hash The mix digest hash
* @param boundary The boundary is defined as (2^256 / difficulty)
* @return true for succesful pre-verification and false otherwise
*/
bool ethash_quick_check_difficulty(
ethash_h256_t const* header_hash,
uint64_t const nonce,
ethash_h256_t const* mix_hash,
ethash_h256_t const* boundary
);
struct ethash_light {
void* cache;
uint64_t cache_size;
@ -111,69 +69,15 @@ ethash_return_value_t ethash_light_compute_internal(
uint64_t nonce
);
struct ethash_full {
FILE* file;
uint64_t file_size;
node* data;
};
/**
* Allocate and initialize a new ethash_full handler. Internal version.
*
* @param dirname The directory in which to put the DAG file.
* @param seedhash The seed hash of the block. Used in the DAG file naming.
* @param full_size The size of the full data in bytes.
* @param cache A cache object to use that was allocated with @ref ethash_cache_new().
* Iff this function succeeds the ethash_full_t will take memory
* memory ownership of the cache and free it at deletion. If
* not then the user still has to handle freeing of the cache himself.
* @param callback A callback function with signature of @ref ethash_callback_t
* It accepts an unsigned with which a progress of DAG calculation
* can be displayed. If all goes well the callback should return 0.
* If a non-zero value is returned then DAG generation will stop.
* @return Newly allocated ethash_full handler or NULL in case of
* ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data()
*/
ethash_full_t ethash_full_new_internal(
char const* dirname,
ethash_h256_t const seed_hash,
uint64_t full_size,
ethash_light_t const light,
ethash_callback_t callback
);
void ethash_calculate_dag_item(
node* const ret,
uint32_t node_index,
ethash_light_t const cache
);
void ethash_quick_hash(
ethash_h256_t* return_hash,
ethash_h256_t const* header_hash,
const uint64_t nonce,
ethash_h256_t const* mix_hash
);
uint64_t ethash_get_datasize(uint64_t const block_number);
uint64_t ethash_get_cachesize(uint64_t const block_number);
/**
* Compute the memory data for a full node's memory
*
* @param mem A pointer to an ethash full's memory
* @param full_size The size of the full data in bytes
* @param cache A cache object to use in the calculation
* @param callback The callback function. Check @ref ethash_full_new() for details.
* @return true if all went fine and false for invalid parameters
*/
bool ethash_compute_full_data(
void* mem,
uint64_t full_size,
ethash_light_t const light,
ethash_callback_t callback
);
#ifdef __cplusplus
}
#endif

119
libethash/io.c

@ -1,119 +0,0 @@
/*
This file is part of ethash.
ethash 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, either version 3 of the License, or
(at your option) any later version.
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file io.c
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#include "io.h"
#include <string.h>
#include <stdio.h>
#include <errno.h>
enum ethash_io_rc ethash_io_prepare(
char const* dirname,
ethash_h256_t const seedhash,
FILE** output_file,
uint64_t file_size,
bool force_create
)
{
char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
enum ethash_io_rc ret = ETHASH_IO_FAIL;
// reset errno before io calls
errno = 0;
// assert directory exists
if (!ethash_mkdir(dirname)) {
ETHASH_CRITICAL("Could not create the ethash directory");
goto end;
}
ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name);
char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name));
if (!tmpfile) {
ETHASH_CRITICAL("Could not create the full DAG pathname");
goto end;
}
FILE *f;
if (!force_create) {
// try to open the file
f = ethash_fopen(tmpfile, "rb+");
if (f) {
size_t found_size;
if (!ethash_file_size(f, &found_size)) {
fclose(f);
ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile);
goto free_memo;
}
if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) {
fclose(f);
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
goto free_memo;
}
// compare the magic number, no need to care about endianess since it's local
uint64_t magic_num;
if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) {
// I/O error
fclose(f);
ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile);
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
goto free_memo;
}
if (magic_num != ETHASH_DAG_MAGIC_NUM) {
fclose(f);
ret = ETHASH_IO_MEMO_SIZE_MISMATCH;
goto free_memo;
}
ret = ETHASH_IO_MEMO_MATCH;
goto set_file;
}
}
// file does not exist, will need to be created
f = ethash_fopen(tmpfile, "wb+");
if (!f) {
ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile);
goto free_memo;
}
// make sure it's of the proper size
if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) {
fclose(f);
ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile);
goto free_memo;
}
if (fputc('\n', f) == EOF) {
fclose(f);
ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile);
goto free_memo;
}
if (fflush(f) != 0) {
fclose(f);
ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile);
goto free_memo;
}
ret = ETHASH_IO_MEMO_MISMATCH;
goto set_file;
ret = ETHASH_IO_MEMO_MATCH;
set_file:
*output_file = f;
free_memo:
free(tmpfile);
end:
return ret;
}

202
libethash/io.h

@ -1,202 +0,0 @@
/*
This file is part of ethash.
ethash 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, either version 3 of the License, or
(at your option) any later version.
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file io.h
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#pragma once
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#ifdef __cplusplus
#define __STDC_FORMAT_MACROS 1
#endif
#include <inttypes.h>
#include "endian.h"
#include "ethash.h"
#ifdef __cplusplus
extern "C" {
#endif
// Maximum size for mutable part of DAG file name
// 6 is for "full-R", the suffix of the filename
// 10 is for maximum number of digits of a uint32_t (for REVISION)
// 1 is for - and 16 is for the first 16 hex digits for first 8 bytes of
// the seedhash and last 1 is for the null terminating character
// Reference: https://github.com/ethereum/wiki/wiki/Ethash-DAG
#define DAG_MUTABLE_NAME_MAX_SIZE (6 + 10 + 1 + 16 + 1)
/// Possible return values of @see ethash_io_prepare
enum ethash_io_rc {
ETHASH_IO_FAIL = 0, ///< There has been an IO failure
ETHASH_IO_MEMO_SIZE_MISMATCH, ///< DAG with revision/hash match, but file size was wrong.
ETHASH_IO_MEMO_MISMATCH, ///< The DAG file did not exist or there was revision/hash mismatch
ETHASH_IO_MEMO_MATCH, ///< DAG file existed and revision/hash matched. No need to do anything
};
// small hack for windows. I don't feel I should use va_args and forward just
// to have this one function properly cross-platform abstracted
#if defined(_WIN32) && !defined(__GNUC__)
#define snprintf(...) sprintf_s(__VA_ARGS__)
#endif
/**
* Logs a critical error in important parts of ethash. Should mostly help
* figure out what kind of problem (I/O, memory e.t.c.) causes a NULL
* ethash_full_t
*/
#ifdef ETHASH_PRINT_CRITICAL_OUTPUT
#define ETHASH_CRITICAL(...) \
do \
{ \
printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \
printf("\n"); \
fflush(stdout); \
} while (0)
#else
#define ETHASH_CRITICAL(...)
#endif
/**
* Prepares io for ethash
*
* Create the DAG directory and the DAG file if they don't exist.
*
* @param[in] dirname A null terminated c-string of the path of the ethash
* data directory. If it does not exist it's created.
* @param[in] seedhash The seedhash of the current block number, used in the
* naming of the file as can be seen from the spec at:
* https://github.com/ethereum/wiki/wiki/Ethash-DAG
* @param[out] output_file If there was no failure then this will point to an open
* file descriptor. User is responsible for closing it.
* In the case of memo match then the file is open on read
* mode, while on the case of mismatch a new file is created
* on write mode
* @param[in] file_size The size that the DAG file should have on disk
* @param[out] force_create If true then there is no check to see if the file
* already exists
* @return For possible return values @see enum ethash_io_rc
*/
enum ethash_io_rc ethash_io_prepare(
char const* dirname,
ethash_h256_t const seedhash,
FILE** output_file,
uint64_t file_size,
bool force_create
);
/**
* An fopen wrapper for no-warnings crossplatform fopen.
*
* Msvc compiler considers fopen to be insecure and suggests to use their
* alternative. This is a wrapper for this alternative. Another way is to
* #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
* not sound like a good idea.
*
* @param file_name The path to the file to open
* @param mode Opening mode. Check fopen()
* @return The FILE* or NULL in failure
*/
FILE* ethash_fopen(char const* file_name, char const* mode);
/**
* An strncat wrapper for no-warnings crossplatform strncat.
*
* Msvc compiler considers strncat to be insecure and suggests to use their
* alternative. This is a wrapper for this alternative. Another way is to
* #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
* not sound like a good idea.
*
* @param des Destination buffer
* @param dest_size Maximum size of the destination buffer. This is the
* extra argument for the MSVC secure strncat
* @param src Souce buffer
* @param count Number of bytes to copy from source
* @return If all is well returns the dest buffer. If there is an
* error returns NULL
*/
char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count);
/**
* A cross-platform mkdir wrapper to create a directory or assert it's there
*
* @param dirname The full path of the directory to create
* @return true if the directory was created or if it already
* existed
*/
bool ethash_mkdir(char const* dirname);
/**
* Get a file's size
*
* @param[in] f The open file stream whose size to get
* @param[out] size Pass a size_t by reference to contain the file size
* @return true in success and false if there was a failure
*/
bool ethash_file_size(FILE* f, size_t* ret_size);
/**
* Get a file descriptor number from a FILE stream
*
* @param f The file stream whose fd to get
* @return Platform specific fd handler
*/
int ethash_fileno(FILE* f);
/**
* Create the filename for the DAG.
*
* @param dirname The directory name in which the DAG file should reside
* If it does not end with a directory separator it is appended.
* @param filename The actual name of the file
* @param filename_length The length of the filename in bytes
* @return A char* containing the full name. User must deallocate.
*/
char* ethash_io_create_filename(
char const* dirname,
char const* filename,
size_t filename_length
);
/**
* Gets the default directory name for the DAG depending on the system
*
* The spec defining this directory is here: https://github.com/ethereum/wiki/wiki/Ethash-DAG
*
* @param[out] strbuf A string buffer of sufficient size to keep the
* null termninated string of the directory name
* @param[in] buffsize Size of @a strbuf in bytes
* @return true for success and false otherwise
*/
bool ethash_get_default_dirname(char* strbuf, size_t buffsize);
static inline bool ethash_io_mutable_name(
uint32_t revision,
ethash_h256_t const* seed_hash,
char* output
)
{
uint64_t hash = *((uint64_t*)seed_hash);
#if LITTLE_ENDIAN == BYTE_ORDER
hash = ethash_swap_u64(hash);
#endif
return snprintf(output, DAG_MUTABLE_NAME_MAX_SIZE, "full-R%u-%016" PRIx64, revision, hash) >= 0;
}
#ifdef __cplusplus
}
#endif

111
libethash/io_posix.c

@ -1,111 +0,0 @@
/*
This file is part of ethash.
ethash 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, either version 3 of the License, or
(at your option) any later version.
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file io_posix.c
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#include "io.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <libgen.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pwd.h>
FILE* ethash_fopen(char const* file_name, char const* mode)
{
return fopen(file_name, mode);
}
char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count)
{
return strlen(dest) + count + 1 <= dest_size ? strncat(dest, src, count) : NULL;
}
bool ethash_mkdir(char const* dirname)
{
int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
return rc != -1 || errno == EEXIST;
}
int ethash_fileno(FILE *f)
{
return fileno(f);
}
char* ethash_io_create_filename(
char const* dirname,
char const* filename,
size_t filename_length
)
{
size_t dirlen = strlen(dirname);
size_t dest_size = dirlen + filename_length + 1;
if (dirname[dirlen] != '/') {
dest_size += 1;
}
char* name = malloc(dest_size);
if (!name) {
return NULL;
}
name[0] = '\0';
ethash_strncat(name, dest_size, dirname, dirlen);
if (dirname[dirlen] != '/') {
ethash_strncat(name, dest_size, "/", 1);
}
ethash_strncat(name, dest_size, filename, filename_length);
return name;
}
bool ethash_file_size(FILE* f, size_t* ret_size)
{
struct stat st;
int fd;
if ((fd = fileno(f)) == -1 || fstat(fd, &st) != 0) {
return false;
}
*ret_size = st.st_size;
return true;
}
bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
{
static const char dir_suffix[] = ".ethash/";
strbuf[0] = '\0';
char* home_dir = getenv("HOME");
if (!home_dir || strlen(home_dir) == 0)
{
struct passwd* pwd = getpwuid(getuid());
if (pwd)
home_dir = pwd->pw_dir;
}
size_t len = strlen(home_dir);
if (!ethash_strncat(strbuf, buffsize, home_dir, len)) {
return false;
}
if (home_dir[len] != '/') {
if (!ethash_strncat(strbuf, buffsize, "/", 1)) {
return false;
}
}
return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix));
}

100
libethash/io_win32.c

@ -1,100 +0,0 @@
/*
This file is part of ethash.
ethash 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, either version 3 of the License, or
(at your option) any later version.
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file io_win32.c
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#include "io.h"
#include <direct.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <shlobj.h>
FILE* ethash_fopen(char const* file_name, char const* mode)
{
FILE* f;
return fopen_s(&f, file_name, mode) == 0 ? f : NULL;
}
char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count)
{
return strncat_s(dest, dest_size, src, count) == 0 ? dest : NULL;
}
bool ethash_mkdir(char const* dirname)
{
int rc = _mkdir(dirname);
return rc != -1 || errno == EEXIST;
}
int ethash_fileno(FILE* f)
{
return _fileno(f);
}
char* ethash_io_create_filename(
char const* dirname,
char const* filename,
size_t filename_length
)
{
size_t dirlen = strlen(dirname);
size_t dest_size = dirlen + filename_length + 1;
if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') {
dest_size += 1;
}
char* name = malloc(dest_size);
if (!name) {
return NULL;
}
name[0] = '\0';
ethash_strncat(name, dest_size, dirname, dirlen);
if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') {
ethash_strncat(name, dest_size, "\\", 1);
}
ethash_strncat(name, dest_size, filename, filename_length);
return name;
}
bool ethash_file_size(FILE* f, size_t* ret_size)
{
struct _stat st;
int fd;
if ((fd = _fileno(f)) == -1 || _fstat(fd, &st) != 0) {
return false;
}
*ret_size = st.st_size;
return true;
}
bool ethash_get_default_dirname(char* strbuf, size_t buffsize)
{
static const char dir_suffix[] = "Ethash\\";
strbuf[0] = '\0';
if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, (CHAR*)strbuf))) {
return false;
}
if (!ethash_strncat(strbuf, buffsize, "\\", 1)) {
return false;
}
return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix));
}

47
libethash/mmap.h

@ -1,47 +0,0 @@
/*
This file is part of ethash.
ethash 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, either version 3 of the License, or
(at your option) any later version.
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file mmap.h
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#pragma once
#if defined(__MINGW32__) || defined(_WIN32)
#include <sys/types.h>
#define PROT_READ 0x1
#define PROT_WRITE 0x2
/* This flag is only available in WinXP+ */
#ifdef FILE_MAP_EXECUTE
#define PROT_EXEC 0x4
#else
#define PROT_EXEC 0x0
#define FILE_MAP_EXECUTE 0
#endif
#define MAP_SHARED 0x01
#define MAP_PRIVATE 0x02
#define MAP_ANONYMOUS 0x20
#define MAP_ANON MAP_ANONYMOUS
#define MAP_FAILED ((void *) -1)
void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset);
void munmap(void* addr, size_t length);
#else // posix, yay! ^_^
#include <sys/mman.h>
#endif

84
libethash/mmap_win32.c

@ -1,84 +0,0 @@
/* mmap() replacement for Windows
*
* Author: Mike Frysinger <vapier@gentoo.org>
* Placed into the public domain
*/
/* References:
* CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx
* CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx
* MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx
* UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx
*/
#include <io.h>
#include <windows.h>
#include "mmap.h"
#ifdef __USE_FILE_OFFSET64
# define DWORD_HI(x) (x >> 32)
# define DWORD_LO(x) ((x) & 0xffffffff)
#else
# define DWORD_HI(x) (0)
# define DWORD_LO(x) (x)
#endif
void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset)
{
if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
return MAP_FAILED;
if (fd == -1) {
if (!(flags & MAP_ANON) || offset)
return MAP_FAILED;
} else if (flags & MAP_ANON)
return MAP_FAILED;
DWORD flProtect;
if (prot & PROT_WRITE) {
if (prot & PROT_EXEC)
flProtect = PAGE_EXECUTE_READWRITE;
else
flProtect = PAGE_READWRITE;
} else if (prot & PROT_EXEC) {
if (prot & PROT_READ)
flProtect = PAGE_EXECUTE_READ;
else if (prot & PROT_EXEC)
flProtect = PAGE_EXECUTE;
} else
flProtect = PAGE_READONLY;
off_t end = length + offset;
HANDLE mmap_fd, h;
if (fd == -1)
mmap_fd = INVALID_HANDLE_VALUE;
else
mmap_fd = (HANDLE)_get_osfhandle(fd);
h = CreateFileMapping(mmap_fd, NULL, flProtect, DWORD_HI(end), DWORD_LO(end), NULL);
if (h == NULL)
return MAP_FAILED;
DWORD dwDesiredAccess;
if (prot & PROT_WRITE)
dwDesiredAccess = FILE_MAP_WRITE;
else
dwDesiredAccess = FILE_MAP_READ;
if (prot & PROT_EXEC)
dwDesiredAccess |= FILE_MAP_EXECUTE;
if (flags & MAP_PRIVATE)
dwDesiredAccess |= FILE_MAP_COPY;
void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length);
if (ret == NULL) {
ret = MAP_FAILED;
}
// since we are handling the file ourselves with fd, close the Windows Handle here
CloseHandle(h);
return ret;
}
void munmap(void* addr, size_t length)
{
UnmapViewOfFile(addr);
}
#undef DWORD_HI
#undef DWORD_LO

37
libethash/sha3_cryptopp.cpp

@ -1,37 +0,0 @@
/*
This file is part of ethash.
ethash 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, either version 3 of the License, or
(at your option) any later version.
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file sha3.cpp
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#include <stdint.h>
#include <cryptopp/sha3.h>
extern "C" {
struct ethash_h256;
typedef struct ethash_h256 ethash_h256_t;
void SHA3_256(ethash_h256_t const* ret, uint8_t const* data, size_t size)
{
CryptoPP::SHA3_256().CalculateDigest((uint8_t*)ret, data, size);
}
void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size)
{
CryptoPP::SHA3_512().CalculateDigest(ret, data, size);
}
}

18
libethash/sha3_cryptopp.h

@ -1,18 +0,0 @@
#pragma once
#include "compiler.h"
#include <stdint.h>
#include <stdlib.h>
#ifdef __cplusplus
extern "C" {
#endif
struct ethash_h256;
void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t size);
void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size);
#ifdef __cplusplus
}
#endif

41
libethash/util.c

@ -1,41 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum 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, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file util.c
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#include <stdarg.h>
#include <stdio.h>
#include "util.h"
#ifdef _MSC_VER
// foward declare without all of Windows.h
__declspec(dllimport) void __stdcall OutputDebugStringA(const char* lpOutputString);
void debugf(const char *str, ...)
{
va_list args;
va_start(args, str);
char buf[1<<16];
_vsnprintf_s(buf, sizeof(buf), sizeof(buf), str, args);
buf[sizeof(buf)-1] = '\0';
OutputDebugStringA(buf);
}
#endif

47
libethash/util.h

@ -1,47 +0,0 @@
/*
This file is part of ethash.
ethash 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, either version 3 of the License, or
(at your option) any later version.
ethash 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 ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file util.h
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#pragma once
#include <stdint.h>
#include "compiler.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef _MSC_VER
void debugf(char const* str, ...);
#else
#define debugf printf
#endif
static inline uint32_t min_u32(uint32_t a, uint32_t b)
{
return a < b ? a : b;
}
static inline uint32_t clamp_u32(uint32_t x, uint32_t min_, uint32_t max_)
{
return x < min_ ? min_ : (x > max_ ? max_ : x);
}
#ifdef __cplusplus
}
#endif

38
libethash/util_win32.c

@ -1,38 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum 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, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file util.c
* @author Tim Hughes <tim@twistedfury.com>
* @date 2015
*/
#include <stdarg.h>
#include <stdio.h>
#include "util.h"
// foward declare without all of Windows.h
__declspec(dllimport) void __stdcall OutputDebugStringA(char const* lpOutputString);
void debugf(char const* str, ...)
{
va_list args;
va_start(args, str);
char buf[1<<16];
_vsnprintf_s(buf, sizeof(buf), sizeof(buf), str, args);
buf[sizeof(buf)-1] = '\0';
OutputDebugStringA(buf);
}

50
libethcore/BlockInfo.cpp → libethcore/BlockHeader.cpp

@ -19,59 +19,31 @@
* @date 2014
*/
#include "BlockHeader.h"
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include <libdevcore/RLP.h>
#include <libethcore/Common.h>
#include "EthashAux.h"
#include "Exceptions.h"
#include "BlockInfo.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
namespace
{
h256 const EmptyTrie = sha3(rlp(""));
}
BlockInfo::BlockInfo(): m_timestamp(Invalid256)
{
}
BlockInfo::BlockInfo(bytesConstRef _block, Strictness _s, h256 const& _hashWith, BlockDataType _bdt)
{
RLP header = _bdt == BlockData ? extractHeader(_block) : RLP(_block);
m_hash = _hashWith ? _hashWith : sha3(header.data());
populateFromHeader(header, _s);
}
void BlockInfo::clear()
BlockHeader::BlockHeader(bytesConstRef _block)
{
m_parentHash = h256();
m_sha3Uncles = EmptyListSHA3;
m_coinbaseAddress = Address();
m_stateRoot = EmptyTrie;
m_transactionsRoot = EmptyTrie;
m_receiptsRoot = EmptyTrie;
m_logBloom = LogBloom();
m_difficulty = 0;
m_number = 0;
m_gasLimit = 0;
m_gasUsed = 0;
m_timestamp = 0;
m_extraData.clear();
noteDirty();
RLP header = extractHeader(_block);
populateFromHeader(header);
}
h256 const& BlockInfo::boundary() const
h256 const& BlockHeader::boundary() const
{
if (!m_boundary && m_difficulty)
m_boundary = (h256)(u256)((bigint(1) << 256) / m_difficulty);
return m_boundary;
}
h256 const& BlockInfo::hashWithout() const
h256 const& BlockHeader::hashWithout() const
{
if (!m_hashWithout)
{
@ -82,13 +54,13 @@ h256 const& BlockInfo::hashWithout() const
return m_hashWithout;
}
void BlockInfo::streamRLPFields(RLPStream& _s) const
void BlockHeader::streamRLPFields(RLPStream& _s) const
{
_s << m_parentHash << m_sha3Uncles << m_coinbaseAddress << m_stateRoot << m_transactionsRoot << m_receiptsRoot << m_logBloom
<< m_difficulty << m_number << m_gasLimit << m_gasUsed << m_timestamp << m_extraData;
}
RLP BlockInfo::extractHeader(bytesConstRef _block)
RLP BlockHeader::extractHeader(bytesConstRef _block)
{
RLP root(_block);
if (!root.isList())
@ -103,7 +75,7 @@ RLP BlockInfo::extractHeader(bytesConstRef _block)
return header;
}
void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s)
void BlockHeader::populateFromHeader(RLP const& _header)
{
int field = 0;
try
@ -131,6 +103,6 @@ void BlockInfo::populateFromHeader(RLP const& _header, Strictness _s)
if (m_number > ~(unsigned)0)
BOOST_THROW_EXCEPTION(InvalidNumber());
if (_s != CheckNothing && m_gasUsed > m_gasLimit)
if (m_gasUsed > m_gasLimit)
BOOST_THROW_EXCEPTION(TooMuchGasUsed() << RequirementError(bigint(m_gasLimit), bigint(m_gasUsed)));
}

121
libethcore/BlockHeader.h

@ -0,0 +1,121 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum 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, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file BlockInfo.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcore/SHA3.h>
#include "Exceptions.h"
namespace dev
{
namespace eth
{
/// An Ethereum address: 20 bytes.
using Address = h160;
/// The log bloom's size (2048-bit).
using LogBloom = h2048;
using Nonce = h64;
using BlockNumber = unsigned;
/** @brief Encapsulation of a block header.
* Class to contain all of a block header's data. It is able to parse a block header and populate
* from some given RLP block serialisation with the static fromHeader(), through the method
* populateFromHeader(). This will conduct a minimal level of verification. In this case extra
* verification can be performed through verifyInternals() and verifyParent().
*
* The object may also be populated from an entire block through the explicit
* constructor BlockInfo(bytesConstRef) and manually with the populate() method. These will
* conduct verification of the header against the other information in the block.
*
* The object may be populated with a template given a parent BlockInfo object with the
* populateFromParent() method. The genesis block info may be retrieved with genesis() and the
* corresponding RLP block created with createGenesisBlock().
*
* The difficulty and gas-limit derivations may be calculated with the calculateDifficulty()
* and calculateGasLimit() and the object serialised to RLP with streamRLP. To determine the
* header hash without the nonce (for mining), the method headerHash(WithoutNonce) is provided.
*
* The default constructor creates an empty object, which can be tested against with the boolean
* conversion operator.
*/
class BlockHeader
{
public:
static const unsigned BasicFields = 13;
BlockHeader() = default;
explicit BlockHeader(bytesConstRef _data);
explicit BlockHeader(bytes const& _data): BlockHeader(&_data) {}
static RLP extractHeader(bytesConstRef _block);
explicit operator bool() const { return m_timestamp != Invalid256; }
h256 const& boundary() const;
void setNumber(u256 const& _v) { m_number = _v; noteDirty(); }
void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); }
u256 const& number() const { return m_number; }
/// sha3 of the header only.
h256 const& hashWithout() const;
void noteDirty() const { m_hashWithout = m_boundary = h256(); }
h256 const& seedHash() const;
Nonce const& nonce() const { return m_nonce; }
private:
void populateFromHeader(RLP const& _header);
void streamRLPFields(RLPStream& _s) const;
h256 m_parentHash;
h256 m_sha3Uncles;
Address m_coinbaseAddress;
h256 m_stateRoot;
h256 m_transactionsRoot;
h256 m_receiptsRoot;
LogBloom m_logBloom;
u256 m_number;
u256 m_gasLimit;
u256 m_gasUsed;
u256 m_timestamp = Invalid256;
bytes m_extraData;
u256 m_difficulty;
mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised.
mutable h256 m_boundary; ///< 2^256 / difficulty
Nonce m_nonce;
mutable h256 m_seedHash;
};
}
}

225
libethcore/BlockInfo.h

@ -1,225 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum 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, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file BlockInfo.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <libdevcore/Common.h>
#include <libdevcore/RLP.h>
#include <libdevcore/SHA3.h>
#include "Common.h"
#include "Exceptions.h"
namespace dev
{
namespace eth
{
enum IncludeProof
{
WithoutProof = 0,
WithProof = 1
};
enum Strictness
{
CheckEverything,
JustSeal,
QuickNonce,
IgnoreSeal,
CheckNothing
};
enum BlockDataType
{
HeaderData,
BlockData
};
DEV_SIMPLE_EXCEPTION(NoHashRecorded);
DEV_SIMPLE_EXCEPTION(GenesisBlockCannotBeCalculated);
/** @brief Encapsulation of a block header.
* Class to contain all of a block header's data. It is able to parse a block header and populate
* from some given RLP block serialisation with the static fromHeader(), through the method
* populateFromHeader(). This will conduct a minimal level of verification. In this case extra
* verification can be performed through verifyInternals() and verifyParent().
*
* The object may also be populated from an entire block through the explicit
* constructor BlockInfo(bytesConstRef) and manually with the populate() method. These will
* conduct verification of the header against the other information in the block.
*
* The object may be populated with a template given a parent BlockInfo object with the
* populateFromParent() method. The genesis block info may be retrieved with genesis() and the
* corresponding RLP block created with createGenesisBlock().
*
* The difficulty and gas-limit derivations may be calculated with the calculateDifficulty()
* and calculateGasLimit() and the object serialised to RLP with streamRLP. To determine the
* header hash without the nonce (for mining), the method headerHash(WithoutNonce) is provided.
*
* The default constructor creates an empty object, which can be tested against with the boolean
* conversion operator.
*/
class BlockInfo
{
public:
static const unsigned BasicFields = 13;
BlockInfo();
explicit BlockInfo(bytesConstRef _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData);
explicit BlockInfo(bytes const& _data, Strictness _s = CheckEverything, h256 const& _hashWith = h256(), BlockDataType _bdt = BlockData): BlockInfo(&_data, _s, _hashWith, _bdt) {}
static RLP extractHeader(bytesConstRef _block);
explicit operator bool() const { return m_timestamp != Invalid256; }
bool operator==(BlockInfo const& _cmp) const
{
return m_parentHash == _cmp.parentHash() &&
m_sha3Uncles == _cmp.sha3Uncles() &&
m_coinbaseAddress == _cmp.beneficiary() &&
m_stateRoot == _cmp.stateRoot() &&
m_transactionsRoot == _cmp.transactionsRoot() &&
m_receiptsRoot == _cmp.receiptsRoot() &&
m_logBloom == _cmp.logBloom() &&
m_difficulty == _cmp.difficulty() &&
m_number == _cmp.number() &&
m_gasLimit == _cmp.gasLimit() &&
m_gasUsed == _cmp.gasUsed() &&
m_timestamp == _cmp.timestamp() &&
m_extraData == _cmp.extraData();
}
bool operator!=(BlockInfo const& _cmp) const { return !operator==(_cmp); }
h256 const& boundary() const;
h256 const& parentHash() const { return m_parentHash; }
h256 const& sha3Uncles() const { return m_sha3Uncles; }
void setNumber(u256 const& _v) { m_number = _v; noteDirty(); }
void setDifficulty(u256 const& _v) { m_difficulty = _v; noteDirty(); }
Address const& beneficiary() const { return m_coinbaseAddress; }
h256 const& stateRoot() const { return m_stateRoot; }
h256 const& transactionsRoot() const { return m_transactionsRoot; }
h256 const& receiptsRoot() const { return m_receiptsRoot; }
LogBloom const& logBloom() const { return m_logBloom; }
u256 const& number() const { return m_number; }
u256 const& gasLimit() const { return m_gasLimit; }
u256 const& gasUsed() const { return m_gasUsed; }
u256 const& timestamp() const { return m_timestamp; }
bytes const& extraData() const { return m_extraData; }
u256 const& difficulty() const { return m_difficulty; } // TODO: pull out into BlockHeader
/// sha3 of the header only.
h256 const& hashWithout() const;
h256 const& hash() const { if (m_hash) return m_hash; BOOST_THROW_EXCEPTION(NoHashRecorded()); }
void clear();
void noteDirty() const { m_hashWithout = m_boundary = m_hash = h256(); }
protected:
void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal);
void streamRLPFields(RLPStream& _s) const;
mutable h256 m_hash; ///< SHA3 hash of the block header! Not serialised.
h256 m_parentHash;
h256 m_sha3Uncles;
Address m_coinbaseAddress;
h256 m_stateRoot;
h256 m_transactionsRoot;
h256 m_receiptsRoot;
LogBloom m_logBloom;
u256 m_number;
u256 m_gasLimit;
u256 m_gasUsed;
u256 m_timestamp = Invalid256;
bytes m_extraData;
u256 m_difficulty; // TODO: pull out into BlockHeader
private:
mutable h256 m_hashWithout; ///< SHA3 hash of the block header! Not serialised.
mutable h256 m_boundary; ///< 2^256 / difficulty
};
template <class BlockInfoSub>
class BlockHeaderPolished: public BlockInfoSub
{
public:
BlockHeaderPolished() {}
BlockHeaderPolished(BlockInfo const& _bi): BlockInfoSub(_bi) {}
explicit BlockHeaderPolished(bytes const& _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(&_data, _s, _h, _bdt); }
explicit BlockHeaderPolished(bytesConstRef _data, Strictness _s = IgnoreSeal, h256 const& _h = h256(), BlockDataType _bdt = BlockData) { populate(_data, _s, _h, _bdt); }
// deprecated for public API - use constructor.
// TODO: make private.
void populate(bytesConstRef _data, Strictness _s, h256 const& _h = h256(), BlockDataType _bdt = BlockData)
{
populateFromHeader(_bdt == BlockData ? BlockInfo::extractHeader(_data) : RLP(_data), _s, _h);
}
// deprecated for public API - use constructor.
// TODO: make private.
void populateFromHeader(RLP const& _header, Strictness _s = IgnoreSeal, h256 const& _h = h256())
{
BlockInfo::m_hash = _h;
if (_h)
assert(_h == dev::sha3(_header.data()));
else
BlockInfo::m_hash = dev::sha3(_header.data());
if (_header.itemCount() != BlockInfo::BasicFields + BlockInfoSub::SealFields)
BOOST_THROW_EXCEPTION(InvalidBlockHeaderItemCount());
BlockInfo::populateFromHeader(_header, _s);
BlockInfoSub::populateFromHeader(_header, _s);
}
void clear() { BlockInfo::clear(); BlockInfoSub::clear(); BlockInfoSub::noteDirty(); }
void noteDirty() const { BlockInfo::noteDirty(); BlockInfoSub::noteDirty(); }
h256 headerHash(IncludeProof _i = WithProof) const
{
RLPStream s;
streamRLP(s, _i);
return sha3(s.out());
}
h256 const& hash() const
{
if (!BlockInfo::m_hash)
BlockInfo::m_hash = headerHash(WithProof);
return BlockInfo::m_hash;
}
void streamRLP(RLPStream& _s, IncludeProof _i = WithProof) const
{
_s.appendList(BlockInfo::BasicFields + (_i == WithProof ? BlockInfoSub::SealFields : 0));
BlockInfo::streamRLPFields(_s);
if (_i == WithProof)
BlockInfoSub::streamRLPFields(_s);
}
};
}
}

14
libethcore/CMakeLists.txt

@ -1,18 +1,16 @@
file(GLOB SOURCES "*.cpp")
file(GLOB HEADERS "*.h")
include_directories(BEFORE ..)
if (ETHASHCUDA)
include_directories(${CUDA_INCLUDE_DIRS})
endif ()
include_directories(BEFORE ..)
add_library(ethcore ${SOURCES} ${HEADERS})
target_link_libraries(ethcore ethash devcore)
if (ETHASHCL)
if(ETHASHCL)
target_link_libraries(ethcore ethash-cl)
endif ()
if (ETHASHCUDA)
endif()
if(ETHASHCUDA)
target_include_directories(ethcore PRIVATE ${CUDA_INCLUDE_DIRS})
target_link_libraries(ethcore ethash-cuda)
endif ()
endif()

66
libethcore/Common.h

@ -1,66 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum 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, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Common.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Ethereum-specific data structures & algorithms.
*/
#pragma once
#include <string>
#include <functional>
#include <libdevcore/Common.h>
#include <libdevcore/Exceptions.h>
#include <libdevcore/FixedHash.h>
namespace dev
{
namespace eth
{
/// An Ethereum address: 20 bytes.
/// @NOTE This is not endian-specific; it's just a bunch of bytes.
using Address = h160;
DEV_SIMPLE_EXCEPTION(InvalidAddress);
/// The log bloom's size (2048-bit).
using LogBloom = h2048;
/// Many log blooms.
using LogBlooms = std::vector<LogBloom>;
using Nonce = h64;
using BlockNumber = unsigned;
// TODO: move back into a mining subsystem and have it be accessible from Sealant only via a dynamic_cast.
/**
* @brief Describes the progress of a mining operation.
*/
struct WorkingProgress
{
// MiningProgress& operator+=(MiningProgress const& _mp) { hashes += _mp.hashes; ms = std::max(ms, _mp.ms); return *this; }
uint64_t hashes = 0; ///< Total number of hashes computed.
uint64_t ms = 0; ///< Total number of milliseconds of mining thus far.
uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; }
};
}
}

38
libethcore/Ethash.cpp

@ -1,38 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum 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, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Ethash.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#include "Ethash.h"
#include "EthashAux.h"
namespace dev
{
namespace eth
{
h256 const& Ethash::BlockHeaderRaw::seedHash() const
{
if (!m_seedHash)
m_seedHash = EthashAux::seedHash((unsigned)m_number);
return m_seedHash;
}
}
}

78
libethcore/Ethash.h

@ -1,78 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum 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, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file Ethash.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* A proof of work algorithm.
*/
#pragma once
#include <chrono>
#include <thread>
#include <cstdint>
#include "Common.h"
#include "Miner.h"
#include "Farm.h"
class ethash_cl_miner;
class ethash_cuda_miner;
namespace dev
{
class RLP;
class RLPStream;
namespace eth
{
class BlockInfo;
class EthashCLHook;
class EthashCUDAHook;
class Ethash
{
public:
using Nonce = h64;
class BlockHeaderRaw: public BlockInfo
{
friend class EthashSealEngine;
public:
h256 const& seedHash() const;
Nonce const& nonce() const { return m_nonce; }
protected:
BlockHeaderRaw() = default;
BlockHeaderRaw(BlockInfo const& _bi): BlockInfo(_bi) {}
void clear() { m_mixHash = h256(); m_nonce = Nonce(); }
private:
Nonce m_nonce;
h256 m_mixHash;
mutable h256 m_seedHash;
};
using BlockHeader = BlockHeaderPolished<BlockHeaderRaw>;
};
}
}

151
libethcore/EthashAux.cpp

@ -20,48 +20,24 @@
*/
#include "EthashAux.h"
#include <boost/detail/endian.hpp>
#include <chrono>
#include <array>
#include <thread>
#include <libdevcore/Common.h>
#include <libdevcore/Guards.h>
#include <libdevcore/Log.h>
#include <libdevcore/SHA3.h>
#include <libethash/internal.h>
#include <libethash/io.h>
#include "BlockInfo.h"
#include "Exceptions.h"
using namespace std;
using namespace chrono;
using namespace dev;
using namespace eth;
const char* DAGChannel::name() { return EthGreen "DAG"; }
EthashAux* dev::eth::EthashAux::s_this = nullptr;
char dev::eth::EthashAux::s_dagDirName[256] = "";
const unsigned EthashProofOfWork::defaultLocalWorkSize = 64;
const unsigned EthashProofOfWork::defaultGlobalWorkSizeMultiplier = 4096; // * CL_DEFAULT_LOCAL_WORK_SIZE
const unsigned EthashProofOfWork::defaultMSPerBatch = 0;
const EthashProofOfWork::WorkPackage EthashProofOfWork::NullWorkPackage = EthashProofOfWork::WorkPackage();
EthashAux::~EthashAux()
h256 const& BlockHeader::seedHash() const
{
if (!m_seedHash)
m_seedHash = EthashAux::seedHash((unsigned)m_number);
return m_seedHash;
}
EthashAux* EthashAux::get()
{
static std::once_flag flag;
std::call_once(flag, []{s_this = new EthashAux();});
return s_this;
}
char * EthashAux::dagDirName()
{
return s_dagDirName;
static EthashAux instance;
return &instance;
}
h256 EthashAux::seedHash(unsigned _number)
@ -78,12 +54,8 @@ h256 EthashAux::seedHash(unsigned _number)
n = get()->m_seedHashes.size() - 1;
}
get()->m_seedHashes.resize(epoch + 1);
// cdebug << "Searching for seedHash of epoch " << epoch;
for (; n <= epoch; ++n, ret = sha3(ret))
{
get()->m_seedHashes[n] = ret;
// cdebug << "Epoch" << n << "is" << ret;
}
}
return get()->m_seedHashes[epoch];
}
@ -95,7 +67,6 @@ uint64_t EthashAux::number(h256 const& _seedHash)
auto epochIter = get()->m_epochs.find(_seedHash);
if (epochIter == get()->m_epochs.end())
{
// cdebug << "Searching for seedHash " << _seedHash;
for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {}
if (epoch == 2048)
{
@ -136,112 +107,22 @@ bytesConstRef EthashAux::LightAllocation::data() const
return bytesConstRef((byte const*)light->cache, size);
}
EthashAux::FullAllocation::FullAllocation(ethash_light_t _light, ethash_callback_t _cb)
{
// cdebug << "About to call ethash_full_new...";
full = ethash_full_new(_light, EthashAux::dagDirName(), _cb);
// cdebug << "Called OK.";
if (!full)
{
clog(DAGChannel) << "DAG Generation Failure. Reason: " << strerror(errno);
BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new"));
}
}
EthashAux::FullAllocation::~FullAllocation()
{
ethash_full_delete(full);
}
bytesConstRef EthashAux::FullAllocation::data() const
{
return bytesConstRef((byte const*)ethash_full_dag(full), size());
}
static std::function<int(unsigned)> s_dagCallback;
static int dagCallbackShim(unsigned _p)
{
clog(DAGChannel) << "Generating DAG file. Progress: " << toString(_p) << "%";
return s_dagCallback ? s_dagCallback(_p) : 0;
}
EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing, function<int(unsigned)> const& _f)
{
FullType ret;
auto l = light(_seedHash);
DEV_GUARDED(get()->x_fulls)
if ((ret = get()->m_fulls[_seedHash].lock()))
return ret;
if (_createIfMissing || computeFull(_seedHash, false) == 100)
{
s_dagCallback = _f;
ret = make_shared<FullAllocation>(l->light, dagCallbackShim);
DEV_GUARDED(get()->x_fulls)
get()->m_fulls[_seedHash] = ret;
}
return ret;
}
unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing)
{
Guard l(get()->x_fulls);
uint64_t blockNumber;
DEV_IF_THROWS(blockNumber = EthashAux::number(_seedHash))
{
return 0;
}
if (FullType ret = get()->m_fulls[_seedHash].lock())
{
return 100;
}
if (_createIfMissing && (!get()->m_fullGenerator || !get()->m_fullGenerator->joinable()))
{
get()->m_fullProgress = 0;
get()->m_generatingFullNumber = blockNumber / ETHASH_EPOCH_LENGTH * ETHASH_EPOCH_LENGTH;
get()->m_fullGenerator = unique_ptr<thread>(new thread([=](){
cnote << "Loading full DAG of seedhash: " << _seedHash;
get()->full(_seedHash, true, [](unsigned p){ get()->m_fullProgress = p; return 0; });
cnote << "Full DAG loaded";
get()->m_fullProgress = 0;
get()->m_generatingFullNumber = NotGenerating;
}));
}
return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0;
}
EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
{
ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
if (!r.success)
BOOST_THROW_EXCEPTION(DAGCreationFailure());
return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
}
EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
{
ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
if (!r.success)
BOOST_THROW_EXCEPTION(DAGCreationFailure());
return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
return Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
}
EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) noexcept
{
DEV_GUARDED(get()->x_fulls)
if (FullType dag = get()->m_fulls[_seedHash].lock())
return dag->compute(_headerHash, _nonce);
DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce))
try
{
return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce);
}
catch(...)
{
return EthashProofOfWork::Result{ ~h256(), h256() };
return Result{~h256(), h256()};
}
}

116
libethcore/EthashAux.h

@ -25,74 +25,47 @@
#include <libethash/ethash.h>
#include <libdevcore/Log.h>
#include <libdevcore/Worker.h>
#include "Ethash.h"
#include "BlockHeader.h"
namespace dev
{
namespace eth
{
struct DAGChannel: public LogChannel { static const char* name(); static const int verbosity = 1; };
/// Proof of work definition for Ethash.
struct EthashProofOfWork
struct Solution
{
struct Solution
{
Nonce nonce;
h256 mixHash;
};
struct Result
{
h256 value;
h256 mixHash;
};
struct WorkPackage
{
WorkPackage() = default;
WorkPackage(Ethash::BlockHeader const& _bh) :
boundary(_bh.boundary()),
headerHash(_bh.hashWithout()),
seedHash(_bh.seedHash())
{ }
void reset() { headerHash = h256(); }
operator bool() const { return headerHash != h256(); }
h256 boundary;
h256 headerHash; ///< When h256() means "pause until notified a new work package is available".
h256 seedHash;
uint64_t startNonce = 0;
int exSizeBits = -1;
};
static const WorkPackage NullWorkPackage;
/// Default value of the local work size. Also known as workgroup size.
static const unsigned defaultLocalWorkSize;
/// Default value of the global work size as a multiplier of the local work size
static const unsigned defaultGlobalWorkSizeMultiplier;
/// Default value of the milliseconds per global work size (per batch)
static const unsigned defaultMSPerBatch;
Nonce nonce;
h256 mixHash;
};
struct Result
{
h256 value;
h256 mixHash;
};
enum class DAGEraseMode
struct WorkPackage
{
None,
Old,
Bench,
All
WorkPackage() = default;
WorkPackage(BlockHeader const& _bh) :
boundary(_bh.boundary()),
headerHash(_bh.hashWithout()),
seedHash(_bh.seedHash())
{ }
void reset() { headerHash = h256(); }
operator bool() const { return headerHash != h256(); }
h256 boundary;
h256 headerHash; ///< When h256() means "pause until notified a new work package is available".
h256 seedHash;
uint64_t startNonce = 0;
int exSizeBits = -1;
};
class EthashAux
{
public:
~EthashAux();
static EthashAux* get();
struct LightAllocation
@ -100,56 +73,25 @@ public:
LightAllocation(h256 const& _seedHash);
~LightAllocation();
bytesConstRef data() const;
EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
ethash_light_t light;
uint64_t size;
};
struct FullAllocation
{
FullAllocation(ethash_light_t _light, ethash_callback_t _cb);
~FullAllocation();
EthashProofOfWork::Result compute(h256 const& _headerHash, Nonce const& _nonce) const;
bytesConstRef data() const;
uint64_t size() const { return ethash_full_dag_size(full); }
ethash_full_t full;
};
using LightType = std::shared_ptr<LightAllocation>;
using FullType = std::shared_ptr<FullAllocation>;
static h256 seedHash(unsigned _number);
static uint64_t number(h256 const& _seedHash);
static char * dagDirName();
static LightType light(h256 const& _seedHash);
static const uint64_t NotGenerating = (uint64_t)-1;
/// Kicks off generation of DAG for @a _seedHash and @returns false or @returns true if ready.
static unsigned computeFull(h256 const& _seedHash, bool _createIfMissing = true);
/// Information on the generation progress.
static std::pair<uint64_t, unsigned> fullGeneratingProgress() { return std::make_pair(get()->m_generatingFullNumber, get()->m_fullProgress); }
/// Kicks off generation of DAG for @a _blocknumber and blocks until ready; @returns result or empty pointer if not existing and _createIfMissing is false.
static FullType full(h256 const& _seedHash, bool _createIfMissing = false, std::function<int(unsigned)> const& _f = std::function<int(unsigned)>());
static EthashProofOfWork::Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce);
static Result eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce) noexcept;
private:
EthashAux() {}
static EthashAux* s_this;
static char s_dagDirName[256];
EthashAux() = default;
Mutex x_lights;
std::unordered_map<h256, std::shared_ptr<LightAllocation>> m_lights;
Mutex x_fulls;
std::unordered_map<h256, std::weak_ptr<FullAllocation>> m_fulls;
std::unique_ptr<std::thread> m_fullGenerator;
uint64_t m_generatingFullNumber = NotGenerating;
unsigned m_fullProgress;
std::unordered_map<h256, LightType> m_lights;
Mutex x_epochs;
std::unordered_map<h256, unsigned> m_epochs;

4
libethcore/EthashCUDAMiner.cpp

@ -108,7 +108,7 @@ unsigned EthashCUDAMiner::s_numInstances = 0;
int EthashCUDAMiner::s_devices[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
EthashCUDAMiner::EthashCUDAMiner(ConstructionInfo const& _ci) :
GenericMiner<EthashProofOfWork>(_ci),
Miner(_ci),
Worker("cudaminer" + toString(index())),
m_hook( new EthashCUDAHook(this))
{
@ -124,7 +124,7 @@ EthashCUDAMiner::~EthashCUDAMiner()
bool EthashCUDAMiner::report(uint64_t _nonce)
{
Nonce n = (Nonce)(u64)_nonce;
EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
if (r.value < work().boundary)
return submitProof(Solution{ n, r.mixHash });
return false;

8
libethcore/EthashCUDAMiner.h

@ -28,11 +28,15 @@ along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
#include "EthashAux.h"
#include "Miner.h"
class ethash_cuda_miner;
namespace dev
{
namespace eth
{
class EthashCUDAMiner : public GenericMiner<EthashProofOfWork>, Worker
class EthashCUDAHook;
class EthashCUDAMiner : public Miner, Worker
{
friend class dev::eth::EthashCUDAHook;
@ -76,7 +80,7 @@ namespace eth
void workLoop() override;
bool report(uint64_t _nonce);
using GenericMiner<EthashProofOfWork>::accumulateHashes;
using Miner::accumulateHashes;
EthashCUDAHook* m_hook = nullptr;
ethash_cuda_miner* m_miner = nullptr;

22
libethcore/EthashGPUMiner.cpp

@ -27,6 +27,7 @@
#include <thread>
#include <chrono>
#include <libethash-cl/ethash_cl_miner.h>
using namespace std;
using namespace dev;
using namespace eth;
@ -106,7 +107,7 @@ unsigned EthashGPUMiner::s_numInstances = 0;
int EthashGPUMiner::s_devices[16] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
EthashGPUMiner::EthashGPUMiner(ConstructionInfo const& _ci):
GenericMiner<EthashProofOfWork>(_ci),
Miner(_ci),
Worker("openclminer" + toString(index())),
m_hook(new EthashCLHook(this))
{
@ -122,7 +123,7 @@ EthashGPUMiner::~EthashGPUMiner()
bool EthashGPUMiner::report(uint64_t _nonce)
{
Nonce n = (Nonce)(u64)_nonce;
EthashProofOfWork::Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
Result r = EthashAux::eval(work().seedHash, work().headerHash, n);
if (r.value < work().boundary)
return submitProof(Solution{n, r.mixHash});
return false;
@ -157,23 +158,6 @@ void EthashGPUMiner::workLoop()
unsigned device = s_devices[index()] > -1 ? s_devices[index()] : index();
/*
EthashAux::FullType dag;
while (true)
{
if ((dag = EthashAux::full(w.seedHash, true)))
break;
if (shouldStop())
{
delete m_miner;
m_miner = nullptr;
return;
}
cnote << "Awaiting DAG";
this_thread::sleep_for(chrono::milliseconds(500));
}
*/
EthashAux::LightType light;
light = EthashAux::light(w.seedHash);
bytesConstRef lightData = light->data();

9
libethcore/EthashGPUMiner.h

@ -24,16 +24,19 @@
#pragma once
#if ETH_ETHASHCL
#include "libdevcore/Worker.h"
#include <libdevcore/Worker.h>
#include "EthashAux.h"
#include "Miner.h"
class ethash_cl_miner;
namespace dev
{
namespace eth
{
class EthashCLHook;
class EthashGPUMiner: public GenericMiner<EthashProofOfWork>, Worker
class EthashGPUMiner: public Miner, Worker
{
friend class dev::eth::EthashCLHook;
@ -73,7 +76,7 @@ private:
void workLoop() override;
bool report(uint64_t _nonce);
using GenericMiner<EthashProofOfWork>::accumulateHashes;
using Miner::accumulateHashes;
EthashCLHook* m_hook = nullptr;
ethash_cl_miner* m_miner = nullptr;

54
libethcore/EthashSealEngine.cpp

@ -1,54 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum 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, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file EthashSealEngine.cpp
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#include "EthashSealEngine.h"
#include "EthashGPUMiner.h"
#include "EthashCUDAMiner.h"
using namespace std;
using namespace dev;
using namespace eth;
EthashSealEngine::EthashSealEngine()
{
map<string, GenericFarm<EthashProofOfWork>::SealerDescriptor> sealers;
#if ETH_ETHASHCL
sealers["opencl"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashGPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashGPUMiner(ci); }};
#endif
#if ETH_ETHASHCUDA
sealers["cuda"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{ &EthashCUDAMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashCUDAMiner(ci); } };
#endif
m_farm.setSealers(sealers);
}
strings EthashSealEngine::sealers() const
{
return {
"cpu"
#if ETH_ETHASHCL
, "opencl"
#endif
#if ETH_ETHASHCUDA
, "cuda"
#endif
};
}

48
libethcore/EthashSealEngine.h

@ -1,48 +0,0 @@
/*
This file is part of cpp-ethereum.
cpp-ethereum 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, either version 3 of the License, or
(at your option) any later version.
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file EthashSealEngine.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*
* Determines the PoW algorithm.
*/
#pragma once
#include "Ethash.h"
#include "EthashAux.h"
namespace dev
{
namespace eth
{
class EthashSealEngine
{
friend class Ethash;
public:
EthashSealEngine();
strings sealers() const;
private:
eth::GenericFarm<EthashProofOfWork> m_farm;
};
}
}

1
libethcore/Exceptions.h

@ -22,7 +22,6 @@
#pragma once
#include <libdevcore/Exceptions.h>
#include "Common.h"
namespace dev
{

14
libethcore/Farm.h

@ -26,9 +26,8 @@
#include <atomic>
#include <libdevcore/Common.h>
#include <libdevcore/Worker.h>
#include <libethcore/Common.h>
#include <libethcore/Miner.h>
#include <libethcore/BlockInfo.h>
#include <libethcore/BlockHeader.h>
namespace dev
{
@ -41,21 +40,16 @@ namespace eth
* Miners ask for work, then submit proofs
* @threadsafe
*/
template <class PoW>
class GenericFarm: public GenericFarmFace<PoW>
class Farm: public FarmFace
{
public:
using WorkPackage = typename PoW::WorkPackage;
using Solution = typename PoW::Solution;
using Miner = GenericMiner<PoW>;
struct SealerDescriptor
{
std::function<unsigned()> instances;
std::function<Miner*(typename Miner::ConstructionInfo ci)> create;
std::function<Miner*(Miner::ConstructionInfo ci)> create;
};
~GenericFarm()
~Farm()
{
stop();
}

12
libethcore/Miner.cpp

@ -4,16 +4,12 @@
using namespace dev;
using namespace eth;
template <>
unsigned dev::eth::GenericMiner<dev::eth::EthashProofOfWork>::s_dagLoadMode = 0;
unsigned dev::eth::Miner::s_dagLoadMode = 0;
template <>
volatile unsigned dev::eth::GenericMiner<dev::eth::EthashProofOfWork>::s_dagLoadIndex = 0;
volatile unsigned dev::eth::Miner::s_dagLoadIndex = 0;
template <>
unsigned dev::eth::GenericMiner<dev::eth::EthashProofOfWork>::s_dagCreateDevice = 0;
unsigned dev::eth::Miner::s_dagCreateDevice = 0;
template <>
volatile void* dev::eth::GenericMiner<dev::eth::EthashProofOfWork>::s_dagInHostMemory = NULL;
volatile void* dev::eth::Miner::s_dagInHostMemory = NULL;

30
libethcore/Miner.h

@ -29,7 +29,7 @@
#include <libdevcore/Common.h>
#include <libdevcore/Log.h>
#include <libdevcore/Worker.h>
#include <libethcore/Common.h>
#include "EthashAux.h"
#define MINER_WAIT_STATE_UNKNOWN 0
#define MINER_WAIT_STATE_WORK 1
@ -67,7 +67,13 @@ enum class MinerType
Mixed
};
struct MineInfo: public WorkingProgress {};
/// Describes the progress of a mining operation.
struct WorkingProgress
{
uint64_t hashes = 0; ///< Total number of hashes computed.
uint64_t ms = 0; ///< Total number of milliseconds of mining thus far.
uint64_t rate() const { return ms == 0 ? 0 : hashes * 1000 / ms; }
};
inline std::ostream& operator<<(std::ostream& _out, WorkingProgress _p)
{
@ -109,7 +115,7 @@ inline std::ostream& operator<<(std::ostream& os, SolutionStats s)
return os << "[A" << s.getAccepts() << "+" << s.getAcceptedStales() << ":R" << s.getRejects() << "+" << s.getRejectedStales() << ":F" << s.getFailures() << "]";
}
template <class PoW> class GenericMiner;
class Miner;
/**
@ -117,19 +123,14 @@ template <class PoW> class GenericMiner;
* @warning Must be implemented in a threadsafe manner since it will be called from multiple
* miner threads.
*/
template <class PoW> class GenericFarmFace
class FarmFace
{
public:
using WorkPackage = typename PoW::WorkPackage;
using Solution = typename PoW::Solution;
using Miner = GenericMiner<PoW>;
virtual ~GenericFarmFace() {}
virtual ~FarmFace() = default;
/**
* @brief Called from a Miner to note a WorkPackage has a solution.
* @param _p The solution.
* @param _wp The WorkPackage that the Solution is for; this will be reset if the work is accepted.
* @param _finder The miner that found it.
* @return true iff the solution was good (implying that mining should be .
*/
@ -140,19 +141,16 @@ public:
* @brief A miner - a member and adoptee of the Farm.
* @warning Not threadsafe. It is assumed Farm will synchronise calls to/from this class.
*/
template <class PoW> class GenericMiner
class Miner
{
public:
using WorkPackage = typename PoW::WorkPackage;
using Solution = typename PoW::Solution;
using FarmFace = GenericFarmFace<PoW>;
using ConstructionInfo = std::pair<FarmFace*, unsigned>;
GenericMiner(ConstructionInfo const& _ci):
Miner(ConstructionInfo const& _ci):
m_farm(_ci.first),
m_index(_ci.second)
{}
virtual ~GenericMiner() {}
virtual ~Miner() {}
// API FOR THE FARM TO CALL IN WITH

21
libstratum/EthStratumClient.cpp

@ -27,7 +27,7 @@ static void diffToTarget(uint32_t *target, double diff)
}
EthStratumClient::EthStratumClient(GenericFarm<EthashProofOfWork> * f, MinerType m, string const & host, string const & port, string const & user, string const & pass, int const & retries, int const & worktimeout, int const & protocol, string const & email)
EthStratumClient::EthStratumClient(Farm* f, MinerType m, string const & host, string const & port, string const & user, string const & pass, int const & retries, int const & worktimeout, int const & protocol, string const & email)
: m_socket(m_io_service)
{
m_minerType = m;
@ -82,7 +82,16 @@ void EthStratumClient::connect()
cnote << "Connecting to stratum server " << p_active->host + ":" + p_active->port;
m_serviceThread = std::thread{boost::bind(&boost::asio::io_service::run, &m_io_service)};
if (m_serviceThread.joinable())
{
// If the service thread have been created try to reset the service.
m_io_service.reset();
}
else
{
// Otherwise, if the first time here, create new thread.
m_serviceThread = std::thread{boost::bind(&boost::asio::io_service::run, &m_io_service)};
}
}
#define BOOST_ASIO_ENABLE_CANCELIO
@ -121,7 +130,7 @@ void EthStratumClient::reconnect()
}
cnote << "Reconnecting in 3 seconds...";
boost::asio::deadline_timer timer(m_io_service, boost::posix_time::seconds(3));
boost::asio::deadline_timer timer(m_io_service, boost::posix_time::seconds(3));
timer.wait();
connect();
@ -495,11 +504,11 @@ void EthStratumClient::work_timeout_handler(const boost::system::error_code& ec)
}
}
bool EthStratumClient::submit(EthashProofOfWork::Solution solution) {
bool EthStratumClient::submit(Solution solution) {
x_current.lock();
EthashProofOfWork::WorkPackage tempWork(m_current);
WorkPackage tempWork(m_current);
string temp_job = m_job;
EthashProofOfWork::WorkPackage tempPreviousWork(m_previous);
WorkPackage tempPreviousWork(m_previous);
string temp_previous_job = m_previousJob;
x_current.unlock();

10
libstratum/EthStratumClient.h

@ -21,7 +21,7 @@ using namespace dev::eth;
class EthStratumClient
{
public:
EthStratumClient(GenericFarm<EthashProofOfWork> * f, MinerType m, string const & host, string const & port, string const & user, string const & pass, int const & retries, int const & worktimeout, int const & protocol, string const & email);
EthStratumClient(Farm* f, MinerType m, string const & host, string const & port, string const & user, string const & pass, int const & retries, int const & worktimeout, int const & protocol, string const & email);
~EthStratumClient();
void setFailover(string const & host, string const & port);
@ -32,7 +32,7 @@ public:
h256 currentHeaderHash() { return m_current.headerHash; }
bool current() { return m_current; }
unsigned waitState() { return m_waitState; }
bool submit(EthashProofOfWork::Solution solution);
bool submit(Solution solution);
void reconnect();
private:
void connect();
@ -68,10 +68,10 @@ private:
std::mutex x_pending;
int m_pending;
GenericFarm<EthashProofOfWork> * p_farm;
Farm* p_farm;
std::mutex x_current;
EthashProofOfWork::WorkPackage m_current;
EthashProofOfWork::WorkPackage m_previous;
WorkPackage m_current;
WorkPackage m_previous;
bool m_stale = false;

8
libstratum/EthStratumClientV2.cpp

@ -27,7 +27,7 @@ static void diffToTarget(uint32_t *target, double diff)
}
EthStratumClientV2::EthStratumClientV2(GenericFarm<EthashProofOfWork> * f, MinerType m, string const & host, string const & port, string const & user, string const & pass, int const & retries, int const & worktimeout, int const & protocol, string const & email)
EthStratumClientV2::EthStratumClientV2(Farm* f, MinerType m, string const & host, string const & port, string const & user, string const & pass, int const & retries, int const & worktimeout, int const & protocol, string const & email)
: Worker("stratum"),
m_socket(m_io_service)
{
@ -446,11 +446,11 @@ void EthStratumClientV2::work_timeout_handler(const boost::system::error_code& e
}
}
bool EthStratumClientV2::submit(EthashProofOfWork::Solution solution) {
bool EthStratumClientV2::submit(Solution solution) {
x_current.lock();
EthashProofOfWork::WorkPackage tempWork(m_current);
WorkPackage tempWork(m_current);
string temp_job = m_job;
EthashProofOfWork::WorkPackage tempPreviousWork(m_previous);
WorkPackage tempPreviousWork(m_previous);
string temp_previous_job = m_previousJob;
x_current.unlock();

11
libstratum/EthStratumClientV2.h

@ -22,7 +22,7 @@ using namespace dev::eth;
class EthStratumClientV2 : public Worker
{
public:
EthStratumClientV2(GenericFarm<EthashProofOfWork> * f, MinerType m, string const & host, string const & port, string const & user, string const & pass, int const & retries, int const & worktimeout, int const & protocol, string const & email);
EthStratumClientV2(Farm* f, MinerType m, string const & host, string const & port, string const & user, string const & pass, int const & retries, int const & worktimeout, int const & protocol, string const & email);
~EthStratumClientV2();
void setFailover(string const & host, string const & port);
@ -33,7 +33,7 @@ public:
h256 currentHeaderHash() { return m_current.headerHash; }
bool current() { return m_current; }
unsigned waitState() { return m_waitState; }
bool submit(EthashProofOfWork::Solution solution);
bool submit(Solution solution);
void reconnect();
private:
void workLoop() override;
@ -64,16 +64,15 @@ private:
string m_response;
GenericFarm<EthashProofOfWork> * p_farm;
Farm* p_farm;
mutex x_current;
EthashProofOfWork::WorkPackage m_current;
EthashProofOfWork::WorkPackage m_previous;
WorkPackage m_current;
WorkPackage m_previous;
bool m_stale = false;
string m_job;
string m_previousJob;
EthashAux::FullType m_dag;
boost::asio::io_service m_io_service;
tcp::socket m_socket;

2
scripts/install-cuda-trusty.sh

@ -14,7 +14,7 @@ travis_retry sudo dpkg -i cuda-repo-ubuntu1404_${CUDA_VER}_amd64.deb
travis_retry sudo apt-get update -qq
export CUDA_APT=${CUDA_VER:0:3}
export CUDA_APT=${CUDA_APT/./-}
travis_retry sudo apt-get install -qy cuda-drivers cuda-core-${CUDA_APT} cuda-cudart-dev-${CUDA_APT}
travis_retry sudo apt-get install -qy cuda-core-${CUDA_APT} cuda-cudart-dev-${CUDA_APT}
travis_retry sudo apt-get clean
export CUDA_HOME=/usr/local/cuda-${CUDA_VER:0:3}
export PATH=${CUDA_HOME}/bin:${PATH}

Loading…
Cancel
Save