From b9133db9fb84a4c4f0c6d066cbefcefd5e369814 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Fri, 15 May 2015 16:46:02 +0200 Subject: [PATCH 1/9] printf logging for ethash_full_new() errors --- internal.c | 12 +++++++++++- io.c | 18 ++++++++++++++++-- io.h | 13 +++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/internal.c b/internal.c index e881e0c7b..ec2275f32 100644 --- a/internal.c +++ b/internal.c @@ -400,38 +400,48 @@ ethash_full_t ethash_full_new_internal( ret->file_size = (size_t)full_size; switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) { case ETHASH_IO_FAIL: + // ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case goto fail_free_full; case ETHASH_IO_MEMO_MATCH: if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); goto fail_close_file; } return ret; case ETHASH_IO_MEMO_SIZE_MISMATCH: // if a DAG of same filename but unexpected size is found, silently force new file creation if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) { + ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size."); goto fail_free_full; } // fallthrough to the mismatch case here, DO NOT go through match case ETHASH_IO_MEMO_MISMATCH: if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); goto fail_close_file; } break; } if (!ethash_compute_full_data(ret->data, full_size, light, callback)) { + ETHASH_CRITICAL("Failure at computing DAG data."); goto fail_free_full_data; } // after the DAG has been filled then we finalize it by writting the magic number at the beginning if (fseek(f, 0, SEEK_SET) != 0) { + ETHASH_CRITICAL("Could not seek to DAG file start to write magic number."); goto fail_free_full_data; } uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM; if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { + ETHASH_CRITICAL("Could not write magic number to DAG's beginning."); + goto fail_free_full_data; + } + if (fflush(f) != 0) {// make sure the magic number IS there + ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?"); goto fail_free_full_data; } - fflush(f); // make sure the magic number IS there return ret; fail_free_full_data: diff --git a/io.c b/io.c index 5b4e7da2b..f53827ee0 100644 --- a/io.c +++ b/io.c @@ -35,12 +35,14 @@ enum ethash_io_rc ethash_io_prepare( // assert directory exists if (!ethash_mkdir(dirname)) { + ETHASH_CRITICAL("Could not create the ethash directory"); goto end; } ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name); char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name)); if (!tmpfile) { + ETHASH_CRITICAL("Could not create the full DAG pathname"); goto end; } @@ -52,6 +54,7 @@ enum ethash_io_rc ethash_io_prepare( size_t found_size; if (!ethash_file_size(f, &found_size)) { fclose(f); + ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile); goto free_memo; } if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) { @@ -64,6 +67,7 @@ enum ethash_io_rc ethash_io_prepare( if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { // I/O error fclose(f); + ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile); ret = ETHASH_IO_MEMO_SIZE_MISMATCH; goto free_memo; } @@ -80,15 +84,25 @@ enum ethash_io_rc ethash_io_prepare( // file does not exist, will need to be created f = ethash_fopen(tmpfile, "wb+"); if (!f) { + ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile); goto free_memo; } // make sure it's of the proper size if (fseek(f, (long int)(file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1), SEEK_SET) != 0) { fclose(f); + ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fputc('\n', f) == EOF) { + fclose(f); + ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fflush(f) != 0) { + fclose(f); + ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile); goto free_memo; } - fputc('\n', f); - fflush(f); ret = ETHASH_IO_MEMO_MISMATCH; goto set_file; diff --git a/io.h b/io.h index 05aa5ed37..58ec90a9e 100644 --- a/io.h +++ b/io.h @@ -54,6 +54,19 @@ enum ethash_io_rc { #define snprintf(...) sprintf_s(__VA_ARGS__) #endif +/** + * Logs a critical error in important parts of ethash. Should mostly help + * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL + * ethash_full_t + */ +#define ETHASH_CRITICAL(...) \ + do \ + { \ + printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) + /** * Prepares io for ethash * From d4a4b6e2850a1df8247939119f3812477e1659b3 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Sun, 17 May 2015 17:29:38 +0200 Subject: [PATCH 2/9] Using errno to detect ethash_io failures - Printf debug output is still printed by ethash itself unless one compiles with -DETHASH_NO_CRITICAL_OUTPUT. --- internal.c | 1 + io.c | 3 +++ io.h | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/internal.c b/internal.c index ec2275f32..b28a59e43 100644 --- a/internal.c +++ b/internal.c @@ -364,6 +364,7 @@ static bool ethash_mmap(struct ethash_full* ret, FILE* f) { int fd; char* mmapped_data; + errno = 0; ret->file = f; if ((fd = ethash_fileno(ret->file)) == -1) { return false; diff --git a/io.c b/io.c index f53827ee0..f4db477c2 100644 --- a/io.c +++ b/io.c @@ -21,6 +21,7 @@ #include "io.h" #include #include +#include enum ethash_io_rc ethash_io_prepare( char const* dirname, @@ -32,6 +33,8 @@ enum ethash_io_rc ethash_io_prepare( { char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE]; enum ethash_io_rc ret = ETHASH_IO_FAIL; + // reset errno before io calls + errno = 0; // assert directory exists if (!ethash_mkdir(dirname)) { diff --git a/io.h b/io.h index 58ec90a9e..da35eacba 100644 --- a/io.h +++ b/io.h @@ -59,6 +59,7 @@ enum ethash_io_rc { * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL * ethash_full_t */ +#ifndef ETHASH_NO_CRITICAL_OUTPUT #define ETHASH_CRITICAL(...) \ do \ { \ @@ -66,6 +67,9 @@ enum ethash_io_rc { printf("\n"); \ fflush(stdout); \ } while (0) +#else +#define ETHASH_CRITICAL(...) +#endif /** * Prepares io for ethash From c11326c22189c3a72af90820cf97d58ef2b7780c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Mon, 18 May 2015 11:37:31 +0200 Subject: [PATCH 3/9] Ethash critical output should be disabled by default - If the user needs it simply compile with -DETHASH_PRINT_CRITICAL_OUTPUT --- io.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/io.h b/io.h index da35eacba..7a27089c7 100644 --- a/io.h +++ b/io.h @@ -59,7 +59,7 @@ enum ethash_io_rc { * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL * ethash_full_t */ -#ifndef ETHASH_NO_CRITICAL_OUTPUT +#ifdef ETHASH_PRINT_CRITICAL_OUTPUT #define ETHASH_CRITICAL(...) \ do \ { \ From 371d23decc70bde894ef794aa9e7fc08237535a1 Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Jun 2015 16:10:21 +0200 Subject: [PATCH 4/9] Check if GPU has over 2GB of memory If the user's machine contains no OpenCL device that has enough GPU memory then don't allow creation of a GPU miner. Instead default to CPU. --- ethminer/MinerAux.h | 12 +++++- libethash-cl/ethash_cl_miner.cpp | 65 +++++++++++++++++++++++++++----- libethash-cl/ethash_cl_miner.h | 1 + libethcore/Ethash.cpp | 5 +++ libethcore/Ethash.h | 1 + 5 files changed, 72 insertions(+), 12 deletions(-) diff --git a/ethminer/MinerAux.h b/ethminer/MinerAux.h index 47fd2e2ae..bae4b942c 100644 --- a/ethminer/MinerAux.h +++ b/ethminer/MinerAux.h @@ -171,8 +171,16 @@ public: m_minerType = MinerType::CPU; else if (arg == "-G" || arg == "--opencl") { - m_minerType = MinerType::GPU; - miningThreads = 1; + if (!ProofOfWork::GPUMiner::haveSufficientGPUMemory()) + { + cout << "No GPU device with sufficient memory was found. Defaulting to CPU" << endl; + m_minerType = MinerType::CPU; + } + else + { + m_minerType = MinerType::GPU; + miningThreads = 1; + } } else if (arg == "--no-precompute") { diff --git a/libethash-cl/ethash_cl_miner.cpp b/libethash-cl/ethash_cl_miner.cpp index 93ce9ab22..7e2dfd46e 100644 --- a/libethash-cl/ethash_cl_miner.cpp +++ b/libethash-cl/ethash_cl_miner.cpp @@ -35,6 +35,7 @@ #include "ethash_cl_miner_kernel.h" #define ETHASH_BYTES 32 +#define ETHASH_CL_MINIMUM_MEMORY 2000000000 // workaround lame platforms #if !CL_VERSION_1_2 @@ -47,6 +48,9 @@ using namespace std; +// TODO: If at any point we can use libdevcore in here then we should switch to using a LogChannel +#define ETHCL_LOG(_contents) cout << "[OPENCL]:" << _contents << endl + static void add_definition(std::string& source, char const* id, unsigned value) { char buf[256]; @@ -72,7 +76,7 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return std::string(); } @@ -82,7 +86,7 @@ std::string ethash_cl_miner::platform_info(unsigned _platformId, unsigned _devic platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return std::string(); } @@ -107,7 +111,7 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return 0; } @@ -116,12 +120,53 @@ unsigned ethash_cl_miner::get_num_devices(unsigned _platformId) platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return 0; } return devices.size(); } +bool ethash_cl_miner::haveSufficientGPUMemory(unsigned _platformId) +{ + std::vector platforms; + cl::Platform::get(&platforms); + if (platforms.empty()) + { + ETHCL_LOG("No OpenCL platforms found."); + return false; + } + + std::vector devices; + unsigned platform_num = std::min(_platformId, platforms.size() - 1); + platforms[platform_num].getDevices(CL_DEVICE_TYPE_ALL, &devices); + if (devices.empty()) + { + ETHCL_LOG("No OpenCL devices found."); + return false; + } + + for (cl::Device const& device: devices) + { + cl_ulong result; + device.getInfo(CL_DEVICE_GLOBAL_MEM_SIZE, &result); + if (result >= ETHASH_CL_MINIMUM_MEMORY) + { + ETHCL_LOG( + "Found suitable OpenCL device [" << device.getInfo() + << "] with " << result << " bytes of GPU memory" + ); + return true; + } + else + ETHCL_LOG( + "OpenCL device " << device.getInfo() + << " has insufficient GPU memory." << result << + " bytes of memory found < " << ETHASH_CL_MINIMUM_MEMORY << " bytes of memory required" + ); + } + return false; +} + void ethash_cl_miner::finish() { if (m_queue()) @@ -135,7 +180,7 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work cl::Platform::get(&platforms); if (platforms.empty()) { - cout << "No OpenCL platforms found." << endl; + ETHCL_LOG("No OpenCL platforms found."); return false; } @@ -143,25 +188,25 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work _platformId = std::min(_platformId, platforms.size() - 1); - cout << "Using platform: " << platforms[_platformId].getInfo().c_str() << endl; + ETHCL_LOG("Using platform: " << platforms[_platformId].getInfo().c_str()); // get GPU device of the default platform std::vector devices; platforms[_platformId].getDevices(CL_DEVICE_TYPE_ALL, &devices); if (devices.empty()) { - cout << "No OpenCL devices found." << endl; + ETHCL_LOG("No OpenCL devices found."); return false; } // use selected device cl::Device& device = devices[std::min(_deviceId, devices.size() - 1)]; std::string device_version = device.getInfo(); - cout << "Using device: " << device.getInfo().c_str() << "(" << device_version.c_str() << ")" << endl; + ETHCL_LOG("Using device: " << device.getInfo().c_str() << "(" << device_version.c_str() << ")"); if (strncmp("OpenCL 1.0", device_version.c_str(), 10) == 0) { - cout << "OpenCL 1.0 is not supported." << endl; + ETHCL_LOG("OpenCL 1.0 is not supported."); return false; } if (strncmp("OpenCL 1.1", device_version.c_str(), 10) == 0) @@ -193,7 +238,7 @@ bool ethash_cl_miner::init(uint8_t const* _dag, uint64_t _dagSize, unsigned work } catch (cl::Error err) { - cout << program.getBuildInfo(device).c_str(); + ETHCL_LOG(program.getBuildInfo(device).c_str()); return false; } m_hash_kernel = cl::Kernel(program, "ethash_hash"); diff --git a/libethash-cl/ethash_cl_miner.h b/libethash-cl/ethash_cl_miner.h index 43bfa2336..ef6745d76 100644 --- a/libethash-cl/ethash_cl_miner.h +++ b/libethash-cl/ethash_cl_miner.h @@ -35,6 +35,7 @@ public: static unsigned get_num_platforms(); static unsigned get_num_devices(unsigned _platformId = 0); static std::string platform_info(unsigned _platformId = 0, unsigned _deviceId = 0); + static bool haveSufficientGPUMemory(unsigned _platformId = 0); bool init(uint8_t const* _dag, uint64_t _dagSize, unsigned workgroup_size = 64, unsigned _platformId = 0, unsigned _deviceId = 0); void finish(); diff --git a/libethcore/Ethash.cpp b/libethcore/Ethash.cpp index f62c1f9cd..0be0b520c 100644 --- a/libethcore/Ethash.cpp +++ b/libethcore/Ethash.cpp @@ -363,6 +363,11 @@ void Ethash::GPUMiner::pause() stopWorking(); } +bool Ethash::GPUMiner::haveSufficientGPUMemory() +{ + return ethash_cl_miner::haveSufficientGPUMemory(s_platformId); +} + std::string Ethash::GPUMiner::platformInfo() { return ethash_cl_miner::platform_info(s_platformId, s_deviceId); diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 86540678f..9986c6a03 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -115,6 +115,7 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : 1; } static std::string platformInfo(); + static bool haveSufficientGPUMemory(); static unsigned getNumDevices(); static void setDefaultPlatform(unsigned _id) { s_platformId = _id; } static void setDefaultDevice(unsigned _id) { s_deviceId = _id; } From 3e2fc17e8139d418a6e39ee91d0a8b3c23f6fd9f Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Jun 2015 16:57:24 +0200 Subject: [PATCH 5/9] Print additional info if DAG creation fails --- libethcore/EthashAux.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libethcore/EthashAux.cpp b/libethcore/EthashAux.cpp index 4b546404a..0c1e84ebc 100644 --- a/libethcore/EthashAux.cpp +++ b/libethcore/EthashAux.cpp @@ -137,7 +137,10 @@ EthashAux::FullAllocation::FullAllocation(ethash_light_t _light, ethash_callback full = ethash_full_new(_light, _cb); // cdebug << "Called OK."; if (!full) - BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new()")); + { + clog(DAGChannel) << "DAG Generation Failure. Reason: " << strerror(errno); + BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new")); + } } EthashAux::FullAllocation::~FullAllocation() From bedddefda06c6c4934653d3e6e5056dd5d04ff8b Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 3 Jun 2015 17:09:23 +0200 Subject: [PATCH 6/9] Implement memory check function also for the CPU - Should fix the build, since Ethash is an interface. --- libethcore/Ethash.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libethcore/Ethash.h b/libethcore/Ethash.h index 9986c6a03..075b0522b 100644 --- a/libethcore/Ethash.h +++ b/libethcore/Ethash.h @@ -87,6 +87,7 @@ public: static unsigned instances() { return s_numInstances > 0 ? s_numInstances : std::thread::hardware_concurrency(); } static std::string platformInfo(); + static bool haveSufficientGPUMemory() { return false; } static void setDefaultPlatform(unsigned) {} static void setDefaultDevice(unsigned) {} static void setNumInstances(unsigned _instances) { s_numInstances = std::min(_instances, std::thread::hardware_concurrency()); } From 1a37f2b3dadb851f1377ac336d42c323050d98a9 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 3 Jun 2015 17:14:20 +0200 Subject: [PATCH 7/9] fixed blockchain kill --- libethereum/Client.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libethereum/Client.cpp b/libethereum/Client.cpp index 96353ade2..1491c83d7 100644 --- a/libethereum/Client.cpp +++ b/libethereum/Client.cpp @@ -269,9 +269,11 @@ void Client::killChain() { WriteGuard l(x_postMine); WriteGuard l2(x_preMine); + WriteGuard l3(x_working); m_preMine = State(); m_postMine = State(); + m_working = State(); m_stateDB = OverlayDB(); m_stateDB = State::openDB(Defaults::dbPath(), WithExisting::Kill); @@ -284,6 +286,7 @@ void Client::killChain() if (auto h = m_host.lock()) h->reset(); + startedWorking(); doWork(); startWorking(); From bf6ec8e32a1855d1609740d565c527e76544b319 Mon Sep 17 00:00:00 2001 From: winsvega Date: Fri, 22 May 2015 16:21:34 +0300 Subject: [PATCH 8/9] evmJit warnings fix --- evmjit/libevmjit-cpp/Env.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/evmjit/libevmjit-cpp/Env.cpp b/evmjit/libevmjit-cpp/Env.cpp index 86a65dbab..4d7865bd0 100644 --- a/evmjit/libevmjit-cpp/Env.cpp +++ b/evmjit/libevmjit-cpp/Env.cpp @@ -54,7 +54,7 @@ extern "C" if (_env->balance(_env->myAddress) >= endowment && _env->depth < 1024) { u256 gas = *io_gas; - h256 address(_env->create(endowment, gas, {_initBeg, _initSize}, {}), h256::AlignRight); + h256 address(_env->create(endowment, gas, {_initBeg, (size_t)_initSize}, {}), h256::AlignRight); *io_gas = static_cast(gas); *o_address = address; } @@ -69,8 +69,8 @@ extern "C" params.senderAddress = _env->myAddress; params.receiveAddress = right160(*_receiveAddress); params.codeAddress = right160(*_codeAddress); - params.data = {_inBeg, _inSize}; - params.out = {_outBeg, _outSize}; + params.data = {_inBeg, (size_t)_inSize}; + params.out = {_outBeg, (size_t)_outSize}; params.onOp = {}; const auto isCall = params.receiveAddress == params.codeAddress; // OPT: The same address pointer can be used if not CODECALL @@ -102,7 +102,7 @@ extern "C" EXPORT void env_sha3(byte* _begin, uint64_t _size, h256* o_hash) { - auto hash = sha3({_begin, _size}); + auto hash = sha3({_begin, (size_t)_size}); *o_hash = hash; } @@ -130,7 +130,7 @@ extern "C" if (_topic4) topics.push_back(*_topic4); - _env->log(std::move(topics), {_beg, _size}); + _env->log(std::move(topics), {_beg, (size_t)_size}); } } From 78e6e007d654590c7b72a740a23fbbcbf3428222 Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 3 Jun 2015 20:00:38 +0300 Subject: [PATCH 9/9] TransactionTest: V = unit64+28 --- .../ttTransactionTestFiller.json | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json b/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json index 5b24b9e51..410434d1d 100644 --- a/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json +++ b/test/libethereum/TransactionTestsFiller/ttTransactionTestFiller.json @@ -63,12 +63,12 @@ } }, - "V_overflow64bit" : { + "V_overflow64bitPlus27" : { "expect" : "invalid", "transaction" : { "data" : "0x5544", - "gasLimit" : "21000", + "gasLimit" : "22000", "gasPrice" : "1", "nonce" : "3", "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", @@ -79,6 +79,22 @@ } }, + "V_overflow64bitPlus28" : { + "expect" : "invalid", + "transaction" : + { + "data" : "0x5544", + "gasLimit" : "22000", + "gasPrice" : "1", + "nonce" : "3", + "to" : "b94f5374fce5edbc8e2a8697c15331677e6ebf0b", + "value" : "10", + "v" : "18446744073709551644", + "r" : "0x98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a", + "s" : "0x8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a3" + } + }, + "V_overflow64bitSigned" : { "expect" : "invalid", "transaction" :