Fabcoin Core  0.16.2
P2P Digital Currency
EthashAux.cpp
Go to the documentation of this file.
1 /*
2  This file is part of cpp-ethereum.
3 
4  cpp-ethereum is free software: you can redistribute it and/or modify
5  it under the terms of the GNU General Public License as published by
6  the Free Software Foundation, either version 3 of the License, or
7  (at your option) any later version.
8 
9  cpp-ethereum is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
16 */
22 #include "EthashAux.h"
23 #include <boost/detail/endian.hpp>
24 #include <boost/filesystem.hpp>
25 #include <chrono>
26 #include <array>
27 #include <thread>
28 #include <libethash/internal.h>
29 #include <libdevcore/Common.h>
30 #include <libdevcore/Guards.h>
31 #include <libdevcore/Log.h>
32 #include <libdevcrypto/CryptoPP.h>
33 #include <libdevcore/SHA3.h>
34 #include <libdevcore/FileSystem.h>
35 #include <libethcore/Exceptions.h>
36 #include <libethcore/BlockHeader.h>
37 #include "Ethash.h"
38 using namespace std;
39 using namespace chrono;
40 using namespace dev;
41 using namespace eth;
42 
43 const char* DAGChannel::name() { return EthGreen "DAG"; }
44 
46 
47 EthashAux::~EthashAux()
48 {
49 }
50 
51 EthashAux* EthashAux::get()
52 {
53  static std::once_flag flag;
54  std::call_once(flag, []{s_this = new EthashAux();});
55  return s_this;
56 }
57 
58 uint64_t EthashAux::cacheSize(BlockHeader const& _header)
59 {
60  return ethash_get_cachesize((uint64_t)_header.number());
61 }
62 
63 uint64_t EthashAux::dataSize(uint64_t _blockNumber)
64 {
65  return ethash_get_datasize(_blockNumber);
66 }
67 
68 h256 EthashAux::seedHash(unsigned _number)
69 {
70  unsigned epoch = _number / ETHASH_EPOCH_LENGTH;
71  Guard l(get()->x_epochs);
72  if (epoch >= get()->m_seedHashes.size())
73  {
74  h256 ret;
75  unsigned n = 0;
76  if (!get()->m_seedHashes.empty())
77  {
78  ret = get()->m_seedHashes.back();
79  n = get()->m_seedHashes.size() - 1;
80  }
81  get()->m_seedHashes.resize(epoch + 1);
82 // cdebug << "Searching for seedHash of epoch " << epoch;
83  for (; n <= epoch; ++n, ret = sha3(ret))
84  {
85  get()->m_seedHashes[n] = ret;
86 // cdebug << "Epoch" << n << "is" << ret;
87  }
88  }
89  return get()->m_seedHashes[epoch];
90 }
91 
92 uint64_t EthashAux::number(h256 const& _seedHash)
93 {
94  Guard l(get()->x_epochs);
95  unsigned epoch = 0;
96  auto epochIter = get()->m_epochs.find(_seedHash);
97  if (epochIter == get()->m_epochs.end())
98  {
99  // cdebug << "Searching for seedHash " << _seedHash;
100  for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {}
101  if (epoch == 2048)
102  {
103  std::ostringstream error;
104  error << "apparent block number for " << _seedHash << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048);
105  throw std::invalid_argument(error.str());
106  }
107  }
108  else
109  epoch = epochIter->second;
110  return epoch * ETHASH_EPOCH_LENGTH;
111 }
112 
113 void EthashAux::killCache(h256 const& _s)
114 {
115  WriteGuard l(x_lights);
116  m_lights.erase(_s);
117 }
118 
119 EthashAux::LightType EthashAux::light(h256 const& _seedHash)
120 {
121  UpgradableGuard l(get()->x_lights);
122  if (get()->m_lights.count(_seedHash))
123  return get()->m_lights.at(_seedHash);
124  UpgradeGuard l2(l);
125  return (get()->m_lights[_seedHash] = make_shared<LightAllocation>(_seedHash));
126 }
127 
128 EthashAux::LightAllocation::LightAllocation(h256 const& _seedHash)
129 {
130  uint64_t blockNumber = EthashAux::number(_seedHash);
131  light = ethash_light_new(blockNumber);
132  if (!light)
133  BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_light_new()"));
134  size = ethash_get_cachesize(blockNumber);
135 }
136 
137 EthashAux::LightAllocation::~LightAllocation()
138 {
139  ethash_light_delete(light);
140 }
141 
143 {
144  return bytesConstRef((byte const*)light->cache, size);
145 }
146 
147 EthashAux::FullAllocation::FullAllocation(ethash_light_t _light, ethash_callback_t _cb)
148 {
149 // cdebug << "About to call ethash_full_new...";
150  full = ethash_full_new(_light, _cb);
151 // cdebug << "Called OK.";
152  if (!full)
153  {
154  clog(DAGChannel) << "DAG Generation Failure. Reason: " << strerror(errno);
155  BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new"));
156  }
157 }
158 
159 EthashAux::FullAllocation::~FullAllocation()
160 {
161  ethash_full_delete(full);
162 }
163 
165 {
166  return bytesConstRef((byte const*)ethash_full_dag(full), size());
167 }
168 
169 static std::function<int(unsigned)> s_dagCallback;
170 static int dagCallbackShim(unsigned _p)
171 {
172  clog(DAGChannel) << "Generating DAG file. Progress: " << toString(_p) << "%";
173  return s_dagCallback ? s_dagCallback(_p) : 0;
174 }
175 
176 EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing, function<int(unsigned)> const& _f)
177 {
178  FullType ret;
179  auto l = light(_seedHash);
180 
181  DEV_GUARDED(get()->x_fulls)
182  if ((ret = get()->m_fulls[_seedHash].lock()))
183  {
184  get()->m_lastUsedFull = ret;
185  return ret;
186  }
187 
188  if (_createIfMissing || computeFull(_seedHash, false) == 100)
189  {
190  s_dagCallback = _f;
191 // cnote << "Loading from libethash...";
192  ret = make_shared<FullAllocation>(l->light, dagCallbackShim);
193 // cnote << "Done loading.";
194 
195  DEV_GUARDED(get()->x_fulls)
196  get()->m_fulls[_seedHash] = get()->m_lastUsedFull = ret;
197  }
198 
199  return ret;
200 }
201 
202 unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing)
203 {
204  Guard l(get()->x_fulls);
205  uint64_t blockNumber;
206 
207  DEV_IF_THROWS(blockNumber = EthashAux::number(_seedHash))
208  {
209  return 0;
210  }
211 
212  if (FullType ret = get()->m_fulls[_seedHash].lock())
213  {
214  get()->m_lastUsedFull = ret;
215  return 100;
216  }
217 
218  if (_createIfMissing && (!get()->m_fullGenerator || !get()->m_fullGenerator->joinable()))
219  {
220  get()->m_fullProgress = 0;
221  get()->m_generatingFullNumber = blockNumber / ETHASH_EPOCH_LENGTH * ETHASH_EPOCH_LENGTH;
222  get()->m_fullGenerator = unique_ptr<thread>(new thread([=](){
223  cnote << "Loading full DAG of seedhash: " << _seedHash;
224  get()->full(_seedHash, true, [](unsigned p){ get()->m_fullProgress = p; return 0; });
225  cnote << "Full DAG loaded";
226  get()->m_fullProgress = 0;
227  get()->m_generatingFullNumber = NotGenerating;
228  }));
229  }
230 
231  return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0;
232 }
233 
234 EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
235 {
236  ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
237  if (!r.success)
238  BOOST_THROW_EXCEPTION(DAGCreationFailure());
239  return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
240 }
241 
242 EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
243 {
244  ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
245  if (!r.success)
246  BOOST_THROW_EXCEPTION(DAGCreationFailure());
247  return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
248 }
249 
250 EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
251 {
252  DEV_GUARDED(get()->x_fulls)
253  if (FullType dag = get()->m_fulls[_seedHash].lock())
254  return dag->compute(_headerHash, _nonce);
255  DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce))
256  {
257  return EthashProofOfWork::Result{ ~h256(), h256() };
258  }
259 }
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
#define DEV_IF_THROWS(X)
Definition: Common.h:65
bool error(const char *fmt, const Args &...args)
Definition: util.h:178
u256 const & number() const
Definition: BlockHeader.h:162
uint8_t byte
Definition: Common.h:57
byte * data()
Definition: FixedHash.h:139
uint64_t ethash_get_datasize(uint64_t const block_number)
Definition: internal.c:76
Encapsulation of a block header.
Definition: BlockHeader.h:95
std::shared_ptr< FullAllocation > FullType
Definition: EthashAux.h:68
#define h(i)
Definition: sha.cpp:736
static EthashAux * s_this
Definition: EthashAux.h:94
ethash_h256_t result
Definition: ethash.h:65
#define EthGreen
Definition: Terminal.h:122
boost::upgrade_to_unique_lock< boost::shared_mutex > UpgradeGuard
Definition: Guards.h:46
std::hash for asio::adress
Definition: Common.h:323
ethash_light_t ethash_light_new(uint64_t block_number)
Allocate and initialize a new ethash_light handler.
Definition: internal.c:400
std::string toString(string32 const &_s)
Make normal string from fixed-length string.
Definition: CommonData.cpp:141
boost::upgrade_lock< boost::shared_mutex > UpgradableGuard
Definition: Guards.h:45
void ethash_light_delete(ethash_light_t light)
Frees a previously allocated ethash_light handler.
Definition: internal.c:409
std::shared_ptr< LightAllocation > LightType
Definition: EthashAux.h:67
#define ETHASH_EPOCH_LENGTH
Definition: ethash.h:34
#define DEV_GUARDED(MUTEX)
Simple block guard.
Definition: Guards.h:144
void const * ethash_full_dag(ethash_full_t full)
Get a pointer to the full DAG data.
Definition: internal.c:595
std::lock_guard< std::mutex > Guard
Definition: Guards.h:41
void ethash_full_delete(ethash_full_t full)
Frees a previously allocated ethash_full handler.
Definition: internal.c:565
const char * name
Definition: rest.cpp:36
ethash_return_value_t ethash_light_compute(ethash_light_t light, ethash_h256_t const header_hash, uint64_t nonce)
Calculate the light client data.
Definition: internal.c:432
vector_ref< byte const > bytesConstRef
Definition: Common.h:77
FixedHash< 32 > h256
Definition: FixedHash.h:340
boost::unique_lock< boost::shared_mutex > WriteGuard
Definition: Guards.h:47
Type of a seedhash/blockhash e.t.c.
Definition: ethash.h:48
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 64, 64, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u64
Definition: Common.h:123
#define cnote
Definition: Log.h:303
uint8_t const size_t const size
Definition: sha3.h:20
uint64_t ethash_get_cachesize(uint64_t const block_number)
Definition: internal.c:82
bool sha3(bytesConstRef _input, bytesRef o_output)
Calculate SHA3-256 hash of the given input and load it into the given output.
Definition: SHA3.cpp:214
int(* ethash_callback_t)(unsigned)
Definition: ethash.h:62
#define clog(X)
Definition: Log.h:295
ethash_return_value_t ethash_full_compute(ethash_full_t full, ethash_h256_t const header_hash, uint64_t nonce)
Calculate the full client data.
Definition: internal.c:575
ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback)
Allocate and initialize a new ethash_full handler.
Definition: internal.c:554
uint8_t const * data
Definition: sha3.h:19
ethash_h256_t mix_hash
Definition: ethash.h:66