aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/github.com/ethereum/ethash/src/libethash/io.h
blob: 7a27089c7d2bfcf3163c33c42201efeaf41750d5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*
  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.h
 * @author Lefteris Karapetsas <lefteris@ethdev.com>
 * @date 2015
 */
#pragma once
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#ifdef __cplusplus
#define __STDC_FORMAT_MACROS 1
#endif
#include <inttypes.h>
#include "endian.h"
#include "ethash.h"

#ifdef __cplusplus
extern "C" {
#endif
// Maximum size for mutable part of DAG file name
// 6 is for "full-R", the suffix of the filename
// 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 (6 + 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_SIZE_MISMATCH, ///< DAG with revision/hash match, but file size was wrong.
    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
};

// small hack for windows. I don't feel I should use va_args and forward just
// to have this one function properly cross-platform abstracted
#if defined(_WIN32) && !defined(__GNUC__)
#define snprintf(...) sprintf_s(__VA_ARGS__)
#endif

/**
 * Logs a critical error in important parts of ethash. Should mostly help
 * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL
 * ethash_full_t
 */
#ifdef ETHASH_PRINT_CRITICAL_OUTPUT
#define ETHASH_CRITICAL(...)                            \
    do                                                  \
    {                                                   \
        printf("ETHASH CRITICAL ERROR: "__VA_ARGS__);   \
        printf("\n");                                   \
        fflush(stdout);                                 \
    } while (0)
#else
#define ETHASH_CRITICAL(...)          
#endif

/**
 * Prepares io for ethash
 *
 * Create the DAG directory and the DAG file if they don't exist.
 *
 * @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[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] output_file   If there was no failure then this will point to an open
 *                           file descriptor. User is responsible for closing it.
 *                           In the case of memo match then the file is open on read
 *                           mode, while on the case of mismatch a new file is created
 *                           on write mode
 * @param[in] file_size      The size that the DAG file should have on disk
 * @param[out] force_create  If true then there is no check to see if the file
 *                           already exists
 * @return                   For possible return values @see enum ethash_io_rc
 */
enum ethash_io_rc ethash_io_prepare(
    char const* dirname,
    ethash_h256_t const seedhash,
    FILE** output_file,
    uint64_t file_size,
    bool force_create
);

/**
 * An fopen wrapper for no-warnings crossplatform fopen.
 *
 * Msvc compiler considers fopen to be insecure and suggests to use their
 * alternative. This is a wrapper for this alternative. Another way is to
 * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
 * not sound like a good idea.
 *
 * @param file_name        The path to the file to open
 * @param mode             Opening mode. Check fopen()
 * @return                 The FILE* or NULL in failure
 */
FILE* ethash_fopen(char const* file_name, char const* mode);

/**
 * 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
 * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
 * not sound like a good idea.
 *
 * @param des              Destination buffer
 * @param dest_size        Maximum size of the destination buffer. This is the
 *                         extra argument for the MSVC secure strncat
 * @param src              Souce buffer
 * @param count            Number of bytes to copy from source
 * @return                 If all is well returns the dest buffer. If there is an
 *                         error returns NULL
 */
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
 */
bool ethash_mkdir(char const* dirname);

/**
 * Get a file's size
 *
 * @param[in] f        The open file stream whose size to get
 * @param[out] size    Pass a size_t by reference to contain the file size
 * @return             true in success and false if there was a failure
 */
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
 */
int ethash_fileno(FILE* f);

/**
 * Create the filename for the DAG.
 *
 * @param dirname            The directory name in which the DAG file should reside
 *                           If it does not end with a directory separator it is appended.
 * @param filename           The actual name of the file
 * @param filename_length    The length of the filename in bytes
 * @return                   A char* containing the full name. User must deallocate.
 */
char* ethash_io_create_filename(
    char const* dirname,
    char const* 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,
    char* output
)
{
    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, "full-R%u-%016" PRIx64, revision, hash) >= 0;
}

#ifdef __cplusplus
}
#endif