Fabcoin Core  0.16.2
P2P Digital Currency
MinerAux.h
Go to the documentation of this file.
1 #pragma once
2 
3 /*
4  This file is part of cpp-ethereum.
5 
6  cpp-ethereum is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  cpp-ethereum is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
18 */
25 #include <boost/algorithm/string/case_conv.hpp>
26 #include <libdevcore/CommonJS.h>
28 #include <libethcore/Exceptions.h>
30 #include <jsonrpccpp/client/connectors/httpclient.h>
31 #include "FarmClient.h"
32 
33 // TODO - having using derivatives in header files is very poor style, and we need to fix these up.
34 //
35 // http://stackoverflow.com/questions/4872373/why-is-including-using-namespace-into-a-header-file-a-bad-idea-in-c
36 //
37 // "However you'll virtually never see a using directive in a header file (at least not outside of scope).
38 // The reason is that using directive eliminate the protection of that particular namespace, and the effect last
39 // until the end of current compilation unit. If you put a using directive (outside of a scope) in a header file,
40 // it means that this loss of "namespace protection" will occur within any file that include this header,
41 // which often mean other header files."
42 //
43 // Bob has already done just that in https://github.com/bobsummerwill/cpp-ethereum/commits/cmake_fixes/ethminer,
44 // and we should apply those changes back to 'develop'. It is probably best to defer that cleanup
45 // until after attempting to backport the Genoil ethminer changes, because they are fairly extensive
46 // in terms of lines of change, though all the changes are just adding explicit namespace prefixes.
47 // So let's start with just the subset of changes which minimizes the #include dependencies.
48 //
49 // See https://github.com/bobsummerwill/cpp-ethereum/commit/53af845268b91bc6aa1dab53a6eac675157a072b
50 // See https://github.com/bobsummerwill/cpp-ethereum/commit/3b9e581d7c04c637ebda18d3d86b5a24d29226f4
51 //
52 // More generally, the fact that nearly all of the code for ethminer is actually in the 'MinerAux.h'
53 // header file, rather than in a source file, is also poor style and should probably be addressed.
54 // Perhaps there is some historical reason for this which I am unaware of?
55 
56 using namespace std;
57 using namespace dev;
58 using namespace dev::eth;
59 
60 bool isTrue(std::string const& _m)
61 {
62  return _m == "on" || _m == "yes" || _m == "true" || _m == "1";
63 }
64 
65 bool isFalse(std::string const& _m)
66 {
67  return _m == "off" || _m == "no" || _m == "false" || _m == "0";
68 }
69 
70 inline std::string credits()
71 {
72  std::ostringstream out;
73  out
74  << "cpp-ethereum " << dev::Version << endl
75  << " By cpp-ethereum contributors, (c) 2013-2016." << endl
76  << " See the README for contributors and credits." << endl;
77  return out.str();
78 }
79 
80 class BadArgument: public Exception {};
81 struct MiningChannel: public LogChannel
82 {
83  static const char* name() { return EthGreen "miner"; }
84  static const int verbosity = 2;
85  static const bool debug = false;
86 };
87 #define minelog clog(MiningChannel)
88 
89 class MinerCLI
90 {
91 public:
92  enum class OperationMode
93  {
94  None,
95  DAGInit,
96  Benchmark,
97  Farm
98  };
99 
100 
101  MinerCLI(OperationMode _mode = OperationMode::None): mode(_mode) {
102  Ethash::init();
103  NoProof::init();
104  BasicAuthority::init();
105  }
106 
107  bool interpretOption(int& i, int argc, char** argv)
108  {
109  string arg = argv[i];
110  if ((arg == "-F" || arg == "--farm") && i + 1 < argc)
111  {
112  mode = OperationMode::Farm;
113  m_farmURL = argv[++i];
114  }
115  else if (arg == "--farm-recheck" && i + 1 < argc)
116  try {
117  m_farmRecheckPeriod = stol(argv[++i]);
118  }
119  catch (...)
120  {
121  cerr << "Bad " << arg << " option: " << argv[i] << endl;
122  BOOST_THROW_EXCEPTION(BadArgument());
123  }
124  else if (arg == "--benchmark-warmup" && i + 1 < argc)
125  try {
126  m_benchmarkWarmup = stol(argv[++i]);
127  }
128  catch (...)
129  {
130  cerr << "Bad " << arg << " option: " << argv[i] << endl;
131  BOOST_THROW_EXCEPTION(BadArgument());
132  }
133  else if (arg == "--benchmark-trial" && i + 1 < argc)
134  try {
135  m_benchmarkTrial = stol(argv[++i]);
136  }
137  catch (...)
138  {
139  cerr << "Bad " << arg << " option: " << argv[i] << endl;
140  BOOST_THROW_EXCEPTION(BadArgument());
141  }
142  else if (arg == "--benchmark-trials" && i + 1 < argc)
143  try {
144  m_benchmarkTrials = stol(argv[++i]);
145  }
146  catch (...)
147  {
148  cerr << "Bad " << arg << " option: " << argv[i] << endl;
149  BOOST_THROW_EXCEPTION(BadArgument());
150  }
151  else if (arg == "-C" || arg == "--cpu")
152  m_minerType = "cpu";
153  else if (arg == "--current-block" && i + 1 < argc)
154  m_currentBlock = stol(argv[++i]);
155  else if (arg == "--no-precompute")
156  {
157  m_precompute = false;
158  }
159  else if ((arg == "-D" || arg == "--create-dag") && i + 1 < argc)
160  {
161  string m = boost::to_lower_copy(string(argv[++i]));
162  mode = OperationMode::DAGInit;
163  try
164  {
165  m_initDAG = stol(m);
166  }
167  catch (...)
168  {
169  cerr << "Bad " << arg << " option: " << m << endl;
170  BOOST_THROW_EXCEPTION(BadArgument());
171  }
172  }
173  else if ((arg == "-w" || arg == "--check-pow") && i + 4 < argc)
174  {
175  string m;
176  try
177  {
178  BlockHeader bi;
179  m = boost::to_lower_copy(string(argv[++i]));
180  h256 powHash(m);
181  m = boost::to_lower_copy(string(argv[++i]));
182  h256 seedHash;
183  if (m.size() == 64 || m.size() == 66)
184  seedHash = h256(m);
185  else
186  seedHash = EthashAux::seedHash(stol(m));
187  m = boost::to_lower_copy(string(argv[++i]));
188  bi.setDifficulty(u256(m));
189  auto boundary = Ethash::boundary(bi);
190  m = boost::to_lower_copy(string(argv[++i]));
191  Ethash::setNonce(bi, h64(m));
192  auto r = EthashAux::eval(seedHash, powHash, h64(m));
193  bool valid = r.value < boundary;
194  cout << (valid ? "VALID :-)" : "INVALID :-(") << endl;
195  cout << r.value << (valid ? " < " : " >= ") << boundary << endl;
196  cout << " where " << boundary << " = 2^256 / " << bi.difficulty() << endl;
197  cout << " and " << r.value << " = ethash(" << powHash << ", " << h64(m) << ")" << endl;
198  cout << " with seed as " << seedHash << endl;
199  if (valid)
200  cout << "(mixHash = " << r.mixHash << ")" << endl;
201  cout << "SHA3( light(seed) ) = " << sha3(EthashAux::light(Ethash::seedHash(bi))->data()) << endl;
202  exit(0);
203  }
204  catch (...)
205  {
206  cerr << "Bad " << arg << " option: " << m << endl;
207  BOOST_THROW_EXCEPTION(BadArgument());
208  }
209  }
210  else if (arg == "-M" || arg == "--benchmark")
211  mode = OperationMode::Benchmark;
212  else if ((arg == "-t" || arg == "--mining-threads") && i + 1 < argc)
213  {
214  try {
215  m_miningThreads = stol(argv[++i]);
216  }
217  catch (...)
218  {
219  cerr << "Bad " << arg << " option: " << argv[i] << endl;
220  BOOST_THROW_EXCEPTION(BadArgument());
221  }
222  }
223  else if (arg == "--disable-submit-hashrate")
224  m_submitHashrate = false;
225  else
226  return false;
227  return true;
228  }
229 
230  void execute()
231  {
232  if (m_minerType == "cpu")
233  EthashCPUMiner::setNumInstances(m_miningThreads);
234  if (mode == OperationMode::DAGInit)
235  doInitDAG(m_initDAG);
236  else if (mode == OperationMode::Benchmark)
237  doBenchmark(m_minerType, m_benchmarkWarmup, m_benchmarkTrial, m_benchmarkTrials);
238  else if (mode == OperationMode::Farm)
239  doFarm(m_minerType, m_farmURL, m_farmRecheckPeriod);
240  }
241 
242  static void streamHelp(ostream& _out)
243  {
244  _out
245  << "Work farming mode:" << endl
246  << " -F,--farm <url> Put into mining farm mode with the work server at URL (default: http://127.0.0.1:8545)" << endl
247  << " --farm-recheck <n> Leave n ms between checks for changed work (default: 500)." << endl
248  << " --no-precompute Don't precompute the next epoch's DAG." << endl
249  << "Ethash verify mode:" << endl
250  << " -w,--check-pow <headerHash> <seedHash> <difficulty> <nonce> Check PoW credentials for validity." << endl
251  << endl
252  << "Benchmarking mode:" << endl
253  << " -M,--benchmark Benchmark for mining and exit; use with --cpu and --opencl." << endl
254  << " --benchmark-warmup <seconds> Set the duration of warmup for the benchmark tests (default: 3)." << endl
255  << " --benchmark-trial <seconds> Set the duration for each trial for the benchmark tests (default: 3)." << endl
256  << " --benchmark-trials <n> Set the number of trials for the benchmark tests (default: 5)." << endl
257  << "DAG creation mode:" << endl
258  << " -D,--create-dag <number> Create the DAG in preparation for mining on given block and exit." << endl
259  << "Mining configuration:" << endl
260  << " -C,--cpu When mining, use the CPU." << endl
261  << " -t, --mining-threads <n> Limit number of CPU/GPU miners to n (default: use everything available on selected platform)" << endl
262  << " --current-block Let the miner know the current block number at configuration time. Will help determine DAG size and required GPU memory." << endl
263  << " --disable-submit-hashrate When mining, don't submit hashrate to node." << endl;
264  }
265 
266  std::string minerType() const { return m_minerType; }
267  bool shouldPrecompute() const { return m_precompute; }
268 
269 private:
270  void doInitDAG(unsigned _n)
271  {
272  h256 seedHash = EthashAux::seedHash(_n);
273  cout << "Initializing DAG for epoch beginning #" << (_n / 30000 * 30000) << " (seedhash " << seedHash.abridged() << "). This will take a while." << endl;
274  EthashAux::full(seedHash, true);
275  exit(0);
276  }
277 
278  void doBenchmark(std::string _m, unsigned _warmupDuration = 15, unsigned _trialDuration = 3, unsigned _trials = 5)
279  {
280  BlockHeader genesis;
281  genesis.setDifficulty(1 << 18);
282  cdebug << Ethash::boundary(genesis);
283 
285  map<string, GenericFarm<EthashProofOfWork>::SealerDescriptor> sealers;
286  sealers["cpu"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashCPUMiner(ci); }};
287  f.setSealers(sealers);
288  f.onSolutionFound([&](EthashProofOfWork::Solution) { return false; });
289 
290  string platformInfo = EthashCPUMiner::platformInfo();
291  cout << "Benchmarking on platform: " << platformInfo << endl;
292 
293  cout << "Preparing DAG..." << endl;
294  Ethash::ensurePrecomputed(0);
295 
296  genesis.setDifficulty(u256(1) << 63);
297  f.setWork(genesis);
298  f.start(_m);
299 
300  map<u256, WorkingProgress> results;
301  u256 mean = 0;
302  u256 innerMean = 0;
303  for (unsigned i = 0; i <= _trials; ++i)
304  {
305  if (!i)
306  cout << "Warming up..." << endl;
307  else
308  cout << "Trial " << i << "... " << flush;
309  this_thread::sleep_for(chrono::seconds(i ? _trialDuration : _warmupDuration));
310 
311  auto mp = f.miningProgress();
313  if (!i)
314  continue;
315  auto rate = mp.rate();
316 
317  cout << rate << endl;
318  results[rate] = mp;
319  mean += rate;
320  }
321  f.stop();
322  int j = -1;
323  for (auto const& r: results)
324  if (++j > 0 && j < (int)_trials - 1)
325  innerMean += r.second.rate();
326  innerMean /= (_trials - 2);
327  cout << "min/mean/max: " << results.begin()->second.rate() << "/" << (mean / _trials) << "/" << results.rbegin()->second.rate() << " H/s" << endl;
328  cout << "inner mean: " << innerMean << " H/s" << endl;
329  exit(0);
330  }
331 
332  // dummy struct for special exception.
333  struct NoWork {};
334  void doFarm(std::string _m, string const& _remote, unsigned _recheckPeriod)
335  {
336  map<string, GenericFarm<EthashProofOfWork>::SealerDescriptor> sealers;
337  sealers["cpu"] = GenericFarm<EthashProofOfWork>::SealerDescriptor{&EthashCPUMiner::instances, [](GenericMiner<EthashProofOfWork>::ConstructionInfo ci){ return new EthashCPUMiner(ci); }};
338  (void)_m;
339  (void)_remote;
340  (void)_recheckPeriod;
341  jsonrpc::HttpClient client(_remote);
342 
343  h256 id = h256::random();
344  ::FarmClient rpc(client);
346  f.setSealers(sealers);
347  f.start(_m);
348 
351  while (true)
352  try
353  {
354  bool completed = false;
357  {
358  solution = sol;
359  completed = true;
360  return true;
361  });
362 
363  while (!completed)
364  {
365  auto mp = f.miningProgress();
367  if (current)
368  minelog << "Mining on PoWhash" << current.headerHash << ": " << mp;
369  else
370  minelog << "Getting work package...";
371 
372  if (m_submitHashrate)
373  {
374  auto rate = mp.rate();
375  try
376  {
377  rpc.eth_submitHashrate(toJS((u256)rate), "0x" + id.hex());
378  }
379  catch (jsonrpc::JsonRpcException const& _e)
380  {
381  cwarn << "Failed to submit hashrate.";
382  cwarn << boost::diagnostic_information(_e);
383  }
384  }
385 
386  Json::Value v = rpc.eth_getWork();
387  if (v[0].asString().empty())
388  throw NoWork();
389  h256 hh(v[0].asString());
390  h256 newSeedHash(v[1].asString());
391  if (current.seedHash != newSeedHash)
392  minelog << "Grabbing DAG for" << newSeedHash;
393  if (!(dag = EthashAux::full(newSeedHash, true, [&](unsigned _pc){ cout << "\rCreating DAG. " << _pc << "% done..." << flush; return 0; })))
394  BOOST_THROW_EXCEPTION(DAGCreationFailure());
395  if (m_precompute)
396  EthashAux::computeFull(sha3(newSeedHash), true);
397  if (hh != current.headerHash)
398  {
399  current.headerHash = hh;
400  current.seedHash = newSeedHash;
401  current.boundary = h256(fromHex(v[2].asString()), h256::AlignRight);
402  minelog << "Got work package:";
403  minelog << " Header-hash:" << current.headerHash.hex();
404  minelog << " Seedhash:" << current.seedHash.hex();
405  minelog << " Target: " << h256(current.boundary).hex();
406  f.setWork(current);
407  }
408  this_thread::sleep_for(chrono::milliseconds(_recheckPeriod));
409  }
410  cnote << "Solution found; Submitting to" << _remote << "...";
411  cnote << " Nonce:" << solution.nonce.hex();
412  cnote << " Mixhash:" << solution.mixHash.hex();
413  cnote << " Header-hash:" << current.headerHash.hex();
414  cnote << " Seedhash:" << current.seedHash.hex();
415  cnote << " Target: " << h256(current.boundary).hex();
416  cnote << " Ethash: " << h256(EthashAux::eval(current.seedHash, current.headerHash, solution.nonce).value).hex();
417  if (EthashAux::eval(current.seedHash, current.headerHash, solution.nonce).value < current.boundary)
418  {
419  bool ok = rpc.eth_submitWork("0x" + toString(solution.nonce), "0x" + toString(current.headerHash), "0x" + toString(solution.mixHash));
420  if (ok)
421  cnote << "B-) Submitted and accepted.";
422  else
423  cwarn << ":-( Not accepted.";
424  }
425  else
426  cwarn << "FAILURE: GPU gave incorrect result!";
427  current.reset();
428  }
429  catch (jsonrpc::JsonRpcException&)
430  {
431  for (auto i = 3; --i; this_thread::sleep_for(chrono::seconds(1)))
432  cerr << "JSON-RPC problem. Probably couldn't connect. Retrying in " << i << "... \r";
433  cerr << endl;
434  }
435  catch (NoWork&)
436  {
437  this_thread::sleep_for(chrono::milliseconds(100));
438  }
439  exit(0);
440  }
441 
444 
446  std::string m_minerType = "cpu";
447  unsigned m_miningThreads = UINT_MAX;
448  uint64_t m_currentBlock = 0;
449 
451  unsigned m_initDAG = 0;
452 
454  unsigned m_benchmarkWarmup = 3;
455  unsigned m_benchmarkTrial = 3;
456  unsigned m_benchmarkTrials = 5;
457 
459  string m_farmURL = "http://127.0.0.1:8545";
460  unsigned m_farmRecheckPeriod = 500;
461  bool m_precompute = true;
462  bool m_submitHashrate = true;
463 };
Adapted from code found on http://stackoverflow.com/questions/180947/base64-decode-snippet-in-c Origi...
Definition: Arith256.cpp:15
void setSealers(std::map< std::string, SealerDescriptor > const &_sealers)
Definition: GenericFarm.h:78
MinerCLI(OperationMode _mode=OperationMode::None)
Definition: MinerAux.h:101
WorkingProgress const & miningProgress() const
Get information on the progress of mining this work package.
Definition: GenericFarm.h:124
Encapsulation of a block header.
Definition: BlockHeader.h:95
OperationMode
Definition: MinerAux.h:92
std::shared_ptr< FullAllocation > FullType
Definition: EthashAux.h:68
bool eth_submitWork(const std::string &param1, const std::string &param2, const std::string &param3)
Definition: FarmClient.h:25
evm_mode mode
Definition: SmartVM.cpp:47
#define EthGreen
Definition: Terminal.h:122
void doBenchmark(std::string _m, unsigned _warmupDuration=15, unsigned _trialDuration=3, unsigned _trials=5)
Definition: MinerAux.h:278
FixedHash< 8 > h64
Definition: FixedHash.h:343
void stop()
Stop all mining activities.
Definition: GenericFarm.h:107
std::hash for asio::adress
Definition: Common.h:323
EXPORT void debug(uint64_t a, uint64_t b, uint64_t c, uint64_t d, char z)
Definition: Arith256.cpp:415
static void streamHelp(ostream &_out)
Definition: MinerAux.h:242
A collective of Miners.
Definition: GenericFarm.h:45
std::string toString(string32 const &_s)
Make normal string from fixed-length string.
Definition: CommonData.cpp:141
#define cdebug
Definition: Log.h:302
void resetMiningProgress()
Reset the mining progess counter.
Definition: GenericFarm.h:141
Json::Value eth_getWork()
Definition: FarmClient.h:15
bytes fromHex(std::string const &_s, WhenError _throw=WhenError::DontThrow)
Definition: CommonData.cpp:99
void onSolutionFound(SolutionFound const &_handler)
Provides a valid header based upon that received previously with setWork().
Definition: GenericFarm.h:156
Base class for all exceptions.
Definition: Exceptions.h:39
Config::Value_type Value
This file is generated by jsonrpcstub, DO NOT CHANGE IT MANUALLY!
Definition: Farm.h:10
std::string toJS(FixedHash< S > const &_h)
Definition: CommonJS.h:34
std::string minerType() const
Definition: MinerAux.h:266
bool interpretOption(int &i, int argc, char **argv)
Definition: MinerAux.h:107
FixedHash< 32 > h256
Definition: FixedHash.h:340
#define cwarn
Definition: Log.h:304
bool start(std::string const &_sealer)
Start a number of miners.
Definition: GenericFarm.h:83
bool eth_submitHashrate(const std::string &param1, const std::string &param2)
Definition: FarmClient.h:37
boost::multiprecision::number< boost::multiprecision::cpp_int_backend< 256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void >> u256
Definition: Common.h:125
std::string credits()
Definition: MinerAux.h:70
#define minelog
Definition: MinerAux.h:87
#define f(x)
Definition: gost.cpp:57
void setWork(WorkPackage const &_wp)
Sets the current mining mission.
Definition: GenericFarm.h:67
#define cnote
Definition: Log.h:303
void doInitDAG(unsigned _n)
Definition: MinerAux.h:270
OperationMode mode
Operating mode.
Definition: MinerAux.h:443
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
char const * Version
Definition: Common.cpp:36
std::string abridged() const
Definition: FixedHash.h:124
bool shouldPrecompute() const
Definition: MinerAux.h:267
The default logging channels.
Definition: Log.h:130
A miner - a member and adoptee of the Farm.
Definition: GenericMiner.h:43
This file is generated by jsonrpcstub, DO NOT CHANGE IT MANUALLY!
Definition: FarmClient.h:10
h256 headerHash
When h256() means "pause until notified a new work package is available".
static const char * name()
Definition: MinerAux.h:83
void doFarm(std::string _m, string const &_remote, unsigned _recheckPeriod)
Definition: MinerAux.h:334
u256 const & difficulty() const
Definition: BlockHeader.h:166
uint8_t const * data
Definition: sha3.h:19
bool isFalse(std::string const &_m)
Definition: MinerAux.h:65
void setDifficulty(u256 const &_v)
Definition: BlockHeader.h:150
std::string asString(bytes const &_b)
Converts byte array to a string containing the same (binary) data.
Definition: CommonData.h:79
void execute()
Definition: MinerAux.h:230
bool isTrue(std::string const &_m)
Definition: MinerAux.h:60
std::string hex() const
Definition: FixedHash.h:130