Browse Source

Memoization is done with the DAG filename

cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
fbf7fc5b66
  1. 8
      ethash.h
  2. 2
      internal.h
  3. 39
      io.c
  4. 78
      io.h
  5. 36
      io_posix.c

8
ethash.h

@ -67,6 +67,14 @@ static inline void ethash_h256_reset(ethash_h256_t *hash)
memset(hash, 0, 32);
}
// convenience macro to statically initialize an h256_t
// usage:
// ethash_h256_t a = ethash_h256_static_init(1, 2, 3, ... )
// have to provide all 32 values. If you don't provide all the rest
// will simply be unitialized (not guranteed to be 0)
#define ethash_h256_static_init(...) \
{.b = {__VA_ARGS__} }
struct ethash_light;
typedef struct ethash_light* ethash_light_t;
struct ethash_full;

2
internal.h

@ -2,6 +2,7 @@
#include "compiler.h"
#include "endian.h"
#include "ethash.h"
#include <stdio.h>
#define ENABLE_SSE 0
@ -35,6 +36,7 @@ struct ethash_light {
};
struct ethash_full {
FILE *file;
ethash_cache *cache;
node *data;
ethash_callback_t callback;

39
io.c

@ -22,9 +22,6 @@
#include <string.h>
#include <stdio.h>
// silly macro to save some typing
#define PASS_ARR(c_) (c_), sizeof(c_)
static bool ethash_io_write_file(char const *dirname,
char const* filename,
size_t filename_length,
@ -51,39 +48,3 @@ free_name:
free(fullname);
return ret;
}
bool ethash_io_write(char const *dirname,
ethash_params const* params,
ethash_h256_t seedhash,
void const* cache,
uint8_t **data,
uint64_t *data_size)
{
char info_buffer[DAG_MEMO_BYTESIZE];
// allocate the bytes
uint8_t *temp_data_ptr = malloc((size_t)params->full_size);
if (!temp_data_ptr) {
goto end;
}
ethash_compute_full_data(temp_data_ptr, params, cache);
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, (size_t)params->full_size)) {
goto fail_free;
}
ethash_io_serialize_info(REVISION, seedhash, info_buffer);
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_MEMO_NAME), info_buffer, DAG_MEMO_BYTESIZE)) {
goto fail_free;
}
*data = temp_data_ptr;
*data_size = params->full_size;
return true;
fail_free:
free(temp_data_ptr);
end:
return false;
}
#undef PASS_ARR

78
io.h

