diff --git a/ethash.h b/ethash.h index a0860097e..83d4d569a 100644 --- a/ethash.h +++ b/ethash.h @@ -44,20 +44,6 @@ extern "C" { /// Type of a seedhash/blockhash e.t.c. typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t; -static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i) -{ - return hash->b[i]; -} - -static inline void ethash_h256_set(ethash_h256_t* hash, unsigned int i, uint8_t v) -{ - hash->b[i] = v; -} - -static inline void ethash_h256_reset(ethash_h256_t* hash) -{ - memset(hash, 0, 32); -} // convenience macro to statically initialize an h256_t // usage: @@ -76,42 +62,17 @@ typedef int(*ethash_callback_t)(unsigned); typedef struct ethash_return_value { ethash_h256_t result; ethash_h256_t mix_hash; + bool success; } ethash_return_value_t; -uint64_t ethash_get_datasize(uint64_t const block_number); -uint64_t ethash_get_cachesize(uint64_t const block_number); - -typedef struct ethash_cache { - void* mem; - uint64_t cache_size; -} ethash_cache_t; - -/** - * Allocate and initialize a new ethash_cache object - * - * @param cache_size The size of the cache in bytes - * @param seed Block seedhash to be used during the computation of the - * cache nodes - * @return Newly allocated ethash_cache on success or NULL in case of - * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() - */ -ethash_cache_t* ethash_cache_new(uint64_t cache_size, ethash_h256_t const* seed); -/** - * Frees a previously allocated ethash_cache - * @param c The object to free - */ -void ethash_cache_delete(ethash_cache_t* c); - /** * Allocate and initialize a new ethash_light handler * - * @param cache_size The size of the cache in bytes - * @param seed Block seedhash to be used during the computation of the - * cache nodes + * @param block_number The block number for which to create the handler * @return Newly allocated ethash_light handler or NULL in case of * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() */ -ethash_light_t ethash_light_new(uint64_t cache_size, ethash_h256_t const* seed); +ethash_light_t ethash_light_new(uint64_t const block_number); /** * Frees a previously allocated ethash_light handler * @param light The light handler to free @@ -120,48 +81,21 @@ void ethash_light_delete(ethash_light_t light); /** * Calculate the light client data * - * @param ret An object of ethash_return_value to hold the return value * @param light The light client handler - * @param full_size The size of the full data in bytes. * @param header_hash The header hash to pack into the mix * @param nonce The nonce to pack into the mix - * @return true if all went well and false if there were invalid - * parameters given. + * @return an object of ethash_return_value_t holding the return values */ -bool ethash_light_compute( - ethash_return_value_t* ret, +ethash_return_value_t ethash_light_compute( ethash_light_t light, - uint64_t full_size, - const ethash_h256_t* header_hash, + const ethash_h256_t header_hash, uint64_t const nonce ); -/** - * Get a pointer to the cache object held by the light client - * - * @param light The light client whose cache to request - * @return A pointer to the cache held by the light client or NULL if - * there was no cache in the first place - */ -ethash_cache_t* ethash_light_get_cache(ethash_light_t light); -/** - * Move the memory ownership of the cache somewhere else - * - * @param light The light client whose cache's memory ownership to acquire. - * After this function concludes it will no longer have a cache. - * @return A pointer to the moved cache or NULL if there was no cache in the first place - */ -ethash_cache_t* ethash_light_acquire_cache(ethash_light_t light); /** * Allocate and initialize a new ethash_full handler * - * @param dirname The directory in which to put the DAG file. - * @param seedhash The seed hash of the block. Used in the DAG file naming. - * @param full_size The size of the full data in bytes. - * @param cache A cache object to use that was allocated with @ref ethash_cache_new(). - * Iff this function succeeds the ethash_full_t will take memory - * memory ownership of the cache and free it at deletion. If - * not then the user still has to handle freeing of the cache himself. + * @param dirname The light handler containing the cache. * @param callback A callback function with signature of @ref ethash_callback_t * It accepts an unsigned with which a progress of DAG calculation * can be displayed. If all goes well the callback should return 0. @@ -169,13 +103,8 @@ ethash_cache_t* ethash_light_acquire_cache(ethash_light_t light); * @return Newly allocated ethash_full handler or NULL in case of * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() */ -ethash_full_t ethash_full_new( - char const* dirname, - ethash_h256_t const* seed_hash, - uint64_t full_size, - ethash_cache_t const* cache, - ethash_callback_t callback -); +ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback); + /** * Frees a previously allocated ethash_full handler * @param full The light handler to free @@ -184,98 +113,29 @@ void ethash_full_delete(ethash_full_t full); /** * Calculate the full client data * - * @param ret An object of ethash_return_value to hold the return value * @param full The full client handler * @param header_hash The header hash to pack into the mix * @param nonce The nonce to pack into the mix - * @return true if all went well and false if there were invalid - * parameters given or if there was a callback given and - * at some point return a non-zero value + * @return An object of ethash_return_value to hold the return value */ -bool ethash_full_compute( - ethash_return_value_t* ret, +ethash_return_value_t ethash_full_compute( ethash_full_t full, - ethash_h256_t const* header_hash, + ethash_h256_t const header_hash, uint64_t const nonce ); /** * Get a pointer to the full DAG data */ -void *ethash_full_data(ethash_full_t full); - -void ethash_get_seedhash(ethash_h256_t *seedhash, const uint32_t block_number); - -// Returns if hash is less than or equal to difficulty -static inline int ethash_check_difficulty( - ethash_h256_t const* hash, - ethash_h256_t const* difficulty -) -{ - // Difficulty is big endian - for (int i = 0; i < 32; i++) { - if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) { - continue; - } - return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i); - } - return 1; -} - -int ethash_quick_check_difficulty( - ethash_h256_t const* header_hash, - uint64_t const nonce, - ethash_h256_t const* mix_hash, - ethash_h256_t const* difficulty -); - +void const* ethash_full_dag(ethash_full_t full); /** - * Compute the memory data for a full node's memory - * - * @param mem A pointer to an ethash full's memory - * @param full_size The size of the full data in bytes - * @param cache A cache object to use in the calculation - * @return true if all went fine and false for invalid parameters + * Get the size of the DAG data */ -bool ethash_compute_full_data(void* mem, uint64_t full_size, ethash_cache_t const* cache); - +uint64_t ethash_full_dag_size(ethash_full_t full); /** - * ========================= - * = DEPRECATED API = - * ========================= - * - * Kept for backwards compatibility with whoever still uses it. Please consider - * switching to the new API (look above) + * Calculate the seedhash for a given block number */ -typedef struct ethash_params { - /// Size of full data set (in bytes, multiple of mix size (128)). - uint64_t full_size; - /// Size of compute cache (in bytes, multiple of node size (64)). - uint64_t cache_size; -} ethash_params; - -// initialize the parameters -static inline void ethash_params_init(ethash_params* params, uint32_t const block_number) -{ - params->full_size = ethash_get_datasize(block_number); - params->cache_size = ethash_get_cachesize(block_number); -} - -void ethash_mkcache(ethash_cache_t* cache, ethash_params const* params, ethash_h256_t const* seed); -void ethash_full( - ethash_return_value_t* ret, - void const* full_mem, - ethash_params const* params, - ethash_h256_t const* header_hash, - uint64_t const nonce -); -void ethash_light( - ethash_return_value_t* ret, - ethash_cache_t const* cache, - ethash_params const* params, - ethash_h256_t const* header_hash, - uint64_t const nonce -); +void ethash_get_seedhash(ethash_h256_t *seedhash, uint64_t const block_number); #ifdef __cplusplus } diff --git a/internal.c b/internal.c index d5d7bfda2..c52ca773c 100644 --- a/internal.c +++ b/internal.c @@ -90,46 +90,14 @@ bool static ethash_compute_cache_nodes( return true; } -ethash_cache_t* ethash_cache_new(uint64_t cache_size, ethash_h256_t const* seed) -{ - ethash_cache_t* ret; - ret = malloc(sizeof(*ret)); - if (!ret) { - return NULL; - } - ret->mem = malloc((size_t)cache_size); - if (!ret->mem) { - goto fail_free_cache; - } - - node* nodes = (node*)ret->mem; - if (!ethash_compute_cache_nodes(nodes, cache_size, seed)) { - goto fail_free_cache_mem; - } - ret->cache_size = cache_size; - return ret; - -fail_free_cache_mem: - free(ret->mem); -fail_free_cache: - free(ret); - return NULL; -} - -void ethash_cache_delete(ethash_cache_t* c) -{ - free(c->mem); - free(c); -} - void ethash_calculate_dag_item( node* const ret, const unsigned node_index, - ethash_cache_t const* cache + ethash_light_t const light ) { - uint32_t num_parent_nodes = (uint32_t) (cache->cache_size / sizeof(node)); - node const* cache_nodes = (node const *) cache->mem; + uint32_t num_parent_nodes = (uint32_t) (light->cache_size / sizeof(node)); + node const* cache_nodes = (node const *) light->cache; node const* init = &cache_nodes[node_index % num_parent_nodes]; memcpy(ret, init, sizeof(node)); ret->words[0] ^= node_index; @@ -174,7 +142,7 @@ void ethash_calculate_dag_item( SHA3_512(ret->bytes, ret->bytes, sizeof(node)); } -bool ethash_compute_full_data(void* mem, uint64_t full_size, ethash_cache_t const* cache) +bool ethash_compute_full_data(void* mem, uint64_t full_size, ethash_light_t const light) { if (full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 || (full_size % sizeof(node)) != 0) { @@ -183,7 +151,7 @@ bool ethash_compute_full_data(void* mem, uint64_t full_size, ethash_cache_t cons node* full_nodes = mem; // now compute full nodes for (unsigned n = 0; n != (full_size / sizeof(node)); ++n) { - ethash_calculate_dag_item(&(full_nodes[n]), n, cache); + ethash_calculate_dag_item(&(full_nodes[n]), n, light); } return true; } @@ -191,9 +159,9 @@ bool ethash_compute_full_data(void* mem, uint64_t full_size, ethash_cache_t cons static bool ethash_hash( ethash_return_value_t* ret, node const* full_nodes, - ethash_cache_t const* cache, + ethash_light_t const light, uint64_t full_size, - ethash_h256_t const* header_hash, + ethash_h256_t const header_hash, uint64_t const nonce, ethash_callback_t callback ) @@ -205,7 +173,7 @@ static bool ethash_hash( // pack hash and nonce together into first 40 bytes of s_mix assert(sizeof(node) * 8 == 512); node s_mix[MIX_NODES + 1]; - memcpy(s_mix[0].bytes, header_hash, 32); + memcpy(s_mix[0].bytes, &header_hash, 32); fix_endian64(s_mix[0].double_words[4], nonce); // compute sha3-512 hash and replicate across mix @@ -236,7 +204,7 @@ static bool ethash_hash( dag_node = &full_nodes[MIX_NODES * index + n]; } else { node tmp_node; - ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, cache); + ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, light); dag_node = &tmp_node; } @@ -295,7 +263,7 @@ void ethash_quick_hash( SHA3_256(return_hash, buf, 64 + 32); } -void ethash_get_seedhash(ethash_h256_t* seedhash, const uint32_t block_number) +void ethash_get_seedhash(ethash_h256_t* seedhash, uint64_t const block_number) { ethash_h256_reset(seedhash); const uint32_t epochs = block_number / ETHASH_EPOCH_LENGTH; @@ -316,44 +284,61 @@ int ethash_quick_check_difficulty( return ethash_check_difficulty(&return_hash, difficulty); } -ethash_light_t ethash_light_new(uint64_t cache_size, ethash_h256_t const* seed) +ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed) { struct ethash_light *ret; ret = calloc(sizeof(*ret), 1); if (!ret) { return NULL; } - ret->cache = ethash_cache_new(cache_size, seed); + ret->cache = malloc((size_t)cache_size); if (!ret->cache) { goto fail_free_light; } + node* nodes = (node*)ret->cache; + if (!ethash_compute_cache_nodes(nodes, cache_size, seed)) { + goto fail_free_cache_mem; + } + ret->cache_size = cache_size; return ret; +fail_free_cache_mem: + free(ret->cache); fail_free_light: free(ret); return NULL; } +ethash_light_t ethash_light_new(uint64_t const block_number) +{ + ethash_h256_t seedhash; + ethash_light_t ret; + ethash_get_seedhash(&seedhash, block_number); + ret = ethash_light_new_internal(ethash_get_cachesize(block_number), &seedhash); + ret->block_number = block_number; + return ret; +} + void ethash_light_delete(ethash_light_t light) { if (light->cache) { - ethash_cache_delete(light->cache); + free(light->cache); } free(light); } -bool ethash_light_compute( +bool ethash_light_compute_internal( ethash_return_value_t* ret, ethash_light_t light, uint64_t full_size, - const ethash_h256_t* header_hash, + const ethash_h256_t header_hash, uint64_t const nonce ) { return ethash_hash( ret, NULL, - light->cache, + light, full_size, header_hash, nonce, @@ -361,18 +346,23 @@ bool ethash_light_compute( ); } -ethash_cache_t *ethash_light_get_cache(ethash_light_t light) -{ - return light->cache; -} - -ethash_cache_t *ethash_light_acquire_cache(ethash_light_t light) +ethash_return_value_t ethash_light_compute( + ethash_light_t light, + const ethash_h256_t header_hash, + uint64_t const nonce +) { - ethash_cache_t* ret = light->cache; - light->cache = 0; + ethash_return_value_t ret; + ret.success = true; + uint64_t full_size = ethash_get_datasize(light->block_number); + if (!ethash_light_compute_internal(&ret, light, full_size, header_hash, nonce)) { + ret.success = false; + } return ret; } + + static bool ethash_mmap(struct ethash_full* ret, FILE* f) { int fd; @@ -391,11 +381,11 @@ static bool ethash_mmap(struct ethash_full* ret, FILE* f) return ret->data != MAP_FAILED; } -ethash_full_t ethash_full_new( +ethash_full_t ethash_full_new_internal( char const* dirname, ethash_h256_t const* seed_hash, uint64_t full_size, - ethash_cache_t const* cache, + ethash_light_t const light, ethash_callback_t callback ) { @@ -427,7 +417,7 @@ ethash_full_t ethash_full_new( break; } - if (!ethash_compute_full_data(ret->data, full_size, cache)) { + if (!ethash_compute_full_data(ret->data, full_size, light)) { goto fail_free_full_data; } ret->callback = callback; @@ -443,6 +433,18 @@ fail_free_full: return NULL; } +ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback) +{ + char strbuf[256]; + if (!ethash_get_default_dirname(strbuf, 256)) { + return NULL; + } + uint64_t full_size = ethash_get_datasize(light->block_number); + ethash_h256_t seedhash; + ethash_get_seedhash(&seedhash, light->block_number); + return ethash_full_new_internal(strbuf, &seedhash, full_size, light, callback); +} + void ethash_full_delete(ethash_full_t full) { // could check that munmap(..) == 0 but even if it did not can't really do anything here @@ -453,64 +455,33 @@ void ethash_full_delete(ethash_full_t full) free(full); } -bool ethash_full_compute( - ethash_return_value_t* ret, +ethash_return_value_t ethash_full_compute( ethash_full_t full, - ethash_h256_t const* header_hash, + ethash_h256_t const header_hash, uint64_t const nonce ) { - return ethash_hash( - ret, + ethash_return_value_t ret; + ret.success = true; + if (!ethash_hash( + &ret, (node const*)full->data, NULL, full->file_size, header_hash, nonce, - full->callback - ); -} - -void *ethash_full_data(ethash_full_t full) -{ - return full->data; + full->callback)) { + ret.success = false; + } + return ret; } -/** - * ========================= - * = DEPRECATED API = - * ========================= - * - * Kept for backwards compatibility with whoever still uses it. Please consider - * switching to the new API (look above) - */ -void ethash_mkcache( - ethash_cache_t* cache, - ethash_params const* params, - ethash_h256_t const* seed -) +void const* ethash_full_dag(ethash_full_t full) { - node* nodes = (node*) cache->mem; - ethash_compute_cache_nodes(nodes, params->cache_size, seed); + return full->data; } -void ethash_full( - ethash_return_value_t* ret, - void const* full_mem, - ethash_params const* params, - ethash_h256_t const* header_hash, - uint64_t const nonce -) -{ - ethash_hash(ret, (node const *) full_mem, NULL, params->full_size, header_hash, nonce, NULL); -} -void ethash_light( - ethash_return_value_t* ret, - ethash_cache_t const* cache, - ethash_params const* params, - ethash_h256_t const* header_hash, - uint64_t const nonce -) +uint64_t ethash_full_dag_size(ethash_full_t full) { - ethash_hash(ret, NULL, cache, params->full_size, header_hash, nonce, NULL); + return full->file_size; } diff --git a/internal.h b/internal.h index b5fcf71fe..bb622177d 100644 --- a/internal.h +++ b/internal.h @@ -31,10 +31,80 @@ typedef union node { } node; +static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i) +{ + return hash->b[i]; +} + +static inline void ethash_h256_set(ethash_h256_t* hash, unsigned int i, uint8_t v) +{ + hash->b[i] = v; +} + +static inline void ethash_h256_reset(ethash_h256_t* hash) +{ + memset(hash, 0, 32); +} + +// Returns if hash is less than or equal to difficulty +static inline int ethash_check_difficulty( + ethash_h256_t const* hash, + ethash_h256_t const* difficulty +) +{ + // Difficulty is big endian + for (int i = 0; i < 32; i++) { + if (ethash_h256_get(hash, i) == ethash_h256_get(difficulty, i)) { + continue; + } + return ethash_h256_get(hash, i) < ethash_h256_get(difficulty, i); + } + return 1; +} + +int ethash_quick_check_difficulty( + ethash_h256_t const* header_hash, + uint64_t const nonce, + ethash_h256_t const* mix_hash, + ethash_h256_t const* difficulty +); + struct ethash_light { - ethash_cache_t* cache; + void* cache; + uint64_t cache_size; + uint64_t block_number; }; +/** + * Allocate and initialize a new ethash_light handler. Internal version + * + * @param cache_size The size of the cache in bytes + * @param seed Block seedhash to be used during the computation of the + * cache nodes + * @return Newly allocated ethash_light handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() + */ +ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed); + +/** + * Calculate the light client data. Internal version. + * + * @param ret An object of ethash_return_value to hold the return value + * @param light The light client handler + * @param full_size The size of the full data in bytes. + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return true if all went well and false if there were invalid + * parameters given. + */ +bool ethash_light_compute_internal( + ethash_return_value_t* ret, + ethash_light_t light, + uint64_t full_size, + const ethash_h256_t header_hash, + uint64_t const nonce +); + struct ethash_full { FILE* file; uint64_t file_size; @@ -42,10 +112,35 @@ struct ethash_full { ethash_callback_t callback; }; +/** + * Allocate and initialize a new ethash_full handler. Internal version. + * + * @param dirname The directory in which to put the DAG file. + * @param seedhash The seed hash of the block. Used in the DAG file naming. + * @param full_size The size of the full data in bytes. + * @param cache A cache object to use that was allocated with @ref ethash_cache_new(). + * Iff this function succeeds the ethash_full_t will take memory + * memory ownership of the cache and free it at deletion. If + * not then the user still has to handle freeing of the cache himself. + * @param callback A callback function with signature of @ref ethash_callback_t + * It accepts an unsigned with which a progress of DAG calculation + * can be displayed. If all goes well the callback should return 0. + * If a non-zero value is returned then DAG generation will stop. + * @return Newly allocated ethash_full handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() + */ +ethash_full_t ethash_full_new_internal( + char const* dirname, + ethash_h256_t const* seed_hash, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +); + void ethash_calculate_dag_item( node* const ret, const unsigned node_index, - ethash_cache_t const* cache + ethash_light_t const cache ); void ethash_quick_hash( @@ -55,6 +150,19 @@ void ethash_quick_hash( ethash_h256_t const* mix_hash ); +uint64_t ethash_get_datasize(uint64_t const block_number); +uint64_t ethash_get_cachesize(uint64_t const block_number); + +/** + * Compute the memory data for a full node's memory + * + * @param mem A pointer to an ethash full's memory + * @param full_size The size of the full data in bytes + * @param cache A cache object to use in the calculation + * @return true if all went fine and false for invalid parameters + */ +bool ethash_compute_full_data(void* mem, uint64_t full_size, ethash_light_t const cache); + #ifdef __cplusplus } #endif diff --git a/io.h b/io.h index d47dd83bb..c4cebcda1 100644 --- a/io.h +++ b/io.h @@ -115,7 +115,7 @@ char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count /** * A cross-platform mkdir wrapper to create a directory or assert it's there - * + * * @param dirname The full path of the directory to create * @return true if the directory was created or if it already * existed @@ -133,7 +133,7 @@ bool ethash_file_size(FILE* f, size_t* ret_size); /** * Get a file descriptor number from a FILE stream - * + * * @param f The file stream whose fd to get * @return Platform specific fd handler */ @@ -154,6 +154,18 @@ char* ethash_io_create_filename( size_t filename_length ); +/** + * Gets the default directory name for the DAG depending on the system + * + * The spec defining this directory is here: https://github.com/ethereum/wiki/wiki/Ethash-DAG + * + * @param[out] strbuf A string buffer of sufficient size to keep the + * null termninated string of the directory name + * @param[in] buffsize Size of @a strbuf in bytes + * @return true for success and false otherwise + */ +bool ethash_get_default_dirname(char* strbuf, size_t buffsize); + static inline bool ethash_io_mutable_name( uint32_t revision, ethash_h256_t const* seed_hash, diff --git a/io_posix.c b/io_posix.c index c16521d5a..0f5d2b082 100644 --- a/io_posix.c +++ b/io_posix.c @@ -55,10 +55,10 @@ char* ethash_io_create_filename( ) { size_t dirlen = strlen(dirname); - size_t dest_size = dirlen + filename_length + 1; - if (dirname[dirlen] != '/') { - dest_size += 1; - } + size_t dest_size = dirlen + filename_length + 1; + if (dirname[dirlen] != '/') { + dest_size += 1; + } char* name = malloc(dest_size); if (!name) { return NULL; @@ -66,9 +66,9 @@ char* ethash_io_create_filename( name[0] = '\0'; ethash_strncat(name, dest_size, dirname, dirlen); - if (dirname[dirlen] != '/') { - ethash_strncat(name, dest_size, "/", 1); - } + if (dirname[dirlen] != '/') { + ethash_strncat(name, dest_size, "/", 1); + } ethash_strncat(name, dest_size, filename, filename_length); return name; } @@ -83,3 +83,19 @@ bool ethash_file_size(FILE* f, size_t* ret_size) *ret_size = st.st_size; return true; } + +bool ethash_get_default_dirname(char* strbuf, size_t buffsize) +{ + strbuf[0] = '\n'; + char* home_dir = getenv("HOME"); + size_t len = strlen(home_dir); + if (!ethash_strncat(strbuf, buffsize, home_dir, len)) { + return false; + } + if (home_dir[len] != '/') { + if (!ethash_strncat(strbuf, buffsize, "/", 1)) { + return false; + } + } + return ethash_strncat(strbuf, buffsize, ".ethash/", 8); +} diff --git a/io_win32.c b/io_win32.c index d64362914..84a249883 100644 --- a/io_win32.c +++ b/io_win32.c @@ -55,10 +55,10 @@ char* ethash_io_create_filename( ) { size_t dirlen = strlen(dirname); - size_t dest_size = dirlen + filename_length + 1; - if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { - dest_size += 1; - } + size_t dest_size = dirlen + filename_length + 1; + if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { + dest_size += 1; + } char* name = malloc(dest_size); if (!name) { return NULL; @@ -66,9 +66,9 @@ char* ethash_io_create_filename( name[0] = '\0'; ethash_strncat(name, dest_size, dirname, dirlen); - if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { - ethash_strncat(name, dest_size, "\\", 1); - } + if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { + ethash_strncat(name, dest_size, "\\", 1); + } ethash_strncat(name, dest_size, filename, filename_length); return name; } @@ -83,3 +83,19 @@ bool ethash_file_size(FILE* f, size_t* ret_size) *ret_size = st.st_size; return true; } + +bool ethash_get_default_dirname(char* strbuf, size_t buffsize) +{ + strbuf[0] = '\n'; + if (!SUCCEEDED(SHGetFolderPathW(NULL, CSIDL_PROFILE, NULL, 0, (WCHAR*)strbuf))) { + return false; + } + if (!ethash_strncat(strbuf, buffsize, home_dir, len)) { + return false; + } + if (!ethash_strncat(strbuf, buffsize, "\\", 1)) { + return false; + } + + return ethash_strncat(strbuf, buffsize, "Appdata\\Ethash\\", 14); +}