From f24d60e856d864adad4b53f37bae9ebbdb91b9c7 Mon Sep 17 00:00:00 2001 From: Lip Wee Yeo Amano <13805146+lwYeo@users.noreply.github.com> Date: Mon, 3 Dec 2018 09:23:57 +0800 Subject: [PATCH] 2.2 branch (#12) * Commit #11 Improve the miner to have a master/slave mode * Fix invalid effective hashrate output * Fix invalid address for nonce * Added effective hashrate output for master instance Clean up code Raised version * Fixed miner not resuming on connection restore * Fix invalid nonce on very low difficulty CPU mining * Add error handling for failed master instance initialization * Add Windows 7 SP1 target in preprocessor * Added master/slave launch scripts, update Readme * Add submit nonce count output in slave instance * Fix ArgumentNullException if not able to retreive GPU name * Update launch scripts * Add slave behavior for Solo/Pool mining at master Solo mining should submit only 1 valid nonce per challange * Clean up code * Add slave URL printing upon receive solution from slave miner * Fix incorrect difficulty comparison * Update guides --- .../CPUSoliditySHA3Solver.vcxproj | 2 + CPUSoliditySHA3Solver/cpuSolver.cpp | 12 +- CPUSoliditySHA3Solver/instance.h | 8 +- CPUSoliditySHA3Solver/sha3/sha3-midstate.c | 446 +++++----- CPUSoliditySHA3Solver/solver.cpp | 3 +- .../CudaSoliditySHA3Solver.vcxproj | 4 +- CudaSoliditySHA3Solver/solver.cpp | 3 +- .../OpenCLSoliditySHA3Solver.vcxproj | 4 +- OpenCLSoliditySHA3Solver/solver.cpp | 3 +- README.md | 96 +- SoliditySHA3Miner/API/Ccminer.cs | 4 +- SoliditySHA3Miner/API/Json.cs | 5 +- SoliditySHA3Miner/Config.cs | 42 +- SoliditySHA3Miner/Miner/CPU.cs | 50 +- SoliditySHA3Miner/Miner/Device/CPU.cs | 2 +- SoliditySHA3Miner/Miner/MasterInterface.cs | 483 ++++++++++ SoliditySHA3Miner/Miner/MinerBase.cs | 55 +- SoliditySHA3Miner/Miner/Work.cs | 9 +- .../MiningGuide/GuideForEthOS.txt | 17 +- .../MiningGuide/GuideForHiveOS.txt | 34 +- .../MiningGuide/GuideForMasterSlaveMining.txt | 113 +++ .../MiningGuide/GuideForPoolMining.txt | 9 + .../MiningGuide/GuideForSoloMining.txt | 9 + .../NetworkInterface/INetworkInterface.cs | 43 +- .../NetworkInterface/MiningParameters.cs | 186 +++- .../NetworkInterface/NetworkInterfaceBase.cs | 174 ++++ .../NetworkInterface/PoolInterface.cs | 605 ++++++------- .../NetworkInterface/SlaveInterface.cs | 335 +++++++ .../NetworkInterface/Web3Interface.cs | 838 ++++++++---------- SoliditySHA3Miner/Program.cs | 55 +- .../Properties/Resources.Designer.cs | 64 +- SoliditySHA3Miner/Readme.txt | 11 +- SoliditySHA3Miner/Scripts/0xbtcPoolMaster.bat | 31 + SoliditySHA3Miner/Scripts/0xbtcPoolMaster.sh | 15 + SoliditySHA3Miner/Scripts/0xbtcSolo.bat | 2 +- SoliditySHA3Miner/Scripts/0xbtcSolo.sh | 7 +- SoliditySHA3Miner/Scripts/0xbtcSoloMaster.bat | 37 + SoliditySHA3Miner/Scripts/0xbtcSoloMaster.sh | 15 + .../Scripts/SoliditySHA3MinerSlave.bat | 29 + .../Scripts/SoliditySHA3MinerSlave.sh | 16 + SoliditySHA3Miner/Scripts/clmSolo.bat | 3 +- SoliditySHA3Miner/Scripts/clmSolo.sh | 7 +- SoliditySHA3Miner/SoliditySHA3Miner.conf | 18 +- SoliditySHA3Miner/SoliditySHA3Miner.csproj | 28 +- SoliditySHA3Miner/Structs/DeviceCL.cs | 1 + SoliditySHA3Miner/Structs/DeviceCPU.cs | 8 +- SoliditySHA3Miner/Structs/DeviceCUDA.cs | 1 + SoliditySHA3Miner/Utils/Json.cs | 8 +- SoliditySHA3Miner/Utils/Numerics.cs | 33 +- 49 files changed, 2666 insertions(+), 1317 deletions(-) create mode 100644 SoliditySHA3Miner/Miner/MasterInterface.cs create mode 100644 SoliditySHA3Miner/MiningGuide/GuideForMasterSlaveMining.txt create mode 100644 SoliditySHA3Miner/NetworkInterface/NetworkInterfaceBase.cs create mode 100644 SoliditySHA3Miner/NetworkInterface/SlaveInterface.cs create mode 100644 SoliditySHA3Miner/Scripts/0xbtcPoolMaster.bat create mode 100644 SoliditySHA3Miner/Scripts/0xbtcPoolMaster.sh create mode 100644 SoliditySHA3Miner/Scripts/0xbtcSoloMaster.bat create mode 100644 SoliditySHA3Miner/Scripts/0xbtcSoloMaster.sh create mode 100644 SoliditySHA3Miner/Scripts/SoliditySHA3MinerSlave.bat create mode 100644 SoliditySHA3Miner/Scripts/SoliditySHA3MinerSlave.sh diff --git a/CPUSoliditySHA3Solver/CPUSoliditySHA3Solver.vcxproj b/CPUSoliditySHA3Solver/CPUSoliditySHA3Solver.vcxproj index e65a6b4..d073de8 100644 --- a/CPUSoliditySHA3Solver/CPUSoliditySHA3Solver.vcxproj +++ b/CPUSoliditySHA3Solver/CPUSoliditySHA3Solver.vcxproj @@ -72,6 +72,7 @@ Disabled + _WIN32_WINNT=0x0601;%(PreprocessorDefinitions) @@ -80,6 +81,7 @@ true true Speed + _WIN32_WINNT=0x0601;%(PreprocessorDefinitions) true diff --git a/CPUSoliditySHA3Solver/cpuSolver.cpp b/CPUSoliditySHA3Solver/cpuSolver.cpp index 9c43852..9bc1b06 100644 --- a/CPUSoliditySHA3Solver/cpuSolver.cpp +++ b/CPUSoliditySHA3Solver/cpuSolver.cpp @@ -88,7 +88,7 @@ namespace CPUSolver std::memcpy(¤tSolution, deviceInstance->SolutionTemplate, UINT256_LENGTH); uint64_t const endWorkPosition = processor->WorkPosition + processor->WorkSize; - uint32_t const maxSolutionCount = deviceInstance->MaxSolutionCount; + uint32_t const maxSolutionCount = processor->MaxSolutionCount; for (auto currentWorkPosition = processor->WorkPosition; currentWorkPosition < endWorkPosition; ++currentWorkPosition) { @@ -99,10 +99,10 @@ namespace CPUSolver if (IslessThan(digest, currentTarget)) { - if (deviceInstance->SolutionCount < maxSolutionCount) + if (processor->SolutionCount < maxSolutionCount) { - deviceInstance->Solutions[deviceInstance->SolutionCount] = currentWorkPosition; - deviceInstance->SolutionCount++; + processor->Solutions[processor->SolutionCount] = currentWorkPosition; + processor->SolutionCount++; } } } @@ -112,7 +112,7 @@ namespace CPUSolver { uint64_t const endWorkPosition = processor->WorkPosition + processor->WorkSize; uint64_t const currentHigh64Target = *deviceInstance->High64Target; - uint32_t const maxSolutionCount = deviceInstance->MaxSolutionCount; + uint32_t const maxSolutionCount = processor->MaxSolutionCount; uint64_t currentMidState[SPONGE_LENGTH / UINT64_LENGTH]; std::memcpy(¤tMidState, deviceInstance->MidState, SPONGE_LENGTH); @@ -120,7 +120,7 @@ namespace CPUSolver for (auto currentWorkPosition = processor->WorkPosition; currentWorkPosition < endWorkPosition; ++currentWorkPosition) { sha3_midstate(currentMidState, currentHigh64Target, currentWorkPosition, maxSolutionCount, - &deviceInstance->SolutionCount, deviceInstance->Solutions); + &processor->SolutionCount, processor->Solutions); } } diff --git a/CPUSoliditySHA3Solver/instance.h b/CPUSoliditySHA3Solver/instance.h index d726058..d60c140 100644 --- a/CPUSoliditySHA3Solver/instance.h +++ b/CPUSoliditySHA3Solver/instance.h @@ -23,6 +23,10 @@ struct Processor int Affinity; uint64_t WorkSize; uint64_t WorkPosition; + + uint32_t MaxSolutionCount; + uint32_t SolutionCount; + uint64_t *Solutions; }; struct Instance @@ -36,8 +40,4 @@ struct Instance uint8_t *Target; uint64_t *High64Target; - - uint32_t MaxSolutionCount; - uint32_t SolutionCount; - uint64_t *Solutions; }; \ No newline at end of file diff --git a/CPUSoliditySHA3Solver/sha3/sha3-midstate.c b/CPUSoliditySHA3Solver/sha3/sha3-midstate.c index 216bbf4..91327e3 100644 --- a/CPUSoliditySHA3Solver/sha3/sha3-midstate.c +++ b/CPUSoliditySHA3Solver/sha3/sha3-midstate.c @@ -16,12 +16,7 @@ #include "sha3-midstate.h" -#if defined(_MSC_VER) -# pragma intrinsic(_rotl64) -# define ROTL_64(x, n) _rotl64(x, n) -# pragma intrinsic(_rotr64) -# define ROTR_64(x, n) _rotr64(x, n) -#elif defined(__clang__) +#if defined(__clang__) # define ROTL_64(x, n) __builtin_rotateleft64(x, n) # define ROTR_64(x, n) __builtin_rotateright64(x, n) #else @@ -35,35 +30,34 @@ static inline uint64_t bswap64(uint64_t const input) { - return ((input << 56) & 0xff00000000000000ull) | + return + ((input << 56) & 0xff00000000000000ull) | ((input << 40) & 0x00ff000000000000ull) | ((input << 24) & 0x0000ff0000000000ull) | - ((input << 8) & 0x000000ff00000000ull) | - ((input >> 8) & 0x00000000ff000000ull) | + ((input << 8) & 0x000000ff00000000ull) | + ((input >> 8) & 0x00000000ff000000ull) | ((input >> 24) & 0x0000000000ff0000ull) | ((input >> 40) & 0x000000000000ff00ull) | ((input >> 56) & 0x00000000000000ffull); } -static uint64_t const Keccak_f1600_RC[24] = -{ - 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, - 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, - 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, - 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, - 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, - 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, - 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, - 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 -}; - void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t const workPosition, uint32_t const maxSolutionCount, uint32_t *solutionCount, uint64_t *solutions) { - uint64_t nonce, state[25], C[5], D[5], n[11]; - nonce = workPosition; - - n[0] = ROTL_64(nonce, 7); + uint64_t state[25], C[5], D[5], n[11]; + uint64_t const rc[24] = + { + 0x0000000000000001, 0x0000000000008082, 0x800000000000808a, + 0x8000000080008000, 0x000000000000808b, 0x0000000080000001, + 0x8000000080008081, 0x8000000000008009, 0x000000000000008a, + 0x0000000000000088, 0x0000000080008009, 0x000000008000000a, + 0x000000008000808b, 0x800000000000008b, 0x8000000000008089, + 0x8000000000008003, 0x8000000000008002, 0x8000000000000080, + 0x000000000000800a, 0x800000008000000a, 0x8000000080008081, + 0x8000000000008080, 0x0000000080000001, 0x8000000080008008 + }; + + n[0] = ROTL_64(workPosition, 7); n[1] = ROTL_64(n[0], 1); n[2] = ROTL_64(n[1], 6); n[3] = ROTL_64(n[2], 2); @@ -80,7 +74,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con C[2] = midState[2] ^ n[7]; C[3] = midState[3]; C[4] = midState[4] ^ n[2]; - state[0] = CHI(C[0], C[1], C[2]) ^ Keccak_f1600_RC[0]; + state[0] = CHI(C[0], C[1], C[2]) ^ rc[0]; state[1] = CHI(C[1], C[2], C[3]); state[2] = CHI(C[2], C[3], C[4]); state[3] = CHI(C[3], C[4], C[0]); @@ -220,15 +214,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -252,7 +246,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[1]; + state[0] = state[0] ^ rc[1]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -344,15 +338,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -376,7 +370,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[2]; + state[0] = state[0] ^ rc[2]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -468,15 +462,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -500,7 +494,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[3]; + state[0] = state[0] ^ rc[3]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -592,15 +586,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -624,7 +618,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[4]; + state[0] = state[0] ^ rc[4]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -716,15 +710,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -748,7 +742,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[5]; + state[0] = state[0] ^ rc[5]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -840,15 +834,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -872,7 +866,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[6]; + state[0] = state[0] ^ rc[6]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -964,15 +958,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -996,7 +990,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[7]; + state[0] = state[0] ^ rc[7]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -1088,15 +1082,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -1120,7 +1114,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[8]; + state[0] = state[0] ^ rc[8]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -1212,15 +1206,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -1244,7 +1238,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[9]; + state[0] = state[0] ^ rc[9]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -1336,15 +1330,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -1368,7 +1362,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[10]; + state[0] = state[0] ^ rc[10]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -1460,15 +1454,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -1492,7 +1486,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[11]; + state[0] = state[0] ^ rc[11]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -1584,15 +1578,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -1616,7 +1610,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[12]; + state[0] = state[0] ^ rc[12]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -1708,15 +1702,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -1740,7 +1734,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[13]; + state[0] = state[0] ^ rc[13]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -1832,15 +1826,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -1864,7 +1858,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[14]; + state[0] = state[0] ^ rc[14]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -1956,15 +1950,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -1988,7 +1982,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[15]; + state[0] = state[0] ^ rc[15]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -2080,15 +2074,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -2112,7 +2106,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[16]; + state[0] = state[0] ^ rc[16]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -2204,15 +2198,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -2236,7 +2230,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[17]; + state[0] = state[0] ^ rc[17]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -2328,15 +2322,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -2360,7 +2354,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[18]; + state[0] = state[0] ^ rc[18]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -2452,15 +2446,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -2484,7 +2478,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[19]; + state[0] = state[0] ^ rc[19]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -2576,15 +2570,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -2608,7 +2602,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[20]; + state[0] = state[0] ^ rc[20]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -2700,15 +2694,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -2732,7 +2726,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[21]; + state[0] = state[0] ^ rc[21]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -2824,15 +2818,15 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[9] = CHI(C[4], C[0], C[1]); C[0] = state[10]; - C[1] = state[10 + 1]; - C[2] = state[10 + 2]; - C[3] = state[10 + 3]; - C[4] = state[10 + 4]; + C[1] = state[11]; + C[2] = state[12]; + C[3] = state[13]; + C[4] = state[14]; state[10] = CHI(C[0], C[1], C[2]); - state[10 + 1] = CHI(C[1], C[2], C[3]); - state[10 + 2] = CHI(C[2], C[3], C[4]); - state[10 + 3] = CHI(C[3], C[4], C[0]); - state[10 + 4] = CHI(C[4], C[0], C[1]); + state[11] = CHI(C[1], C[2], C[3]); + state[12] = CHI(C[2], C[3], C[4]); + state[13] = CHI(C[3], C[4], C[0]); + state[14] = CHI(C[4], C[0], C[1]); C[0] = state[15]; C[1] = state[16]; @@ -2856,7 +2850,7 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[23] = CHI(C[3], C[4], C[0]); state[24] = CHI(C[4], C[0], C[1]); - state[0] = state[0] ^ Keccak_f1600_RC[22]; + state[0] = state[0] ^ rc[22]; C[1] = XOR5(state[0], state[5], state[10], state[15], state[20]); C[2] = XOR5(state[1], state[6], state[11], state[16], state[21]); @@ -2874,13 +2868,13 @@ void sha3_midstate(uint64_t const *midState, uint64_t const target, uint64_t con state[6] = ROTR_64(state[6], 20); state[12] = ROTR_64(state[12], 21); - state[0] = CHI(state[0], state[6], state[12]) ^ Keccak_f1600_RC[23]; + state[0] = CHI(state[0], state[6], state[12]) ^ rc[23]; if (bswap64(state[0]) <= target) // LTE is allowed because target is high 64 bits of uint256 { if (*solutionCount < maxSolutionCount) { - solutions[*solutionCount] = nonce; + solutions[*solutionCount] = workPosition; (*solutionCount)++; } } diff --git a/CPUSoliditySHA3Solver/solver.cpp b/CPUSoliditySHA3Solver/solver.cpp index a6e8e41..4990b3a 100644 --- a/CPUSoliditySHA3Solver/solver.cpp +++ b/CPUSoliditySHA3Solver/solver.cpp @@ -35,8 +35,7 @@ namespace CPUSolver void DisposeInstance(CpuSolver *instance) noexcept { - instance->~CpuSolver(); - free(instance); + delete instance; } void SetThreadAffinity(CpuSolver *instance, int affinityMask, const char *errorMessage) diff --git a/CudaSoliditySHA3Solver/CudaSoliditySHA3Solver.vcxproj b/CudaSoliditySHA3Solver/CudaSoliditySHA3Solver.vcxproj index d7bfa28..7c37638 100644 --- a/CudaSoliditySHA3Solver/CudaSoliditySHA3Solver.vcxproj +++ b/CudaSoliditySHA3Solver/CudaSoliditySHA3Solver.vcxproj @@ -16,7 +16,7 @@ {8541A1A2-DD45-4F28-9303-B28D3236DCB4} CUDASoliditySHASolver - 10.0.10240.0 + 10.0.17134.0 @@ -52,6 +52,7 @@ Disabled + _WIN32_WINNT=0x0601;%(PreprocessorDefinitions) cudart_static.lib;%(AdditionalDependencies) @@ -68,6 +69,7 @@ true true Speed + _WIN32_WINNT=0x0601;%(PreprocessorDefinitions) true diff --git a/CudaSoliditySHA3Solver/solver.cpp b/CudaSoliditySHA3Solver/solver.cpp index 4aab5ef..53e9599 100644 --- a/CudaSoliditySHA3Solver/solver.cpp +++ b/CudaSoliditySHA3Solver/solver.cpp @@ -40,8 +40,7 @@ namespace CUDASolver void DisposeInstance(CudaSolver *instance) noexcept { - instance->~CudaSolver(); - free(instance); + delete instance; } void GetDeviceProperties(CudaSolver *instance, DeviceCUDA *device, const char *errorMessage) diff --git a/OpenCLSoliditySHA3Solver/OpenCLSoliditySHA3Solver.vcxproj b/OpenCLSoliditySHA3Solver/OpenCLSoliditySHA3Solver.vcxproj index f2a6c3d..73e7599 100644 --- a/OpenCLSoliditySHA3Solver/OpenCLSoliditySHA3Solver.vcxproj +++ b/OpenCLSoliditySHA3Solver/OpenCLSoliditySHA3Solver.vcxproj @@ -13,7 +13,7 @@ {A73B12B6-272F-4837-B5A3-C1AA545BE4C5} OpenCLSoliditySHA3Solver - 10.0.10240.0 + 10.0.17134.0 @@ -49,6 +49,7 @@ Disabled $(AMDAPPSDKROOT)/include;$(AMDAPPSDKROOT)/include/SDKUtil;%(AdditionalIncludeDirectories) + _WIN32_WINNT=0x0601;%(PreprocessorDefinitions) OpenCL.lib;%(AdditionalDependencies) @@ -62,6 +63,7 @@ true $(AMDAPPSDKROOT)/include;$(AMDAPPSDKROOT)/include/SDKUtil;%(AdditionalIncludeDirectories) Speed + _WIN32_WINNT=0x0601;%(PreprocessorDefinitions) true diff --git a/OpenCLSoliditySHA3Solver/solver.cpp b/OpenCLSoliditySHA3Solver/solver.cpp index f907586..94ac2db 100644 --- a/OpenCLSoliditySHA3Solver/solver.cpp +++ b/OpenCLSoliditySHA3Solver/solver.cpp @@ -45,8 +45,7 @@ namespace OpenCLSolver void DisposeInstance(OpenCLSolver *instance) noexcept { - instance->~OpenCLSolver(); - free(instance); + delete instance; } void InitializeDevice(OpenCLSolver *instance, DeviceCL *device, bool isKingMaking, const char *errorMessage) diff --git a/README.md b/README.md index 083ad97..08ba43d 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # SoliditySHA3Miner All-in-one mixed multi-GPU (nVidia, AMD, Intel) & CPU miner solves proof of work to mine supported EIP918 tokens in a single instance (with API). -Current latest public release version: [2.1.1](https://github.com/lwYeo/SoliditySHA3Miner/releases/latest) +Current latest public release version: [2.2.0](https://github.com/lwYeo/SoliditySHA3Miner/releases/latest) -Runs on Windows 10, HiveOS, EthOS, and Ubuntu. +Runs on Windows x64, HiveOS, EthOS, and Ubuntu. Built with .NET Core 2.1.5 SDK, VC++ 2017, gcc 4.8.5, nVidia CUDA SDK 9.2 64-bits, and AMD APP SDK v3.0.130.135 (OpenCL) @@ -49,83 +49,89 @@ Usage: SoliditySHA3Miner [OPTIONS] Options: help Display this help text and exit - + allowCPU Allow to use CPU, may slow down system (default: false) - + cpuAffinity Comma separated list of CPU affinity ID to use (default: all odd number logical processors) - + allowIntel Allow to use Intel GPU (OpenCL) (default: true) - + allowAMD Allow to use AMD GPU (OpenCL) (default: true) - + allowCUDA Allow to use Nvidia GPU (CUDA) (default: true) - + intelIntensity GPU (Intel OpenCL) intensity (default: 17, decimals allowed) - + listAmdDevices List of all AMD (OpenCL) devices in this system and exit (device ID: GPU name) - + amdDevice Comma separated list of AMD (OpenCL) devices to use (default: all devices) - + amdIntensity GPU (AMD OpenCL) intensity (default: 24.056, decimals allowed) - + listCudaDevices List of all CUDA devices in this system (device ID: GPU name) - + cudaDevice Comma separated list of CUDA devices to use (default: all devices) - + cudaIntensity GPU (CUDA) intensity (default: auto, decimals allowed) - + minerJsonAPI 'http://IP:port/' for the miner JSON-API (default: http://127.0.0.1:4078 [0 disabled]) - + minerCcminerAPI 'IP:port' for the ccminer-style API (default: 127.0.0.1:4068 [0 disabled]) - + overrideMaxTarget (Pool only) Use maximum target and skips query from web3 - + customDifficulty (Pool only) Set custom difficulity (check with your pool operator) - + maxScanRetry Number of retries to scan for new work (default: 3) - + pauseOnFailedScans Pauses mining after number of connection fails, including secondary and retries (default: 3) - + submitStale Submit stale jobs, may create more rejected shares (default: false) - - abiFile Token abi in a file (default: '0xbtc.abi' in the same folder as this miner) - + + abiFile Token abi in a file (default: '0xBTC.abi' in the same folder as this miner) + web3api User-defined web3 provider URL (default: Infura mainnet provider [dev account, for TESTING PURPOSE only]) - + contract Token contract address (default: 0xbtc contract address) - + hashrateUpdateInterval Interval (miliseconds) for GPU hashrate logs (default: 30000) - + networkUpdateInterval Interval (miliseconds) to scan for new work (default: 15000) - - kingAddress Add MiningKing address to nounce, only CPU mining supported (default: none) - + + masterMode Enable Master mode that virtually acts as a \"pool\" for slave miners connecting to it (default: false [requires admin/sudo mode]) + + masterURL Master instance IP:port, slave mode if 'masterMode' is false (default: none [if 'masterMode' is true, default: http://{localIP}:4080/]) + + slaveUpdateInterval (Slave only)Interval (miliseconds) to scan for new work (default: 5000) + + kingAddress Add MiningKing address to nonce, only CPU mining supported (default: none) + address (Pool only) Miner's ethereum address (default: developer's address) - + privateKey (Solo only) Miner's private key - + gasToMine (Solo only) Gas price to mine in GWei (default: 3, decimals allowed; note: will override lower dynamic gas price) - + gasLimit (Solo only) Gas limit to submit proof of work (default: 1704624) - + gasApiURL (Solo only) Get dynamic gas price to mine from this JSON API URL (note: leave empty to disable) - + gasApiPath (Solo only) JSON path expression to retrieve dynamic gas price value from 'gasApiURL' - + gasApiMultiplier (Solo only) Multiplier to dynamic gas price value from 'gasApiURL' => 'gasApiPath' (note: use 0.1 for EthGasStation API) - + gasApiOffset (Solo only) Offset to dynamic gas price value from 'gasApiURL' => 'gasApiPath' (after 'gasApiMultiplier', decimals allowed) - + gasApiMax (Solo only) Maximum gas price to mine in GWei from API (default: 7, decimals allowed) - + pool (Pool only) URL of pool mining server (default: http://mike.rs:8080) - + secondaryPool (Optional) URL of failover pool mining server - + logFile Enables logging of console output to '{appPath}\\Log\\{yyyy-MM-dd}.log' (default: false) - + devFee Set developer fee in percentage (default: 2.0%, minimum: 1.5%) - + ### NOTES @@ -139,11 +145,11 @@ Configuration is based on CLI (similar to ccminer), except ".abi" files are requ Note that there is a configuration file "SoliditySHA3Miner.conf" that saves previous CLI parameters/settings, delete it prior to changing CLI parameters. -A sample CLI launch parameter can be found in the ".bat" file found together with this miner, please refer to it if you need help. +Sample CLI launch parameter can be found in the ".bat" and ".sh" file found together with this miner, please refer to it if you need help. You will have to supply your own Ethereum address (or Private key if you solo mine). It is your own responsibility to mine to the correct address/account. -It is recommended to use your own web3api (e.g. Geth / Parity) if you solo mine. +It is recommended to use your own web3api (e.g. Infura / Geth / Parity) if you solo mine, default value is for TESTING PURPOSE ONLY. There is a default of 2.0% dev fee (Once every 50th nonce: starting from 11th if Pool mine, or starting from 50th if Solo mine). diff --git a/SoliditySHA3Miner/API/Ccminer.cs b/SoliditySHA3Miner/API/Ccminer.cs index 5ef698e..8c41ec3 100644 --- a/SoliditySHA3Miner/API/Ccminer.cs +++ b/SoliditySHA3Miner/API/Ccminer.cs @@ -141,7 +141,9 @@ private static void Listen(IPAddress ipAddress, int port) var acc = solv - rej; var uptime = (DateTime.Now - Program.LaunchTime).TotalSeconds; var accmn = (60.0 * acc) / (uptime > 0.0 ? uptime : 1.0); - var diff = m_miners.Average(m => (long)m.NetworkInterface.Difficulty); + double diff; + try { diff = m_miners.Average(m => (long)m.NetworkInterface.Difficulty.Value); } + catch { diff = long.MaxValue; } var netkhs = 0; // TODO: get network hashrate var pools = m_miners.Select(m => m.NetworkInterface).OfType().Distinct().Count(); var wait = Program.WaitSeconds; diff --git a/SoliditySHA3Miner/API/Json.cs b/SoliditySHA3Miner/API/Json.cs index b814fb6..9d1b13d 100644 --- a/SoliditySHA3Miner/API/Json.cs +++ b/SoliditySHA3Miner/API/Json.cs @@ -20,6 +20,7 @@ limitations under the License. using System.Linq; using System.Net; using System.Net.Sockets; +using System.Numerics; using System.Text; using System.Threading.Tasks; @@ -324,7 +325,7 @@ private void PopulateCommonApiData(ref JsonAPI api, ref double divisor) if (networkInterface.CurrentChallenge != null) api.CurrentChallenge = Utils.Numerics.Byte32ArrayToHexString(networkInterface.CurrentChallenge); - api.CurrentDifficulty = networkInterface.Difficulty; + api.CurrentDifficulty = networkInterface.Difficulty.Value; api.LastSubmitLatencyMS = networkInterface?.LastSubmitLatency ?? -1; @@ -615,7 +616,7 @@ public class JsonAPI public string MinerAddress { get; set; } public string MiningURL { get; set; } public string CurrentChallenge { get; set; } - public ulong CurrentDifficulty { get; set; } + public BigInteger CurrentDifficulty { get; set; } public long EstimateTimeLeftToSolveBlock { get; set; } public float EffectiveHashRate { get; set; } public float TotalHashRate { get; set; } diff --git a/SoliditySHA3Miner/Config.cs b/SoliditySHA3Miner/Config.cs index 6faef8f..e3b32c7 100644 --- a/SoliditySHA3Miner/Config.cs +++ b/SoliditySHA3Miner/Config.cs @@ -33,12 +33,15 @@ public class Config public string contractAddress { get; set; } public string abiFile { get; set; } public HexBigInteger overrideMaxTarget { get; set; } - public ulong customDifficulty { get; set; } + public BigInteger customDifficulty { get; set; } public bool submitStale { get; set; } public int maxScanRetry { get; set; } public int pauseOnFailedScans { get; set; } public int networkUpdateInterval { get; set; } public int hashrateUpdateInterval { get; set; } + public bool masterMode { get; set; } + public string masterURL { get; set; } + public int slaveUpdateInterval { get; set; } public string kingAddress { get; set; } public string minerAddress { get; set; } public string primaryPool { get; set; } @@ -69,19 +72,26 @@ public Config() // set defaults contractAddress = Defaults.Contract0xBTC_mainnet; abiFile = Defaults.AbiFile0xBTC; overrideMaxTarget = new HexBigInteger(BigInteger.Zero); - customDifficulty = 0u; + customDifficulty = BigInteger.Zero; submitStale = Defaults.SubmitStale; maxScanRetry = Defaults.MaxScanRetry; pauseOnFailedScans = Defaults.PauseOnFailedScan; networkUpdateInterval = Defaults.NetworkUpdateInterval; hashrateUpdateInterval = Defaults.HashrateUpdateInterval; + masterMode = false; + masterURL = string.Empty; kingAddress = string.Empty; - minerAddress = string.Empty; - primaryPool = string.Empty; + minerAddress = DevFee.Address; + slaveUpdateInterval = Defaults.SlaveUpdateInterval; + primaryPool = Defaults.PoolPrimary; secondaryPool = string.Empty; privateKey = string.Empty; gasToMine = Defaults.GasToMine; gasLimit = Defaults.GasLimit; + gasApiURL = Defaults.GasApiURL; + gasApiPath = Defaults.GasApiPath; + gasApiMultiplier = Defaults.GasApiMultiplier; + gasApiOffset = Defaults.GasApiOffset; gasApiMax = Defaults.GasApiMax; allowCPU = false; cpuDevice = new Miner.Device.CPU(); @@ -123,6 +133,9 @@ private static void PrintHelp() " contract Token contract address (default: 0xbtc contract address)\n" + " hashrateUpdateInterval Interval (miliseconds) for GPU hashrate logs (default: " + Defaults.HashrateUpdateInterval + ")\n" + " networkUpdateInterval Interval (miliseconds) to scan for new work (default: " + Defaults.NetworkUpdateInterval + ")\n" + + " masterMode Enable Master mode that virtually acts as a \"pool\" for slave miners connecting to it (default: false [requires admin/sudo mode])\n" + + " masterURL Master instance IP:port, slave mode if 'masterMode' is false (default: none [if 'masterMode' is true, default: http://{localIP}:4080/])\n" + + " slaveUpdateInterval (Slave only)Interval (miliseconds) to scan for new work (default: " + Defaults.SlaveUpdateInterval + ")\n" + " kingAddress Add MiningKing address to nonce, only CPU mining supported (default: none)\n" + " address (Pool only) Miner's ethereum address (default: developer's address)\n" + " privateKey (Solo only) Miner's private key\n" + @@ -694,7 +707,7 @@ public bool ParseArgumentsToConfig(string[] args) break; case "customDifficulty": - customDifficulty = uint.Parse(arg.Split('=')[1]); + customDifficulty = BigInteger.Parse(arg.Split('=')[1]); break; case "maxScanRetry": @@ -737,6 +750,18 @@ public bool ParseArgumentsToConfig(string[] args) minerAddress = arg.Split('=')[1]; break; + case "masterMode": + masterMode = bool.Parse(arg.Split('=')[1]); + break; + + case "masterURL": + masterURL = arg.Split('=')[1]; + break; + + case "slaveUpdateInterval": + slaveUpdateInterval = int.Parse(arg.Split('=')[1]); + break; + case "privateKey": privateKey = arg.Split('=')[1]; break; @@ -800,10 +825,16 @@ public static class Defaults public const string Contract0xBTC_ropsten = "0x9D2Cc383E677292ed87f63586086CfF62a009010"; public const string AbiFile0xBTC = "0xBTC.abi"; + public const string GasApiURL = "https://ethgasstation.info/json/ethgasAPI.json"; + public const string GasApiPath = "$.safeLow"; + public const float GasApiMultiplier = 0.1f; + public const float GasApiOffset = 0.5f; + public const string PoolPrimary = "http://mike.rs:8080"; public const string PoolSecondary = "http://mike.rs:8080"; public const string JsonAPIPath = "http://127.0.0.1:4078"; public const string CcminerAPIPath = "127.0.0.1:4068"; + public const string MasterIpAddress = "http://{0}:4080"; public const bool SubmitStale = false; public const float GasToMine = 3.0f; @@ -813,6 +844,7 @@ public static class Defaults public const int PauseOnFailedScan = 3; public const int NetworkUpdateInterval = 15000; public const int HashrateUpdateInterval = 30000; + public const int SlaveUpdateInterval = 5000; public const bool LogFile = false; } diff --git a/SoliditySHA3Miner/Miner/CPU.cs b/SoliditySHA3Miner/Miner/CPU.cs index 0afa6ae..3a89b31 100644 --- a/SoliditySHA3Miner/Miner/CPU.cs +++ b/SoliditySHA3Miner/Miner/CPU.cs @@ -123,14 +123,20 @@ protected override void AssignDevices() { PrintMessage(device.Type, device.Platform, device.DeviceID, "Info", "Initializing device..."); - device.DeviceCPU_Struct.MaxSolutionCount = Device.DeviceBase.MAX_SOLUTION_COUNT; device.DeviceCPU_Struct.ProcessorCount = device.Affinities.Length; device.Processor_Structs = (Structs.Processor[])Array.CreateInstance(typeof(Structs.Processor), device.Affinities.Length); - - for (var i = 0; i < device.Processor_Structs.Length; i++) + device.Solutions = (ulong[][])Array.CreateInstance(typeof(ulong[]), device.Affinities.Length); + + for (var i = 0; i < device.Affinities.Length; i++) { device.Processor_Structs[i].Affinity = device.Affinities[i]; device.Processor_Structs[i].WorkSize = (ulong)Math.Pow(2, 16); + device.Processor_Structs[i].MaxSolutionCount = Device.DeviceBase.MAX_SOLUTION_COUNT; + + device.Solutions[i] = (ulong[])Array.CreateInstance(typeof(ulong), Device.DeviceBase.MAX_SOLUTION_COUNT); + var solutionsHandle = GCHandle.Alloc(device.Solutions[i], GCHandleType.Pinned); + device.Processor_Structs[i].Solutions = solutionsHandle.AddrOfPinnedObject(); + device.AddHandle(solutionsHandle); } var processorsHandle = GCHandle.Alloc(device.Processor_Structs, GCHandleType.Pinned); @@ -142,11 +148,6 @@ protected override void AssignDevices() device.DeviceCPU_Struct.SolutionTemplate = solutionTemplateHandle.AddrOfPinnedObject(); device.AddHandle(solutionTemplateHandle); - device.Solutions = (ulong[])Array.CreateInstance(typeof(ulong), Device.DeviceBase.MAX_SOLUTION_COUNT); - var solutionsHandle = GCHandle.Alloc(device.Solutions, GCHandleType.Pinned); - device.DeviceCPU_Struct.Solutions = solutionsHandle.AddrOfPinnedObject(); - device.AddHandle(solutionsHandle); - device.DeviceCPU_Struct.Message = device.CommonPointers.Message; device.DeviceCPU_Struct.MidState = device.CommonPointers.MidState; device.DeviceCPU_Struct.High64Target = device.CommonPointers.High64Target; @@ -201,15 +202,20 @@ private void StartThreadFinding(Device.CPU device, Structs.Processor processor, var errorMessage = new StringBuilder(1024); var currentChallenge = (byte[])Array.CreateInstance(typeof(byte), UINT256_LENGTH); - double timeAccuracy; - int loopTimeElapsed; DateTime loopStartTime; + int loopTimeElapsed; + double timeAccuracy; var loopTimeTarget = (int)(m_hashPrintTimer.Interval * 0.1); + var processorIndex = -1; + for (var i = 0; i < device.Processor_Structs.Length; i++) + if (device.Processor_Structs[i].Affinity == processor.Affinity) + processorIndex = i; + Helper.CPU.Solver.SetThreadAffinity(UnmanagedInstance, processor.Affinity, errorMessage); if (errorMessage.Length > 0) { - PrintMessage(device.Type, device.Platform, Array.IndexOf(device.Processor_Structs, processor), "Error", errorMessage.ToString()); + PrintMessage(device.Type, device.Platform, processorIndex, "Error", errorMessage.ToString()); return; } @@ -246,16 +252,18 @@ private void StartThreadFinding(Device.CPU device, Structs.Processor processor, if (timeAccuracy > 1.2f || timeAccuracy < 0.8f) processor.WorkSize = (ulong)(timeAccuracy * processor.WorkSize); - if (device.DeviceCPU_Struct.SolutionCount > 0) - lock (this) - if (device.DeviceCPU_Struct.SolutionCount > 0) - { - SubmitSolutions(device.Solutions.ToArray(), currentChallenge, - device.Type, device.Platform, device.DeviceID, - device.DeviceCPU_Struct.SolutionCount, isKingMaking); - - device.DeviceCPU_Struct.SolutionCount = 0; - } + if (processor.SolutionCount > 0) + { + SubmitSolutions(device.Solutions[processorIndex].ToArray(), + currentChallenge, + device.Type, + device.Platform, + device.DeviceID, + processor.SolutionCount, + isKingMaking); + + processor.SolutionCount = 0; + } } while (device.IsMining); if (processor.Affinity == device.Processor_Structs.First().Affinity) diff --git a/SoliditySHA3Miner/Miner/Device/CPU.cs b/SoliditySHA3Miner/Miner/Device/CPU.cs index 47dd9ef..5d8caf8 100644 --- a/SoliditySHA3Miner/Miner/Device/CPU.cs +++ b/SoliditySHA3Miner/Miner/Device/CPU.cs @@ -32,6 +32,6 @@ public class CPU : DeviceBase public byte[] SolutionTemplate; [JsonIgnore] - public ulong[] Solutions; + public ulong[][] Solutions; } } \ No newline at end of file diff --git a/SoliditySHA3Miner/Miner/MasterInterface.cs b/SoliditySHA3Miner/Miner/MasterInterface.cs new file mode 100644 index 0000000..bb72dd4 --- /dev/null +++ b/SoliditySHA3Miner/Miner/MasterInterface.cs @@ -0,0 +1,483 @@ +/* + Copyright 2018 Lip Wee Yeo Amano + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using Nethereum.Hex.HexTypes; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using SoliditySHA3Miner.Miner.Device; +using SoliditySHA3Miner.NetworkInterface; +using System; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; + +namespace SoliditySHA3Miner.Miner +{ + public class MasterInterface : IMiner + { + #region static + + public static class RequestMethods + { + public const string GetMinerAddress = "GetMinerAddress"; + public const string GetMaximumTarget = "GetMaximumTarget"; + public const string GetKingAddress = "GetKingAddress"; + public const string GetChallenge = "GetChallenge"; + public const string GetDifficulty = "GetDifficulty"; + public const string GetTarget = "GetTarget"; + public const string GetPause = "GetPause"; + public const string GetPoolMining = "GetPoolMining"; + public const string SubmitSolution = "SubmitSolution"; + } + + public static JObject GetMasterParameter(string method, params string[] parameters) + { + var paramObject = new JObject + { + ["jsonrpc"] = "2.0", + ["id"] = "1", + ["method"] = method + }; + if (parameters != null && parameters.Any()) + { + var props = new JArray(); + foreach (var p in parameters) + props.Add(p); + + paramObject.Add(new JProperty("params", props)); + } + return paramObject; + } + + public static JObject GetMasterResult(params string[] results) + { + if (results.Length == 1) + { + return new JObject + { + ["jsonrpc"] = "2.0", + ["id"] = "1", + ["result"] = results[0] + }; + } + else + { + var resultsArray = new JArray(); + foreach (var p in results) + resultsArray.Add(p); + + return new JObject + { + ["jsonrpc"] = "2.0", + ["id"] = "1", + ["result"] = resultsArray + }; + } + } + + public static string GetMasterDefaultIpAddress() + { + var defaultIP = "127.0.0.1"; + string[] ipAddresses = { "1.1.1.1", "1.0.0.1", "8.8.8.8", "8.8.4.4" }; + + foreach (var address in ipAddresses) + using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.IP)) + try + { + socket.Connect(address, 65530); + var endPoint = socket.LocalEndPoint as IPEndPoint; + defaultIP = endPoint.Address.ToString(); + break; + } + catch { } + + return string.Format(Config.Defaults.MasterIpAddress, defaultIP); + } + + #endregion + + public bool IsSupported { get; } + public string IpAddress { get; } + + private readonly HttpListener m_Listener; + private readonly int m_pauseOnFailedScan; + private readonly string m_kingEthAddress; + private readonly string m_maxTarget; + private int m_failedScanCount; + private bool m_isOngoing; + private bool m_isCurrentChallengeStopSolving; + private string m_minerEthAddress; + private string m_challenge; + private string m_difficulty; + private string m_target; + + #region IMiner + + public INetworkInterface NetworkInterface { get; } + public DeviceBase[] Devices => Enumerable.Empty().ToArray(); + public bool HasMonitoringAPI => false; + public bool IsAnyInitialised => true; + public bool IsMining => true; + public bool IsStopped => false; + public bool IsPause { get; private set; } + public bool HasAssignedDevices { get; private set; } + + public void Dispose() + { + // Do nothing + } + + public void StartMining(int networkUpdateInterval, int hashratePrintInterval) + { + // Do nothing + } + + public void StopMining() + { + Program.Print("[INFO] Master instance stopping..."); + m_isOngoing = false; + + NetworkInterface.OnGetMiningParameterStatus -= NetworkInterface_OnGetMiningParameterStatus; + NetworkInterface.OnNewChallenge -= NetworkInterface_OnNewChallenge; + NetworkInterface.OnNewTarget -= NetworkInterface_OnNewTarget; + NetworkInterface.OnNewDifficulty -= NetworkInterface_OnNewDifficulty; + NetworkInterface.OnStopSolvingCurrentChallenge -= NetworkInterface_OnStopSolvingCurrentChallenge; + + m_Listener?.Stop(); + m_Listener?.Close(); + } + + public ulong GetTotalHashrate() + { + return 0ul; + } + + public ulong GetHashRateByDevice(DeviceBase device) + { + return 0ul; + } + + #endregion + + public MasterInterface(INetworkInterface networkInterface, int pauseOnFailedScans, string ipAddress = null) + { + m_failedScanCount = 0; + m_pauseOnFailedScan = pauseOnFailedScans; + NetworkInterface = networkInterface; + NetworkInterface.OnGetMiningParameterStatus += NetworkInterface_OnGetMiningParameterStatus; + NetworkInterface.OnNewChallenge += NetworkInterface_OnNewChallenge; + NetworkInterface.OnNewTarget += NetworkInterface_OnNewTarget; + NetworkInterface.OnNewDifficulty += NetworkInterface_OnNewDifficulty; + NetworkInterface.OnStopSolvingCurrentChallenge += NetworkInterface_OnStopSolvingCurrentChallenge; + + IsSupported = HttpListener.IsSupported; + if (!IsSupported) + { + Program.Print("[ERROR] Obsolete OS detected, Master instance will not start."); + return; + } + + if (string.IsNullOrWhiteSpace(ipAddress)) + { + ipAddress = GetMasterDefaultIpAddress(); + Program.Print(string.Format("[INFO] masterIpAddress is null or empty, using default {0}", ipAddress)); + } + + if (!ipAddress.StartsWith("http://") || ipAddress.StartsWith("https://")) + ipAddress = "http://" + ipAddress; + + if (!ipAddress.EndsWith("/")) ipAddress += "/"; + + if (!int.TryParse(ipAddress.Split(':')[2].TrimEnd('/'), out int port)) + { + Program.Print("[ERROR] Invalid port provided for masterIpAddress."); + return; + } + + var tempIPAddress = ipAddress.Split(new string[] { "//" }, StringSplitOptions.None)[1].Split(':')[0]; + if (!IPAddress.TryParse(tempIPAddress, out IPAddress ipAddressObj)) + { + Program.Print("[ERROR] Invalid IP address provided for Master instance."); + return; + } + + using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + { + try { socket.Bind(new IPEndPoint(ipAddressObj, port)); } + catch (Exception) + { + Program.Print("[ERROR] Master instance failed to bind to: " + ipAddress); + return; + } + }; + + try + { + if (Work.KingAddress != null) + m_kingEthAddress = Utils.Numerics.Byte20ArrayToAddressString(Work.KingAddress); + + m_maxTarget = Utils.Numerics.Byte32ArrayToHexString( + networkInterface.MaxTarget.Value.ToByteArray(isUnsigned: true, isBigEndian: true)); + + if (networkInterface.CurrentChallenge == null) + networkInterface.UpdateMiningParameters(); + else + { + m_minerEthAddress = networkInterface.MinerAddress; + m_challenge = Utils.Numerics.Byte32ArrayToHexString(networkInterface.CurrentChallenge); + m_difficulty = Utils.Numerics.Byte32ArrayToHexString( + networkInterface.Difficulty.Value.ToByteArray(isUnsigned: true, isBigEndian: true)); + m_target = Utils.Numerics.Byte32ArrayToHexString( + networkInterface.CurrentTarget.Value.ToByteArray(isUnsigned: true, isBigEndian: true)); + } + + m_Listener = new HttpListener(); + m_Listener.Prefixes.Add(ipAddress); + m_Listener.Start(); + + Process(m_Listener); + } + catch (HttpListenerException ex) + { + HandleException(ex, errorPostfix: string.Format("Listening failed at ({0}): Check URL validity, firewall settings, and admin/sudo mode.", ipAddress)); + Environment.Exit(1); + } + catch (Exception ex) + { + HandleException(ex); + return; + } + } + + private async void Process(HttpListener listener) + { + HasAssignedDevices = true; + Program.Print(string.Format("[INFO] Master instance started at {0}...", listener.Prefixes.ElementAt(0))); + + m_isOngoing = true; + while (m_isOngoing) + { + HttpListenerContext context = null; + + try { context = await listener.GetContextAsync(); } + catch (HttpListenerException ex) + { + if (ex.ErrorCode == 995) break; + + HandleException(ex, string.Format("{0} Error code: {1}, Message: {2}", + ex.GetType().Name, ex.ErrorCode, ex.Message)); + await Task.Delay(1000); + continue; + } + catch (ObjectDisposedException) + { + break; + } + catch (Exception ex) + { + HandleException(ex); + await Task.Delay(1000); + continue; + } + + var request = context.Request; + var response = context.Response; + if (request != null && response != null) + { + response.AppendHeader("Pragma", "no-cache"); + response.AppendHeader("Expires", "0"); + response.ContentType = "application/json"; + response.StatusCode = (int)HttpStatusCode.OK; + + ProcessApiDataResponse(request, response); + } + } + } + + private void ProcessApiDataResponse(HttpListenerRequest request, HttpListenerResponse response) + { + if (response != null) + Task.Factory.StartNew(() => + { + try + { + var requestJSON = string.Empty; + JObject jResponse = null; + + if (request.HasEntityBody) + using (var body = request.InputStream) + using (var reader = new System.IO.StreamReader(body, request.ContentEncoding)) + requestJSON = reader.ReadToEnd(); + try + { + var jRequest = (JObject)JsonConvert.DeserializeObject(requestJSON); + var jMethodName = jRequest.SelectToken("$.method").Value(); + + switch (jMethodName) + { + case RequestMethods.GetMinerAddress: + jResponse = GetMasterResult(m_minerEthAddress); + break; + + case RequestMethods.GetMaximumTarget: + jResponse = GetMasterResult(m_maxTarget); + break; + + case RequestMethods.GetKingAddress: + jResponse = GetMasterResult(m_kingEthAddress); + break; + + case RequestMethods.GetChallenge: + jResponse = GetMasterResult(m_challenge); + break; + + case RequestMethods.GetDifficulty: + jResponse = GetMasterResult(m_difficulty); + break; + + case RequestMethods.GetTarget: + jResponse = GetMasterResult(m_target); + break; + + case RequestMethods.GetPause: + jResponse = GetMasterResult(IsPause.ToString()); + break; + + case RequestMethods.GetPoolMining: + jResponse = GetMasterResult(NetworkInterface.IsPool.ToString()); + break; + + case RequestMethods.SubmitSolution: + var slaveURL = request.RemoteEndPoint.ToString(); + Program.Print("[INFO] Solution received from slave URL: http://" + slaveURL); + + var jParams = jRequest.SelectToken("$.params").Value(); + var digest = Utils.Numerics.HexStringToByte32Array(jParams[0].Value()); + var challenge = Utils.Numerics.HexStringToByte32Array(jParams[1].Value()); + var difficulty = Utils.Numerics.HexStringToByte32Array(jParams[2].Value()); + var nonce = Utils.Numerics.HexStringToByte32Array(jParams[3].Value()); + var difficultyBigInteger = new HexBigInteger(new BigInteger(difficulty, isUnsigned: true, isBigEndian: true)); + + var result = NetworkInterface.SubmitSolution(m_minerEthAddress, digest, challenge, difficultyBigInteger, nonce, this); + jResponse = GetMasterResult(result.ToString()); + break; + } + } + catch (Exception ex) + { + HandleException(ex); + } + + var buffer = Encoding.UTF8.GetBytes(Utils.Json.SerializeFromObject(jResponse)); + if (buffer != null) + using (var output = response.OutputStream) + { + output.Write(buffer, 0, buffer.Length); + output.Flush(); + } + } + catch (Exception ex) + { + response.StatusCode = (int)HttpStatusCode.InternalServerError; + HandleException(ex); + } + finally + { + try { response.Close(); } + catch (Exception ex) { HandleException(ex); } + } + }, + TaskCreationOptions.LongRunning); + } + + private void NetworkInterface_OnStopSolvingCurrentChallenge(INetworkInterface sender, bool stopSolving = true) + { + m_isCurrentChallengeStopSolving = true; + IsPause = true; + } + + private void NetworkInterface_OnNewTarget(INetworkInterface sender, HexBigInteger target) + { + m_target = Utils.Numerics.Byte32ArrayToHexString(target.Value.ToByteArray(isUnsigned: true, isBigEndian: true)); + } + + private void NetworkInterface_OnNewDifficulty(INetworkInterface sender, HexBigInteger difficulty) + { + m_difficulty = Utils.Numerics.Byte32ArrayToHexString(difficulty.Value.ToByteArray(isUnsigned: true, isBigEndian: true)); + } + + private void NetworkInterface_OnNewChallenge(INetworkInterface sender, byte[] challenge, string address) + { + m_challenge = Utils.Numerics.Byte32ArrayToHexString(challenge); + m_minerEthAddress = address; + + if (m_isCurrentChallengeStopSolving) + { + IsPause = false; + m_isCurrentChallengeStopSolving = false; + } + } + + private void NetworkInterface_OnGetMiningParameterStatus(INetworkInterface sender, bool success) + { + if (success) + { + if (m_isCurrentChallengeStopSolving) + IsPause = true; + + else if (IsPause) + { + if (m_failedScanCount > m_pauseOnFailedScan) + m_failedScanCount = 0; + + IsPause = false; + } + } + else + { + m_failedScanCount++; + + if (m_failedScanCount > m_pauseOnFailedScan) + IsPause = true; + } + } + + private void HandleException(Exception ex, string errorPrefix = null, string errorPostfix = null) + { + var errorMessage = new StringBuilder("[ERROR] Occured at Master instance => "); + + if (!string.IsNullOrWhiteSpace(errorPrefix)) + errorMessage.AppendFormat("{0}: ", errorPrefix); + + errorMessage.Append(ex.Message); + + var innerEx = ex.InnerException; + while (innerEx != null) + { + errorMessage.AppendFormat("\n {0}", innerEx.Message); + innerEx = innerEx.InnerException; + } + + if (!string.IsNullOrWhiteSpace(errorPostfix)) + errorMessage.AppendFormat("\n => {0}", errorPostfix); + + Program.Print(errorMessage.ToString()); + } + } +} \ No newline at end of file diff --git a/SoliditySHA3Miner/Miner/MinerBase.cs b/SoliditySHA3Miner/Miner/MinerBase.cs index 0bec247..895795e 100644 --- a/SoliditySHA3Miner/Miner/MinerBase.cs +++ b/SoliditySHA3Miner/Miner/MinerBase.cs @@ -14,7 +14,6 @@ You may obtain a copy of the License at limitations under the License. */ -using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Hex.HexTypes; using System; using System.Linq; @@ -260,11 +259,11 @@ private void NetworkInterface_OnGetMiningParameterStatus(NetworkInterface.INetwo isPause = false; } foreach (var device in Devices) - device.IsPause = IsPause; + device.IsPause = isPause; } else { - m_failedScanCount += 1; + m_failedScanCount++; var isMining = Devices.Any(d => d.IsMining); @@ -325,7 +324,7 @@ private void NetworkInterface_OnNewTarget(NetworkInterface.INetworkInterface sen { try { - var targetBytes = Utils.Numerics.FilterByte32Array(target.Value.ToByteArray(littleEndian: false)); + var targetBytes = Utils.Numerics.FilterByte32Array(target.Value.ToByteArray(isUnsigned: true, isBigEndian:true)); var high64Bytes = targetBytes.Take(UINT64_LENGTH).Reverse().ToArray(); m_Target = target; @@ -344,16 +343,28 @@ private void NetworkInterface_OnNewTarget(NetworkInterface.INetworkInterface sen } } - private void NetworkInterface_OnStopSolvingCurrentChallenge(NetworkInterface.INetworkInterface sender) + private void NetworkInterface_OnStopSolvingCurrentChallenge(NetworkInterface.INetworkInterface sender, bool stopSolving = true) { - if (m_isCurrentChallengeStopSolving) return; - - m_isCurrentChallengeStopSolving = true; + if (stopSolving) + { + if (m_isCurrentChallengeStopSolving) return; - PrintMessage(string.Empty, string.Empty, -1, "Info", "Mining temporary paused until new challenge receive..."); + m_isCurrentChallengeStopSolving = true; - foreach (var device in Devices) - device.IsPause = true; + foreach (var device in Devices) + device.IsPause = true; + + PrintMessage(string.Empty, string.Empty, -1, "Info", "Mining temporary paused until new challenge receive..."); + } + else if (m_isCurrentChallengeStopSolving) + { + PrintMessage(string.Empty, string.Empty, -1, "Info", "Resume mining..."); + + m_isCurrentChallengeStopSolving = false; + + foreach (var device in Devices) + device.IsPause = false; + } } private void StartFindingAll(bool isKingMaking) @@ -396,13 +407,17 @@ protected void SubmitSolutions(ulong[] solutions, byte[] challenge, string platf { foreach (var solution in solutions) { - if (!NetworkInterface.IsPool) - if (((NetworkInterface.Web3Interface)NetworkInterface).IsChallengedSubmitted(challenge)) + if (NetworkInterface.GetType().IsAssignableFrom(typeof(NetworkInterface.SlaveInterface))) + if (((NetworkInterface.SlaveInterface)NetworkInterface).IsPause) return; - if ((!m_isSubmitStale && !challenge.SequenceEqual(NetworkInterface.CurrentChallenge)) || solution == 0) - continue; - else if (m_isSubmitStale && !challenge.SequenceEqual(NetworkInterface.CurrentChallenge)) + if (!NetworkInterface.IsPool && NetworkInterface.IsChallengedSubmitted(challenge)) + return; // Solo mining should submit only 1 valid nonce per challange + + if (!m_isSubmitStale && !challenge.SequenceEqual(NetworkInterface.CurrentChallenge)) + return; + + if (m_isSubmitStale && !challenge.SequenceEqual(NetworkInterface.CurrentChallenge)) PrintMessage(platformType, platform, deviceID, "Warn", "Found stale solution, verifying..."); else PrintMessage(platformType, platform, deviceID, "Info", "Found solution, verifying..."); @@ -440,9 +455,9 @@ protected void SubmitSolutions(ulong[] solutions, byte[] challenge, string platf "Verification failed: invalid solution" + "\nChallenge: " + challengeString + "\nAddress: " + m_AddressString - + "\nSolution: " + nonceString + + "\nNonce: " + nonceString + "\nDigest: " + digestString - + "\nTarget: " + m_Target.HexValue); + + "\nTarget: " + Utils.Numerics.Byte32ArrayToHexString(m_Target.Value.ToByteArray(isUnsigned: true, isBigEndian: true))); } else { @@ -452,9 +467,9 @@ protected void SubmitSolutions(ulong[] solutions, byte[] challenge, string platf "Solution details..." + "\nChallenge: " + challengeString + "\nAddress: " + m_AddressString - + "\nSolution: " + nonceString + + "\nNonce: " + nonceString + "\nDigest: " + digestString - + "\nTarget: " + m_Target.HexValue); + + "\nTarget: " + Utils.Numerics.Byte32ArrayToHexString(m_Target.Value.ToByteArray(isUnsigned: true, isBigEndian: true))); NetworkInterface.SubmitSolution(m_AddressString, digest, diff --git a/SoliditySHA3Miner/Miner/Work.cs b/SoliditySHA3Miner/Miner/Work.cs index 9374149..bcd81dc 100644 --- a/SoliditySHA3Miner/Miner/Work.cs +++ b/SoliditySHA3Miner/Miner/Work.cs @@ -14,8 +14,6 @@ You may obtain a copy of the License at limitations under the License. */ -using Nethereum.Hex.HexConvertors.Extensions; -using System.Linq; using System.Runtime.CompilerServices; namespace SoliditySHA3Miner.Miner @@ -32,9 +30,10 @@ public static class Work public static string GetKingAddressString() { - if (KingAddress == null) return string.Empty; - - return HexByteConvertorExtensions.ToHex(KingAddress.ToArray(), prefix: true); + if (KingAddress == null) + return string.Empty; + else + return Utils.Numerics.Byte32ArrayToHexString(KingAddress, prefix: true); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/SoliditySHA3Miner/MiningGuide/GuideForEthOS.txt b/SoliditySHA3Miner/MiningGuide/GuideForEthOS.txt index e9f50b1..6b92faa 100644 --- a/SoliditySHA3Miner/MiningGuide/GuideForEthOS.txt +++ b/SoliditySHA3Miner/MiningGuide/GuideForEthOS.txt @@ -1,13 +1,16 @@ ### Before start mining on ethOS -1) Ensure CUDA 9.2 (Nvidia driver 396) is installed +0) Prequisites : -1a) Run the following commands (root/sudo required) - sudo install-nv-beta - -1b) This process will take about 5-10 minutes before rebooting itself. +0a) .Net Core Runtime + * Ethos => run script 'sudo ./install-deps-ethOS.sh' -2) Go to the extracted miner folder and run the following command to install miner dependancy +0b) Ensure CUDA 9.2 (Nvidia driver 396) is installed + * Run the following commands (root/sudo required) + sudo install-nv-beta + * This process will take about 5-10 minutes before rebooting itself. + +1) Go to the extracted miner folder and run the following command to install miner dependancy sudo ./install-deps-ethOS.sh -3) Follow 'GuideForPoolMining.txt' or 'GuideForSoloMining.txt' for essential miner setup +2) Follow 'GuideForPoolMining.txt', 'GuideForSoloMining.txt', or 'GuideForMasterSlaveMining.txt', for essential miner setup diff --git a/SoliditySHA3Miner/MiningGuide/GuideForHiveOS.txt b/SoliditySHA3Miner/MiningGuide/GuideForHiveOS.txt index 2a74adb..a8a82da 100644 --- a/SoliditySHA3Miner/MiningGuide/GuideForHiveOS.txt +++ b/SoliditySHA3Miner/MiningGuide/GuideForHiveOS.txt @@ -1,33 +1,37 @@ ### Before start mining on HiveOS -1) For NVIDIA cards, ensure CUDA 9.2 (NVIDIA driver 396) is installed +0) Prequisites : + +0a) For NVIDIA cards, ensure CUDA 9.2 (NVIDIA driver 396) is installed * Selfupgrade HiveOS to latest version (0.5-76 onwards) -2) Add new "Custom" miner to "Flight Sheet" (Coin: ETH, select your wallet but DO NOT select a pool yet) +1) Add new "Custom" miner to "Flight Sheet" (Coin: ETH, select your wallet but DO NOT select a pool yet) -3) Enter Flight Sheet name of your choice +2) Enter Flight Sheet name of your choice -4) Inside "Setup Miner Config": +3) Inside "Setup Miner Config": -4a) Enter the following in "Installation URL" - https://github.com/lwYeo/SoliditySHA3Miner/releases/download/2.1.0/SoliditySHA3Miner-2.1.0.tar.gz +3a) Enter the following in "Installation URL" + https://github.com/lwYeo/SoliditySHA3Miner/releases/download/2.2.0/SoliditySHA3Miner-2.2.0.tar.gz -4b) "Miner name" will be auto populated, you may leave it as is +3b) "Miner name" will be auto populated, you may leave it as is -4c) Leave "Hash algorithm" as blank +3c) Leave "Hash algorithm" as blank -4d) Enter the following in "Wallet and worker template" +3d) Enter the following in "Wallet and worker template" %WAL% -4e) Enter the pool of your choice in "Pool URL" (you may try http://mike.rs:8080) +3e) Enter the pool of your choice in "Pool URL" (you may try http://mike.rs:8080) -4f) Optionally, you may enter additional terminal arguments in "Extra config arguments" (Refer to Readme.txt for more information) +3f) Optionally, you may enter additional terminal arguments in "Extra config arguments" + * Refer to Readme.txt for more information + * You may refer to arguments used in 'GuideForMasterSlaveMining.txt' for master/slave configuration -4g) Apply the Flight Sheet to the worker rig. +3g) Apply the Flight Sheet to the worker rig. -4h) NOTE: for the first run, it will first take up to about 5 minutes to install dependencies +3h) NOTE: for the first run, it will first take up to about 5 minutes to install dependencies -4i) For rigs with older version of SoliditySHA3Miner, run the following commands in shell/terminal to upgrade SoliditySHA3Miner +3i) For rigs with older version of SoliditySHA3Miner, run the following commands in shell/terminal to upgrade SoliditySHA3Miner miner stop - custom-get https://github.com/lwYeo/SoliditySHA3Miner/releases/download/2.1.0/SoliditySHA3Miner-2.1.0.tar.gz -f + custom-get https://github.com/lwYeo/SoliditySHA3Miner/releases/download/2.2.0/SoliditySHA3Miner-2.2.0.tar.gz -f miner start diff --git a/SoliditySHA3Miner/MiningGuide/GuideForMasterSlaveMining.txt b/SoliditySHA3Miner/MiningGuide/GuideForMasterSlaveMining.txt new file mode 100644 index 0000000..07481c3 --- /dev/null +++ b/SoliditySHA3Miner/MiningGuide/GuideForMasterSlaveMining.txt @@ -0,0 +1,113 @@ +### How to start Master mining instance using SoliditySHA3Miner + +0) Prequisites : + +0a) .Net Core Runtime + * Windows => download and run [https://www.microsoft.com/net/download/thank-you/dotnet-runtime-2.1.6-windows-x64-installer] + * Ubuntu => run script 'sudo ./install-deps.sh' + * Ethos => run script 'sudo ./install-deps-ethOS.sh' + +0b) Nvidia driver (396, CUDA 9.2 onwards), and/or AMD driver. + +1) Clone and rename 0xbtcSolo/PoolMaster.bat/sh file and open the editor for the cloned file. + +2) You only need to edit the line that starts with 'dotnet' for launch parameters. + +3) Below are the following arguments that may/need to be changed : + +3a) allowIntel/AMD/CUDA= + * Set to true if the main instance is mining as well + +3b) networkUpdateInterval= + * Set the frequency (in miliseconds) to query latest information from the network. + * If using Infura, too low a value may get rate-limited or a temporary ban. + * Default value if left empty is 15000. + +3c) abiFile= + * If omitted, the '0xBTC.abi' file will be used by default + * Most tokens are compatible with '0xBTC.abi', most likely no need to change here + * Replace the value to the available filename that ends with '.abi' in the folder for the token interface you are mining. + +3c) contract= + * If omitted, 0xBTC contract address will be used by default. + * Replace the value with the following address if you are mining a different token (case-sensitive): + + 0xBTC 0xB6eD7644C69416d67B522e20bC294A9a9B405B31 + LIRA 0x49AAa160506F7e07E6C3F6cD6316b6866025cDcB + CLM 0xA38FcEdd23dE2191Dc27f9a0240ac170BE0A14fE + SEDO 0x0F00f1696218EaeFa2D2330Df3D6D1f94813b38f + PEPE 0xBC2AFc039d2BFa67d582aC181daB5BE17EC91f82 + 0xBCH 0xe5b9746dfCC2eF1054D47A451A77bb5f390c468d + 0xCATE 0x8F7DbF90E71285552a687097220E1035C2e87639 + 0xLTC 0x33D99EFc0C3cC4F93dA6931EC2CCcF19Ca874b6D + 0xGOLD 0x291DE53a16b76dfE28551Fd3335225F506dB8b82 + ATA 0xd72F60b2E7649bBC5835d25e30Ef917f04D9131c + KIWI 0x2BF91c18Cd4AE9C2f2858ef9FE518180F7B5096D + SKO 0xb3Dc3C839a02134f9932CbD60f3566C231cc90CC + + * If the token is not in the list above, I suggest that you might want to ask from the owner/moderator from their relavant Discord/Telegram/forums. + +4) If pool mining, below are the following arguments that may/need to be changed : (skip to 5 for solo mining) + +4a) pool= + * If omitted, 'http://mike.rs:8080' will be used as default. + * Please ask for the pool address:Port from the owner/moderator from their relavant Discord/Telegram/forums. + * Note that 'http(s)://' is required as a prefix. + * Pool address:Port might change over time, it is your responsibility to keep updated of the pool status. + +4b) address= + * If omitted, you are donating 100% to the developer. + * Replace the value with your own mining Ethereum address (42 characters long including '0x' prefix, case-sensitive). + +5) If solo mining, ensure that you have sufficient ETH stored in your mining address (ETH is required to mint tokens). + * Below are the following arguments that may/need to be changed : + +5a) gasToMine= + * If omitted, 5 GWei will be used. + * Replace the value with the amount of gas you prefer to mint a block with (decimals allowed, no alphabets). + * This value will override dynamic gas price if this value, whichever is higher. + +5b) gasApiURL= + * Required for dynamic gas price minting + * If using 'EthGasStation.info', fill the value with https://ethgasstation.info/json/ethgasAPI.json + +5c) gasApiPath= + * If using 'EthGasStation.info', fill the value with (without quotes) '$.safeLow' + +5d) gasApiMultiplier= + * If using 'EthGasStation.info', fill the value with 0.1 + +5e) gasApiOffset= + * Depends on how much you want to offset (decimals allowed, no alphabets). + +5f) privateKey= + * Replace the value with your own ETH private key (65 characters long excluding '0x' prefix) + * It is your own responsibility to keep your private ETH account safe. + * One suggestion is to create a disposable ETH mining account to mine with then transfer the tokens to your private account later. + +6) Ensure firewall settings has been set correctly. + +7) Save and run the '.bat/sh' file you have newly created, as Administrator/sudo. + + +### How to start Slave mining instance using SoliditySHA3Miner + +0) Prequisites : + +0a) .Net Core Runtime + * Windows => download and run [https://www.microsoft.com/net/download/thank-you/dotnet-runtime-2.1.6-windows-x64-installer] + * Ubuntu => run script 'sudo ./install-deps.sh' + * Ethos => run script 'sudo ./install-deps-ethOS.sh' + +0b) Nvidia driver (396, CUDA 9.2 onwards), and/or AMD driver. + +1 ) Update the following arguments that need to be changed in SoliditySHA3MinerSlave.bat/sh: + +1a) masterURL= + * Replace the URL (http://{IP}:{port}/) with your master instance. + +1b) slaveUpdateInterval= + * Set the frequency (in miliseconds) to query latest information from the master instance. + * Default value if left empty is 5000. + +2) Save and run SoliditySHA3MinerSlave.bat/sh. diff --git a/SoliditySHA3Miner/MiningGuide/GuideForPoolMining.txt b/SoliditySHA3Miner/MiningGuide/GuideForPoolMining.txt index ced26c8..0df7465 100644 --- a/SoliditySHA3Miner/MiningGuide/GuideForPoolMining.txt +++ b/SoliditySHA3Miner/MiningGuide/GuideForPoolMining.txt @@ -1,5 +1,14 @@ ### How to start Pool mining using SoliditySHA3Miner +0) Prequisites : + +0a) .Net Core Runtime + * Windows => download and run [https://www.microsoft.com/net/download/thank-you/dotnet-runtime-2.1.6-windows-x64-installer] + * Ubuntu => run script 'sudo ./install-deps.sh' + * Ethos => run script 'sudo ./install-deps-ethOS.sh' + +0b) Nvidia driver (396, CUDA 9.2 onwards), and/or AMD driver. + 1) Clone 0xbtcPool.bat/0xbtcPool.sh file and open the editor for the cloned file. * For ethOS, refer to 0xbtcPool-ethOS.sh/0xbtcPool-ethOS-screen.sh diff --git a/SoliditySHA3Miner/MiningGuide/GuideForSoloMining.txt b/SoliditySHA3Miner/MiningGuide/GuideForSoloMining.txt index 719bbb2..5c88700 100644 --- a/SoliditySHA3Miner/MiningGuide/GuideForSoloMining.txt +++ b/SoliditySHA3Miner/MiningGuide/GuideForSoloMining.txt @@ -1,5 +1,14 @@ ### How to start Solo mining using SoliditySHA3Miner +0) Prequisites : + +0a) .Net Core Runtime + * Windows => download and run [https://www.microsoft.com/net/download/thank-you/dotnet-runtime-2.1.6-windows-x64-installer] + * Ubuntu => run script 'sudo ./install-deps.sh' + * Ethos => run script 'sudo ./install-deps-ethOS.sh' + +0b) Nvidia driver (396, CUDA 9.2 onwards), and/or AMD driver. + 1) Ensure that you have sufficient ETH stored in your mining address (ETH is required to mint tokens). 2) Clone 0xbtcSolo.bat/0xbtcSolo.sh file and open the editor for the cloned file. diff --git a/SoliditySHA3Miner/NetworkInterface/INetworkInterface.cs b/SoliditySHA3Miner/NetworkInterface/INetworkInterface.cs index dd78b24..58b3ec2 100644 --- a/SoliditySHA3Miner/NetworkInterface/INetworkInterface.cs +++ b/SoliditySHA3Miner/NetworkInterface/INetworkInterface.cs @@ -22,34 +22,51 @@ namespace SoliditySHA3Miner.NetworkInterface public delegate void GetMiningParameterStatusEvent(INetworkInterface sender, bool success); public delegate void NewChallengeEvent(INetworkInterface sender, byte[] challenge, string address); public delegate void NewTargetEvent(INetworkInterface sender, HexBigInteger target); - public delegate void StopSolvingCurrentChallengeEvent(INetworkInterface sender); - + public delegate void NewDifficultyEvent(INetworkInterface sender, HexBigInteger difficulty); + public delegate void StopSolvingCurrentChallengeEvent(INetworkInterface sender, bool stopSolving = true); public delegate void GetTotalHashrateEvent(INetworkInterface sender, ref ulong totalHashrate); public interface INetworkInterface : IDisposable { - event GetMiningParameterStatusEvent OnGetMiningParameterStatus; - event NewChallengeEvent OnNewChallenge; - event NewTargetEvent OnNewTarget; - event StopSolvingCurrentChallengeEvent OnStopSolvingCurrentChallenge; - - event GetTotalHashrateEvent OnGetTotalHashrate; - bool IsPool { get; } + ulong SubmittedShares { get; } + ulong RejectedShares { get; } - ulong Difficulty { get; } + + HexBigInteger Difficulty { get; } + + HexBigInteger MaxTarget { get; } + int LastSubmitLatency { get; } + int Latency { get; } + string MinerAddress { get; } + string SubmitURL { get; } + byte[] CurrentChallenge { get; } - TimeSpan GetTimeLeftToSolveBlock(ulong hashrate); + HexBigInteger CurrentTarget { get; } + + event GetMiningParameterStatusEvent OnGetMiningParameterStatus; + event NewChallengeEvent OnNewChallenge; + event NewTargetEvent OnNewTarget; + event NewDifficultyEvent OnNewDifficulty; + event StopSolvingCurrentChallengeEvent OnStopSolvingCurrentChallenge; + event GetTotalHashrateEvent OnGetTotalHashrate; + + bool SubmitSolution(string address, byte[] digest, byte[] challenge, HexBigInteger difficulty, byte[] nonce, object sender); + ulong GetEffectiveHashrate(); + + TimeSpan GetTimeLeftToSolveBlock(ulong hashrate); + + bool IsChallengedSubmitted(byte[] challenge); + void ResetEffectiveHashrate(); - void UpdateMiningParameters(); - bool SubmitSolution(string address, byte[] digest, byte[] challenge, ulong difficulty, byte[] nonce, Miner.IMiner sender); + void UpdateMiningParameters(); } } \ No newline at end of file diff --git a/SoliditySHA3Miner/NetworkInterface/MiningParameters.cs b/SoliditySHA3Miner/NetworkInterface/MiningParameters.cs index 2b09c5c..dff2a17 100644 --- a/SoliditySHA3Miner/NetworkInterface/MiningParameters.cs +++ b/SoliditySHA3Miner/NetworkInterface/MiningParameters.cs @@ -15,7 +15,6 @@ limitations under the License. */ using Nethereum.Contracts; -using Nethereum.Hex.HexConvertors.Extensions; using Nethereum.Hex.HexTypes; using Newtonsoft.Json.Linq; using System; @@ -29,11 +28,19 @@ public class MiningParameters public HexBigInteger MiningDifficulty { get; private set; } public HexBigInteger MiningTarget { get; private set; } public HexBigInteger Challenge { get; private set; } + public HexBigInteger MaximumTarget { get; private set; } public byte[] MiningTargetByte32 { get; private set; } public byte[] ChallengeByte32 { get; private set; } + public byte[] MaximumTargetByte32 { get; private set; } + public byte[] EthAddressByte20 { get; private set; } + public byte[] KingAddressByte20 { get; private set; } public string EthAddress { get; private set; } public string MiningTargetByte32String { get; private set; } + public string MaximumTargetByte32String { get; private set; } public string ChallengeByte32String { get; private set; } + public string KingAddress { get; private set; } + public bool IsPause { get; private set; } + public bool IsPoolMining { get; private set; } public static MiningParameters GetSoloMiningParameters(string ethAddress, Function getMiningDifficulty, @@ -43,13 +50,25 @@ public static MiningParameters GetSoloMiningParameters(string ethAddress, return new MiningParameters(ethAddress, getMiningDifficulty, getMiningTarget, getChallengeNumber); } - public static MiningParameters GetPoolMiningParameters(string poolURL, - JObject getPoolEthAddress, - JObject getChallengeNumber, - JObject getMinimumShareDifficulty, - JObject getMinimumShareTarget) + public static MiningParameters GetMiningParameters(string masterURL, + JObject getEthAddress = null, + JObject getChallenge = null, + JObject getDifficulty = null, + JObject getTarget = null, + JObject getMaximumTarget = null, + JObject getKingAddress = null, + JObject getPause = null, + JObject getPoolMining = null) { - return new MiningParameters(poolURL, getPoolEthAddress, getChallengeNumber, getMinimumShareDifficulty, getMinimumShareTarget); + return new MiningParameters(masterURL, + getEthAddress: getEthAddress, + getChallenge: getChallenge, + getDifficulty: getDifficulty, + getTarget: getTarget, + getMaximumTarget: getMaximumTarget, + getKingAddress: getKingAddress, + getPause: getPause, + getPoolMining: getPoolMining); } private MiningParameters(string ethAddress, @@ -58,6 +77,9 @@ private MiningParameters(string ethAddress, Function getChallengeNumber) { EthAddress = ethAddress; + var ethAddressByte20 = (byte[])Array.CreateInstance(typeof(byte), Miner.MinerBase.ADDRESS_LENGTH); + Utils.Numerics.AddressStringToByte20Array(EthAddress, ref ethAddressByte20); + EthAddressByte20 = ethAddressByte20; var retryCount = 0; @@ -71,7 +93,7 @@ private MiningParameters(string ethAddress, { retryCount++; if (retryCount < 10) - Task.Delay(200).Wait(); + Task.Delay(500).Wait(); else throw new OperationCanceledException("Failed to get difficulty from network: " + ex.Message, ex.InnerException); } @@ -80,7 +102,7 @@ private MiningParameters(string ethAddress, try { MiningTarget = new HexBigInteger(getMiningTarget.CallAsync().Result); - MiningTargetByte32 = Utils.Numerics.FilterByte32Array(MiningTarget.Value.ToByteArray(littleEndian: false)); + MiningTargetByte32 = Utils.Numerics.FilterByte32Array(MiningTarget.Value.ToByteArray(isUnsigned: true, isBigEndian: true)); MiningTargetByte32String = Utils.Numerics.Byte32ArrayToHexString(MiningTargetByte32); break; } @@ -88,7 +110,7 @@ private MiningParameters(string ethAddress, { retryCount++; if (retryCount < 10) - Task.Delay(200).Wait(); + Task.Delay(500).Wait(); else throw new OperationCanceledException("Failed to get target from network: " + ex.Message, ex.InnerException); } @@ -97,48 +119,55 @@ private MiningParameters(string ethAddress, try { ChallengeByte32 = Utils.Numerics.FilterByte32Array(getChallengeNumber.CallAsync().Result); - Challenge = new HexBigInteger(HexByteConvertorExtensions.ToHex(ChallengeByte32, prefix: true)); ChallengeByte32String = Utils.Numerics.Byte32ArrayToHexString(ChallengeByte32); + Challenge = new HexBigInteger(new BigInteger(ChallengeByte32, isUnsigned: true, isBigEndian: true)); break; } catch (Exception ex) { retryCount++; if (retryCount < 10) - Task.Delay(200).Wait(); + Task.Delay(500).Wait(); else throw new OperationCanceledException("Failed to get challenge from network: " + ex.Message, ex.InnerException); } } - private MiningParameters(string poolURL, - JObject getPoolEthAddress, - JObject getChallengeNumber, - JObject getMinimumShareDifficulty, - JObject getMinimumShareTarget) + private MiningParameters(string url, + JObject getEthAddress = null, + JObject getChallenge = null, + JObject getDifficulty = null, + JObject getTarget = null, + JObject getMaximumTarget = null, + JObject getKingAddress = null, + JObject getPause = null, + JObject getPoolMining = null) { var retryCount = 0; - while (true) + while (getEthAddress != null) try { - EthAddress = Utils.Json.InvokeJObjectRPC(poolURL, getPoolEthAddress).SelectToken("$.result").Value(); + EthAddress = Utils.Json.InvokeJObjectRPC(url, getEthAddress).SelectToken("$.result").Value(); + var ethAddressByte20 = (byte[])Array.CreateInstance(typeof(byte), Miner.MinerBase.ADDRESS_LENGTH); + Utils.Numerics.AddressStringToByte20Array(EthAddress, ref ethAddressByte20); + EthAddressByte20 = ethAddressByte20; break; } catch (Exception ex) { retryCount++; if (retryCount < 10) - Task.Delay(200).Wait(); + Task.Delay(500).Wait(); else - throw new OperationCanceledException("Failed to get pool address: " + ex.Message, ex.InnerException); + throw new OperationCanceledException("Failed to get address: " + ex.Message, ex.InnerException); } - while (true) + while (getChallenge != null) try { - Challenge = new HexBigInteger(Utils.Json.InvokeJObjectRPC(poolURL, getChallengeNumber).SelectToken("$.result").Value()); - ChallengeByte32 = Utils.Numerics.FilterByte32Array(Challenge.Value.ToByteArray(littleEndian: false)); + Challenge = new HexBigInteger(Utils.Json.InvokeJObjectRPC(url, getChallenge).SelectToken("$.result").Value()); + ChallengeByte32 = Utils.Numerics.FilterByte32Array(Challenge.Value.ToByteArray(isUnsigned: true, isBigEndian: true)); ChallengeByte32String = Utils.Numerics.Byte32ArrayToHexString(ChallengeByte32); break; } @@ -146,41 +175,126 @@ private MiningParameters(string poolURL, { retryCount++; if (retryCount < 10) - Task.Delay(200).Wait(); + Task.Delay(500).Wait(); else - throw new OperationCanceledException("Failed to get pool challenge: " + ex.Message, ex.InnerException); + throw new OperationCanceledException("Failed to get challenge: " + ex.Message, ex.InnerException); } - while (true) + while (getDifficulty != null) try { - MiningDifficulty = new HexBigInteger(Utils.Json.InvokeJObjectRPC(poolURL, getMinimumShareDifficulty).SelectToken("$.result").Value()); + var rawDifficulty = Utils.Json.InvokeJObjectRPC(url, getDifficulty).SelectToken("$.result").Value(); + if (rawDifficulty.StartsWith("0x")) + MiningDifficulty = new HexBigInteger(new BigInteger(Utils.Numerics.HexStringToByte32Array(rawDifficulty), isUnsigned: true, isBigEndian: true)); + else + MiningDifficulty = new HexBigInteger(BigInteger.Parse(rawDifficulty)); break; } catch (Exception ex) { retryCount++; if (retryCount < 10) - Task.Delay(200).Wait(); + Task.Delay(500).Wait(); else - throw new OperationCanceledException("Failed to get pool difficulty: " + ex.Message, ex.InnerException); + throw new OperationCanceledException("Failed to get difficulty: " + ex.Message, ex.InnerException); } - while (true) + while (getTarget != null) try { - MiningTarget = new HexBigInteger(BigInteger.Parse(Utils.Json.InvokeJObjectRPC(poolURL, getMinimumShareTarget).SelectToken("$.result").Value())); - MiningTargetByte32 = Utils.Numerics.FilterByte32Array(MiningTarget.Value.ToByteArray(littleEndian: false)); - MiningTargetByte32String = Utils.Numerics.Byte32ArrayToHexString(MiningTargetByte32); + var rawMiningTarget = Utils.Json.InvokeJObjectRPC(url, getTarget).SelectToken("$.result").Value(); + if (rawMiningTarget.StartsWith("0x")) + { + MiningTargetByte32String = rawMiningTarget; + MiningTargetByte32 = Utils.Numerics.HexStringToByte32Array(rawMiningTarget); + MiningTarget = new HexBigInteger(new BigInteger(MiningTargetByte32, isUnsigned: true, isBigEndian: true)); + } + else // currently pool returns in decimal format + { + MiningTarget = new HexBigInteger(BigInteger.Parse(rawMiningTarget)); + MiningTargetByte32 = Utils.Numerics.FilterByte32Array(MiningTarget.Value.ToByteArray(isUnsigned: true, isBigEndian: true)); + MiningTargetByte32String = Utils.Numerics.Byte32ArrayToHexString(MiningTargetByte32); + } + break; + } + catch (Exception ex) + { + retryCount++; + if (retryCount < 10) + Task.Delay(500).Wait(); + else + throw new OperationCanceledException("Failed to get target: " + ex.Message, ex.InnerException); + } + + while (getMaximumTarget != null) + try + { + MaximumTargetByte32String = Utils.Json.InvokeJObjectRPC(url, getMaximumTarget).SelectToken("$.result").Value(); + MaximumTargetByte32 = Utils.Numerics.HexStringToByte32Array(MaximumTargetByte32String); + MaximumTarget = new HexBigInteger(new BigInteger(MaximumTargetByte32, isUnsigned: true, isBigEndian: true)); + break; + } + catch (Exception ex) + { + retryCount++; + if (retryCount < 10) + Task.Delay(500).Wait(); + else + throw new OperationCanceledException("Failed to get maximum target: " + ex.Message, ex.InnerException); + } + + while (getKingAddress != null) + try + { + KingAddress = Utils.Json.InvokeJObjectRPC(url, getKingAddress).SelectToken("$.result").Value(); + + if (!string.IsNullOrWhiteSpace(KingAddress)) + { + var kingAddressByte20 = (byte[])Array.CreateInstance(typeof(byte), Miner.MinerBase.ADDRESS_LENGTH); + Utils.Numerics.AddressStringToByte20Array(KingAddress, ref kingAddressByte20, "king address"); + KingAddressByte20 = kingAddressByte20; + } + break; + } + catch (Exception ex) + { + retryCount++; + if (retryCount < 10) + Task.Delay(500).Wait(); + else + throw new OperationCanceledException("Failed to get king address: " + ex.Message, ex.InnerException); + } + + while (getPause != null) + try + { + var pauseString = Utils.Json.InvokeJObjectRPC(url, getPause).SelectToken("$.result").Value(); + IsPause = bool.Parse(pauseString); + break; + } + catch (Exception ex) + { + retryCount++; + if (retryCount < 10) + Task.Delay(500).Wait(); + else + throw new OperationCanceledException("Failed to get pause: " + ex.Message, ex.InnerException); + } + + while (getPoolMining != null) + try + { + var poolMiningString = Utils.Json.InvokeJObjectRPC(url, getPoolMining).SelectToken("$.result").Value(); + IsPoolMining = bool.Parse(poolMiningString); break; } catch (Exception ex) { retryCount++; if (retryCount < 10) - Task.Delay(200).Wait(); + Task.Delay(500).Wait(); else - throw new OperationCanceledException("Failed to get pool target: " + ex.Message, ex.InnerException); + throw new OperationCanceledException("Failed to get pool mining: " + ex.Message, ex.InnerException); } } } diff --git a/SoliditySHA3Miner/NetworkInterface/NetworkInterfaceBase.cs b/SoliditySHA3Miner/NetworkInterface/NetworkInterfaceBase.cs new file mode 100644 index 0000000..8e4537a --- /dev/null +++ b/SoliditySHA3Miner/NetworkInterface/NetworkInterfaceBase.cs @@ -0,0 +1,174 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Timers; +using Nethereum.Hex.HexTypes; + +namespace SoliditySHA3Miner.NetworkInterface +{ + public abstract class NetworkInterfaceBase : INetworkInterface + { + protected const int MAX_SUBMIT_DTM_COUNT = 50; + protected readonly List m_submitDateTimeList; + protected readonly List m_submittedChallengeList; + protected readonly BigInteger UInt256_MaxValue = BigInteger.Pow(2, 256); + protected readonly int m_updateInterval; + + protected DateTime m_challengeReceiveDateTime; + protected MiningParameters m_lastParameters; + protected Timer m_updateMinerTimer; + protected Timer m_hashPrintTimer; + + #region INetworkInterface + + public abstract bool IsPool { get; } + + public ulong SubmittedShares { get; protected set; } + + public ulong RejectedShares { get; protected set; } + + public HexBigInteger Difficulty { get; protected set; } + + public HexBigInteger MaxTarget { get; protected set; } + + public int LastSubmitLatency { get; protected set; } + + public int Latency { get; protected set; } + + public string MinerAddress { get; protected set; } + + public virtual string SubmitURL { get; protected set; } + + public byte[] CurrentChallenge { get; protected set; } + + public HexBigInteger CurrentTarget { get; protected set; } + + public abstract event GetMiningParameterStatusEvent OnGetMiningParameterStatus; + public abstract event NewChallengeEvent OnNewChallenge; + public abstract event NewTargetEvent OnNewTarget; + public abstract event NewDifficultyEvent OnNewDifficulty; + public abstract event StopSolvingCurrentChallengeEvent OnStopSolvingCurrentChallenge; + public abstract event GetTotalHashrateEvent OnGetTotalHashrate; + + public abstract bool SubmitSolution(string address, byte[] digest, byte[] challenge, HexBigInteger difficulty, byte[] nonce, object sender); + + public virtual void Dispose() // Pool and Web3 Interface has more to dispose + { + if (m_submitDateTimeList != null) + m_submitDateTimeList.Clear(); + + if (m_submittedChallengeList != null) + m_submittedChallengeList.Clear(); + + if (m_updateMinerTimer != null) + try + { + m_updateMinerTimer.Stop(); + m_updateMinerTimer.Elapsed -= UpdateMinerTimer_Elapsed; + m_updateMinerTimer.Dispose(); + } + catch { } + m_updateMinerTimer = null; + + if (m_hashPrintTimer != null) + try + { + m_hashPrintTimer.Stop(); + m_hashPrintTimer.Elapsed -= HashPrintTimer_Elapsed; + m_hashPrintTimer.Dispose(); + } + catch { } + m_hashPrintTimer = null; + } + + /// + /// Since a single hash is a random number between 1 and 2^256, and difficulty [1] target = 2^234 + /// Then we can find difficulty [N] target = 2^234 / N + /// Hence, # of hashes to find block with difficulty [N] = N * 2^256 / 2^234 + /// Which simplifies to # of hashes to find block difficulty [N] = N * 2^22 + /// Time to find block in seconds with difficulty [N] = N * 2^22 / hashes per second + /// Hashes per second with difficulty [N] and time to find block [T] = N * 2^22 / T + /// + public ulong GetEffectiveHashrate() + { + var hashrate = 0ul; + + if (m_submitDateTimeList.Count > 1) + { + var avgSolveTime = (ulong)((DateTime.Now - m_submitDateTimeList.First()).TotalSeconds / m_submitDateTimeList.Count - 1); + hashrate = (ulong)(Difficulty.Value * UInt256_MaxValue / MaxTarget.Value / new BigInteger(avgSolveTime)); + } + + return hashrate; + } + + /// + /// Since a single hash is a random number between 1 and 2^256, and difficulty [1] target = 2^234 + /// Then we can find difficulty [N] target = 2^234 / N + /// Hence, # of hashes to find block with difficulty [N] = N * 2^256 / 2^234 + /// Which simplifies to # of hashes to find block difficulty [N] = N * 2^22 + /// Time to find block in seconds with difficulty [N] = N * 2^22 / hashes per second + /// + public TimeSpan GetTimeLeftToSolveBlock(ulong hashrate) + { + if (MaxTarget == null || MaxTarget.Value == 0 || Difficulty == null || Difficulty.Value == 0 || hashrate == 0 || m_challengeReceiveDateTime == DateTime.MinValue) + return TimeSpan.Zero; + + var timeToSolveBlock = new BigInteger(Difficulty) * UInt256_MaxValue / MaxTarget.Value / new BigInteger(hashrate); + + var secondsLeftToSolveBlock = timeToSolveBlock - (long)(DateTime.Now - m_challengeReceiveDateTime).TotalSeconds; + + return (secondsLeftToSolveBlock > (long)TimeSpan.MaxValue.TotalSeconds) + ? TimeSpan.MaxValue + : TimeSpan.FromSeconds((long)secondsLeftToSolveBlock); + } + + public bool IsChallengedSubmitted(byte[] challenge) + { + return m_submittedChallengeList.Any(s => challenge.SequenceEqual(s)); + } + + public void ResetEffectiveHashrate() + { + m_submitDateTimeList.Clear(); + m_submitDateTimeList.Add(DateTime.Now); + } + + public void UpdateMiningParameters() + { + UpdateMinerTimer_Elapsed(this, null); + + if (m_updateMinerTimer == null && m_updateInterval > 0) + { + m_updateMinerTimer = new Timer(m_updateInterval); + m_updateMinerTimer.Elapsed += UpdateMinerTimer_Elapsed; + m_updateMinerTimer.Start(); + } + } + + #endregion + + public NetworkInterfaceBase(int updateInterval, int hashratePrintInterval) + { + m_submittedChallengeList = new List(); + m_submitDateTimeList = new List(MAX_SUBMIT_DTM_COUNT + 1); + m_updateInterval = updateInterval; + + Difficulty = new HexBigInteger(0); + SubmittedShares = 0; + RejectedShares = 0; + LastSubmitLatency = -1; + Latency = -1; + + if (hashratePrintInterval > 0) + { + m_hashPrintTimer = new Timer(hashratePrintInterval); + m_hashPrintTimer.Elapsed += HashPrintTimer_Elapsed; + } + } + + protected abstract void UpdateMinerTimer_Elapsed(object sender, ElapsedEventArgs e); + protected abstract void HashPrintTimer_Elapsed(object sender, ElapsedEventArgs e); + } +} diff --git a/SoliditySHA3Miner/NetworkInterface/PoolInterface.cs b/SoliditySHA3Miner/NetworkInterface/PoolInterface.cs index 2c5de8d..191ef88 100644 --- a/SoliditySHA3Miner/NetworkInterface/PoolInterface.cs +++ b/SoliditySHA3Miner/NetworkInterface/PoolInterface.cs @@ -15,10 +15,9 @@ limitations under the License. */ using Nethereum.Hex.HexTypes; +using Nethereum.Util; using Newtonsoft.Json.Linq; using System; -using System.Collections.Generic; -using System.Globalization; using System.Linq; using System.Net.NetworkInformation; using System.Numerics; @@ -28,120 +27,302 @@ limitations under the License. namespace SoliditySHA3Miner.NetworkInterface { - public class PoolInterface : INetworkInterface + public class PoolInterface : NetworkInterfaceBase { - private readonly BigInteger uint256_MaxValue = BigInteger.Pow(2, 256); - private HexBigInteger m_maxTarget; - private DateTime m_challengeReceiveDateTime; - - private const int MAX_SUBMIT_DTM_COUNT = 50; - private readonly List m_submitDateTimeList; + public bool IsSecondaryPool { get; } + public PoolInterface SecondaryPool { get; } - private readonly string s_PoolURL; - private readonly ulong m_customDifficulity; + private readonly HexBigInteger m_customDifficulity; private readonly int m_maxScanRetry; - private readonly int m_updateInterval; private bool m_isGetMiningParameters; - private Timer m_updateMinerTimer; - private Timer m_hashPrintTimer; private bool m_runFailover; private int m_retryCount; - private MiningParameters m_lastParameters; + private string m_PoolURL; - public event GetMiningParameterStatusEvent OnGetMiningParameterStatus; - public event NewChallengeEvent OnNewChallenge; - public event NewTargetEvent OnNewTarget; - -# pragma warning disable 67 // Unused event - public event StopSolvingCurrentChallengeEvent OnStopSolvingCurrentChallenge; -# pragma warning restore 67 + #region NetworkInterfaceBase - public event GetTotalHashrateEvent OnGetTotalHashrate; + public override bool IsPool => true; - public bool IsPool => true; - public bool IsSecondaryPool { get; } - public ulong SubmittedShares { get; private set; } - public ulong RejectedShares { get; private set; } - public PoolInterface SecondaryPool { get; } - public ulong Difficulty { get; private set; } - public int LastSubmitLatency { get; private set; } - public int Latency { get; private set; } - public string MinerAddress { get; } - - public string SubmitURL + public override string SubmitURL { get { return m_runFailover ? SecondaryPool.SubmitURL - : s_PoolURL; + : m_PoolURL; } + protected set => m_PoolURL = value; } - public byte[] CurrentChallenge { get; private set; } - - public PoolInterface(string minerAddress, string poolURL, int maxScanRetry, int updateInterval, int hashratePrintInterval, - ulong customDifficulity, bool isSecondary, HexBigInteger maxTarget, PoolInterface secondaryPool = null) - { - m_retryCount = 0; - m_maxScanRetry = maxScanRetry; - m_customDifficulity = customDifficulity; - m_maxTarget = maxTarget; - m_updateInterval = updateInterval; - m_isGetMiningParameters = false; - LastSubmitLatency = -1; - Latency = -1; - SecondaryPool = secondaryPool; - IsSecondaryPool = isSecondary; + public override event GetMiningParameterStatusEvent OnGetMiningParameterStatus; + public override event NewChallengeEvent OnNewChallenge; + public override event NewTargetEvent OnNewTarget; + public override event NewDifficultyEvent OnNewDifficulty; - if (m_customDifficulity > 0) - Difficulty = m_customDifficulity; +# pragma warning disable 67 // Unused event + public override event StopSolvingCurrentChallengeEvent OnStopSolvingCurrentChallenge; +# pragma warning restore 67 - MinerAddress = minerAddress; - s_PoolURL = poolURL; - SubmittedShares = 0ul; - RejectedShares = 0ul; + public override event GetTotalHashrateEvent OnGetTotalHashrate; - m_submitDateTimeList = new List(MAX_SUBMIT_DTM_COUNT + 1); + public override bool SubmitSolution(string address, byte[] digest, byte[] challenge, HexBigInteger difficulty, byte[] nonce, object sender) + { + m_challengeReceiveDateTime = DateTime.Now; + var startSubmitDateTime = DateTime.Now; - if (hashratePrintInterval > 0) + if (m_runFailover) { - m_hashPrintTimer = new Timer(hashratePrintInterval); - m_hashPrintTimer.Elapsed += HashPrintTimer_Elapsed; - m_hashPrintTimer.Start(); + if (SecondaryPool.SubmitSolution(address, digest, challenge, difficulty, nonce, sender)) + { + LastSubmitLatency = (int)((DateTime.Now - startSubmitDateTime).TotalMilliseconds); + Program.Print(string.Format("[INFO] Submission roundtrip latency: {0}ms", LastSubmitLatency)); + + if (m_submitDateTimeList.Count >= MAX_SUBMIT_DTM_COUNT) m_submitDateTimeList.RemoveAt(0); + m_submitDateTimeList.Add(DateTime.Now); + } + return false; } + + bool success = false, submitted = false; + int retryCount = 0, maxRetries = 10; + var devFee = (long)Math.Round(100 / Math.Abs(DevFee.UserPercent)); + const long devShareOffset = 10; + do + { + try + { + lock (this) + { + if (SubmittedShares == ulong.MaxValue) + { + SubmittedShares = 0; + RejectedShares = 0; + } + var minerAddress = (((long)(SubmittedShares - RejectedShares) - devShareOffset) % devFee) == 0 + ? DevFee.Address + : MinerAddress; + + JObject submitShare = GetPoolParameter("submitShare", + Utils.Numerics.Byte32ArrayToHexString(nonce), + minerAddress, + Utils.Numerics.Byte32ArrayToHexString(digest), + difficulty.Value.ToString(), + Utils.Numerics.Byte32ArrayToHexString(challenge), + m_customDifficulity.Value > 0 ? "true" : "false", + Miner.Work.GetKingAddressString()); + + var response = Utils.Json.InvokeJObjectRPC(m_PoolURL, submitShare); + + LastSubmitLatency = (int)((DateTime.Now - startSubmitDateTime).TotalMilliseconds); + + if (!IsChallengedSubmitted(challenge)) + { + m_submittedChallengeList.Insert(0, challenge.ToArray()); + if (m_submittedChallengeList.Count > 100) m_submittedChallengeList.Remove(m_submittedChallengeList.Last()); + } + + var result = response.SelectToken("$.result")?.Value(); + + success = (result ?? string.Empty).Equals("true", StringComparison.OrdinalIgnoreCase); + SubmittedShares++; + submitted = true; + + Program.Print(string.Format("[INFO] {0} [{1}] submitted to {2} pool: {3} ({4}ms)", + (minerAddress == DevFee.Address ? "Dev. fee share" : "Miner share"), + SubmittedShares, + IsSecondaryPool ? "secondary" : "primary", + (success ? "success" : "failed"), + LastSubmitLatency)); + if (success) + { + if (m_submitDateTimeList.Count > MAX_SUBMIT_DTM_COUNT) + m_submitDateTimeList.RemoveAt(0); + + m_submitDateTimeList.Add(DateTime.Now); + } + else + { + RejectedShares++; + UpdateMiningParameters(); + } +#if DEBUG + Program.Print(submitShare.ToString()); + Program.Print(response.ToString()); +#endif + } + } + catch (Exception ex) + { + retryCount++; + + if (retryCount >= Math.Min(maxRetries, 3)) + HandleException(ex); + + if (retryCount < maxRetries) + Task.Delay(500); + } + } while (!submitted && retryCount < maxRetries); + + return success; } - public void Dispose() + public override void Dispose() { - if (SecondaryPool != null) SecondaryPool.Dispose(); + base.Dispose(); - if (m_submitDateTimeList != null) - m_submitDateTimeList.Clear(); + if (SecondaryPool != null) + SecondaryPool.Dispose(); + } - if (m_updateMinerTimer != null) + protected override void HashPrintTimer_Elapsed(object sender, ElapsedEventArgs e) + { + var totalHashRate = 0ul; + try + { + OnGetTotalHashrate(this, ref totalHashRate); + Program.Print(string.Format("[INFO] Total Hashrate: {0} MH/s (Effective) / {1} MH/s (Local)", + GetEffectiveHashrate() / 1000000.0f, totalHashRate / 1000000.0f)); + } + catch (Exception) { try { - m_updateMinerTimer.Elapsed -= UpdateMinerTimer_Elapsed; - m_updateMinerTimer.Stop(); - m_updateMinerTimer.Dispose(); + totalHashRate = GetEffectiveHashrate(); + Program.Print(string.Format("[INFO] Effective Hashrate: {0} MH/s", totalHashRate / 1000000.0f)); } catch { } - m_updateMinerTimer = null; } + try + { + if (totalHashRate > 0) + { + var timeLeftToSolveBlock = GetTimeLeftToSolveBlock(totalHashRate); - if (m_hashPrintTimer != null) + if (timeLeftToSolveBlock.TotalSeconds < 0) + { + Program.Print(string.Format("[INFO] Estimated time left to solution: -({0}d {1}h {2}m {3}s)", + Math.Abs(timeLeftToSolveBlock.Days), + Math.Abs(timeLeftToSolveBlock.Hours), + Math.Abs(timeLeftToSolveBlock.Minutes), + Math.Abs(timeLeftToSolveBlock.Seconds))); + } + else + { + Program.Print(string.Format("[INFO] Estimated time left to solution: {0}d {1}h {2}m {3}s", + Math.Abs(timeLeftToSolveBlock.Days), + Math.Abs(timeLeftToSolveBlock.Hours), + Math.Abs(timeLeftToSolveBlock.Minutes), + Math.Abs(timeLeftToSolveBlock.Seconds))); + } + } + } + catch { } + } + + protected override void UpdateMinerTimer_Elapsed(object sender, ElapsedEventArgs e) + { + if (m_isGetMiningParameters) return; + try { - try + m_isGetMiningParameters = true; + var miningParameters = GetMiningParameters(); + if (miningParameters == null) { - m_hashPrintTimer.Elapsed -= HashPrintTimer_Elapsed; - m_hashPrintTimer.Stop(); - m_hashPrintTimer.Dispose(); + OnGetMiningParameterStatus(this, false); + return; } - catch { } - m_hashPrintTimer = null; + + CurrentChallenge = miningParameters.ChallengeByte32; + + if (m_lastParameters == null || miningParameters.Challenge.Value != m_lastParameters.Challenge.Value) + { + Program.Print(string.Format("[INFO] New challenge detected {0}...", miningParameters.ChallengeByte32String)); + OnNewChallenge(this, miningParameters.ChallengeByte32, miningParameters.EthAddress); + + if (m_challengeReceiveDateTime == DateTime.MinValue) + m_challengeReceiveDateTime = DateTime.Now; + } + + if (m_customDifficulity.Value == 0) + { + if (m_lastParameters == null || miningParameters.MiningTarget.Value != m_lastParameters.MiningTarget.Value) + { + Program.Print(string.Format("[INFO] New target detected {0}...", miningParameters.MiningTargetByte32String)); + OnNewTarget(this, miningParameters.MiningTarget); + CurrentTarget = miningParameters.MiningTarget; + } + + if (m_lastParameters == null || miningParameters.MiningDifficulty.Value != m_lastParameters.MiningDifficulty.Value) + { + Program.Print(string.Format("[INFO] New difficulity detected ({0})...", miningParameters.MiningDifficulty.Value)); + OnNewDifficulty?.Invoke(this, miningParameters.MiningDifficulty); + Difficulty = miningParameters.MiningDifficulty; + + // Actual difficulty should have decimals + var calculatedDifficulty = BigDecimal.Exp(BigInteger.Log(MaxTarget.Value) - BigInteger.Log(miningParameters.MiningTarget.Value)); + var calculatedDifficultyBigInteger = BigInteger.Parse(calculatedDifficulty.ToString().Split(",.".ToCharArray())[0]); + + try // Perform rounding + { + if (uint.Parse(calculatedDifficulty.ToString().Split(",.".ToCharArray())[1].First().ToString()) >= 5) + calculatedDifficultyBigInteger++; + } + catch { } + + if (Difficulty.Value != calculatedDifficultyBigInteger) + { + Difficulty = new HexBigInteger(calculatedDifficultyBigInteger); + var expValue = BigInteger.Log10(calculatedDifficultyBigInteger); + var calculatedTarget = BigInteger.Parse( + (BigDecimal.Parse(MaxTarget.Value.ToString()) * BigDecimal.Pow(10, expValue) / (calculatedDifficulty * BigDecimal.Pow(10, expValue))). + ToString().Split(",.".ToCharArray())[0]); + var calculatedTargetHex = new HexBigInteger(calculatedTarget); + + Program.Print(string.Format("[INFO] Update target 0x{0}...", calculatedTarget.ToString("x64"))); + OnNewTarget(this, calculatedTargetHex); + CurrentTarget = calculatedTargetHex; + } + } + } + else + { + Difficulty = new HexBigInteger(m_customDifficulity); + var calculatedTarget = MaxTarget.Value / m_customDifficulity; + var newTarget = new HexBigInteger(calculatedTarget); + + OnNewTarget(this, newTarget); + } + + m_lastParameters = miningParameters; + OnGetMiningParameterStatus(this, true); + } + catch (Exception ex) + { + HandleException(ex); } + finally { m_isGetMiningParameters = false; } + } + + #endregion + + public PoolInterface(string minerAddress, string poolURL, int maxScanRetry, int updateInterval, int hashratePrintInterval, + BigInteger customDifficulity, bool isSecondary, HexBigInteger maxTarget, PoolInterface secondaryPool = null) + : base(updateInterval, hashratePrintInterval) + { + m_retryCount = 0; + m_maxScanRetry = maxScanRetry; + m_PoolURL = poolURL; + m_isGetMiningParameters = false; + m_customDifficulity = new HexBigInteger(customDifficulity); + + Difficulty = new HexBigInteger((customDifficulity > 0) ? customDifficulity : 0); + SecondaryPool = secondaryPool; + IsSecondaryPool = isSecondary; + MaxTarget = maxTarget; + MinerAddress = minerAddress; + + if (m_hashPrintTimer != null) + m_hashPrintTimer.Start(); } private JObject GetPoolParameter(string method, params string[] parameters) @@ -157,14 +338,16 @@ private JObject GetPoolParameter(string method, params string[] parameters) if (parameters.Length > 0) { JArray props = new JArray(); - foreach (var p in parameters) { props.Add(p); } + foreach (var p in parameters) + props.Add(p); + paramObject.Add(new JProperty("params", props)); } } return paramObject; } - public MiningParameters GetMiningParameters() + private MiningParameters GetMiningParameters() { Program.Print(string.Format("[INFO] Checking latest parameters from {0} pool...", IsSecondaryPool ? "secondary" : "primary")); @@ -177,23 +360,17 @@ public MiningParameters GetMiningParameters() var startTime = DateTime.Now; try { - return MiningParameters.GetPoolMiningParameters(s_PoolURL, getPoolEthAddress, getPoolChallengeNumber, - getPoolMinimumShareDifficulty, getPoolMinimumShareTarget); + return MiningParameters.GetMiningParameters(m_PoolURL, + getEthAddress: getPoolEthAddress, + getChallenge: getPoolChallengeNumber, + getDifficulty: getPoolMinimumShareDifficulty, + getTarget: getPoolMinimumShareTarget); } catch (Exception ex) { m_retryCount++; success = false; - var errorMessage = new StringBuilder("[ERROR] " + ex.Message); - - var innerEx = ex.InnerException; - while (innerEx != null) - { - errorMessage.AppendFormat("\n {0}", innerEx.Message); - innerEx = innerEx.InnerException; - } - - Program.Print(errorMessage.ToString()); + HandleException(ex); } finally { @@ -205,7 +382,7 @@ public MiningParameters GetMiningParameters() { using (var ping = new Ping()) { - var poolURL = s_PoolURL.Contains("://") ? s_PoolURL.Split(new string[] { "://" }, StringSplitOptions.None)[1] : s_PoolURL; + var poolURL = m_PoolURL.Contains("://") ? m_PoolURL.Split(new string[] { "://" }, StringSplitOptions.None)[1] : m_PoolURL; try { var response = ping.Send(poolURL); @@ -250,246 +427,22 @@ public MiningParameters GetMiningParameters() return null; } - private void HashPrintTimer_Elapsed(object sender, ElapsedEventArgs e) - { - var totalHashRate = 0ul; - OnGetTotalHashrate(this, ref totalHashRate); - Program.Print(string.Format("[INFO] Total Hashrate: {0} MH/s (Effective) / {1} MH/s (Local)", - GetEffectiveHashrate() / 1000000.0f, totalHashRate / 1000000.0f)); - - var timeLeftToSolveBlock = GetTimeLeftToSolveBlock(totalHashRate); - - if (timeLeftToSolveBlock.TotalSeconds < 0) - { - Program.Print(string.Format("[INFO] Estimated time left to solution: -({0}d {1}h {2}m {3}s)", - Math.Abs(timeLeftToSolveBlock.Days), - Math.Abs(timeLeftToSolveBlock.Hours), - Math.Abs(timeLeftToSolveBlock.Minutes), - Math.Abs(timeLeftToSolveBlock.Seconds))); - } - else - { - Program.Print(string.Format("[INFO] Estimated time left to solution: {0}d {1}h {2}m {3}s", - Math.Abs(timeLeftToSolveBlock.Days), - Math.Abs(timeLeftToSolveBlock.Hours), - Math.Abs(timeLeftToSolveBlock.Minutes), - Math.Abs(timeLeftToSolveBlock.Seconds))); - } - } - - private void UpdateMinerTimer_Elapsed(object sender, ElapsedEventArgs e) - { - if (m_isGetMiningParameters) return; - try - { - m_isGetMiningParameters = true; - var miningParameters = GetMiningParameters(); - if (miningParameters == null) - { - OnGetMiningParameterStatus(this, false); - return; - } - - CurrentChallenge = miningParameters.ChallengeByte32; - - if (m_lastParameters == null || miningParameters.Challenge.Value != m_lastParameters.Challenge.Value) - { - Program.Print(string.Format("[INFO] New challenge detected {0}...", miningParameters.ChallengeByte32String)); - OnNewChallenge(this, miningParameters.ChallengeByte32, miningParameters.EthAddress); - - if (m_challengeReceiveDateTime == DateTime.MinValue) - m_challengeReceiveDateTime = DateTime.Now; - } - - if (m_customDifficulity == 0) - { - if (m_lastParameters == null || miningParameters.MiningTarget.Value != m_lastParameters.MiningTarget.Value) - { - Program.Print(string.Format("[INFO] New target detected {0}...", miningParameters.MiningTargetByte32String)); - OnNewTarget(this, miningParameters.MiningTarget); - } - - if (m_lastParameters == null || miningParameters.MiningDifficulty.Value != m_lastParameters.MiningDifficulty.Value) - { - Program.Print(string.Format("[INFO] New difficulity detected ({0})...", miningParameters.MiningDifficulty.Value)); - Difficulty = Convert.ToUInt64(miningParameters.MiningDifficulty.Value.ToString()); - - var calculatedTarget = m_maxTarget.Value / Difficulty; - if (calculatedTarget != miningParameters.MiningTarget.Value) - { - Program.Print(string.Format("[INFO] Update target {0}...", calculatedTarget.ToString())); - OnNewTarget(this, new HexBigInteger(calculatedTarget)); - } - } - } - else - { - Difficulty = m_customDifficulity; - var calculatedTarget = m_maxTarget.Value / m_customDifficulity; - var newTarget = new HexBigInteger(new BigInteger(m_customDifficulity)); - - OnNewTarget(this, newTarget); - } - - m_lastParameters = miningParameters; - OnGetMiningParameterStatus(this, true); - } - catch (Exception ex) - { - Program.Print(string.Format("[ERROR] {0}", ex.Message)); - } - finally { m_isGetMiningParameters = false; } - } - - /// - /// Since a single hash is a random number between 1 and 2^256, and difficulty [1] target = 2^234 - /// Then we can find difficulty [N] target = 2^234 / N - /// Hence, # of hashes to find block with difficulty [N] = N * 2^256 / 2^234 - /// Which simplifies to # of hashes to find block difficulty [N] = N * 2^22 - /// Time to find block in seconds with difficulty [N] = N * 2^22 / hashes per second - /// - public TimeSpan GetTimeLeftToSolveBlock(ulong hashrate) - { - if (m_maxTarget == null || m_maxTarget.Value == 0 || Difficulty == 0 || hashrate == 0 || m_challengeReceiveDateTime == DateTime.MinValue) - return TimeSpan.Zero; - - var timeToSolveBlock = new BigInteger(Difficulty) * uint256_MaxValue / m_maxTarget.Value / new BigInteger(hashrate); - - var secondsLeftToSolveBlock = timeToSolveBlock - (long)(DateTime.Now - m_challengeReceiveDateTime).TotalSeconds; - - return (secondsLeftToSolveBlock > (long)TimeSpan.MaxValue.TotalSeconds) - ? TimeSpan.MaxValue - : TimeSpan.FromSeconds((long)secondsLeftToSolveBlock); - } - - /// - /// Since a single hash is a random number between 1 and 2^256, and difficulty [1] target = 2^234 - /// Then we can find difficulty [N] target = 2^234 / N - /// Hence, # of hashes to find block with difficulty [N] = N * 2^256 / 2^234 - /// Which simplifies to # of hashes to find block difficulty [N] = N * 2^22 - /// Time to find block in seconds with difficulty [N] = N * 2^22 / hashes per second - /// Hashes per second with difficulty [N] and time to find block [T] = N * 2^22 / T - /// - public ulong GetEffectiveHashrate() - { - var hashrate = 0ul; - - if (m_submitDateTimeList.Count > 1) - { - var avgSolveTime = (ulong)((DateTime.Now - m_submitDateTimeList.First()).TotalSeconds / m_submitDateTimeList.Count - 1); - hashrate = (ulong)(new BigInteger(Difficulty) * uint256_MaxValue / m_maxTarget.Value / new BigInteger(avgSolveTime)); - } - - return hashrate; - } - - public void ResetEffectiveHashrate() - { - m_submitDateTimeList.Clear(); - m_submitDateTimeList.Add(DateTime.Now); - } - - public void UpdateMiningParameters() - { - UpdateMinerTimer_Elapsed(this, null); - - if (m_updateMinerTimer == null && m_updateInterval > 0) - { - m_updateMinerTimer = new Timer(m_updateInterval); - m_updateMinerTimer.Elapsed += UpdateMinerTimer_Elapsed; - m_updateMinerTimer.Start(); - } - } - - public bool SubmitSolution(string address, byte[] digest, byte[] challenge, ulong difficulty, byte[] nonce, Miner.IMiner sender) + private void HandleException(Exception ex, string errorPrefix = null) { - m_challengeReceiveDateTime = DateTime.Now; - var startSubmitDateTime = DateTime.Now; - - if (m_runFailover) - { - if (SecondaryPool.SubmitSolution(address, digest, challenge, difficulty, nonce, sender)) - { - LastSubmitLatency = (int)((DateTime.Now - startSubmitDateTime).TotalMilliseconds); - Program.Print(string.Format("[INFO] Submission roundtrip latency: {0}ms", LastSubmitLatency)); - - if (m_submitDateTimeList.Count >= MAX_SUBMIT_DTM_COUNT) m_submitDateTimeList.RemoveAt(0); - m_submitDateTimeList.Add(DateTime.Now); - } - return false; - } - - bool success = false, submitted = false; - int retryCount = 0, maxRetries = 10; - var devFee = (long)Math.Round(100 / Math.Abs(DevFee.UserPercent)); - const long devShareOffset = 10; - do - { - try - { - lock (this) - { - if (SubmittedShares == ulong.MaxValue) - { - SubmittedShares = 0; - RejectedShares = 0; - } - var minerAddress = (((long)(SubmittedShares - RejectedShares) - devShareOffset) % devFee) == 0 - ? DevFee.Address - : MinerAddress; - - JObject submitShare = GetPoolParameter("submitShare", - Utils.Numerics.Byte32ArrayToHexString(nonce), - minerAddress, - Utils.Numerics.Byte32ArrayToHexString(digest), - difficulty.ToString(CultureInfo.InvariantCulture), - Utils.Numerics.Byte32ArrayToHexString(challenge), - m_customDifficulity > 0 ? "true" : "false", - Miner.Work.GetKingAddressString()); - - var response = Utils.Json.InvokeJObjectRPC(s_PoolURL, submitShare); + var errorMessage = new StringBuilder("[ERROR] "); - LastSubmitLatency = (int)((DateTime.Now - startSubmitDateTime).TotalMilliseconds); + if (!string.IsNullOrWhiteSpace(errorPrefix)) + errorMessage.AppendFormat("{0}: ", errorPrefix); - var result = response.SelectToken("$.result")?.Value(); + errorMessage.Append(ex.Message); - success = (result ?? string.Empty).Equals("true", StringComparison.OrdinalIgnoreCase); - if (!success) RejectedShares++; - SubmittedShares++; - - Program.Print(string.Format("[INFO] {0} [{1}] submitted to {2} pool: {3} ({4}ms)", - (minerAddress == DevFee.Address ? "Dev. fee share" : "Miner share"), - SubmittedShares, - IsSecondaryPool ? "secondary" : "primary", - (success ? "success" : "failed"), - LastSubmitLatency)); -#if DEBUG - Program.Print(submitShare.ToString()); - Program.Print(response.ToString()); -#endif - } - submitted = true; - } - catch (Exception ex) - { - retryCount += 1; - - if (retryCount >= Math.Min(maxRetries, 3)) - Program.Print(string.Format("[ERROR] Pool not receiving nonce: {0}", ex.Message)); - - if (retryCount < maxRetries) - Task.Delay(500); - } - } while (!submitted && retryCount < maxRetries); - - if (success) + var innerEx = ex.InnerException; + while (innerEx != null) { - if (m_submitDateTimeList.Count > MAX_SUBMIT_DTM_COUNT) m_submitDateTimeList.RemoveAt(0); - m_submitDateTimeList.Add(DateTime.Now); + errorMessage.AppendFormat("\n {0}", innerEx.Message); + innerEx = innerEx.InnerException; } - else UpdateMiningParameters(); - - return success; + Program.Print(errorMessage.ToString()); } } } \ No newline at end of file diff --git a/SoliditySHA3Miner/NetworkInterface/SlaveInterface.cs b/SoliditySHA3Miner/NetworkInterface/SlaveInterface.cs new file mode 100644 index 0000000..99b4b98 --- /dev/null +++ b/SoliditySHA3Miner/NetworkInterface/SlaveInterface.cs @@ -0,0 +1,335 @@ +/* + Copyright 2018 Lip Wee Yeo Amano + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +using Nethereum.Hex.HexTypes; +using Nethereum.Util; +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Text; +using System.Threading.Tasks; +using System.Timers; + +namespace SoliditySHA3Miner.NetworkInterface +{ + public class SlaveInterface : NetworkInterfaceBase + { + public bool IsPause { get; private set; } + + private readonly bool m_isPool; + private bool m_isGetMiningParameters; + + #region NetworkInterfaceBase + + public override bool IsPool => m_isPool; + + public override event GetMiningParameterStatusEvent OnGetMiningParameterStatus; + public override event NewChallengeEvent OnNewChallenge; + public override event NewTargetEvent OnNewTarget; + public override event NewDifficultyEvent OnNewDifficulty; + public override event StopSolvingCurrentChallengeEvent OnStopSolvingCurrentChallenge; + public override event GetTotalHashrateEvent OnGetTotalHashrate; + + public override bool SubmitSolution(string address, byte[] digest, byte[] challenge, HexBigInteger difficulty, byte[] nonce, object sender) + { + m_challengeReceiveDateTime = DateTime.Now; + var startSubmitDateTime = DateTime.Now; + + bool success = false, submitted = false; + int retryCount = 0, maxRetries = 10; + do + { + try + { + lock (this) + { + if (IsPause) return false; + + if (SubmittedShares == ulong.MaxValue) + { + SubmittedShares = 0; + RejectedShares = 0; + } + + Program.Print(string.Format("[INFO] Submitting solution to master URL({0})...", SubmitURL)); + + JObject submitSolution = Miner.MasterInterface.GetMasterParameter(Miner.MasterInterface.RequestMethods.SubmitSolution, + Utils.Numerics.Byte32ArrayToHexString(digest), + Utils.Numerics.Byte32ArrayToHexString(challenge), + Utils.Numerics.Byte32ArrayToHexString(difficulty.Value.ToByteArray(isUnsigned: true, isBigEndian: true)), + Utils.Numerics.Byte32ArrayToHexString(nonce)); + + var response = Utils.Json.InvokeJObjectRPC(SubmitURL, submitSolution, customTimeout: 10 * 60); + + LastSubmitLatency = (int)((DateTime.Now - startSubmitDateTime).TotalMilliseconds); + + if (!IsChallengedSubmitted(challenge)) + { + m_submittedChallengeList.Insert(0, challenge.ToArray()); + if (m_submittedChallengeList.Count > 100) m_submittedChallengeList.Remove(m_submittedChallengeList.Last()); + } + + var result = response.SelectToken("$.result")?.Value(); + + success = (result ?? string.Empty).Equals("true", StringComparison.OrdinalIgnoreCase); + SubmittedShares++; + submitted = true; + + if (success) + { + if (m_submitDateTimeList.Count > MAX_SUBMIT_DTM_COUNT) + m_submitDateTimeList.RemoveAt(0); + + m_submitDateTimeList.Add(DateTime.Now); + } + else + { + RejectedShares++; + } + + Program.Print(string.Format("[INFO] Nonce [{0}] submitted to master URL({1}): {2} ({3}ms)", + SubmittedShares, + SubmitURL, + (success ? "success" : "failed"), + LastSubmitLatency)); +#if DEBUG + Program.Print(submitSolution.ToString()); + Program.Print(response.ToString()); +#endif + UpdateMiningParameters(); + } + } + catch (Exception ex) + { + retryCount += 1; + + if (retryCount >= Math.Min(maxRetries, 3)) + HandleException(ex, "Master not receiving nonce:"); + + if (retryCount < maxRetries) + Task.Delay(500); + } + } while (!submitted && retryCount < maxRetries); + + return success; + } + + protected override void HashPrintTimer_Elapsed(object sender, ElapsedEventArgs e) + { + try + { + var totalHashRate = 0ul; + OnGetTotalHashrate(this, ref totalHashRate); + Program.Print(string.Format("[INFO] Total Hashrate: {0} MH/s (Effective) / {1} MH/s (Local)", + GetEffectiveHashrate() / 1000000.0f, totalHashRate / 1000000.0f)); + + var timeLeftToSolveBlock = GetTimeLeftToSolveBlock(totalHashRate); + + if (timeLeftToSolveBlock.TotalSeconds < 0) + { + Program.Print(string.Format("[INFO] Estimated time left to solution: -({0}d {1}h {2}m {3}s)", + Math.Abs(timeLeftToSolveBlock.Days), + Math.Abs(timeLeftToSolveBlock.Hours), + Math.Abs(timeLeftToSolveBlock.Minutes), + Math.Abs(timeLeftToSolveBlock.Seconds))); + } + else + { + Program.Print(string.Format("[INFO] Estimated time left to solution: {0}d {1}h {2}m {3}s", + Math.Abs(timeLeftToSolveBlock.Days), + Math.Abs(timeLeftToSolveBlock.Hours), + Math.Abs(timeLeftToSolveBlock.Minutes), + Math.Abs(timeLeftToSolveBlock.Seconds))); + } + } + catch { } + } + + protected override void UpdateMinerTimer_Elapsed(object sender, ElapsedEventArgs e) + { + if (m_isGetMiningParameters) return; + try + { + m_isGetMiningParameters = true; + var miningParameters = GetMiningParameters(); + if (miningParameters == null) + { + OnGetMiningParameterStatus(this, false); + return; + } + + CurrentChallenge = miningParameters.ChallengeByte32; + + if (m_lastParameters == null || miningParameters.Challenge.Value != m_lastParameters.Challenge.Value) + { + Program.Print(string.Format("[INFO] New challenge detected {0}...", miningParameters.ChallengeByte32String)); + OnNewChallenge(this, miningParameters.ChallengeByte32, MinerAddress); + + if (m_challengeReceiveDateTime == DateTime.MinValue) + m_challengeReceiveDateTime = DateTime.Now; + } + + if (m_lastParameters == null || miningParameters.MiningTarget.Value != m_lastParameters.MiningTarget.Value) + { + Program.Print(string.Format("[INFO] New target detected {0}...", miningParameters.MiningTargetByte32String)); + OnNewTarget(this, miningParameters.MiningTarget); + } + + if (m_lastParameters == null || miningParameters.MiningDifficulty.Value != m_lastParameters.MiningDifficulty.Value) + { + Program.Print(string.Format("[INFO] New difficulity detected ({0})...", miningParameters.MiningDifficulty.Value)); + OnNewDifficulty?.Invoke(this, miningParameters.MiningDifficulty); + Difficulty = miningParameters.MiningDifficulty; + + // Actual difficulty should have decimals + var calculatedDifficulty = BigDecimal.Exp(BigInteger.Log(MaxTarget.Value) - BigInteger.Log(miningParameters.MiningTarget.Value)); + var calculatedDifficultyBigInteger = BigInteger.Parse(calculatedDifficulty.ToString().Split(",.".ToCharArray())[0]); + + try // Perform rounding + { + if (uint.Parse(calculatedDifficulty.ToString().Split(",.".ToCharArray())[1].First().ToString()) >= 5) + calculatedDifficultyBigInteger++; + } + catch { } + + if (Difficulty.Value != calculatedDifficultyBigInteger) + { + Difficulty = new HexBigInteger(calculatedDifficultyBigInteger); + var expValue = BigInteger.Log10(calculatedDifficultyBigInteger); + var calculatedTarget = BigInteger.Parse( + (BigDecimal.Parse(MaxTarget.Value.ToString()) * BigDecimal.Pow(10, expValue) / (calculatedDifficulty * BigDecimal.Pow(10, expValue))). + ToString().Split(",.".ToCharArray())[0]); + var calculatedTargetHex = new HexBigInteger(calculatedTarget); + + Program.Print(string.Format("[INFO] Update target 0x{0}...", calculatedTarget.ToString("x64"))); + OnNewTarget(this, calculatedTargetHex); + CurrentTarget = calculatedTargetHex; + } + } + + IsPause = miningParameters.IsPause; + m_lastParameters = miningParameters; + + OnStopSolvingCurrentChallenge(this, stopSolving: miningParameters.IsPause); + OnGetMiningParameterStatus(this, true); + } + catch (Exception ex) + { + HandleException(ex); + } + finally { m_isGetMiningParameters = false; } + } + + #endregion + + public SlaveInterface(string masterURL, int updateInterval, int hashratePrintInterval) + : base(updateInterval, hashratePrintInterval) + { + m_isGetMiningParameters = false; + SubmitURL = masterURL; + + Program.Print(string.Format("[INFO] Waiting for master instance ({0}) to start...", SubmitURL)); + + var getMasterAddress = Miner.MasterInterface.GetMasterParameter(Miner.MasterInterface.RequestMethods.GetMinerAddress); + var getMaximumTarget = Miner.MasterInterface.GetMasterParameter(Miner.MasterInterface.RequestMethods.GetMaximumTarget); + var getKingAddress = Miner.MasterInterface.GetMasterParameter(Miner.MasterInterface.RequestMethods.GetKingAddress); + var getPoolMining = Miner.MasterInterface.GetMasterParameter(Miner.MasterInterface.RequestMethods.GetPoolMining); + + var retryCount = 0; + while (true) + try + { + var parameters = MiningParameters.GetMiningParameters(SubmitURL, + getEthAddress: getMasterAddress, + getMaximumTarget: getMaximumTarget, + getKingAddress: getKingAddress, + getPoolMining: getPoolMining); + m_isPool = parameters.IsPoolMining; + MinerAddress = parameters.EthAddress; + MaxTarget = parameters.MaximumTarget; + Miner.Work.KingAddress = parameters.KingAddressByte20; + break; + } + catch (Exception ex) + { + retryCount++; + if (retryCount > 3) + HandleException(ex); + + Task.Delay(1000).Wait(); + } + + if (hashratePrintInterval > 0) + { + m_hashPrintTimer = new Timer(hashratePrintInterval); + m_hashPrintTimer.Elapsed += HashPrintTimer_Elapsed; + m_hashPrintTimer.Start(); + } + } + + private MiningParameters GetMiningParameters() + { + Program.Print(string.Format("[INFO] Checking latest parameters from master URL: {0}", SubmitURL)); + + var getChallenge = Miner.MasterInterface.GetMasterParameter(Miner.MasterInterface.RequestMethods.GetChallenge); + var getDifficulty = Miner.MasterInterface.GetMasterParameter(Miner.MasterInterface.RequestMethods.GetDifficulty); + var getTarget = Miner.MasterInterface.GetMasterParameter(Miner.MasterInterface.RequestMethods.GetTarget); + var getPause = Miner.MasterInterface.GetMasterParameter(Miner.MasterInterface.RequestMethods.GetPause); + + var success = true; + var startTime = DateTime.Now; + try + { + return MiningParameters.GetMiningParameters(SubmitURL, + getChallenge: getChallenge, + getDifficulty: getDifficulty, + getTarget: getTarget, + getPause: getPause); + } + catch (Exception ex) + { + HandleException(ex); + success = false; + } + finally + { + if (success) + Latency = (int)(DateTime.Now - startTime).TotalMilliseconds; + } + return null; + } + + private void HandleException(Exception ex, string errorPrefix = null) + { + var errorMessage = new StringBuilder("[ERROR] Occured at Slave instance => "); + + if (!string.IsNullOrWhiteSpace(errorPrefix)) + errorMessage.AppendFormat("{0}: ", errorPrefix); + + errorMessage.Append(ex.Message); + + var innerEx = ex.InnerException; + while (innerEx != null) + { + errorMessage.AppendFormat("\n {0}", innerEx.Message); + innerEx = innerEx.InnerException; + } + Program.Print(errorMessage.ToString()); + } + } +} \ No newline at end of file diff --git a/SoliditySHA3Miner/NetworkInterface/Web3Interface.cs b/SoliditySHA3Miner/NetworkInterface/Web3Interface.cs index eae09d1..beecaf4 100644 --- a/SoliditySHA3Miner/NetworkInterface/Web3Interface.cs +++ b/SoliditySHA3Miner/NetworkInterface/Web3Interface.cs @@ -23,7 +23,6 @@ limitations under the License. using Nethereum.Web3.Accounts; using Newtonsoft.Json.Linq; using System; -using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.NetworkInformation; @@ -34,16 +33,11 @@ limitations under the License. namespace SoliditySHA3Miner.NetworkInterface { - public class Web3Interface : INetworkInterface + public class Web3Interface : NetworkInterfaceBase { - private readonly BigInteger uint256_MaxValue = BigInteger.Pow(2, 256); - private HexBigInteger m_maxTarget; - private DateTime m_challengeReceiveDateTime; + public HexBigInteger LastSubmitGasPrice { get; private set; } - private const int MAX_TIMEOUT = 10; - private const string DEFAULT_WEB3_API = Config.Defaults.InfuraAPI_mainnet; - private const int MAX_SUBMIT_DTM_COUNT = 50; - private readonly List m_submitDateTimeList; + private const int MAX_TIMEOUT = 15; private readonly Web3 m_web3; private readonly Contract m_contract; @@ -63,50 +57,321 @@ public class Web3Interface : INetworkInterface private readonly float m_gasToMine; private readonly float m_gasApiMax; private readonly ulong m_gasLimit; - private readonly List m_submittedChallengeList; - private readonly int m_updateInterval; - private Timer m_updateMinerTimer; - private Timer m_hashPrintTimer; - private MiningParameters m_lastParameters; - private System.Threading.ManualResetEvent m_newChallengeResetEvent; private readonly string m_gasApiURL; private readonly string m_gasApiPath; private readonly float m_gasApiOffset; private readonly float m_gasApiMultiplier; - public event GetMiningParameterStatusEvent OnGetMiningParameterStatus; - public event NewChallengeEvent OnNewChallenge; - public event NewTargetEvent OnNewTarget; - public event StopSolvingCurrentChallengeEvent OnStopSolvingCurrentChallenge; + private System.Threading.ManualResetEvent m_newChallengeResetEvent; - public event GetTotalHashrateEvent OnGetTotalHashrate; + #region NetworkInterfaceBase - public bool IsPool => false; - public ulong SubmittedShares { get; private set; } - public ulong RejectedShares { get; private set; } - public ulong Difficulty { get; private set; } - public HexBigInteger LastSubmitGasPrice { get; private set; } - public int LastSubmitLatency { get; private set; } - public int Latency { get; private set; } - public string MinerAddress { get; } - public string SubmitURL { get; private set; } - public byte[] CurrentChallenge { get; private set; } + public override bool IsPool => false; + + public override event GetMiningParameterStatusEvent OnGetMiningParameterStatus; + public override event NewChallengeEvent OnNewChallenge; + public override event NewTargetEvent OnNewTarget; + public override event NewDifficultyEvent OnNewDifficulty; + public override event StopSolvingCurrentChallengeEvent OnStopSolvingCurrentChallenge; + public override event GetTotalHashrateEvent OnGetTotalHashrate; + + public override bool SubmitSolution(string address, byte[] digest, byte[] challenge, HexBigInteger difficulty, byte[] nonce, object sender) + { + lock (this) + { + if (IsChallengedSubmitted(challenge)) + { + Program.Print(string.Format("[INFO] Submission cancelled, nonce has been submitted for the current challenge.")); + return false; + } + m_challengeReceiveDateTime = DateTime.MinValue; + + var transactionID = string.Empty; + var gasLimit = new HexBigInteger(m_gasLimit); + var userGas = new HexBigInteger(UnitConversion.Convert.ToWei(new BigDecimal(m_gasToMine), UnitConversion.EthUnit.Gwei)); + + if (!string.IsNullOrWhiteSpace(m_gasApiURL)) + { + try + { + var apiGasPrice = Utils.Json.DeserializeFromURL(m_gasApiURL).SelectToken(m_gasApiPath).Value(); + if (apiGasPrice > 0) + { + apiGasPrice *= m_gasApiMultiplier; + apiGasPrice += m_gasApiOffset; + + if (apiGasPrice < m_gasToMine) + { + Program.Print(string.Format("[INFO] Using 'gasToMine' price of {0} GWei, due to lower gas price from API: {1}", + m_gasToMine, m_gasApiURL)); + } + else if (apiGasPrice > m_gasApiMax) + { + userGas = new HexBigInteger(UnitConversion.Convert.ToWei(new BigDecimal(m_gasApiMax), UnitConversion.EthUnit.Gwei)); + Program.Print(string.Format("[INFO] Using 'gasApiMax' price of {0} GWei, due to higher gas price from API: {1}", + m_gasApiMax, m_gasApiURL)); + } + else + { + userGas = new HexBigInteger(UnitConversion.Convert.ToWei(new BigDecimal(apiGasPrice), UnitConversion.EthUnit.Gwei)); + Program.Print(string.Format("[INFO] Using gas price of {0} GWei (after {1} offset) from API: {2}", + apiGasPrice, m_gasApiOffset, m_gasApiURL)); + } + } + else + { + Program.Print(string.Format("[ERROR] Gas price of 0 GWei was retuned by API: {0}", m_gasApiURL)); + Program.Print(string.Format("[INFO] Using 'gasToMine' parameter of {0} GWei.", m_gasToMine)); + } + } + catch (Exception ex) + { + HandleException(ex, string.Format("Failed to read gas price from API ({0})", m_gasApiURL)); + + if (LastSubmitGasPrice == null || LastSubmitGasPrice.Value <= 0) + Program.Print(string.Format("[INFO] Using 'gasToMine' parameter of {0} GWei.", m_gasToMine)); + else + { + Program.Print(string.Format("[INFO] Using last submitted gas price of {0} GWei.", + UnitConversion.Convert.FromWeiToBigDecimal(LastSubmitGasPrice, UnitConversion.EthUnit.Gwei).ToString())); + userGas = LastSubmitGasPrice; + } + } + } + + object[] dataInput = null; + + if (m_mintMethodInputParamCount > 1) // 0xBitcoin compatibility + dataInput = new object[] { new BigInteger(nonce, isBigEndian: true), digest }; + + else // Draft EIP-918 compatibility [2018-03-07] + dataInput = new object[] { new BigInteger(nonce, isBigEndian: true) }; + + var retryCount = 0; + var startSubmitDateTime = DateTime.Now; + do + { + try + { + var txCount = m_web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(address).Result; + + // Commented as gas limit is dynamic in between submissions and confirmations + //var estimatedGasLimit = m_mintMethod.EstimateGasAsync(from: address, + // gas: gasLimit, + // value: new HexBigInteger(0), + // functionInput: dataInput).Result; + + var transaction = m_mintMethod.CreateTransactionInput(from: address, + gas: gasLimit /*estimatedGasLimit*/, + gasPrice: userGas, + value: new HexBigInteger(0), + functionInput: dataInput); + + var encodedTx = Web3.OfflineTransactionSigner.SignTransaction(privateKey: m_account.PrivateKey, + to: m_contract.Address, + amount: 0, + nonce: txCount.Value, + gasPrice: userGas, + gasLimit: gasLimit /*estimatedGasLimit*/, + data: transaction.Data); + + if (!Web3.OfflineTransactionSigner.VerifyTransaction(encodedTx)) + throw new Exception("Failed to verify transaction."); + + transactionID = m_web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + encodedTx).Result; + + LastSubmitLatency = (int)((DateTime.Now - startSubmitDateTime).TotalMilliseconds); + + if (!string.IsNullOrWhiteSpace(transactionID)) + { + Program.Print("[INFO] Nonce submitted with transaction ID: " + transactionID); + LastSubmitGasPrice = userGas; + + if (!IsChallengedSubmitted(challenge)) + { + m_submittedChallengeList.Insert(0, challenge.ToArray()); + if (m_submittedChallengeList.Count > 100) m_submittedChallengeList.Remove(m_submittedChallengeList.Last()); + } + + Task.Factory.StartNew(() => GetTransactionReciept(transactionID, address, gasLimit, userGas, LastSubmitLatency, DateTime.Now)); + + if (challenge.SequenceEqual(CurrentChallenge)) + OnStopSolvingCurrentChallenge(this); + } + } + catch (AggregateException ex) + { + HandleAggregateException(ex); + + if (IsChallengedSubmitted(challenge)) + return false; + } + catch (Exception ex) + { + HandleException(ex); + + if (IsChallengedSubmitted(challenge) || ex.Message == "Failed to verify transaction.") + return false; + } + + if (string.IsNullOrWhiteSpace(transactionID)) + { + retryCount++; + + if (retryCount > 10) + { + Program.Print("[ERROR] Failed to submit solution for 10 times, submission cancelled."); + return false; + } + else { Task.Delay(m_updateInterval / 2).Wait(); } + } + } while (string.IsNullOrWhiteSpace(transactionID)); + + return !string.IsNullOrWhiteSpace(transactionID); + } + } + + public override void Dispose() + { + base.Dispose(); + + if (m_newChallengeResetEvent != null) + try + { + m_newChallengeResetEvent.Dispose(); + m_newChallengeResetEvent = null; + } + catch { } + m_newChallengeResetEvent = null; + } + + protected override void HashPrintTimer_Elapsed(object sender, ElapsedEventArgs e) + { + var totalHashRate = 0ul; + try + { + OnGetTotalHashrate(this, ref totalHashRate); + Program.Print(string.Format("[INFO] Total Hashrate: {0} MH/s (Effective) / {1} MH/s (Local)", + GetEffectiveHashrate() / 1000000.0f, totalHashRate / 1000000.0f)); + } + catch (Exception) + { + try + { + totalHashRate = GetEffectiveHashrate(); + Program.Print(string.Format("[INFO] Effective Hashrate: {0} MH/s", totalHashRate / 1000000.0f)); + } + catch { } + } + try + { + if (totalHashRate > 0) + { + var timeLeftToSolveBlock = GetTimeLeftToSolveBlock(totalHashRate); + + if (timeLeftToSolveBlock.TotalSeconds < 0) + { + Program.Print(string.Format("[INFO] Estimated time left to solution: -({0}d {1}h {2}m {3}s)", + Math.Abs(timeLeftToSolveBlock.Days), + Math.Abs(timeLeftToSolveBlock.Hours), + Math.Abs(timeLeftToSolveBlock.Minutes), + Math.Abs(timeLeftToSolveBlock.Seconds))); + } + else + { + Program.Print(string.Format("[INFO] Estimated time left to solution: {0}d {1}h {2}m {3}s", + Math.Abs(timeLeftToSolveBlock.Days), + Math.Abs(timeLeftToSolveBlock.Hours), + Math.Abs(timeLeftToSolveBlock.Minutes), + Math.Abs(timeLeftToSolveBlock.Seconds))); + } + } + } + catch { } + } + + protected override void UpdateMinerTimer_Elapsed(object sender, ElapsedEventArgs e) + { + try + { + var miningParameters = GetMiningParameters(); + if (miningParameters == null) + { + OnGetMiningParameterStatus(this, false); + return; + } + + CurrentChallenge = miningParameters.ChallengeByte32; + + if (m_lastParameters == null || miningParameters.Challenge.Value != m_lastParameters.Challenge.Value) + { + Program.Print(string.Format("[INFO] New challenge detected {0}...", miningParameters.ChallengeByte32String)); + OnNewChallenge(this, miningParameters.ChallengeByte32, MinerAddress); + + if (m_challengeReceiveDateTime == DateTime.MinValue) + m_challengeReceiveDateTime = DateTime.Now; + + m_newChallengeResetEvent.Set(); + } + + if (m_lastParameters == null || miningParameters.MiningTarget.Value != m_lastParameters.MiningTarget.Value) + { + Program.Print(string.Format("[INFO] New target detected {0}...", miningParameters.MiningTargetByte32String)); + OnNewTarget(this, miningParameters.MiningTarget); + CurrentTarget = miningParameters.MiningTarget; + } + + if (m_lastParameters == null || miningParameters.MiningDifficulty.Value != m_lastParameters.MiningDifficulty.Value) + { + Program.Print(string.Format("[INFO] New difficulity detected ({0})...", miningParameters.MiningDifficulty.Value)); + OnNewDifficulty?.Invoke(this, miningParameters.MiningDifficulty); + Difficulty = miningParameters.MiningDifficulty; + + // Actual difficulty should have decimals + var calculatedDifficulty = BigDecimal.Exp(BigInteger.Log(MaxTarget.Value) - BigInteger.Log(miningParameters.MiningTarget.Value)); + var calculatedDifficultyBigInteger = BigInteger.Parse(calculatedDifficulty.ToString().Split(",.".ToCharArray())[0]); + + try // Perform rounding + { + if (uint.Parse(calculatedDifficulty.ToString().Split(",.".ToCharArray())[1].First().ToString()) >= 5) + calculatedDifficultyBigInteger++; + } + catch { } + + if (Difficulty.Value != calculatedDifficultyBigInteger) + { + Difficulty = new HexBigInteger(calculatedDifficultyBigInteger); + var expValue = BigInteger.Log10(calculatedDifficultyBigInteger); + var calculatedTarget = BigInteger.Parse( + (BigDecimal.Parse(MaxTarget.Value.ToString()) * BigDecimal.Pow(10, expValue) / (calculatedDifficulty * BigDecimal.Pow(10, expValue))). + ToString().Split(",.".ToCharArray())[0]); + var calculatedTargetHex = new HexBigInteger(calculatedTarget); + + Program.Print(string.Format("[INFO] Update target 0x{0}...", calculatedTarget.ToString("x64"))); + OnNewTarget(this, calculatedTargetHex); + CurrentTarget = calculatedTargetHex; + } + } + + m_lastParameters = miningParameters; + OnGetMiningParameterStatus(this, true); + } + catch (Exception ex) + { + HandleException(ex); + } + } - public bool IsChallengedSubmitted(byte[] challenge) => m_submittedChallengeList.Any(s => challenge.SequenceEqual(s)); + #endregion public Web3Interface(string web3ApiPath, string contractAddress, string minerAddress, string privateKey, float gasToMine, string abiFileName, int updateInterval, int hashratePrintInterval, ulong gasLimit, string gasApiURL, string gasApiPath, float gasApiMultiplier, float gasApiOffset, float gasApiMax) + : base(updateInterval, hashratePrintInterval) { - m_updateInterval = updateInterval; - m_submittedChallengeList = new List(); - m_submitDateTimeList = new List(MAX_SUBMIT_DTM_COUNT + 1); - m_newChallengeResetEvent = new System.Threading.ManualResetEvent(false); - Nethereum.JsonRpc.Client.ClientBase.ConnectionTimeout = MAX_TIMEOUT * 1000; - LastSubmitLatency = -1; - Latency = -1; + m_newChallengeResetEvent = new System.Threading.ManualResetEvent(false); if (string.IsNullOrWhiteSpace(contractAddress)) { @@ -146,7 +411,7 @@ public Web3Interface(string web3ApiPath, string contractAddress, string minerAdd Program.Print("[INFO] Miner's address : " + minerAddress); MinerAddress = minerAddress; - SubmitURL = string.IsNullOrWhiteSpace(web3ApiPath) ? DEFAULT_WEB3_API : web3ApiPath; + SubmitURL = string.IsNullOrWhiteSpace(web3ApiPath) ? Config.Defaults.InfuraAPI_mainnet : web3ApiPath; m_web3 = new Web3(SubmitURL); @@ -421,73 +686,33 @@ public Web3Interface(string web3ApiPath, string contractAddress, string minerAdd #endregion - m_hashPrintTimer = new Timer(hashratePrintInterval); - m_hashPrintTimer.Elapsed += HashPrintTimer_Elapsed; - m_hashPrintTimer.Start(); + if (m_hashPrintTimer != null) + m_hashPrintTimer.Start(); } } - public void Dispose() + public void OverrideMaxTarget(HexBigInteger maxTarget) { - if (m_submitDateTimeList != null) - m_submitDateTimeList.Clear(); - - if (m_submittedChallengeList != null) - m_submittedChallengeList.Clear(); - - if (m_updateMinerTimer != null) + if (maxTarget.Value > 0u) { - try - { - m_updateMinerTimer.Elapsed -= UpdateMinerTimer_Elapsed; - m_updateMinerTimer.Stop(); - m_updateMinerTimer.Dispose(); - } - catch { } - m_updateMinerTimer = null; + Program.Print("[INFO] Override maximum difficulty: " + maxTarget.HexValue); + MaxTarget = maxTarget; } + else { MaxTarget = GetMaxTarget(); } + } + + public HexBigInteger GetMaxTarget() + { + if (MaxTarget != null && MaxTarget.Value > 0) + return MaxTarget; - if (m_hashPrintTimer != null) + Program.Print("[INFO] Checking maximum target from network..."); + while (true) { try { - m_hashPrintTimer.Elapsed -= HashPrintTimer_Elapsed; - m_hashPrintTimer.Stop(); - m_hashPrintTimer.Dispose(); - } - catch { } - m_hashPrintTimer = null; - } - - if (m_newChallengeResetEvent != null) - { - m_newChallengeResetEvent.Dispose(); - m_newChallengeResetEvent = null; - } - } - - public void OverrideMaxTarget(HexBigInteger maxTarget) - { - if (maxTarget.Value > 0u) - { - Program.Print("[INFO] Override maximum difficulty: " + maxTarget.HexValue); - m_maxTarget = maxTarget; - } - else { m_maxTarget = GetMaxTarget(); } - } - - public HexBigInteger GetMaxTarget() - { - if (m_maxTarget != null && m_maxTarget.Value > 0) - return m_maxTarget; - - Program.Print("[INFO] Checking maximum target from network..."); - while (true) - { - try - { - if (m_MAXIMUM_TARGET == null) // assume the same as 0xbtc if not available - return new HexBigInteger("0x40000000000000000000000000000000000000000000000000000000000"); + if (m_MAXIMUM_TARGET == null) // assume the same as 0xBTC + return new HexBigInteger("0x40000000000000000000000000000000000000000000000000000000000"); var maxTarget = new HexBigInteger(m_MAXIMUM_TARGET.CallAsync().Result); @@ -498,21 +723,13 @@ public HexBigInteger GetMaxTarget() } catch (Exception ex) { - var errorMessage = new StringBuilder("[ERROR] Failed to get maximum target: " + ex.Message); - - var innerEx = ex.InnerException; - while (innerEx != null) - { - errorMessage.AppendFormat("\n {0}", innerEx.Message); - innerEx = innerEx.InnerException; - } - Program.Print(errorMessage.ToString()); + HandleException(ex, "Failed to get maximum target"); Task.Delay(m_updateInterval / 2).Wait(); } } } - public MiningParameters GetMiningParameters() + private MiningParameters GetMiningParameters() { Program.Print("[INFO] Checking latest parameters from network..."); var success = true; @@ -523,17 +740,8 @@ public MiningParameters GetMiningParameters() } catch (Exception ex) { + HandleException(ex); success = false; - var errorMessage = new StringBuilder("[ERROR] " + ex.Message); - - var innerEx = ex.InnerException; - while (innerEx != null) - { - errorMessage.AppendFormat("\n {0}", innerEx.Message); - innerEx = innerEx.InnerException; - } - - Program.Print(errorMessage.ToString()); return null; } finally @@ -581,311 +789,6 @@ public MiningParameters GetMiningParameters() } } - private void HashPrintTimer_Elapsed(object sender, ElapsedEventArgs e) - { - var totalHashRate = 0ul; - OnGetTotalHashrate(this, ref totalHashRate); - Program.Print(string.Format("[INFO] Total Hashrate: {0} MH/s (Effective) / {1} MH/s (Local)", - GetEffectiveHashrate() / 1000000.0f, totalHashRate / 1000000.0f)); - - var timeLeftToSolveBlock = GetTimeLeftToSolveBlock(totalHashRate); - - if (timeLeftToSolveBlock.TotalSeconds < 0) - { - Program.Print(string.Format("[INFO] Estimated time left to solution: -({0}d {1}h {2}m {3}s)", - Math.Abs(timeLeftToSolveBlock.Days), - Math.Abs(timeLeftToSolveBlock.Hours), - Math.Abs(timeLeftToSolveBlock.Minutes), - Math.Abs(timeLeftToSolveBlock.Seconds))); - } - else - { - Program.Print(string.Format("[INFO] Estimated time left to solution: {0}d {1}h {2}m {3}s", - Math.Abs(timeLeftToSolveBlock.Days), - Math.Abs(timeLeftToSolveBlock.Hours), - Math.Abs(timeLeftToSolveBlock.Minutes), - Math.Abs(timeLeftToSolveBlock.Seconds))); - } - } - - private void UpdateMinerTimer_Elapsed(object sender, ElapsedEventArgs e) - { - try - { - var miningParameters = GetMiningParameters(); - if (miningParameters == null) - { - OnGetMiningParameterStatus(this, false); - return; - } - - CurrentChallenge = miningParameters.ChallengeByte32; - - if (m_lastParameters == null || miningParameters.Challenge.Value != m_lastParameters.Challenge.Value) - { - Program.Print(string.Format("[INFO] New challenge detected {0}...", miningParameters.ChallengeByte32String)); - OnNewChallenge(this, miningParameters.ChallengeByte32, miningParameters.EthAddress); - - if (m_challengeReceiveDateTime == DateTime.MinValue) - m_challengeReceiveDateTime = DateTime.Now; - - m_newChallengeResetEvent.Set(); - } - - if (m_lastParameters == null || miningParameters.MiningTarget.Value != m_lastParameters.MiningTarget.Value) - { - Program.Print(string.Format("[INFO] New target detected {0}...", miningParameters.MiningTargetByte32String)); - OnNewTarget(this, miningParameters.MiningTarget); - } - - if (m_lastParameters == null || miningParameters.MiningDifficulty.Value != m_lastParameters.MiningDifficulty.Value) - { - Program.Print(string.Format("[INFO] New difficulity detected ({0})...", miningParameters.MiningDifficulty.Value)); - Difficulty = Convert.ToUInt64(miningParameters.MiningDifficulty.Value.ToString()); - - // Actual difficulty should have decimals - var calculatedDifficulty = Math.Exp(BigInteger.Log(m_maxTarget.Value) - BigInteger.Log(miningParameters.MiningTarget.Value)); - - if ((ulong)calculatedDifficulty != Difficulty) // Only replace if the integer portion is different - { - Difficulty = (ulong)calculatedDifficulty; - var expValue = Math.Log10(calculatedDifficulty); - var calculatedTarget = m_maxTarget.Value * (ulong)Math.Pow(10, expValue) / (ulong)(calculatedDifficulty * Math.Pow(10, expValue)); - - Program.Print(string.Format("[INFO] Update target 0x{0}...", calculatedTarget.ToString("x64"))); - OnNewTarget(this, new HexBigInteger(calculatedTarget)); - } - } - - m_lastParameters = miningParameters; - OnGetMiningParameterStatus(this, true); - } - catch (Exception ex) - { - Program.Print(string.Format("[ERROR] {0}", ex.Message)); - } - } - - /// - /// Since a single hash is a random number between 1 and 2^256, and difficulty [1] target = 2^234 - /// Then we can find difficulty [N] target = 2^234 / N - /// Hence, # of hashes to find block with difficulty [N] = N * 2^256 / 2^234 - /// Which simplifies to # of hashes to find block difficulty [N] = N * 2^22 - /// Time to find block in seconds with difficulty [N] = N * 2^22 / hashes per second - /// - public TimeSpan GetTimeLeftToSolveBlock(ulong hashrate) - { - if (m_maxTarget == null || m_maxTarget.Value == 0 || Difficulty == 0 || hashrate == 0 || m_challengeReceiveDateTime == DateTime.MinValue) - return TimeSpan.Zero; - - var timeToSolveBlock = new BigInteger(Difficulty) * uint256_MaxValue / m_maxTarget.Value / new BigInteger(hashrate); - - var secondsLeftToSolveBlock = timeToSolveBlock - (long)(DateTime.Now - m_challengeReceiveDateTime).TotalSeconds; - - return (secondsLeftToSolveBlock > (long)TimeSpan.MaxValue.TotalSeconds) - ? TimeSpan.MaxValue - : TimeSpan.FromSeconds((long)secondsLeftToSolveBlock); - } - - /// - /// Since a single hash is a random number between 1 and 2^256, and difficulty [1] target = 2^234 - /// Then we can find difficulty [N] target = 2^234 / N - /// Hence, # of hashes to find block with difficulty [N] = N * 2^256 / 2^234 - /// Which simplifies to # of hashes to find block difficulty [N] = N * 2^22 - /// Time to find block in seconds with difficulty [N] = N * 2^22 / hashes per second - /// Hashes per second with difficulty [N] and time to find block [T] = N * 2^22 / T - /// - public ulong GetEffectiveHashrate() - { - var hashrate = 0ul; - - if (m_submitDateTimeList.Count > 1) - { - var avgSolveTime = (ulong)((DateTime.Now - m_submitDateTimeList.First()).TotalSeconds / m_submitDateTimeList.Count - 1); - hashrate = (ulong)(new BigInteger(Difficulty) * uint256_MaxValue / m_maxTarget.Value / new BigInteger(avgSolveTime)); - } - - return hashrate; - } - - public void ResetEffectiveHashrate() - { - m_submitDateTimeList.Clear(); - m_submitDateTimeList.Add(DateTime.Now); - } - - public void UpdateMiningParameters() - { - UpdateMinerTimer_Elapsed(this, null); - - if (m_updateMinerTimer == null && m_updateInterval > 0) - { - m_updateMinerTimer = new Timer(m_updateInterval); - m_updateMinerTimer.Elapsed += UpdateMinerTimer_Elapsed; - m_updateMinerTimer.Start(); - } - } - - public bool SubmitSolution(string address, byte[] digest, byte[] challenge, ulong difficulty, byte[] nonce, Miner.IMiner sender) - { - lock (this) - { - if (IsChallengedSubmitted(challenge)) - { - Program.Print(string.Format("[INFO] Submission cancelled, nonce has been submitted for the current challenge.")); - return false; - } - m_challengeReceiveDateTime = DateTime.MinValue; - - var transactionID = string.Empty; - var gasLimit = new HexBigInteger(m_gasLimit); - var userGas = new HexBigInteger(UnitConversion.Convert.ToWei(new BigDecimal(m_gasToMine), UnitConversion.EthUnit.Gwei)); - - if (!string.IsNullOrWhiteSpace(m_gasApiURL)) - { - try - { - var apiGasPrice = Utils.Json.DeserializeFromURL(m_gasApiURL).SelectToken(m_gasApiPath).Value(); - if (apiGasPrice > 0) - { - apiGasPrice *= m_gasApiMultiplier; - apiGasPrice += m_gasApiOffset; - - if (apiGasPrice < m_gasToMine) - { - Program.Print(string.Format("[INFO] Using 'gasToMine' price of {0} GWei, due to lower gas price from API: {1}", - m_gasToMine, m_gasApiURL)); - } - else if (apiGasPrice > m_gasApiMax) - { - userGas = new HexBigInteger(UnitConversion.Convert.ToWei(new BigDecimal(m_gasApiMax), UnitConversion.EthUnit.Gwei)); - Program.Print(string.Format("[INFO] Using 'gasApiMax' price of {0} GWei, due to higher gas price from API: {1}", - m_gasApiMax, m_gasApiURL)); - } - else - { - userGas = new HexBigInteger(UnitConversion.Convert.ToWei(new BigDecimal(apiGasPrice), UnitConversion.EthUnit.Gwei)); - Program.Print(string.Format("[INFO] Using gas price of {0} GWei (after {1} offset) from API: {2}", - apiGasPrice, m_gasApiOffset, m_gasApiURL)); - } - } - else - { - Program.Print(string.Format("[ERROR] Gas price of 0 GWei was retuned by API: {0}", m_gasApiURL)); - Program.Print(string.Format("[INFO] Using 'gasToMine' parameter of {0} GWei.", m_gasToMine)); - } - } - catch (Exception ex) - { - Program.Print(string.Format("[ERROR] Failed to read gas price from API: {0}\n{1}", m_gasApiURL, ex.ToString())); - if (LastSubmitGasPrice == null || LastSubmitGasPrice.Value <= 0) - Program.Print(string.Format("[INFO] Using 'gasToMine' parameter of {0} GWei.", m_gasToMine)); - else - { - Program.Print(string.Format("[INFO] Using last submitted gas price of {0} GWei.", - UnitConversion.Convert.FromWeiToBigDecimal(LastSubmitGasPrice, UnitConversion.EthUnit.Gwei).ToString())); - userGas = LastSubmitGasPrice; - } - } - } - - object[] dataInput = null; - - if (m_mintMethodInputParamCount > 1) // 0xBitcoin compatibility - dataInput = new object[] { new BigInteger(nonce.Reverse().ToArray()), digest }; - - else // Draft EIP-918 compatibility [2018-03-07] - dataInput = new object[] { new BigInteger(nonce.Reverse().ToArray()) }; - - var retryCount = 0; - var startSubmitDateTime = DateTime.Now; - while (string.IsNullOrWhiteSpace(transactionID)) - { - try - { - var txCount = m_web3.Eth.Transactions.GetTransactionCount.SendRequestAsync(address).Result; - - // Commented as gas limit is dynamic in between submissions and confirmations - //var estimatedGasLimit = m_mintMethod.EstimateGasAsync(from: address, - // gas: gasLimit, - // value: new HexBigInteger(0), - // functionInput: dataInput).Result; - - var transaction = m_mintMethod.CreateTransactionInput(from: address, - gas: gasLimit /*estimatedGasLimit*/, - gasPrice: userGas, - value: new HexBigInteger(0), - functionInput: dataInput); - - var encodedTx = Web3.OfflineTransactionSigner.SignTransaction(privateKey: m_account.PrivateKey, - to: m_contract.Address, - amount: 0, - nonce: txCount.Value, - gasPrice: userGas, - gasLimit: gasLimit /*estimatedGasLimit*/, - data: transaction.Data); - - if (!Web3.OfflineTransactionSigner.VerifyTransaction(encodedTx)) - throw new Exception("Failed to verify transaction."); - - transactionID = m_web3.Eth.Transactions.SendRawTransaction.SendRequestAsync("0x" + encodedTx).Result; - - LastSubmitLatency = (int)((DateTime.Now - startSubmitDateTime).TotalMilliseconds); - - if (!string.IsNullOrWhiteSpace(transactionID)) - { - Program.Print("[INFO] Nonce submitted with transaction ID: " + transactionID); - LastSubmitGasPrice = userGas; - - if (!IsChallengedSubmitted(challenge)) - { - m_submittedChallengeList.Insert(0, challenge.ToArray()); - if (m_submittedChallengeList.Count > 100) m_submittedChallengeList.Remove(m_submittedChallengeList.Last()); - } - - Task.Factory.StartNew(() => GetTransactionReciept(transactionID, address, gasLimit, userGas, LastSubmitLatency, DateTime.Now)); - - if (challenge.SequenceEqual(CurrentChallenge)) - OnStopSolvingCurrentChallenge(this); - } - } - catch (AggregateException ex) - { - var errorMessage = "[ERROR] " + ex.Message; - - foreach (var iEx in ex.InnerExceptions) - errorMessage += "\n " + iEx.Message; - - Program.Print(errorMessage); - if (IsChallengedSubmitted(challenge)) return false; - } - catch (Exception ex) - { - var errorMessage = "[ERROR] " + ex.Message; - - if (ex.InnerException != null) - errorMessage += "\n " + ex.InnerException.Message; - - Program.Print(errorMessage); - - if (IsChallengedSubmitted(challenge) || ex.Message == "Failed to verify transaction.") - return false; - } - Task.Delay(m_updateInterval / 2).Wait(); - - if (string.IsNullOrWhiteSpace(transactionID)) - retryCount++; - - if (retryCount > 10) - { - Program.Print("[ERROR] Failed to submit solution for more than 10 times, please check settings."); - sender.StopMining(); - } - } - return true; - } - } - private void GetTransactionReciept(string transactionID, string address, HexBigInteger gasLimit, HexBigInteger userGas, int responseTime, DateTime submitDateTime) { @@ -902,21 +805,11 @@ private void GetTransactionReciept(string transactionID, string address, HexBigI } catch (AggregateException ex) { - var errorMessage = "[ERROR] " + ex.Message; - - foreach (var iEx in ex.InnerExceptions) - errorMessage += "\n " + iEx.Message; - - Program.Print(errorMessage); + HandleAggregateException(ex); } catch (Exception ex) { - var errorMessage = "[ERROR] " + ex.Message; - - if (ex.InnerException != null) - errorMessage += "\n " + ex.InnerException.Message; - - Program.Print(errorMessage); + HandleException(ex); } if (reciept == null) @@ -966,21 +859,11 @@ private void GetTransactionReciept(string transactionID, string address, HexBigI } catch (AggregateException ex) { - var errorMessage = "[ERROR] " + ex.Message; - - foreach (var iEx in ex.InnerExceptions) - errorMessage += "\n " + iEx.Message; - - Program.Print(errorMessage); + HandleAggregateException(ex); } catch (Exception ex) { - var errorMessage = "[ERROR] " + ex.Message; - - if (ex.InnerException != null) - errorMessage += "\n " + ex.InnerException.Message; - - Program.Print(errorMessage); + HandleException(ex); } } @@ -1053,21 +936,11 @@ private void SubmitDevFee(string address, HexBigInteger gasLimit, HexBigInteger } catch (AggregateException ex) { - var errorMessage = "[ERROR] " + ex.Message; - - foreach (var iEx in ex.InnerExceptions) - errorMessage += "\n " + iEx.Message; - - Program.Print(errorMessage); + HandleAggregateException(ex); } catch (Exception ex) { - var errorMessage = "[ERROR] " + ex.Message; - - if (ex.InnerException != null) - errorMessage += "\n " + ex.InnerException.Message; - - Program.Print(errorMessage); + HandleException(ex); } } @@ -1086,22 +959,53 @@ private void SubmitDevFee(string address, HexBigInteger gasLimit, HexBigInteger } catch (AggregateException ex) { - var errorMessage = "[ERROR] " + ex.Message; - - foreach (var iEx in ex.InnerExceptions) - errorMessage += "\n " + iEx.Message; - - Program.Print(errorMessage); + HandleAggregateException(ex); } catch (Exception ex) { - var errorMessage = "[ERROR] " + ex.Message; + HandleException(ex); + } + } + + private void HandleException(Exception ex, string errorPrefix = null) + { + var errorMessage = new StringBuilder("[ERROR] "); + + if (!string.IsNullOrWhiteSpace(errorPrefix)) + errorMessage.AppendFormat("{0}: ", errorPrefix); + + errorMessage.Append(ex.Message); + + var innerEx = ex.InnerException; + while (innerEx != null) + { + errorMessage.AppendFormat("\n {0}", innerEx.Message); + innerEx = innerEx.InnerException; + } + Program.Print(errorMessage.ToString()); + } + + private void HandleAggregateException(AggregateException ex, string errorPrefix = null) + { + var errorMessage = new StringBuilder("[ERROR] "); + + if (!string.IsNullOrWhiteSpace(errorPrefix)) + errorMessage.AppendFormat("{0}: ", errorPrefix); - if (ex.InnerException != null) - errorMessage += "\n " + ex.InnerException.Message; + errorMessage.Append(ex.Message); - Program.Print(errorMessage); + foreach (var innerException in ex.InnerExceptions) + { + errorMessage.AppendFormat("\n {0}", innerException.Message); + + var innerEx = ex.InnerException; + while (innerEx != null) + { + errorMessage.AppendFormat("\n {0}", innerEx.Message); + innerEx = innerEx.InnerException; + } } + Program.Print(errorMessage.ToString()); } } } \ No newline at end of file diff --git a/SoliditySHA3Miner/Program.cs b/SoliditySHA3Miner/Program.cs index 0e7a8a3..14c7c92 100644 --- a/SoliditySHA3Miner/Program.cs +++ b/SoliditySHA3Miner/Program.cs @@ -169,6 +169,7 @@ public static void Print(string message, bool excludePrefix = false) private static Miner.CPU m_cpuMiner; private static Miner.CUDA m_cudaMiner; private static Miner.OpenCL m_openCLMiner; + private static Miner.MasterInterface m_MasterInterface; private static Miner.IMiner[] m_allMiners; private static API.Json m_apiJson; @@ -267,31 +268,38 @@ private static void Main(string[] args) Config.hashrateUpdateInterval = Config.hashrateUpdateInterval < 1000 ? Config.Defaults.HashrateUpdateInterval : Config.hashrateUpdateInterval; Miner.Work.SolutionTemplate = Miner.Helper.CPU.GetSolutionTemplate(kingAddress: Config.kingAddress); + NetworkInterface.INetworkInterface mainNetworkInterface = null; - var web3Interface = new NetworkInterface.Web3Interface(Config.web3api, Config.contractAddress, Config.minerAddress, Config.privateKey, Config.gasToMine, - Config.abiFile, Config.networkUpdateInterval, Config.hashrateUpdateInterval, - Config.gasLimit, Config.gasApiURL, Config.gasApiPath, Config.gasApiMultiplier, Config.gasApiOffset, Config.gasApiMax); + if (!string.IsNullOrWhiteSpace(Config.masterURL) && !Config.masterMode) // Slave mode + mainNetworkInterface = new NetworkInterface.SlaveInterface(Config.masterURL, Config.slaveUpdateInterval, Config.hashrateUpdateInterval); - web3Interface.OverrideMaxTarget(Config.overrideMaxTarget); + else + { + var web3Interface = new NetworkInterface.Web3Interface(Config.web3api, Config.contractAddress, Config.minerAddress, Config.privateKey, Config.gasToMine, + Config.abiFile, Config.networkUpdateInterval, Config.hashrateUpdateInterval, + Config.gasLimit, Config.gasApiURL, Config.gasApiPath, Config.gasApiMultiplier, Config.gasApiOffset, Config.gasApiMax); - if (Config.customDifficulty > 0) - Print("[INFO] Custom difficulity: " + Config.customDifficulty.ToString()); + web3Interface.OverrideMaxTarget(Config.overrideMaxTarget); - NetworkInterface.INetworkInterface mainNetworkInterface = null; - var isSoloMining = !(string.IsNullOrWhiteSpace(Config.privateKey)); + if (Config.customDifficulty > 0) + Print("[INFO] Custom difficulity: " + Config.customDifficulty.ToString()); - if (isSoloMining) { mainNetworkInterface = web3Interface; } - else - { - var secondaryPoolInterface = string.IsNullOrWhiteSpace(Config.secondaryPool) - ? null - : new NetworkInterface.PoolInterface(Config.minerAddress, Config.secondaryPool, Config.maxScanRetry, - -1, -1, Config.customDifficulty, true, web3Interface.GetMaxTarget()); - - var primaryPoolInterface = new NetworkInterface.PoolInterface(Config.minerAddress, Config.primaryPool, Config.maxScanRetry, - Config.networkUpdateInterval, Config.hashrateUpdateInterval, - Config.customDifficulty, false, web3Interface.GetMaxTarget(), secondaryPoolInterface); - mainNetworkInterface = primaryPoolInterface; + var isSoloMining = !(string.IsNullOrWhiteSpace(Config.privateKey)); + + + if (isSoloMining) { mainNetworkInterface = web3Interface; } + else + { + var secondaryPoolInterface = string.IsNullOrWhiteSpace(Config.secondaryPool) + ? null + : new NetworkInterface.PoolInterface(Config.minerAddress, Config.secondaryPool, Config.maxScanRetry, + -1, -1, Config.customDifficulty, true, web3Interface.GetMaxTarget()); + + var primaryPoolInterface = new NetworkInterface.PoolInterface(Config.minerAddress, Config.primaryPool, Config.maxScanRetry, + Config.networkUpdateInterval, Config.hashrateUpdateInterval, + Config.customDifficulty, false, web3Interface.GetMaxTarget(), secondaryPoolInterface); + mainNetworkInterface = primaryPoolInterface; + } } if (AllowCUDA && Config.cudaDevices.Any(d => d.AllowDevice)) @@ -303,11 +311,14 @@ private static void Main(string[] args) if (AllowCPU && Config.cpuDevice.AllowDevice) m_cpuMiner = new Miner.CPU(mainNetworkInterface, Config.cpuDevice, Config.submitStale, Config.pauseOnFailedScans); - m_allMiners = new Miner.IMiner[] { m_openCLMiner, m_cudaMiner, m_cpuMiner }.Where(m => m != null).ToArray(); + if (Config.masterMode) + m_MasterInterface = new Miner.MasterInterface(mainNetworkInterface, Config.pauseOnFailedScans, Config.masterURL); + + m_allMiners = new Miner.IMiner[] { m_openCLMiner, m_cudaMiner, m_cpuMiner, m_MasterInterface }.Where(m => m != null).ToArray(); if (!m_allMiners.Any() || m_allMiners.All(m => !m.HasAssignedDevices)) { - Console.WriteLine("[ERROR] No miner assigned."); + Print("[ERROR] No miner assigned."); Environment.Exit(1); } diff --git a/SoliditySHA3Miner/Properties/Resources.Designer.cs b/SoliditySHA3Miner/Properties/Resources.Designer.cs index 914b076..dbfa5bd 100644 --- a/SoliditySHA3Miner/Properties/Resources.Designer.cs +++ b/SoliditySHA3Miner/Properties/Resources.Designer.cs @@ -61,34 +61,19 @@ internal Resources() { } /// - /// Looks up a localized string similar to #define OPENCL_PLATFORM_UNKNOWN 0 - ///#define OPENCL_PLATFORM_NVIDIA 1 - ///#define OPENCL_PLATFORM_AMD 2 + /// Looks up a localized string similar to /* + /// Copyright 2018 Lip Wee Yeo Amano /// - ///#ifndef PLATFORM - ///# define PLATFORM OPENCL_PLATFORM_UNKNOWN - ///#endif + /// Licensed under the Apache License, Version 2.0 (the "License"); + /// you may not use this file except in compliance with the License. + /// You may obtain a copy of the License at /// - ///#if PLATFORM == OPENCL_PLATFORM_AMD - ///# pragma OPENCL EXTENSION cl_amd_media_ops : enable - ///#endif + /// http://www.apache.org/licenses/LICENSE-2.0 /// - ///#ifndef COMPUTE - ///# define COMPUTE 0 - ///#endif - /// - ///#define STATE_LENGTH 200u - /// - ///typedef union _nonce_t - ///{ - /// uint2 uint2_s; - /// ulong ulong_s; - ///} nonce_t; - /// - ///typedef union _state_t - ///{ - /// uint2 uint2_s[STATE_LENGTH / sizeof(uint2)]; - /// [rest of string was truncated]";. + /// Unless required by applicable law or agreed to in writing, software + /// distributed under the License is distributed on an "AS IS" BASIS, + /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + /// See the Licens [rest of string was truncated]";. /// internal static string sha3Kernel { get { @@ -97,28 +82,19 @@ internal static string sha3Kernel { } /// - /// Looks up a localized string similar to #define OPENCL_PLATFORM_UNKNOWN 0 - ///#define OPENCL_PLATFORM_NVIDIA 1 - ///#define OPENCL_PLATFORM_AMD 2 - /// - ///#ifndef PLATFORM - ///#define PLATFORM OPENCL_PLATFORM_UNKNOWN - ///#endif + /// Looks up a localized string similar to /* + /// Copyright 2018 Lip Wee Yeo Amano /// - ///#if PLATFORM == OPENCL_PLATFORM_AMD - ///#pragma OPENCL EXTENSION cl_amd_media_ops : enable - ///#endif + /// Licensed under the Apache License, Version 2.0 (the "License"); + /// you may not use this file except in compliance with the License. + /// You may obtain a copy of the License at /// - ///#ifndef COMPUTE - ///#define COMPUTE 0 - ///#endif + /// http://www.apache.org/licenses/LICENSE-2.0 /// - ///#define ADDRESS_LENGTH 20u - ///#define UINT64_LENGTH 8u - ///#define UINT256_LENGTH 32u - ///#define MESSAGE_LENGTH 84u - ///#define SPONGE_LENGTH 200u - ///#define NONCE_POSITION UINT256_LENGT [rest of string was truncated]";. + /// Unless required by applicable law or agreed to in writing, software + /// distributed under the License is distributed on an "AS IS" BASIS, + /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + /// See the Licens [rest of string was truncated]";. /// internal static string sha3KingKernel { get { diff --git a/SoliditySHA3Miner/Readme.txt b/SoliditySHA3Miner/Readme.txt index ed76f09..dba4a97 100644 --- a/SoliditySHA3Miner/Readme.txt +++ b/SoliditySHA3Miner/Readme.txt @@ -1,8 +1,8 @@ SoliditySHA3Miner All-in-one mixed multi-GPU (nVidia, AMD, Intel) & CPU miner solves proof of work to mine supported EIP918 tokens in a single instance (with API). -Current latest public release version: 2.1.1 -Runs on Windows 10, HiveOS, EthOS, and Ubuntu. +Current latest public release version: 2.2.0 +Runs on Windows x64, HiveOS, EthOS, and Ubuntu. Built with .NET Core 2.1.5 SDK, VC++ 2017, gcc 4.8.5, nVidia CUDA SDK 9.2 64-bits, and AMD APP SDK v3.0.130.135 (OpenCL) .NET Core 2.1 can be downloaded from https://www.microsoft.com/net/download @@ -50,6 +50,9 @@ Options: contract Token contract address (default: 0xbtc contract address) hashrateUpdateInterval Interval (miliseconds) for GPU hashrate logs (default: 30000) networkUpdateInterval Interval (miliseconds) to scan for new work (default: 15000) + masterMode Enable Master mode that virtually acts as a \"pool\" for slave miners connecting to it (default: false [requires admin/sudo mode]) + masterURL Master instance IP:port, slave mode if 'masterMode' is false (default: none [if 'masterMode' is true, default: http://{localIP}:4080/]) + slaveUpdateInterval (Slave only)Interval (miliseconds) to scan for new work (default: 5000) kingAddress Add MiningKing address to nonce, only CPU mining supported (default: none) address (Pool only) Miner's ethereum address (default: developer's address) privateKey (Solo only) Miner's private key @@ -71,9 +74,9 @@ For EthOS, refer to 'GuideForEthOS.txt' on how to get started. Do refer to 'GuideForPoolMining.txt' and 'GuideForSoloMining.txt' on how to get started. Configuration is based on CLI (similar to ccminer), except ".abi" files are required for new tokens (You can manually create one and copy from etherscan.com -> Contract -> Code -> Contract ABI). Note that there is a configuration file "SoliditySHA3Miner.conf" that saves previous CLI parameters/settings, delete it prior to changing CLI parameters. -A sample CLI launch parameter can be found in the ".bat" file found together with this miner, please refer to it if you need help. +Sample CLI launch parameter can be found in the ".bat" and ".sh" file found together with this miner, please refer to it if you need help. You will have to supply your own Ethereum address (or Private key if you solo mine). It is your own responsibility to mine to the correct address/account. -It is recommended to use your own web3api (e.g. Geth / Parity) if you solo mine. +It is recommended to use your own web3api (e.g. Infura / Geth / Parity) if you solo mine, default value is for TESTING PURPOSE ONLY. There is a default of 2.0% dev fee (Once every 50th nonce: starting from 11th if Pool mine, or starting from 50th if Solo mine). You can set to the lowest 1.5% with "devFee=1.5" (the formula is "(nonce mod (100 / devFee)) = 0"). Dev fee in solo mining is by sending the current reward amount after the successful minted block, using the same gas fee as provided in 'gasToMine'. diff --git a/SoliditySHA3Miner/Scripts/0xbtcPoolMaster.bat b/SoliditySHA3Miner/Scripts/0xbtcPoolMaster.bat new file mode 100644 index 0000000..12284d6 --- /dev/null +++ b/SoliditySHA3Miner/Scripts/0xbtcPoolMaster.bat @@ -0,0 +1,31 @@ +@echo off +pushd %~dp0 + +for %%X in (dotnet.exe) do (set FOUND=%%~$PATH:X) +if defined FOUND (goto dotNetFound) else (goto dotNetNotFound) + +:dotNetNotFound +echo .NET Core is not found or not installed, +echo download and install from https://www.microsoft.com/net/download/windows/run +goto end + +:dotNetFound +:startMiner +DEL /F /Q SoliditySHA3Miner.conf + +dotnet SoliditySHA3Miner.dll ^ +masterMode=true ^ +allowCPU=false ^ +allowIntel=false ^ +allowAMD=false ^ +allowCUDA=false ^ +networkUpdateInterval=10000 ^ +abiFile=0xBTC.abi ^ +contract=0xB6eD7644C69416d67B522e20bC294A9a9B405B31 ^ +overrideMaxTarget=27606985387162255149739023449108101809804435888681546220650096895197184 ^ +pool=http://mike.rs:8080 ^ +address=0x9172ff7884CEFED19327aDaCe9C470eF1796105c + +goto startMiner +:end +pause \ No newline at end of file diff --git a/SoliditySHA3Miner/Scripts/0xbtcPoolMaster.sh b/SoliditySHA3Miner/Scripts/0xbtcPoolMaster.sh new file mode 100644 index 0000000..7a39654 --- /dev/null +++ b/SoliditySHA3Miner/Scripts/0xbtcPoolMaster.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +command -v dotnet >/dev/null 2>&1 || +{ + echo >&2 ".NET Core is not found or not installed," + echo >&2 "run 'sh install-deps.sh' to install dependencies."; + read -p "Press any key to continue..."; + exit 1; +} +while : ; do + if [ -f SoliditySHA3Miner.conf ] ; then + rm -f SoliditySHA3Miner.conf + fi + dotnet SoliditySHA3Miner.dll masterMode=true allowCPU=false allowIntel=false allowAMD=false allowCUDA=false networkUpdateInterval=10000 abiFile=0xBTC.abi contract=0xB6eD7644C69416d67B522e20bC294A9a9B405B31 overrideMaxTarget=27606985387162255149739023449108101809804435888681546220650096895197184 pool=http://mike.rs:8080 address=0x9172ff7884CEFED19327aDaCe9C470eF1796105c +done diff --git a/SoliditySHA3Miner/Scripts/0xbtcSolo.bat b/SoliditySHA3Miner/Scripts/0xbtcSolo.bat index ae540f7..0effea6 100644 --- a/SoliditySHA3Miner/Scripts/0xbtcSolo.bat +++ b/SoliditySHA3Miner/Scripts/0xbtcSolo.bat @@ -27,7 +27,7 @@ gasLimit=600000 ^ gasApiURL=https://ethgasstation.info/json/ethgasAPI.json ^ gasApiPath=$.safeLow ^ gasApiMultiplier=0.1 ^ -gasApiOffset=0.5 ^ +gasApiOffset=1.0 ^ privateKey=YOUR_ETH_PRIVATE_KEY if %errorlevel% EQU 22 ( diff --git a/SoliditySHA3Miner/Scripts/0xbtcSolo.sh b/SoliditySHA3Miner/Scripts/0xbtcSolo.sh index 78536d8..11a29eb 100644 --- a/SoliditySHA3Miner/Scripts/0xbtcSolo.sh +++ b/SoliditySHA3Miner/Scripts/0xbtcSolo.sh @@ -3,11 +3,14 @@ command -v dotnet >/dev/null 2>&1 || { echo >&2 ".NET Core is not found or not installed," - echo >&2 "download and install from https://www.microsoft.com/net/download/linux/run"; + echo >&2 "run 'sh install-deps.sh' to install dependencies."; read -p "Press any key to continue..."; exit 1; } +while : ; do if [ -f SoliditySHA3Miner.conf ] ; then rm -f SoliditySHA3Miner.conf fi -dotnet SoliditySHA3Miner.dll allowCPU=false allowIntel=true allowAMD=true allowCUDA=true web3api=https://mainnet.infura.io/ANueYSYQTstCr2mFJjPE abiFile=0xBTC.abi contract=0xB6eD7644C69416d67B522e20bC294A9a9B405B31 gasToMine=3 gasApiMax=7 gasLimit=600000 gasApiURL=https://ethgasstation.info/json/ethgasAPI.json gasApiPath=$.safeLow gasApiMultiplier=0.1 gasApiOffset=0.5 privateKey=YOUR_ETH_PRIVATE_KEY + dotnet SoliditySHA3Miner.dll allowCPU=false allowIntel=true allowAMD=true allowCUDA=true web3api=https://mainnet.infura.io/ANueYSYQTstCr2mFJjPE abiFile=0xBTC.abi contract=0xB6eD7644C69416d67B522e20bC294A9a9B405B31 gasToMine=3 gasApiMax=7 gasLimit=600000 gasApiURL=https://ethgasstation.info/json/ethgasAPI.json gasApiPath=$.safeLow gasApiMultiplier=0.1 gasApiOffset=1.0 privateKey=YOUR_ETH_PRIVATE_KEY + [[ $? -eq 22 ]] || break +done diff --git a/SoliditySHA3Miner/Scripts/0xbtcSoloMaster.bat b/SoliditySHA3Miner/Scripts/0xbtcSoloMaster.bat new file mode 100644 index 0000000..d4d8ff4 --- /dev/null +++ b/SoliditySHA3Miner/Scripts/0xbtcSoloMaster.bat @@ -0,0 +1,37 @@ +@echo off +pushd %~dp0 + +for %%X in (dotnet.exe) do (set FOUND=%%~$PATH:X) +if defined FOUND (goto dotNetFound) else (goto dotNetNotFound) + +:dotNetNotFound +echo .NET Core is not found or not installed, +echo download and install from https://www.microsoft.com/net/download/windows/run +goto end + +:dotNetFound +:startMiner +DEL /F /Q SoliditySHA3Miner.conf + +dotnet SoliditySHA3Miner.dll ^ +masterMode=true ^ +allowCPU=false ^ +allowIntel=false ^ +allowAMD=false ^ +allowCUDA=false ^ +networkUpdateInterval=10000 ^ +web3api=https://mainnet.infura.io/ANueYSYQTstCr2mFJjPE ^ +abiFile=0xBTC.abi ^ +contract=0xB6eD7644C69416d67B522e20bC294A9a9B405B31 ^ +gasToMine=3 ^ +gasApiMax=7 ^ +gasLimit=600000 ^ +gasApiURL=https://ethgasstation.info/json/ethgasAPI.json ^ +gasApiPath=$.safeLow ^ +gasApiMultiplier=0.1 ^ +gasApiOffset=1.0 ^ +privateKey=YOUR_ETH_PRIVATE_KEY + +goto startMiner +:end +pause \ No newline at end of file diff --git a/SoliditySHA3Miner/Scripts/0xbtcSoloMaster.sh b/SoliditySHA3Miner/Scripts/0xbtcSoloMaster.sh new file mode 100644 index 0000000..3f0060e --- /dev/null +++ b/SoliditySHA3Miner/Scripts/0xbtcSoloMaster.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +command -v dotnet >/dev/null 2>&1 || +{ + echo >&2 ".NET Core is not found or not installed," + echo >&2 "run 'sh install-deps.sh' to install dependencies."; + read -p "Press any key to continue..."; + exit 1; +} +while : ; do + if [ -f SoliditySHA3Miner.conf ] ; then + rm -f SoliditySHA3Miner.conf + fi + dotnet SoliditySHA3Miner.dll masterMode=true allowCPU=false allowIntel=false allowAMD=false allowCUDA=false networkUpdateInterval=10000 web3api=https://mainnet.infura.io/ANueYSYQTstCr2mFJjPE abiFile=0xBTC.abi contract=0xB6eD7644C69416d67B522e20bC294A9a9B405B31 gasToMine=3 gasApiMax=7 gasLimit=600000 gasApiURL=https://ethgasstation.info/json/ethgasAPI.json gasApiPath=$.safeLow gasApiMultiplier=0.1 gasApiOffset=1.0 privateKey=YOUR_ETH_PRIVATE_KEY +done diff --git a/SoliditySHA3Miner/Scripts/SoliditySHA3MinerSlave.bat b/SoliditySHA3Miner/Scripts/SoliditySHA3MinerSlave.bat new file mode 100644 index 0000000..4d65f4d --- /dev/null +++ b/SoliditySHA3Miner/Scripts/SoliditySHA3MinerSlave.bat @@ -0,0 +1,29 @@ +@echo off +pushd %~dp0 + +for %%X in (dotnet.exe) do (set FOUND=%%~$PATH:X) +if defined FOUND (goto dotNetFound) else (goto dotNetNotFound) + +:dotNetNotFound +echo .NET Core is not found or not installed, +echo download and install from https://www.microsoft.com/net/download/windows/run +goto end + +:dotNetFound +:startMiner +DEL /F /Q SoliditySHA3Miner.conf + +dotnet SoliditySHA3Miner.dll ^ +masterMode=false ^ +allowCPU=false ^ +allowIntel=true ^ +allowAMD=true ^ +allowCUDA=true ^ +masterURL=http://192.168.0.1:4080/ ^ +slaveUpdateInterval=5000 + +if %errorlevel% EQU 22 ( + goto startMiner +) +:end +pause \ No newline at end of file diff --git a/SoliditySHA3Miner/Scripts/SoliditySHA3MinerSlave.sh b/SoliditySHA3Miner/Scripts/SoliditySHA3MinerSlave.sh new file mode 100644 index 0000000..e8bcb63 --- /dev/null +++ b/SoliditySHA3Miner/Scripts/SoliditySHA3MinerSlave.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +command -v dotnet >/dev/null 2>&1 || +{ + echo >&2 ".NET Core is not found or not installed," + echo >&2 "run 'sh install-deps.sh' to install dependencies."; + read -p "Press any key to continue..."; + exit 1; +} +while : ; do + if [ -f SoliditySHA3Miner.conf ] ; then + rm -f SoliditySHA3Miner.conf + fi + dotnet SoliditySHA3Miner.dll masterMode=false allowCPU=false allowIntel=true allowAMD=true allowCUDA=true masterURL=http://192.168.0.1:4080/ slaveUpdateInterval=5000 + [[ $? -eq 22 ]] || break +done diff --git a/SoliditySHA3Miner/Scripts/clmSolo.bat b/SoliditySHA3Miner/Scripts/clmSolo.bat index a12dd44..2b2b76f 100644 --- a/SoliditySHA3Miner/Scripts/clmSolo.bat +++ b/SoliditySHA3Miner/Scripts/clmSolo.bat @@ -21,13 +21,14 @@ allowCUDA=true ^ web3api=https://mainnet.infura.io/ANueYSYQTstCr2mFJjPE ^ abiFile=CLM.abi ^ contract=0xA38FcEdd23dE2191Dc27f9a0240ac170BE0A14fE ^ +overrideMaxTarget=27606985387162255149739023449108101809804435888681546220650096895197184 ^ gasToMine=3 ^ gasApiMax=7 ^ gasLimit=600000 ^ gasApiURL=https://ethgasstation.info/json/ethgasAPI.json ^ gasApiPath=$.safeLow ^ gasApiMultiplier=0.1 ^ -gasApiOffset=0.5 ^ +gasApiOffset=1.0 ^ privateKey=YOUR_ETH_PRIVATE_KEY if %errorlevel% EQU 22 ( diff --git a/SoliditySHA3Miner/Scripts/clmSolo.sh b/SoliditySHA3Miner/Scripts/clmSolo.sh index 055ca30..13ac7c1 100644 --- a/SoliditySHA3Miner/Scripts/clmSolo.sh +++ b/SoliditySHA3Miner/Scripts/clmSolo.sh @@ -3,11 +3,14 @@ command -v dotnet >/dev/null 2>&1 || { echo >&2 ".NET Core is not found or not installed," - echo >&2 "download and install from https://www.microsoft.com/net/download/linux/run"; + echo >&2 "run 'sh install-deps.sh' to install dependencies."; read -p "Press any key to continue..."; exit 1; } +while : ; do if [ -f SoliditySHA3Miner.conf ] ; then rm -f SoliditySHA3Miner.conf fi -dotnet SoliditySHA3Miner.dll allowCPU=false allowIntel=true allowAMD=true allowCUDA=true web3api=https://mainnet.infura.io/ANueYSYQTstCr2mFJjPE abiFile=CLM.abi contract=0xA38FcEdd23dE2191Dc27f9a0240ac170BE0A14fE gasToMine=3 gasApiMax=7 gasLimit=600000 gasApiURL=https://ethgasstation.info/json/ethgasAPI.json gasApiPath=$.safeLow gasApiMultiplier=0.1 gasApiOffset=0.5 privateKey=YOUR_ETH_PRIVATE_KEY + dotnet SoliditySHA3Miner.dll allowCPU=false allowIntel=true allowAMD=true allowCUDA=true web3api=https://mainnet.infura.io/ANueYSYQTstCr2mFJjPE abiFile=CLM.abi contract=0xA38FcEdd23dE2191Dc27f9a0240ac170BE0A14fE overrideMaxTarget=27606985387162255149739023449108101809804435888681546220650096895197184 gasToMine=3 gasApiMax=7 gasLimit=600000 gasApiURL=https://ethgasstation.info/json/ethgasAPI.json gasApiPath=$.safeLow gasApiMultiplier=0.1 gasApiOffset=1.0 privateKey=YOUR_ETH_PRIVATE_KEY + [[ $? -eq 22 ]] || break +done diff --git a/SoliditySHA3Miner/SoliditySHA3Miner.conf b/SoliditySHA3Miner/SoliditySHA3Miner.conf index 20fa578..49ed463 100644 --- a/SoliditySHA3Miner/SoliditySHA3Miner.conf +++ b/SoliditySHA3Miner/SoliditySHA3Miner.conf @@ -5,13 +5,16 @@ "web3api": "https://mainnet.infura.io/ANueYSYQTstCr2mFJjPE", "contractAddress": "0xB6eD7644C69416d67B522e20bC294A9a9B405B31", "abiFile": "0xBTC.abi", - "overrideMaxTarget": "0x", + "overrideMaxTarget": "0x0", "customDifficulty": 0, "submitStale": false, "maxScanRetry": 3, "pauseOnFailedScans": 3, "networkUpdateInterval": 15000, "hashrateUpdateInterval": 30000, + "masterMode": false, + "masterURL": "", + "slaveUpdateInterval": 5000, "kingAddress": "", "minerAddress": "0x9172ff7884CEFED19327aDaCe9C470eF1796105c", "primaryPool": "http://mike.rs:8080", @@ -25,11 +28,20 @@ "gasApiOffset": 0.5, "gasApiMax": 7.0, "allowCPU": false, - "cpuDevices": [], + "cpuDevice": { + "Affinities": null, + "AllowDevice": false, + "Type": null, + "Platform": null, + "DeviceID": 0, + "PciBusID": 0, + "Name": null, + "Intensity": 0.0 + }, "allowIntel": true, "intelDevices": [], "allowAMD": true, "amdDevices": [], "allowCUDA": true, "cudaDevices": [] -} +} \ No newline at end of file diff --git a/SoliditySHA3Miner/SoliditySHA3Miner.csproj b/SoliditySHA3Miner/SoliditySHA3Miner.csproj index d352348..ea084b2 100644 --- a/SoliditySHA3Miner/SoliditySHA3Miner.csproj +++ b/SoliditySHA3Miner/SoliditySHA3Miner.csproj @@ -3,7 +3,7 @@ Exe netcoreapp2.1 - 2.1.1 + 2.2.0 lwYeo lwYeo@github https://github.com/lwYeo/SoliditySHA3Miner/blob/master/LICENSE @@ -63,22 +63,22 @@ Always - + Always - + Always - + Always - + Always - + Always - + Always @@ -87,9 +87,6 @@ Always - - Always - Always @@ -105,12 +102,6 @@ Always - - Always - - - Always - Always @@ -144,13 +135,10 @@ Always - - Always - - + diff --git a/SoliditySHA3Miner/Structs/DeviceCL.cs b/SoliditySHA3Miner/Structs/DeviceCL.cs index 5c099f1..65e5853 100644 --- a/SoliditySHA3Miner/Structs/DeviceCL.cs +++ b/SoliditySHA3Miner/Structs/DeviceCL.cs @@ -44,6 +44,7 @@ public struct DeviceCL public unsafe string NameToString() { byte* namePtr = (byte*)Name.ToPointer(); + if (namePtr == null) return null; return string.Concat(Encoding.ASCII.GetString(namePtr, 256).TakeWhile(c => c != '\0').ToArray()); } diff --git a/SoliditySHA3Miner/Structs/DeviceCPU.cs b/SoliditySHA3Miner/Structs/DeviceCPU.cs index 4daf459..c852bfc 100644 --- a/SoliditySHA3Miner/Structs/DeviceCPU.cs +++ b/SoliditySHA3Miner/Structs/DeviceCPU.cs @@ -25,6 +25,10 @@ public struct Processor public int Affinity; public ulong WorkSize; public ulong WorkPosition; + + public uint MaxSolutionCount; + public uint SolutionCount; + public IntPtr Solutions; } [StructLayout(LayoutKind.Sequential)] @@ -39,9 +43,5 @@ public struct DeviceCPU public IntPtr Target; public IntPtr High64Target; - - public uint MaxSolutionCount; - public uint SolutionCount; - public IntPtr Solutions; } } \ No newline at end of file diff --git a/SoliditySHA3Miner/Structs/DeviceCUDA.cs b/SoliditySHA3Miner/Structs/DeviceCUDA.cs index 8addd78..b9b8db1 100644 --- a/SoliditySHA3Miner/Structs/DeviceCUDA.cs +++ b/SoliditySHA3Miner/Structs/DeviceCUDA.cs @@ -44,6 +44,7 @@ public struct DeviceCUDA public unsafe string NameToString() { byte* namePtr = (byte*)Name.ToPointer(); + if (namePtr == null) return null; return string.Concat(Encoding.ASCII.GetString(namePtr, 256).TakeWhile(c => c != '\0').ToArray()); } diff --git a/SoliditySHA3Miner/Utils/Json.cs b/SoliditySHA3Miner/Utils/Json.cs index bdaca3f..aa5e7e3 100644 --- a/SoliditySHA3Miner/Utils/Json.cs +++ b/SoliditySHA3Miner/Utils/Json.cs @@ -28,7 +28,7 @@ namespace SoliditySHA3Miner.Utils { internal static class Json { - private const int MAX_TIMEOUT = 5; + private const int MAX_TIMEOUT = 10; private static object _Object1 = new object(); private static object _Object2 = new object(); private static object _Object3 = new object(); @@ -137,15 +137,15 @@ public static bool SerializeToFile(object jObject, string filePath, JsonSerializ } } - public static JObject InvokeJObjectRPC(string url, JObject obj, JsonSerializerSettings settings = null) + public static JObject InvokeJObjectRPC(string url, JObject obj, JsonSerializerSettings settings = null, int customTimeout = 0) { lock (_Object5) { var serializedJSON = SerializeFromObject(obj, settings); var httpRequest = (HttpWebRequest)WebRequest.Create(url); - httpRequest.Timeout = MAX_TIMEOUT * 1000; - httpRequest.ReadWriteTimeout = MAX_TIMEOUT * 1000; + httpRequest.Timeout = (customTimeout > 0 ? customTimeout : MAX_TIMEOUT) * 1000; + httpRequest.ReadWriteTimeout = (customTimeout > 0 ? customTimeout : MAX_TIMEOUT) * 1000; httpRequest.ContentLength = serializedJSON.Length; httpRequest.ContentType = "application/json-rpc"; httpRequest.Method = "POST"; diff --git a/SoliditySHA3Miner/Utils/Numerics.cs b/SoliditySHA3Miner/Utils/Numerics.cs index 60e1275..f4aa615 100644 --- a/SoliditySHA3Miner/Utils/Numerics.cs +++ b/SoliditySHA3Miner/Utils/Numerics.cs @@ -18,7 +18,6 @@ limitations under the License. using System; using System.Collections.Generic; using System.Linq; -using System.Numerics; namespace SoliditySHA3Miner.Utils { @@ -56,6 +55,10 @@ public static string Byte32ArrayToHexString(byte[] byte32, bool prefix = true) lock (m_Byte32ArrayToHexStringLock) { var byte32String = prefix ? "0x" : string.Empty; + + if (byte32.Length != Miner.MinerBase.UINT256_LENGTH) + byte32 = FilterByte32Array(byte32); + for (var i = 0; i < Miner.MinerBase.UINT256_LENGTH; i++) byte32String += ASCII[byte32[i]]; @@ -107,7 +110,7 @@ public static byte[] FilterByte32Array(IEnumerable bytes) for (int i = 0; i < Miner.MinerBase.UINT256_LENGTH; i++) outBytes[i] = 0; - for (int i = 31, j = (bytes.Count() - 1); i >= 0 && j >= 0; i--, j--) + for (int i = Miner.MinerBase.UINT256_LENGTH - 1, j = (bytes.Count() - 1); i >= 0 && j >= 0; i--, j--) outBytes[i] = bytes.ElementAt(j); return outBytes; @@ -137,5 +140,31 @@ public static void AddressStringToByte20Array(string addressString, ref byte[] a address[bytePosition] = value; } } + + public static string Byte20ArrayToAddressString(byte[] address, bool prefix = true) + { + var addressString = prefix ? "0x" : string.Empty; + + if (address.Length != Miner.MinerBase.ADDRESS_LENGTH) + address = FilterByte20Array(address); + + for (var i = 0; i < Miner.MinerBase.ADDRESS_LENGTH; i++) + addressString += ASCII[address[i]]; + + return addressString; + } + + public static byte[] FilterByte20Array(IEnumerable bytes) + { + var outBytes = (byte[])Array.CreateInstance(typeof(byte), Miner.MinerBase.ADDRESS_LENGTH); + + for (int i = 0; i < Miner.MinerBase.ADDRESS_LENGTH; i++) + outBytes[i] = 0; + + for (int i = Miner.MinerBase.ADDRESS_LENGTH - 1, j = (bytes.Count() - 1); i >= 0 && j >= 0; i--, j--) + outBytes[i] = bytes.ElementAt(j); + + return outBytes; + } } } \ No newline at end of file