From 85bf80272f4d05b5aa09e3d8cc8979ed7671132c Mon Sep 17 00:00:00 2001 From: Lefteris Karapetsas Date: Wed, 8 Apr 2015 10:40:49 +0200 Subject: [PATCH] Implementing the API functions and adding docstrings --- ethash.h | 81 ++++++++++++++++++++++++++++++++++++--------- internal.c | 96 ++++++++++++++++++++++++++++++++++++------------------ internal.h | 4 +-- 3 files changed, 132 insertions(+), 49 deletions(-) diff --git a/ethash.h b/ethash.h index ebe89a9f5..95cb5fbb1 100644 --- a/ethash.h +++ b/ethash.h @@ -42,9 +42,12 @@ extern "C" { #endif +// LTODO: for consistency's sake maybe use ethash_params_t? typedef struct ethash_params { - uint64_t full_size; // Size of full data set (in bytes, multiple of mix size (128)). - uint64_t cache_size; // Size of compute cache (in bytes, multiple of node size (64)). + /// Size of full data set (in bytes, multiple of mix size (128)). + int64_t full_size; + /// Size of compute cache (in bytes, multiple of node size (64)). + uint64_t cache_size; } ethash_params; /// Type of a seedhash/blockhash e.t.c. @@ -81,31 +84,77 @@ uint64_t ethash_get_cachesize(const uint32_t block_number); // initialize the parameters static inline void ethash_params_init(ethash_params *params, const uint32_t block_number) { - params->full_size = ethash_get_datasize(block_number); - params->cache_size = ethash_get_cachesize(block_number); + params->full_size = ethash_get_datasize(block_number); + params->cache_size = ethash_get_cachesize(block_number); } +// LTODO: for consistency's sake maybe use ethash_cache_t? typedef struct ethash_cache { - void *mem; + void *mem; } ethash_cache; -void ethash_mkcache(ethash_cache *cache, ethash_params const *params, ethash_h256_t const *seed); -void ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache); - -ethash_light_t ethash_new_light(ethash_params const *params, ethash_h256_t const *seed); -void ethash_delete_light(ethash_light_t light); -void ethash_compute_light(ethash_return_value *ret, +/** + * Allocate and initialize a new ethash_cache object + * + * @param params The parameters to initialize it with. We are interested in + * the cache_size from here + * @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 *ethash_cache_new(ethash_params const *params, ethash_h256_t const *seed); +/** + * Frees a previously allocated ethash_cache + * @param c The object to free + */ +void ethash_cache_delete(ethash_cache *c); +bool ethash_compute_full_data(void *mem, ethash_params const *params, ethash_cache const *cache); + +/** + * Allocate and initialize a new ethash_light handler + * + * @param params The parameters to initialize it with. We are interested in + * the cache_size from here + * @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(ethash_params const *params, ethash_h256_t const *seed); +/** + * Frees a previously allocated ethash_light handler + * @param light The light handler to free + */ +void ethash_light_delete(ethash_light_t light); +void ethash_light_compute(ethash_return_value *ret, ethash_light_t light, ethash_params const *params, const ethash_h256_t *header_hash, const uint64_t nonce); - -ethash_full_t ethash_new_full(ethash_params const* params, - void const* cache, +/** + * Allocate and initialize a new ethash_full handler + * + * @param params The parameters to initialize it with. We are interested in + * the full_size from here + * @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 + * ownership of the cache and free it at deletion. If not then the user + * still has to handle freeing of the cache himself. + * @param seed Block seedhash. TODO: Do we really need this in this function? + * @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(ethash_params const* params, + ethash_cache const* cache, const ethash_h256_t *seed, ethash_callback_t callback); -void ethash_delete_full(ethash_full_t full); -void ethash_compute_full(ethash_return_value *ret, +/** + * Frees a previously allocated ethash_full handler + * @param full The light handler to free + */ +void ethash_full_delete(ethash_full_t full); +void ethash_full_compute(ethash_return_value *ret, ethash_full_t full, ethash_params const *params, const ethash_h256_t *header_hash, diff --git a/internal.c b/internal.c index 9248f78ed..602bb6a87 100644 --- a/internal.c +++ b/internal.c @@ -50,11 +50,13 @@ uint64_t ethash_get_cachesize(const uint32_t block_number) { // Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) // https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf // SeqMemoHash(s, R, N) -void static ethash_compute_cache_nodes(node *const nodes, +bool static ethash_compute_cache_nodes(node *const nodes, ethash_params const *params, ethash_h256_t const* seed) { - assert((params->cache_size % sizeof(node)) == 0); + if (params->cache_size % sizeof(node) != 0) { + return false; + } uint32_t const num_nodes = (uint32_t) (params->cache_size / sizeof(node)); SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32); @@ -82,14 +84,38 @@ void static ethash_compute_cache_nodes(node *const nodes, nodes->words[w] = fix_endian32(nodes->words[w]); } #endif + return true; } -void ethash_mkcache(ethash_cache *cache, - ethash_params const *params, - ethash_h256_t const *seed) +ethash_cache *ethash_cache_new(ethash_params const *params, ethash_h256_t const *seed) { - node *nodes = (node *) cache->mem; - ethash_compute_cache_nodes(nodes, params, seed); + ethash_cache *ret; + ret = malloc(sizeof(*ret)); + if (!ret) { + return NULL; + } + ret->mem = malloc(params->cache_size); + if (!ret->mem) { + goto fail_free_cache; + } + + node *nodes = (node*)ret->mem; + if (!ethash_compute_cache_nodes(nodes, params, seed)) { + goto fail_free_cache_mem; + } + return ret; + +fail_free_cache_mem: + free(ret->mem); +fail_free_cache: + free(ret); + return NULL; +} + +void ethash_cache_delete(ethash_cache *c) +{ + free(c->mem); + free(c); } void ethash_calculate_dag_item(node *const ret, @@ -146,21 +172,24 @@ void ethash_calculate_dag_item(node *const ret, SHA3_512(ret->bytes, ret->bytes, sizeof(node)); } -void ethash_compute_full_data( - void *mem, - ethash_params const *params, - ethash_cache const *cache) { - assert((params->full_size % (sizeof(uint32_t) * MIX_WORDS)) == 0); - assert((params->full_size % sizeof(node)) == 0); +bool ethash_compute_full_data(void *mem, + ethash_params const *params, + ethash_cache const *cache) +{ + if (params->full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 || + (params->full_size % sizeof(node)) != 0) { + return false; + } node *full_nodes = mem; // now compute full nodes for (unsigned n = 0; n != (params->full_size / sizeof(node)); ++n) { ethash_calculate_dag_item(&(full_nodes[n]), n, params, cache); } + return true; } -static void ethash_hash(ethash_return_value *ret, +static bool ethash_hash(ethash_return_value *ret, node const *full_nodes, ethash_cache const *cache, ethash_params const *params, @@ -168,7 +197,9 @@ static void ethash_hash(ethash_return_value *ret, const uint64_t nonce) { - assert((params->full_size % MIX_WORDS) == 0); + if (params->full_size % MIX_WORDS != 0) { + return false; + } // pack hash and nonce together into first 40 bytes of s_mix assert(sizeof(node) * 8 == 512); @@ -291,18 +322,17 @@ int ethash_quick_check_difficulty(ethash_h256_t const *header_hash, return ethash_check_difficulty(&return_hash, difficulty); } -ethash_light_t ethash_new_light(ethash_params const *params, ethash_h256_t const *seed) +ethash_light_t ethash_light_new(ethash_params const *params, ethash_h256_t const *seed) { struct ethash_light *ret; ret = malloc(sizeof(*ret)); if (!ret) { return NULL; } - ret->cache.mem = malloc(params->cache_size); - if (!ret->cache.mem) { - goto fail_free_light; + ret->cache = ethash_cache_new(params, seed); + if (!ret->cache) { + goto fail_free_light; } - ethash_mkcache(ret->cache.mem, params, seed); return ret; fail_free_light: @@ -310,23 +340,23 @@ fail_free_light: return NULL; } -void ethash_delete_light(ethash_light_t light) +void ethash_light_delete(ethash_light_t light) { - free(light->cache.mem); + ethash_cache_delete(light->cache); free(light); } -void ethash_compute_light(ethash_return_value *ret, +void ethash_light_compute(ethash_return_value *ret, ethash_light_t light, ethash_params const *params, const ethash_h256_t *header_hash, const uint64_t nonce) { - ethash_hash(ret, NULL, &light->cache, params, header_hash, nonce); + ethash_hash(ret, NULL, light->cache, params, header_hash, nonce); } -ethash_full_t ethash_new_full(ethash_params const* params, - void const* cache, +ethash_full_t ethash_full_new(ethash_params const* params, + ethash_cache const* cache, const ethash_h256_t *seed, ethash_callback_t callback) { @@ -335,29 +365,33 @@ ethash_full_t ethash_new_full(ethash_params const* params, if (!ret) { return NULL; } - ret->cache.mem = (void*)cache; + ret->cache = (ethash_cache*)cache; ret->data = malloc(params->full_size); if (!ret->data) { goto fail_free_full; } - ethash_compute_full_data(ret->data, params, cache); + if (!ethash_compute_full_data(ret->data, params, cache)) { + goto fail_free_full_data; + } ret->seed = seed; ret->callback = callback; return ret; +fail_free_full_data: + free(ret->data); fail_free_full: free(ret); return NULL; } -void ethash_delete_full(ethash_full_t full) +void ethash_full_delete(ethash_full_t full) { - // should the cache be freed here? Does ethash_full_t take ownership of the cache? + ethash_cache_delete(full->cache); free(full->data); free(full); } -void ethash_compute_full(ethash_return_value *ret, +void ethash_full_compute(ethash_return_value *ret, ethash_full_t full, ethash_params const *params, const ethash_h256_t *header_hash, diff --git a/internal.h b/internal.h index 8fc7df243..97ac2d125 100644 --- a/internal.h +++ b/internal.h @@ -31,11 +31,11 @@ typedef union node { } node; struct ethash_light { - ethash_cache cache; + ethash_cache *cache; }; struct ethash_full { - ethash_cache cache; + ethash_cache *cache; node *data; const ethash_h256_t* seed; ethash_callback_t callback;