Browse Source

ethash_io_write and win32 specific code

- adding ethash_io_write() function

- only ethash_io_prepare() invoke system dependent functions so it's the
  only one going in system specific source files.
cl-refactor
Lefteris Karapetsas 10 years ago
parent
commit
383865e191
  1. 1
      CMakeLists.txt
  2. 92
      io.c
  3. 64
      io.h
  4. 30
      io_posix.c
  5. 73
      io_win32.c

1
CMakeLists.txt

@ -12,6 +12,7 @@ endif()
set(FILES util.c set(FILES util.c
util.h util.h
io.c
internal.c internal.c
ethash.h ethash.h
endian.h endian.h

92
io.c

@ -0,0 +1,92 @@
/*
This file is part of ethash.
ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file io.c
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#include "io.h"
#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,
void const* data,
size_t data_size)
{
bool ret = false;
char *fullname = ethash_io_create_filename(dirname, filename, filename_length);
if (!fullname) {
return false;
}
FILE *f = fopen(fullname, "wb");
if (!f) {
goto free_name;
}
if (data_size != fwrite(data, 1, data_size, f)) {
goto close;
}
ret = true;
close:
fclose(f);
free_name:
free(fullname);
return ret;
}
bool ethash_io_write(char const *dirname,
uint32_t block_number,
void const* cache,
uint8_t **data,
size_t *data_size)
{
ethash_params p;
char info_buffer[DAG_MEMO_BYTESIZE];
p.cache_size = ethash_get_cachesize(block_number);
p.full_size = ethash_get_datasize(block_number);
// allocate the bytes
uint8_t *temp_data_ptr = malloc(p.full_size);
if (!(*temp_data_ptr)) {
goto end;
}
ethash_prep_full(temp_data_ptr, &p, cache);
if (!ethash_io_write_file(dirname, PASS_ARR(DAG_FILE_NAME), temp_data_ptr, p.full_size)) {
goto fail_free;
}
ethash_io_serialize_info(REVISION, block_number, 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 = p.full_size;
return true;
fail_free:
free(temp_data_ptr);
end:
return false;
}
#undef PASS_ARR

64
io.h

@ -28,16 +28,57 @@
extern "C" { extern "C" {
#endif #endif
static const char DAG_FILE_NAME[] = "full";
static const char DAG_MEMO_NAME[] = "full.info";
static const unsigned int DAG_MEMO_BYTESIZE = 36;
/// 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
};
/** /**
* Prepares io for ethash * 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()
*
* @param dirname A null terminated c-string of the path of the ethash * @param 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 block_number The current block number. Used in seedhash calculation. * @param block_number The current block number. Used in seedhash calculation.
* @returns True if all went fine, and false if there was any kind * @return For possible return values @see enum ethash_io_rc
* of error
*/ */
bool ethash_io_prepare(char const *dirname, uint32_t block_number); enum ethash_io_rc ethash_io_prepare(char const *dirname, uint32_t block_number);
void ethash_io_write(); /**
* 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] block_number 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 size_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,
uint32_t block_number,
void const* cache,
uint8_t **data,
size_t *data_size);
static inline void ethash_io_serialize_info(uint32_t revision, static inline void ethash_io_serialize_info(uint32_t revision,
uint32_t block_number, uint32_t block_number,
char *output) char *output)
@ -47,6 +88,21 @@ static inline void ethash_io_serialize_info(uint32_t revision,
ethash_get_seedhash((uint8_t*)(output + 4), block_number); ethash_get_seedhash((uint8_t*)(output + 4), block_number);
} }
static inline char *ethash_io_create_filename(char const *dirname,
char const* filename,
size_t filename_length)
{
char *name = malloc(strlen(dirname) + filename_length);
if (!name) {
return NULL;
}
name[0] = '\0';
strcat(name, dirname);
strcat(name, filename);
return name;
}
#ifdef __cplusplus #ifdef __cplusplus
} }

30
io_posix.c

@ -18,24 +18,20 @@
* @author Lefteris Karapetsas <lefteris@ethdev.com> * @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015 * @date 2015
*/ */
#include "io.h" #include "io.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <errno.h> #include <errno.h>
#include <libgen.h> #include <libgen.h>
#include <string.h>
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
static const char DAG_FILE_NAME[] = "full"; enum ethash_io_rc ethash_io_prepare(char const *dirname, uint32_t block_number)
static const char DAG_MEMO_NAME[] = "full.info";
static const unsigned int DAG_MEMO_BYTESIZE = 36;
bool ethash_io_prepare(char const *dirname, uint32_t block_number)
{ {
char read_buffer[DAG_MEMO_BYTESIZE]; char read_buffer[DAG_MEMO_BYTESIZE];
char expect_buffer[DAG_MEMO_BYTESIZE]; char expect_buffer[DAG_MEMO_BYTESIZE];
bool ret = false; 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
int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
@ -43,40 +39,38 @@ bool ethash_io_prepare(char const *dirname, uint32_t block_number)
goto end; goto end;
} }
// try to open memo file char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME));
char *memofile = malloc(strlen(dirname) + sizeof(DAG_MEMO_NAME));
if (!memofile) { if (!memofile) {
goto end; goto end;
} }
// try to open memo file
FILE *f = fopen(memofile, "rb"); FILE *f = fopen(memofile, "rb");
if (!f) { if (!f) {
// file does not exist, so no checking happens. All is fine. // file does not exist, so no checking happens. All is fine.
ret = true; ret = ETHASH_IO_MEMO_MISMATCH;
goto free_memo; goto free_memo;
} }
if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) { if (fread(read_buffer, 1, DAG_MEMO_BYTESIZE, f) != DAG_MEMO_BYTESIZE) {
goto free_memo; goto close;
} }
ethash_io_serialize_info(REVISION, block_number, expect_buffer); ethash_io_serialize_info(REVISION, block_number, expect_buffer);
if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) { if (memcmp(read_buffer, expect_buffer, DAG_MEMO_BYTESIZE) != 0) {
// we have different memo contents so delete the memo file // we have different memo contents so delete the memo file
if (unlink(memofile) != 0) { if (unlink(memofile) != 0) {
goto free_memo; ret = ETHASH_IO_MEMO_MISMATCH;
goto close;
} }
} }
ret = true; ret = ETHASH_IO_MEMO_MATCH;
close:
fclose(f);
free_memo: free_memo:
free(memofile); free(memofile);
end: end:
return ret; return ret;
} }
void ethash_io_write()
{
}

