Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 23 additions & 16 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,28 @@
# redeclaration bug (map.go vs linkname_swiss.go conflict).
export GOEXPERIMENT=noswissmap

BUILD_DIR := build
TEST_BIN := $(BUILD_DIR)/test/c/Test
BENCH_LIGHT := $(BUILD_DIR)/src/benchmark/Benchmark_LIGHT
BENCH_FULL := $(BUILD_DIR)/src/benchmark/Benchmark_FULL
BUILD_DIR := build
BENCH_DIR := $(BUILD_DIR)/src/benchmark

BUILD_INPUTS := $(shell find src test/c cmake -type f \( \
-name '*.c' -o -name '*.h' -o -name '*.cpp' -o \
-name '*.cmake' -o -name 'CMakeLists.txt' \))
BUILD_INPUTS += $(wildcard *.go) go.mod go.sum CMakeLists.txt Makefile build.sh \
setup.py test/python/requirements.txt

# ---------------------------------------------------------------------------
# Build targets
# ---------------------------------------------------------------------------

# Stamp file: touched by build.sh on success to track freshness.
$(BUILD_DIR)/.built: $(shell find src -name '*.c' -o -name '*.h' -o -name '*.cpp') \
ethash.go ethashc.go compat.go go.mod CMakeLists.txt
$(BUILD_DIR)/.built: $(BUILD_INPUTS)
./build.sh
@touch $(BUILD_DIR)/.built

build: $(BUILD_DIR)/.built
@test -n "$$(find $(BUILD_DIR)/test/c -type f \( -name Test -o -name Test.exe \) -print 2>/dev/null | head -n 1)" || { echo "Required C test binary is missing under $(BUILD_DIR)/test/c" >&2; exit 1; }

$(BENCH_LIGHT) $(BENCH_FULL): $(BUILD_DIR)/.built
cd $(BUILD_DIR) && make Benchmark_LIGHT Benchmark_FULL

build-bench: $(BENCH_LIGHT) $(BENCH_FULL)
build-bench: $(BUILD_DIR)/.built
cmake --build $(BUILD_DIR) --config Release --target Benchmark_LIGHT Benchmark_FULL

# ---------------------------------------------------------------------------
# Test targets (each depends only on the build it actually needs)
Expand All @@ -46,11 +47,17 @@ test-all: $(BUILD_DIR)/.built
# Benchmark targets
# ---------------------------------------------------------------------------

bench-light: $(BENCH_LIGHT)
cd $(BUILD_DIR) && ./src/benchmark/Benchmark_LIGHT

bench-full: $(BENCH_FULL)
cd $(BUILD_DIR) && ./src/benchmark/Benchmark_FULL
bench-light: build-bench
@BENCH_BIN="$$(find "$(abspath $(BENCH_DIR))" -type f \( -name Benchmark_LIGHT -o -name Benchmark_LIGHT.exe \) -path '*/Release/*' -print -quit)"; \
[ -n "$$BENCH_BIN" ] || BENCH_BIN="$$(find "$(abspath $(BENCH_DIR))" -type f \( -name Benchmark_LIGHT -o -name Benchmark_LIGHT.exe \) -print -quit)"; \
[ -n "$$BENCH_BIN" ] || { echo "Benchmark_LIGHT is missing under $(BENCH_DIR)" >&2; exit 1; }; \
cd $(BUILD_DIR) && "$$BENCH_BIN"

bench-full: build-bench
@BENCH_BIN="$$(find "$(abspath $(BENCH_DIR))" -type f \( -name Benchmark_FULL -o -name Benchmark_FULL.exe \) -path '*/Release/*' -print -quit)"; \
[ -n "$$BENCH_BIN" ] || BENCH_BIN="$$(find "$(abspath $(BENCH_DIR))" -type f \( -name Benchmark_FULL -o -name Benchmark_FULL.exe \) -print -quit)"; \
[ -n "$$BENCH_BIN" ] || { echo "Benchmark_FULL is missing under $(BENCH_DIR)" >&2; exit 1; }; \
cd $(BUILD_DIR) && "$$BENCH_BIN"

bench: bench-light bench-full

Expand Down
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,39 @@
For details on this project, please see the Ethereum wiki:
https://github.com/ethereum/wiki/wiki/Ethash

## Building

The C test suite requires CMake, a C/C++ compiler, and the Boost filesystem,
system, and unit test framework components. Missing components cause the build
to fail during CMake configuration rather than silently skipping the tests.

On Ubuntu/Debian:

```sh
sudo apt update
sudo apt install -y cmake build-essential libboost-test-dev \
libboost-filesystem-dev libboost-system-dev python3-venv python3-dev
```

On macOS with Homebrew:

```sh
brew install cmake boost python@3.13
```

If using a versioned, keg-only Boost formula, expose its prefix to CMake:

```sh
export BOOST_ROOT="$(brew --prefix boost@1.85)"
```

Then build and run all tests:

```sh
make rebuild
make test-all
```

### Coding Style for C++ code:

Follow the same exact style as in [cpp-ethereum](https://github.com/ethereum/cpp-ethereum/blob/develop/CodingStandards.txt)
Expand Down
18 changes: 14 additions & 4 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ fi
# C/C++ build (cmake → libethash.a + Test binary + Python extension)
# ---------------------------------------------------------------------------
mkdir -p "$BUILD_DIR"
# Never leave a stale success marker after a failed rebuild.
rm -f "$BUILD_DIR/.built"
cd "$BUILD_DIR"

cmake "$REPO_ROOT" -DCMAKE_BUILD_TYPE=Release > /dev/null 2>&1 || {
Expand All @@ -44,13 +46,22 @@ if grep -q "microsoft\|WSL" /proc/version 2>/dev/null; then
touch "$REPO_ROOT/src/python/core.c"
fi

make
# Test is a required build artifact. Build it explicitly so a missing CMake
# target fails this script before the success stamp is written. Use CMake's
# build command so this also works with Ninja and non-Makefile generators.
cmake --build "$BUILD_DIR" --config Release --target Test

TEST_BIN="$(find "$BUILD_DIR/test/c" -type f \( -name Test -o -name Test.exe \) -print 2>/dev/null | head -n 1 || true)"
if [[ -z "$TEST_BIN" ]]; then
echo "[build/c] Required C test binary was not generated under $BUILD_DIR/test/c" >&2
exit 1
fi
echo "[build/c] Done — binaries in $BUILD_DIR"

# Build benchmark binaries if --bench flag is passed
if [[ "$DO_BENCH" -eq 1 ]]; then
echo "[build/bench] Building benchmark binaries..."
make Benchmark_LIGHT Benchmark_FULL
cmake --build "$BUILD_DIR" --config Release --target Benchmark_LIGHT Benchmark_FULL
echo "[build/bench] Done — binaries in $BUILD_DIR/src/benchmark/"
fi

Expand All @@ -74,8 +85,6 @@ else
echo "[build/go] vet passed"
fi

touch "$BUILD_DIR/.built"

# ---------------------------------------------------------------------------
# Python extension build (compiles src/python/core.c via pip editable install)
# ---------------------------------------------------------------------------
Expand All @@ -93,4 +102,5 @@ pip install -e "$REPO_ROOT" -q --no-build-isolation
deactivate
echo "[build/python] Done"

touch "$BUILD_DIR/.built"
echo "[build] All done"
90 changes: 42 additions & 48 deletions test/c/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,54 +1,48 @@
if (MSVC)
if (NOT BOOST_ROOT)
set (BOOST_ROOT "$ENV{BOOST_ROOT}")
endif()
set (CMAKE_PREFIX_PATH BOOST_ROOT)
if (NOT BOOST_ROOT AND DEFINED ENV{BOOST_ROOT})
set(BOOST_ROOT "$ENV{BOOST_ROOT}")
endif()
if (BOOST_ROOT)
set(CMAKE_PREFIX_PATH "${BOOST_ROOT};${CMAKE_PREFIX_PATH}")
endif()

IF( NOT Boost_FOUND )
# use multithreaded boost libraries, with -mt suffix
set(Boost_USE_MULTITHREADED ON)

if (MSVC)
# TODO handle other msvc versions or it will fail find them
set(Boost_COMPILER -vc120)
# use static boost libraries *.lib
set(Boost_USE_STATIC_LIBS ON)
elseif (APPLE)

# use static boost libraries *.a
set(Boost_USE_STATIC_LIBS ON)

elseif (UNIX)
# use dynamic boost libraries .dll
set(Boost_USE_STATIC_LIBS OFF)

endif()
find_package(Boost 1.48.0 COMPONENTS unit_test_framework system filesystem)
ENDIF()

IF (Boost_FOUND)
message(STATUS "boost header: ${Boost_INCLUDE_DIRS}")
message(STATUS "boost libs : ${Boost_LIBRARIES}")
# The C test suite is required by the build, so fail during configuration when
# any of its Boost components are unavailable instead of omitting Test.
# use multithreaded boost libraries, with -mt suffix
set(Boost_USE_MULTITHREADED ON)

include_directories( ${Boost_INCLUDE_DIR} )
include_directories(../../src)
if (MSVC)
# use static boost libraries *.lib
set(Boost_USE_STATIC_LIBS ON)
elseif (APPLE)
# use static boost libraries *.a
set(Boost_USE_STATIC_LIBS ON)
elseif (UNIX)
# use dynamic boost libraries .dll

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dll is used for Windows only.

set(Boost_USE_STATIC_LIBS OFF)
endif()

link_directories(${Boost_LIBRARY_DIRS})
file(GLOB HEADERS "*.h")
if ((NOT MSVC) AND (NOT APPLE))
ADD_DEFINITIONS(-DBOOST_TEST_DYN_LINK)
endif()
if (NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ")
endif()
# Prefer the package configuration shipped by modern Boost distributions (for
# example Homebrew on macOS), then fall back to CMake's legacy FindBoost module
# for system packages that do not ship BoostConfig.cmake.
find_package(Boost 1.48.0 CONFIG QUIET COMPONENTS unit_test_framework system filesystem)
if (NOT Boost_FOUND)
find_package(Boost 1.48.0 MODULE REQUIRED COMPONENTS unit_test_framework system filesystem)
endif()

add_executable (Test "./test.cpp" ${HEADERS})
target_link_libraries(Test ${ETHHASH_LIBS})
target_link_libraries(Test ${Boost_FILESYSTEM_LIBRARIES})
target_link_libraries(Test ${Boost_SYSTEM_LIBRARIES})
target_link_libraries(Test ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
file(GLOB HEADERS "*.h")

enable_testing ()
add_test(NAME ethash COMMAND Test)
ENDIF()
add_executable(Test "./test.cpp" ${HEADERS})
target_compile_features(Test PRIVATE cxx_std_11)
target_include_directories(Test PRIVATE ../../src)
if ((NOT MSVC) AND (NOT APPLE))
target_compile_definitions(Test PRIVATE BOOST_TEST_DYN_LINK)
endif()
target_link_libraries(Test PRIVATE
${ETHHASH_LIBS}
Boost::filesystem
Boost::system
Boost::unit_test_framework
)

enable_testing()
add_test(NAME ethash COMMAND Test)
5 changes: 2 additions & 3 deletions test/c/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@
#include <boost/test/unit_test.hpp>

using namespace std;
using byte = uint8_t;
using bytes = std::vector<byte>;
using bytes = std::vector<uint8_t>;
namespace fs = boost::filesystem;

// Just an alloca "wrapper" to silence uint64_t to size_t conversion warnings in windows
Expand Down Expand Up @@ -83,7 +82,7 @@ bytes hexStringToBytes(std::string const& _s)
for (unsigned i = s; i < _s.size(); i += 2)
try
{
ret.push_back((byte)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1])));
ret.push_back((uint8_t)(fromHex(_s[i]) * 16 + fromHex(_s[i + 1])));
}
catch (...){
ret.push_back(0);
Expand Down
9 changes: 9 additions & 0 deletions test/c/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,15 @@ if [ ! -f "$BUILD_DIR/.built" ]; then
"$REPO_ROOT/build.sh"
fi

if [ ! -f "$TEST_BIN" ]; then
TEST_BIN="$(find "$BUILD_DIR/test/c" -type f \( -name Test -o -name Test.exe \) -print 2>/dev/null | head -n 1 || true)"
if [ -z "$TEST_BIN" ]; then
echo "[test/c] Required C test binary is missing under $BUILD_DIR/test/c" >&2
echo "[test/c] Run 'make rebuild' after installing the required Boost components." >&2
exit 1
fi
fi

echo "[test/c] Running $TEST_BIN"

# mmap(MAP_SHARED) on NTFS via WSL DrvFs (/mnt/d/...) does not properly flush
Expand Down
9 changes: 2 additions & 7 deletions test/python/test_pyethash.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,11 @@
- test_mining_* : mine() commented out
"""
import hashlib
import os
import pytest
import pyethash
from random import randint
from Crypto.Hash import keccak

EXPECTED_DIR = os.path.join(os.path.dirname(__file__), "expected")

def _keccak256(data: bytes) -> bytes:
return keccak.new(digest_bits=256, data=data).digest()

Expand Down Expand Up @@ -68,13 +65,13 @@ def test_mkcache_is_as_expected(cache_epoch0):
assert len(cache_epoch0) % pyethash.HASH_BYTES == 0

# Compare SHA-256 fingerprint against stored reference
expected = "396c1ff479b0a02b88bad57fe69a6a4f573b180cc4f108d0d7f431a7d3d666d9" # pre-computed for epoch-0
expected = "396c1ff479b0a02b88bad57fe69a6a4f573b180cc4f108d0d7f431a7d3d666d9"
actual = hashlib.sha256(cache_epoch0).hexdigest()
assert actual == expected, (
f"cache_epoch0 SHA-256 mismatch:\n got: {actual}\n expected: {expected}"
)

expected = "fda2c14d3a454243c6f58f74ec60ae854f7d286497757ad32449e42e2dcd0535" # pre-computed for epoch-1
expected = "fda2c14d3a454243c6f58f74ec60ae854f7d286497757ad32449e42e2dcd0535"
raw = pyethash.mkcache_bytes(pyethash.EPOCH_LENGTH)
actual = hashlib.sha256(raw).hexdigest()
assert actual == expected, (
Expand Down Expand Up @@ -137,5 +134,3 @@ def test_get_seedhash():
# Out-of-range block number must raise
with pytest.raises(ValueError):
pyethash.get_seedhash(pyethash.EPOCH_LENGTH * 2048)