Browse Source

API changes requested by Gavin.

- Following this spec:
  https://github.com/ethereum/wiki/wiki/Ethash-C-API

- This breaks all but the cpp tests. OpenCL miner and go ethereum will
  be fixed in subsequent commits.
cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
d82b609449
  1. 174
      ethash.h
  2. 179
      internal.c
  3. 112
      internal.h
  4. 16
      io.h
  5. 30
      io_posix.c
  6. 30
      io_win32.c

174
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
}

179
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;
}

112
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

16
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,

30
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);
}

30
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);
}

Loading…
Cancel
Save