Skip to content

Commit

Permalink
Add EvrProgpow Algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaolin1579 committed Aug 9, 2024
1 parent 1116634 commit 800ac45
Show file tree
Hide file tree
Showing 38 changed files with 3,476 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/Miningcore/Blockchain/Progpow/ProgpowConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

namespace Miningcore.Blockchain.Progpow;

public class EvrmoreConstants
{
public const int EpochLength = 12000;
public static BigInteger BigMaxValue = BigInteger.Pow(2, 256);
public static readonly BigInteger Diff1B = BigInteger.Parse("00000000ff000000000000000000000000000000000000000000000000000000", NumberStyles.AllowHexSpecifier, null);
public static readonly BigInteger Diff1 = BigInteger.Parse("00000000ff000000000000000000000000000000000000000000000000000000", NumberStyles.HexNumber);
public const int ExtranoncePlaceHolderLength = 2;
public static double Multiplier = (double) new BigRational(BigMaxValue, Diff1);
}

public class FiroConstants
{
public const int EpochLength = 1300;
Expand Down
96 changes: 96 additions & 0 deletions src/Miningcore/Crypto/Hashing/Progpow/Evrprogpow/Cache.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
using System.Diagnostics;
using Miningcore.Blockchain.Progpow;
using Miningcore.Contracts;
using Miningcore.Extensions;
using Miningcore.Messaging;
using Miningcore.Native;
using Miningcore.Notifications.Messages;
using NLog;

namespace Miningcore.Crypto.Hashing.Progpow.Evrprogpow;

[Identifier("evrprogpow")]
public class Cache : IProgpowCache
{
public Cache(int epoch)
{
Epoch = epoch;
LastUsed = DateTime.Now;
}

private IntPtr handle = IntPtr.Zero;
private bool isGenerated = false;
private readonly object genLock = new();
internal static IMessageBus messageBus;
public int Epoch { get; }
public byte[] SeedHash { get; set; }
public DateTime LastUsed { get; set; }

public void Dispose()
{
if(handle != IntPtr.Zero)
{
EvrProgpow.DestroyContext(handle);
handle = IntPtr.Zero;
}
}

public async Task GenerateAsync(ILogger logger)
{
await Task.Run(() =>
{
lock(genLock)
{
if(!isGenerated)
{

var started = DateTime.Now;
logger.Debug(() => $"Generating cache for epoch {Epoch}");

handle = EvrProgpow.CreateContext(Epoch);

logger.Debug(() => $"Done generating cache for epoch {Epoch} after {DateTime.Now - started}");
isGenerated = true;

// get the seed hash for this epoch
var res = EvrProgpow.calculate_epoch_seed(Epoch);
SeedHash = res.bytes;
logger.Info(() => $"Seed hash for epoch {Epoch} is {SeedHash.ToHexString()}");
}
}
});
}

public unsafe bool Compute(ILogger logger, int blockNumber, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result)
{
Contract.RequiresNonNull(hash);

var sw = Stopwatch.StartNew();

mixDigest = null;
result = null;

var value = new EvrProgpow.Ethash_result();

var inputHash = new EvrProgpow.Ethash_hash256();
inputHash.bytes = hash;

fixed(byte* input = hash)
{
value = EvrProgpow.hash(handle, blockNumber, ref inputHash, nonce);
}

if(value.final_hash.bytes == null)
{
logger.Error(() => $"EvrProgpow.hash returned null");
return false;
}

mixDigest = value.mix_hash.bytes;
result = value.final_hash.bytes;

messageBus?.SendTelemetry("EvrProgpow", TelemetryCategory.Hash, sw.Elapsed, true);

return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
using Miningcore.Blockchain.Progpow;
using NLog;

namespace Miningcore.Crypto.Hashing.Progpow.Evrprogpow;

[Identifier("evrprogpow")]
public class EvrProgpowLight : IProgpowLight
{
public void Setup(int totalCache, ulong hardForkBlock = 0)
{
this.numCaches = totalCache;
}

private int numCaches; // Maximum number of caches to keep before eviction (only init, don't modify)
private readonly object cacheLock = new();
private readonly Dictionary<int, Cache> caches = new();
private Cache future;
public string AlgoName { get; } = "EvrProgpow";

public void Dispose()
{
foreach(var value in caches.Values)
value.Dispose();
}

public async Task<IProgpowCache> GetCacheAsync(ILogger logger, int block, CancellationToken ct)
{
var epoch = block / EvrmoreConstants.EpochLength;
Cache result;

lock(cacheLock)
{
if(numCaches == 0)
numCaches = 3;

if(!caches.TryGetValue(epoch, out result))
{
// No cached cache, evict the oldest if the cache limit was reached
while(caches.Count >= numCaches)
{
var toEvict = caches.Values.OrderBy(x => x.LastUsed).First();
var key = caches.First(pair => pair.Value == toEvict).Key;
var epochToEvict = toEvict.Epoch;

logger.Info(() => $"Evicting cache for epoch {epochToEvict} in favour of epoch {epoch}");
toEvict.Dispose();
caches.Remove(key);
}

// If we have the new cache pre-generated, use that, otherwise create a new one
if(future != null && future.Epoch == epoch)
{
logger.Debug(() => $"Using pre-generated cache for epoch {epoch}");

result = future;
future = null;
}

else
{
logger.Info(() => $"No pre-generated cache available, creating new for epoch {epoch}");
result = new Cache(epoch);
}

caches[epoch] = result;
}

// If we used up the future cache, or need a refresh, regenerate
else if(future == null || future.Epoch <= epoch)
{
logger.Info(() => $"Pre-generating cache for epoch {epoch + 1}");
future = new Cache(epoch + 1);

#pragma warning disable 4014
future.GenerateAsync(logger);
#pragma warning restore 4014
}

result.LastUsed = DateTime.Now;
}

// get/generate current one
await result.GenerateAsync(logger);

return result;
}
}
37 changes: 37 additions & 0 deletions src/Miningcore/Native/EvrProgpow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Runtime.InteropServices;

// ReSharper disable FieldCanBeMadeReadOnly.Local
// ReSharper disable MemberCanBePrivate.Local
// ReSharper disable InconsistentNaming

namespace Miningcore.Native;

public static unsafe class EvrProgpow
{
[DllImport("libevrprogpow", EntryPoint = "ethash_create_epoch_context", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr CreateContext(int epoch_number);

[DllImport("libevrprogpow", EntryPoint = "ethash_destroy_epoch_context", CallingConvention = CallingConvention.Cdecl)]
public static extern void DestroyContext(IntPtr context);

[DllImport("libevrprogpow", EntryPoint = "hash", CallingConvention = CallingConvention.Cdecl)]
public static extern Ethash_result hash(IntPtr context, int block_number, ref Ethash_hash256 header_hash, ulong nonce);

[DllImport("libevrprogpow", EntryPoint = "ethash_calculate_epoch_seed", CallingConvention = CallingConvention.Cdecl)]
public static extern Ethash_hash256 calculate_epoch_seed(int epoch_number);

[StructLayout(LayoutKind.Explicit)]
public struct Ethash_hash256
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public byte[] bytes;//x32
}

[StructLayout(LayoutKind.Sequential)]
public struct Ethash_result
{
public Ethash_hash256 final_hash;//32
public Ethash_hash256 mix_hash;//32
}
}
1 change: 1 addition & 0 deletions src/Miningcore/build-libs-linux.sh
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export HAVE_FEATURE="$HAVE_AES $HAVE_SSE2 $HAVE_SSE3 $HAVE_SSSE3 $HAVE_PCLMUL $H
(cd ../Native/libetchash && make clean && make) && mv ../Native/libetchash/libetchash.so "$OutDir"
(cd ../Native/libethhash && make clean && make) && mv ../Native/libethhash/libethhash.so "$OutDir"
(cd ../Native/libethhashb3 && make -j clean && make -j) && mv ../Native/libethhashb3/libethhashb3.so "$OutDir"
(cd ../Native/libevrprogpow && make clean && make) && mv ../Native/libevrprogpow/libevrprogpow.so "$OutDir"
(cd ../Native/libubqhash && make clean && make) && mv ../Native/libubqhash/libubqhash.so "$OutDir"
(cd ../Native/libcryptonote && make clean && make) && mv ../Native/libcryptonote/libcryptonote.so "$OutDir"
(cd ../Native/libcryptonight && make clean && make) && mv ../Native/libcryptonight/libcryptonight.so "$OutDir"
Expand Down
16 changes: 16 additions & 0 deletions src/Native/libevrprogpow/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CFLAGS += -g -Wall -c -fPIC -O2 -Wno-pointer-sign -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-discarded-qualifiers -Wno-unused-const-variable $(CPU_FLAGS)
CXXFLAGS += -g -Wall -fPIC -fpermissive -O2 -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-sign-compare -std=c++11 $(CPU_FLAGS)
LDFLAGS += -shared
TARGET = libevrprogpow.so

OBJECTS = ethash/ethash.o keccak/keccak.o keccak/keccakf800.o keccak/keccakf1600.o ethash/managed.o ethash/primes.o ethash/progpow.o

all: $(TARGET)

$(TARGET): $(OBJECTS)
$(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS)

.PHONY: clean

clean:
$(RM) $(TARGET) $(OBJECTS)
33 changes: 33 additions & 0 deletions src/Native/libevrprogpow/attributes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
* Copyright 2018-2019 Pawel Bylica.
* Licensed under the Apache License, Version 2.0.
*/

#pragma once

/** inline */
#if _MSC_VER || __STDC_VERSION__
#define INLINE inline
#else
#define INLINE
#endif

/** [[always_inline]] */
#if _MSC_VER
#define ALWAYS_INLINE __forceinline
#elif defined(__has_attribute) && __STDC_VERSION__
#if __has_attribute(always_inline)
#define ALWAYS_INLINE __attribute__((always_inline))
#endif
#endif
#if !defined(ALWAYS_INLINE)
#define ALWAYS_INLINE
#endif

/** [[no_sanitize()]] */
#if __clang__
#define NO_SANITIZE(sanitizer) \
__attribute__((no_sanitize(sanitizer)))
#else
#define NO_SANITIZE(sanitizer)
#endif
19 changes: 19 additions & 0 deletions src/Native/libevrprogpow/dllmain.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

37 changes: 37 additions & 0 deletions src/Native/libevrprogpow/ethash/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
# Copyright 2018-2019 Pawel Bylica.
# Licensed under the Apache License, Version 2.0.

include(GNUInstallDirs)

add_library(
ethash SHARED
bit_manipulation.h
builtins.h
endianness.hpp
${include_dir}/ethash/ethash.h
${include_dir}/ethash/ethash.hpp
ethash-internal.hpp
ethash.cpp
${include_dir}/ethash/hash_types.h
managed.cpp
kiss99.hpp
primes.h
primes.c
${include_dir}/ethash/progpow.hpp
progpow.cpp
)
set_property(TARGET ethash PROPERTY POSITION_INDEPENDENT_CODE ON)

target_link_libraries(ethash PRIVATE keccak)
target_include_directories(ethash PUBLIC $<BUILD_INTERFACE:${include_dir}>$<INSTALL_INTERFACE:include>)
if(CABLE_COMPILER_GNULIKE AND NOT SANITIZE MATCHES undefined)
target_compile_options(ethash PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>)
endif()

install(
TARGETS ethash
EXPORT ethashTargets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
Loading

0 comments on commit 800ac45

Please sign in to comment.