1 // ethash: C/C++ implementation of Ethash, the Ethereum Proof of Work algorithm.
2 // Copyright 2018 Pawel Bylica.
3 // Licensed under the Apache License, Version 2.0. See the LICENSE file.
4
5 /// @file
6 ///
7 /// API design decisions:
8 ///
9 /// 1. Signed integer type is used whenever the size of the type is not
10 /// restricted by the Ethash specification.
11 /// See http://www.aristeia.com/Papers/C++ReportColumns/sep95.pdf.
12 /// See https://stackoverflow.com/questions/10168079/why-is-size-t-unsigned/.
13 /// See https://github.com/Microsoft/GSL/issues/171.
14
15 #pragma once
16
17 #include <ethash/ethash.h>
18 #include <ethash/hash_types.hpp>
19
20 #include <cstdint>
21 #include <cstring>
22 #include <memory>
23
24 namespace ethash
25 {
26 static constexpr int epoch_length = ETHASH_EPOCH_LENGTH;
27 static constexpr int light_cache_item_size = ETHASH_LIGHT_CACHE_ITEM_SIZE;
28 static constexpr int full_dataset_item_size = ETHASH_FULL_DATASET_ITEM_SIZE;
29 static constexpr int num_dataset_accesses = ETHASH_NUM_DATASET_ACCESSES;
30
31 using epoch_context = ethash_epoch_context;
32 using epoch_context_full = ethash_epoch_context_full;
33
34 /// Constructs a 256-bit hash from an array of bytes.
35 ///
36 /// @param bytes A pointer to array of at least 32 bytes.
37 /// @return The constructed hash.
hash256_from_bytes(const uint8_t bytes[32])38 inline hash256 hash256_from_bytes(const uint8_t bytes[32]) noexcept
39 {
40 hash256 h;
41 std::memcpy(&h, bytes, sizeof(h));
42 return h;
43 }
44
45 struct result
46 {
47 hash256 final_hash;
48 hash256 mix_hash;
49 };
50
51 struct search_result
52 {
53 bool solution_found = false;
54 uint64_t nonce = 0;
55 hash256 final_hash = {};
56 hash256 mix_hash = {};
57
58 search_result() noexcept = default;
59
search_resultethash::search_result60 search_result(result res, uint64_t nonce) noexcept
61 : solution_found(true), nonce(nonce), final_hash(res.final_hash), mix_hash(res.mix_hash)
62 {}
63 };
64
65
66 /// Alias for ethash_calculate_light_cache_num_items().
67 static constexpr auto calculate_light_cache_num_items = ethash_calculate_light_cache_num_items;
68
69 /// Alias for ethash_calculate_full_dataset_num_items().
70 static constexpr auto calculate_full_dataset_num_items = ethash_calculate_full_dataset_num_items;
71
72 /// Alias for ethash_calculate_epoch_seed().
73 static constexpr auto calculate_epoch_seed = ethash_calculate_epoch_seed;
74
75
76 /// Calculates the epoch number out of the block number.
get_epoch_number(int block_number)77 inline constexpr int get_epoch_number(int block_number) noexcept
78 {
79 return block_number / epoch_length;
80 }
81
82 /**
83 * Coverts the number of items of a light cache to size in bytes.
84 *
85 * @param num_items The number of items in the light cache.
86 * @return The size of the light cache in bytes.
87 */
get_light_cache_size(int num_items)88 inline constexpr size_t get_light_cache_size(int num_items) noexcept
89 {
90 return static_cast<size_t>(num_items) * light_cache_item_size;
91 }
92
93 /**
94 * Coverts the number of items of a full dataset to size in bytes.
95 *
96 * @param num_items The number of items in the full dataset.
97 * @return The size of the full dataset in bytes.
98 */
get_full_dataset_size(int num_items)99 inline constexpr uint64_t get_full_dataset_size(int num_items) noexcept
100 {
101 return static_cast<uint64_t>(num_items) * full_dataset_item_size;
102 }
103
104 /// Owned unique pointer to an epoch context.
105 using epoch_context_ptr = std::unique_ptr<epoch_context, decltype(ðash_destroy_epoch_context)>;
106
107 using epoch_context_full_ptr =
108 std::unique_ptr<epoch_context_full, decltype(ðash_destroy_epoch_context_full)>;
109
110 /// Creates Ethash epoch context.
111 ///
112 /// This is a wrapper for ethash_create_epoch_number C function that returns
113 /// the context as a smart pointer which handles the destruction of the context.
create_epoch_context(int epoch_number)114 inline epoch_context_ptr create_epoch_context(int epoch_number) noexcept
115 {
116 return {ethash_create_epoch_context(epoch_number), ethash_destroy_epoch_context};
117 }
118
create_epoch_context_full(int epoch_number)119 inline epoch_context_full_ptr create_epoch_context_full(int epoch_number) noexcept
120 {
121 return {ethash_create_epoch_context_full(epoch_number), ethash_destroy_epoch_context_full};
122 }
123
124
125 result hash(const epoch_context& context, const hash256& header_hash, uint64_t nonce) noexcept;
126
127 result hash(const epoch_context_full& context, const hash256& header_hash, uint64_t nonce) noexcept;
128
129 bool verify_final_hash(const hash256& header_hash, const hash256& mix_hash, uint64_t nonce,
130 const hash256& boundary) noexcept;
131
132 bool verify(const epoch_context& context, const hash256& header_hash, const hash256& mix_hash,
133 uint64_t nonce, const hash256& boundary) noexcept;
134
135 search_result search_light(const epoch_context& context, const hash256& header_hash,
136 const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept;
137
138 search_result search(const epoch_context_full& context, const hash256& header_hash,
139 const hash256& boundary, uint64_t start_nonce, size_t iterations) noexcept;
140
141
142 /// Tries to find the epoch number matching the given seed hash.
143 ///
144 /// Mining pool protocols (many variants of stratum and "getwork") send out
145 /// seed hash instead of epoch number to workers. This function tries to recover
146 /// the epoch number from this seed hash.
147 ///
148 /// @param seed Ethash seed hash.
149 /// @return The epoch number or -1 if not found.
150 int find_epoch_number(const hash256& seed) noexcept;
151
152
153 /// Get global shared epoch context.
154 const epoch_context& get_global_epoch_context(int epoch_number);
155
156 /// Get global shared epoch context with full dataset initialized.
157 const epoch_context_full& get_global_epoch_context_full(int epoch_number);
158 } // namespace ethash
159