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); 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; struct ethash_light;
typedef struct ethash_light* ethash_light_t; typedef struct ethash_light* ethash_light_t;
struct ethash_full; struct ethash_full;

2
internal.h

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

39
io.c

@ -22,9 +22,6 @@
#include <string.h> #include <string.h>
#include <stdio.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, static bool ethash_io_write_file(char const *dirname,
char const* filename, char const* filename,
size_t filename_length, size_t filename_length,
@ -51,39 +48,3 @@ free_name:
free(fullname); free(fullname);
return ret; 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 <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include "endian.h"
#include "ethash.h" #include "ethash.h"
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
// Maximum size for mutable part of DAG file name
static const char DAG_FILE_NAME[] = "full"; // 10 is for maximum number of digits of a uint32_t (for REVISION)
static const char DAG_MEMO_NAME[] = "full.info"; // 1 is for _ and 16 is for the first 16 hex digits for first 8 bytes of
// MSVC thinks that "static const unsigned int" is not a compile time variable. Sorry for the #define :( // the seedhash and last 1 is for the null terminating character
#define DAG_MEMO_BYTESIZE 36 // 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 /// Possible return values of @see ethash_io_prepare
enum ethash_io_rc { enum ethash_io_rc {
ETHASH_IO_FAIL = 0, ///< There has been an IO failure 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_MISMATCH, ///< The DAG file did not exist or there was revision/hash mismatch
ETHASH_IO_MEMO_MATCH, ///< Memo file existed and contents matched. No need to do anything ETHASH_IO_MEMO_MATCH, ///< DAG file existed and revision/hash matched. No need to do anything
}; };
/** /**
* Prepares io for ethash * Prepares io for ethash
* *
* Create the DAG directory if it does not exist, and check if the memo file matches. * Create the DAG directory and the DAG file if they don't exist.
* If it does not match then it's deleted to pave the way for @ref ethash_io_write()
* *
* @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. * 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 * @return For possible return values @see enum ethash_io_rc
*/ */
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 **f);
/**
* 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);
/** /**
* An fopen wrapper for no-warnings crossplatform fopen. * 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); 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 * Msvc compiler considers strncat to be insecure and suggests to use their
* alternative. This is a wrapper for this alternative. Another way is to * 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); 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, static inline bool ethash_io_mutable_name(uint32_t revision,
ethash_h256_t seed_hash, ethash_h256_t *seed_hash,
char *output) char *output)
{ {
// if .info is only consumed locally we don't really care about endianess uint64_t hash = *((uint64_t*)seed_hash);
memcpy(output, &revision, 4); #if LITTLE_ENDIAN == BYTE_ORDER
memcpy(output + 4, &seed_hash, 32); 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, 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; 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 mutable_name[DAG_MUTABLE_NAME_MAX_SIZE];
char expect_buffer[DAG_MEMO_BYTESIZE];
enum ethash_io_rc ret = ETHASH_IO_FAIL; enum ethash_io_rc ret = ETHASH_IO_FAIL;
// assert directory exists, full owner permissions and read/search for others // 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; goto end;
} }
char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME)); ethash_io_mutable_name(REVISION, &seedhash, mutable_name);
if (!memofile) { char *tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name));
if (!tmpfile) {
goto end; goto end;
} }
// try to open memo file // try to open the file
FILE *f = ethash_fopen(memofile, "rb"); FILE *f = fopen(tmpfile, "rb");
if (!f) { 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; ret = ETHASH_IO_MEMO_MISMATCH;
goto free_memo; 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; ret = ETHASH_IO_MEMO_MATCH;
close: *output_file = f;
fclose(f);
free_memo: free_memo:
free(memofile); free(tmpfile);
end: end:
return ret; return ret;
} }

Loading…
Cancel
Save