73
io_win32.c

@ -0,0 +1,73 @@
/*
This file is part of ethash.
ethash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ethash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with ethash. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file io_win32.c
* @author Lefteris Karapetsas <lefteris@ethdev.com>
* @date 2015
*/
#include "io.h"
#include <direct.h>
#include <errno.h>
#include <stdio.h>
enum ethash_io_rc ethash_io_prepare(char const *dirname, uint32_t block_number)
{
char read_buffer[DAG_MEMO_BYTESIZE];
char expect_buffer[DAG_MEMO_BYTESIZE];
enum ethash_io_rc ret = ETHASH_IO_FAIL;
// assert directory exists
int rc = _mkdir(dirname);
if (rc == -1 && errno != EEXIST) {
goto end;
}
char *memofile = ethash_io_create_filename(dirname, DAG_MEMO_NAME, sizeof(DAG_MEMO_NAME));
if (!memofile) {
goto end;
}
// try to open memo file
FILE *f = fopen(memofile, "rb");
if (!f) {
// file does not exist, so no checking happens. All is fine.
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, block_number, 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) {
ret = ETHASH_IO_MEMO_MISMATCH;
goto close;
}
}
ret = ETHASH_IO_MEMO_MATCH;
close:
fclose(f);
free_memo:
free(memofile);
end:
return ret;
}
Loading…
Cancel
Save