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(&ethash_destroy_epoch_context)>;
106 
107 using epoch_context_full_ptr =
108     std::unique_ptr<epoch_context_full, decltype(&ethash_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