@ -23,67 +23,41 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "endian.h"
#include "ethash.h"
#ifdef __cplusplus
extern "C" {
#endif
static const char DAG_FILE_NAME[] = "full";
static const char DAG_MEMO_NAME[] = "full.info";
// MSVC thinks that "static const unsigned int" is not a compile time variable. Sorry for the #define :(
#define DAG_MEMO_BYTESIZE 36
// Maximum size for mutable part of DAG file name
// 10 is for maximum number of digits of a uint32_t (for REVISION)
// 1 is for _ and 16 is for the first 16 hex digits for first 8 bytes of
// the seedhash and last 1 is for the null terminating character
// Reference: https://github.com/ethereum/wiki/wiki/Ethash-DAG
#define DAG_MUTABLE_NAME_MAX_SIZE (10 + 1 + 16 + 1)
/// Possible return values of @see ethash_io_prepare
enum ethash_io_rc {
ETHASH_IO_FAIL = 0, ///< There has been an IO failure
ETHASH_IO_MEMO_MISMATCH, ///< Memo file either did not exist or there was content mismatch
ETHASH_IO_MEMO_MATCH, ///< Memo file existed and contents matched. No need to do anything
ETHASH_IO_MEMO_MISMATCH, ///< The DAG file did not exist or there was revision/hash mismatch
ETHASH_IO_MEMO_MATCH, ///< DAG file existed and revision/hash matched. No need to do anything
};
/**
* Prepares io for ethash
*
* Create the DAG directory if it does not exist, and check if the memo file matches.
* If it does not match then it's deleted to pave the way for @ref ethash_io_write()
* Create the DAG directory and the DAG file if they don't exist.
*
* @param dirname A null terminated c-string of the path of the ethash
* @param[in] dirname A null terminated c-string of the path of the ethash
* data directory. If it does not exist it's created.
* @param seedhash The seedhash of the current block number
* @param[in] seedhash The seedhash of the current block number, used in the
* naming of the file as can be seen from the spec at:
* https://github.com/ethereum/wiki/wiki/Ethash-DAG
* @param[out] f If the hash/revision combo matched then this will point
* to an opened file handler for that file. User will then
* have to close it.
* @return For possible return values @see enum ethash_io_rc
*/
enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_h256_t seedhash);
/**
* Fully computes data and writes it to the file on disk.
*
* This function should be called after @see ethash_io_prepare() and only if
* its return value is @c ETHASH_IO_MEMO_MISMATCH. Will write both the full data
* and the memo file.
*
* @param[in] dirname A null terminated c-string of the path of the ethash
* data directory. Has to exist.
* @param[in] params An ethash_params object containing the full size
* and the cache size
* @param[in] seedhash The seedhash of the current block number
* @param[in] cache The cache data. Would have usually been calulated by
* @see ethash_prep_light().
* @param[out] data Pass a pointer to uint8_t by reference here. If the
* function is succesfull then this point to the allocated
* data calculated by @see ethash_prep_full(). Memory
* ownership is transfered to the callee. Remember that
* you eventually need to free this with a call to free().
* @param[out] data_size Pass a uint64_t by value. If the function is succesfull
* then this will contain the number of bytes allocated
* for @a data.
* @return True for success and false in case of failure.
*/
bool ethash_io_write(char const *dirname,
ethash_params const* params,
ethash_h256_t seedhash,
void const* cache,
uint8_t **data,
uint64_t *data_size);
enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_h256_t seedhash, FILE **f);
/**
* An fopen wrapper for no-warnings crossplatform fopen.
@ -99,7 +73,7 @@ bool ethash_io_write(char const *dirname,
*/
FILE *ethash_fopen(const char *file_name, const char *mode);
/**
* An stncat wrapper for no-warnings crossplatform strncat.
* An strncat wrapper for no-warnings crossplatform strncat.
*
* Msvc compiler considers strncat to be insecure and suggests to use their
* alternative. This is a wrapper for this alternative. Another way is to
@ -116,13 +90,15 @@ FILE *ethash_fopen(const char *file_name, const char *mode);
*/
char *ethash_strncat(char *dest, size_t dest_size, const char *src, size_t count);
static inline void ethash_io_serialize_info(uint32_t revision,
ethash_h256_t seed_hash,
char *output)
static inline bool ethash_io_mutable_name(uint32_t revision,
ethash_h256_t *seed_hash,
char *output)
{
// if .info is only consumed locally we don't really care about endianess
memcpy(output, &revision, 4);
memcpy(output + 4, &seed_hash, 32);
uint64_t hash = *((uint64_t*)seed_hash);
#if LITTLE_ENDIAN == BYTE_ORDER
hash = ethash_swap_u64(hash);
#endif
return snprintf(output, DAG_MUTABLE_NAME_MAX_SIZE, "%u_%016lx", revision, hash) >= 0;
}
static inline char *ethash_io_create_filename(char const *dirname,

36
io_posix.c

@ -37,10 +37,11 @@ char *ethash_strncat(char *dest, size_t dest_size, const char *src, size_t count
return strlen(dest) + count + 1 <= dest_size ? strncat(dest, src, count) : NULL;
}
enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_h256_t seedhash)
enum ethash_io_rc ethash_io_prepare(char const *dirname,
ethash_h256_t seedhash,
FILE **output_file)
{
char read_buffer[DAG_MEMO_BYTESIZE];
char expect_buffer[DAG_MEMO_BYTESIZE];
char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
enum ethash_io_rc ret = ETHASH_IO_FAIL;
// assert directory exists, full owner permissions and read/search for others
@ -49,38 +50,25 @@ enum ethash_io_rc ethash_io_prepare(char const *dirname, ethash_h256_t seedhash)
goto end;
}
char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME));
if (!memofile) {
ethash_io_mutable_name(REVISION, &seedhash, mutable_name);
char *tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name));
if (!tmpfile) {
goto end;
}
// try to open memo file
FILE *f = ethash_fopen(memofile, "rb");
// try to open the file
FILE *f = fopen(tmpfile, "rb");
if (!f) {
// file does not exist, so no checking happens. All is fine.
// file does not exist, will need to be created
ret = ETHASH_IO_MEMO_MISMATCH;
goto free_memo;
}
if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) {
goto close;
}
ethash_io_serialize_info(REVISION, seedhash, expect_buffer);
if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) {
// we have different memo contents so delete the memo file
if (unlink(memofile) != 0) {
goto close;
}
ret = ETHASH_IO_MEMO_MISMATCH;
}
ret = ETHASH_IO_MEMO_MATCH;
close:
fclose(f);
*output_file = f;
free_memo:
free(memofile);
free(tmpfile);
end:
return ret;
}

Loading…
Cancel
Save