EthashAux.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. /*
  2. This file is part of cpp-ethereum.
  3. cpp-ethereum is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. cpp-ethereum is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /** @file EthashAux.cpp
  15. * @author Gav Wood <i@gavwood.com>
  16. * @date 2014
  17. */
  18. #include "EthashAux.h"
  19. #include <boost/detail/endian.hpp>
  20. #include <boost/filesystem.hpp>
  21. #include <chrono>
  22. #include <array>
  23. #include <thread>
  24. #include <libethash/internal.h>
  25. #include <libdevcore/Common.h>
  26. #include <libdevcore/Guards.h>
  27. #include <libdevcore/Log.h>
  28. #include <libdevcrypto/CryptoPP.h>
  29. #include <libdevcore/SHA3.h>
  30. #include <libdevcore/FileSystem.h>
  31. #include <libethcore/Exceptions.h>
  32. #include <libethcore/BlockHeader.h>
  33. #include "Ethash.h"
  34. using namespace std;
  35. using namespace chrono;
  36. using namespace dev;
  37. using namespace eth;
  38. const char* DAGChannel::name() { return EthGreen "DAG"; }
  39. EthashAux* dev::eth::EthashAux::s_this = nullptr;
  40. EthashAux::~EthashAux()
  41. {
  42. }
  43. EthashAux* EthashAux::get()
  44. {
  45. static std::once_flag flag;
  46. std::call_once(flag, []{s_this = new EthashAux();});
  47. return s_this;
  48. }
  49. uint64_t EthashAux::cacheSize(BlockHeader const& _header)
  50. {
  51. return ethash_get_cachesize((uint64_t)_header.number());
  52. }
  53. uint64_t EthashAux::dataSize(uint64_t _blockNumber)
  54. {
  55. return ethash_get_datasize(_blockNumber);
  56. }
  57. h256 EthashAux::seedHash(unsigned _number)
  58. {
  59. unsigned epoch = _number / ETHASH_EPOCH_LENGTH;
  60. Guard l(get()->x_epochs);
  61. if (epoch >= get()->m_seedHashes.size())
  62. {
  63. h256 ret;
  64. unsigned n = 0;
  65. if (!get()->m_seedHashes.empty())
  66. {
  67. ret = get()->m_seedHashes.back();
  68. n = get()->m_seedHashes.size() - 1;
  69. }
  70. get()->m_seedHashes.resize(epoch + 1);
  71. // cdebug << "Searching for seedHash of epoch " << epoch;
  72. for (; n <= epoch; ++n, ret = sha3(ret))
  73. {
  74. get()->m_seedHashes[n] = ret;
  75. // cdebug << "Epoch" << n << "is" << ret;
  76. }
  77. }
  78. return get()->m_seedHashes[epoch];
  79. }
  80. uint64_t EthashAux::number(h256 const& _seedHash)
  81. {
  82. Guard l(get()->x_epochs);
  83. unsigned epoch = 0;
  84. auto epochIter = get()->m_epochs.find(_seedHash);
  85. if (epochIter == get()->m_epochs.end())
  86. {
  87. // cdebug << "Searching for seedHash " << _seedHash;
  88. for (h256 h; h != _seedHash && epoch < 2048; ++epoch, h = sha3(h), get()->m_epochs[h] = epoch) {}
  89. if (epoch == 2048)
  90. {
  91. std::ostringstream error;
  92. error << "apparent block number for " << _seedHash << " is too high; max is " << (ETHASH_EPOCH_LENGTH * 2048);
  93. throw std::invalid_argument(error.str());
  94. }
  95. }
  96. else
  97. epoch = epochIter->second;
  98. return epoch * ETHASH_EPOCH_LENGTH;
  99. }
  100. void EthashAux::killCache(h256 const& _s)
  101. {
  102. WriteGuard l(x_lights);
  103. m_lights.erase(_s);
  104. }
  105. EthashAux::LightType EthashAux::light(h256 const& _seedHash)
  106. {
  107. UpgradableGuard l(get()->x_lights);
  108. if (get()->m_lights.count(_seedHash))
  109. return get()->m_lights.at(_seedHash);
  110. UpgradeGuard l2(l);
  111. return (get()->m_lights[_seedHash] = make_shared<LightAllocation>(_seedHash));
  112. }
  113. EthashAux::LightAllocation::LightAllocation(h256 const& _seedHash)
  114. {
  115. uint64_t blockNumber = EthashAux::number(_seedHash);
  116. light = ethash_light_new(blockNumber);
  117. if (!light)
  118. BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_light_new()"));
  119. size = ethash_get_cachesize(blockNumber);
  120. }
  121. EthashAux::LightAllocation::~LightAllocation()
  122. {
  123. ethash_light_delete(light);
  124. }
  125. bytesConstRef EthashAux::LightAllocation::data() const
  126. {
  127. return bytesConstRef((byte const*)light->cache, size);
  128. }
  129. EthashAux::FullAllocation::FullAllocation(ethash_light_t _light, ethash_callback_t _cb)
  130. {
  131. // cdebug << "About to call ethash_full_new...";
  132. full = ethash_full_new(_light, _cb);
  133. // cdebug << "Called OK.";
  134. if (!full)
  135. {
  136. clog(DAGChannel) << "DAG Generation Failure. Reason: " << strerror(errno);
  137. BOOST_THROW_EXCEPTION(ExternalFunctionFailure("ethash_full_new"));
  138. }
  139. }
  140. EthashAux::FullAllocation::~FullAllocation()
  141. {
  142. ethash_full_delete(full);
  143. }
  144. bytesConstRef EthashAux::FullAllocation::data() const
  145. {
  146. return bytesConstRef((byte const*)ethash_full_dag(full), size());
  147. }
  148. static std::function<int(unsigned)> s_dagCallback;
  149. static int dagCallbackShim(unsigned _p)
  150. {
  151. clog(DAGChannel) << "Generating DAG file. Progress: " << toString(_p) << "%";
  152. return s_dagCallback ? s_dagCallback(_p) : 0;
  153. }
  154. EthashAux::FullType EthashAux::full(h256 const& _seedHash, bool _createIfMissing, function<int(unsigned)> const& _f)
  155. {
  156. FullType ret;
  157. auto l = light(_seedHash);
  158. DEV_GUARDED(get()->x_fulls)
  159. if ((ret = get()->m_fulls[_seedHash].lock()))
  160. {
  161. get()->m_lastUsedFull = ret;
  162. return ret;
  163. }
  164. if (_createIfMissing || computeFull(_seedHash, false) == 100)
  165. {
  166. s_dagCallback = _f;
  167. // cnote << "Loading from libethash...";
  168. ret = make_shared<FullAllocation>(l->light, dagCallbackShim);
  169. // cnote << "Done loading.";
  170. DEV_GUARDED(get()->x_fulls)
  171. get()->m_fulls[_seedHash] = get()->m_lastUsedFull = ret;
  172. }
  173. return ret;
  174. }
  175. unsigned EthashAux::computeFull(h256 const& _seedHash, bool _createIfMissing)
  176. {
  177. Guard l(get()->x_fulls);
  178. uint64_t blockNumber;
  179. DEV_IF_THROWS(blockNumber = EthashAux::number(_seedHash))
  180. {
  181. return 0;
  182. }
  183. if (FullType ret = get()->m_fulls[_seedHash].lock())
  184. {
  185. get()->m_lastUsedFull = ret;
  186. return 100;
  187. }
  188. if (_createIfMissing && (!get()->m_fullGenerator || !get()->m_fullGenerator->joinable()))
  189. {
  190. get()->m_fullProgress = 0;
  191. get()->m_generatingFullNumber = blockNumber / ETHASH_EPOCH_LENGTH * ETHASH_EPOCH_LENGTH;
  192. get()->m_fullGenerator = unique_ptr<thread>(new thread([=](){
  193. cnote << "Loading full DAG of seedhash: " << _seedHash;
  194. get()->full(_seedHash, true, [](unsigned p){ get()->m_fullProgress = p; return 0; });
  195. cnote << "Full DAG loaded";
  196. get()->m_fullProgress = 0;
  197. get()->m_generatingFullNumber = NotGenerating;
  198. }));
  199. }
  200. return (get()->m_generatingFullNumber == blockNumber) ? get()->m_fullProgress : 0;
  201. }
  202. EthashProofOfWork::Result EthashAux::FullAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
  203. {
  204. ethash_return_value_t r = ethash_full_compute(full, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
  205. if (!r.success)
  206. BOOST_THROW_EXCEPTION(DAGCreationFailure());
  207. return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
  208. }
  209. EthashProofOfWork::Result EthashAux::LightAllocation::compute(h256 const& _headerHash, Nonce const& _nonce) const
  210. {
  211. ethash_return_value r = ethash_light_compute(light, *(ethash_h256_t*)_headerHash.data(), (uint64_t)(u64)_nonce);
  212. if (!r.success)
  213. BOOST_THROW_EXCEPTION(DAGCreationFailure());
  214. return EthashProofOfWork::Result{h256((uint8_t*)&r.result, h256::ConstructFromPointer), h256((uint8_t*)&r.mix_hash, h256::ConstructFromPointer)};
  215. }
  216. EthashProofOfWork::Result EthashAux::eval(h256 const& _seedHash, h256 const& _headerHash, Nonce const& _nonce)
  217. {
  218. DEV_GUARDED(get()->x_fulls)
  219. if (FullType dag = get()->m_fulls[_seedHash].lock())
  220. return dag->compute(_headerHash, _nonce);
  221. DEV_IF_THROWS(return EthashAux::get()->light(_seedHash)->compute(_headerHash, _nonce))
  222. {
  223. return EthashProofOfWork::Result{ ~h256(), h256() };
  224. }
  225. }