Fabcoin Core  0.16.2
P2P Digital Currency
libgpusolver.cpp
Go to the documentation of this file.
1 /* MIT License
2  *
3  * Copyright (c) 2016 Omar Alvarez <omar.alvarez@udc.es>
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy
6  * of this software and associated documentation files (the "Software"), to deal
7  * in the Software without restriction, including without limitation the rights
8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  */
23 
24 #include <chrono>
25 
26 #include "libgpusolver.h"
27 #include "util.h"
28 #include "primitives/block.h"
29 #include "arith_uint256.h"
30 
31 //#define DEBUG
32 
33 char *s_hexdump(const void *_a, uint32_t a_len)
34 {
35  const uint8_t *a = (const uint8_t *) _a;
36  static char buf[1024];
37  uint32_t i;
38  for (i = 0; i < a_len && i + 2 < sizeof (buf); i++)
39  sprintf(buf + i * 2, "%02x", a[i]);
40  buf[i * 2] = 0;
41  return buf;
42 }
43 
45 
46  size_t global_work_size = 1 << 20;
47  size_t local_work_size = 32;
48 
49  miner = new cl_gpuminer();
50 
51  indices = (sols_t *) malloc(sizeof(sols_t));
52  if(indices == NULL)
53  std::cout << "Error allocating indices array!" << std::endl;
54 
55  GPU = miner->configureGPU(0, local_work_size, global_work_size);
56  if(!GPU)
57  std::cout << "ERROR: No suitable GPU found! No work will be performed!" << std::endl;
58 
59  /*Initialize the kernel, compile it and create buffers
60  Currently runs for the gpu-list-gen.c kernel DATA_SIZE=100 times
61  */
62  std::vector<std::string> kernels {"kernel_init_ht", "kernel_round0", "kernel_round1", "kernel_round2","kernel_round3", "kernel_round4", "kernel_round5", "kernel_round6", "kernel_round7", "kernel_round8", "kernel_sols"};
63 
64  if(GPU)
65  initOK = miner->init(0, 0, kernels);
66 
67 }
68 
69 GPUSolver::GPUSolver(unsigned platform, unsigned device) {
70 
71  /* Notes
72  I've added some extra parameters in this interface to assist with dev, such as
73  a kernel string to specify which kernel to run and local/global work sizes.
74  */
75  //TODO This looks like IND_PER_BUCKET, enough for GPU?
76  size_t global_work_size = 1 << 20;
77  size_t local_work_size = 32;
78 
79  miner = new cl_gpuminer();
80 
81  indices = (sols_t *) malloc(sizeof(sols_t));
82  if(indices == NULL)
83  std::cout << "Error allocating indices array!" << std::endl;
84 
85  /* Checks each device for memory requirements and sets local/global sizes
86  TODO: Implement device logic for equihash kernel
87  @params: unsigned platformId
88  @params: unsigned localWorkSizes
89  @params: unsigned globalWorkSizes
90  */
91  GPU = miner->configureGPU(platform, local_work_size, global_work_size);
92  if(!GPU)
93  std::cout << "ERROR: No suitable GPU found! No work will be performed!" << std::endl;
94 
95  /*Initialize the kernel, compile it and create buffers
96  Currently runs for the gpu-list-gen.c kernel DATA_SIZE=100 times
97  TODO: pass base state and nonce's to kernel.
98  @params: unsigned _platformId
99  @params: unsigned _deviceId
100  @params: string& _kernel - The name of the kernel for dev purposes
101  */
102  std::vector<std::string> kernels {"kernel_init_ht", "kernel_round0", "kernel_round1", "kernel_round2","kernel_round3", "kernel_round4", "kernel_round5", "kernel_round6", "kernel_round7", "kernel_round8", "kernel_sols"};
103  if(GPU)
104  initOK = miner->init(platform, device, kernels);
105 
106 }
107 
109 
110  if(GPU)
111  miner->finish();
112 
113  delete miner;
114 
115  if(indices != NULL)
116  free(indices);
117 
118 }
119 
120 bool GPUSolver::run(unsigned int n, unsigned int k, uint8_t *header, size_t header_len, uint256 nonce,
121  const std::function<bool(std::vector<unsigned char>)> validBlock,
122  const std::function<bool(GPUSolverCancelCheck)> cancelled,
123  crypto_generichash_blake2b_state base_state)
124 {
125  if (n == 200 && k == 9) {
126  return GPUSolve(n, k, header, header_len, nonce, validBlock, cancelled, base_state);
127  } else {
128  throw std::invalid_argument("Unsupported Equihash parameters");
129  }
130 }
131 
132 bool GPUSolver::GPUSolve(unsigned int n, unsigned int k, uint8_t *header, size_t header_len, uint256 &nonce,
133  const std::function<bool(std::vector<unsigned char>)> validBlock,
134  const std::function<bool(GPUSolverCancelCheck)> cancelled,
135  crypto_generichash_blake2b_state base_state)
136 {
137  /* Run the kernel
138  TODO: Optimise and figure out how we want this to go
139  @params eh_HashState& base_state - Sends to kernel in a buffer. Will update for specific kernels
140  */
141 
142  if(GPU && initOK)
143  {
144  // auto t = std::chrono::high_resolution_clock::now();
145  uint256 nNonce;
146  miner->run(header, header_len, nonce, indices, &n_sol, &nNonce);
147 
148 // uint256 nNonce = ArithToUint256(ptr);
149  //crypto_generichash_blake2b_update(&base_state, nNonce.begin(), nNonce.size());
150 /*
151  auto d = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - t);
152  auto milis = std::chrono::duration_cast<std::chrono::milliseconds>(d).count();
153 
154  if(!counter) {
155  sum = 1000.f*n_sol/milis;
156  } else {
157  sum += 1000.f*n_sol/milis;
158  }
159 
160  avg = sum/++counter;
161 
162  if(!(counter % 10))
163  std::cout << "Kernel run took " << milis << " ms. (" << avg << " H/s)" << std::endl;
164 */
165 
166  size_t checkedSols = n_sol;
167  size_t s = 0;
168  while (checkedSols)
169  {
170  ++s;
171  if(indices->valid[s-1])
172  --checkedSols;
173  else
174  continue;
175 
176  std::vector<eh_index> index_vector(PROOFSIZE);
177  for (size_t i = 0; i < PROOFSIZE; i++)
178  {
179  index_vector[i] = indices->values[s-1][i];
180  }
181  std::vector<unsigned char> sol_char = GetMinimalFromIndices(index_vector, DIGITBITS_S);
182  //LogPrint(BCLog::POW, "Checking with = %s, %d sols\n",nNonce.ToString(), n_sol);
183 #ifdef DEBUG
184  bool isValid;
185  EhIsValidSolution(n, k, base_state, sol_char, isValid);
186  LogPrint(BCLog::POW,"is valid: \n");
187  if (!isValid)
188  {
189  //If we find invalid solution bail, it cannot be a valid POW
190  LogPrint(BCLog::POW,"Invalid solution found!\n");
191  return false;
192  }
193  else
194  {
195  LogPrint(BCLog::POW,"Valid solution found!\n");
196  }
197 #endif
198  if (validBlock(sol_char))
199  {
200  // If we find a POW solution, do not try other solutions
201  // because they become invalid as we created a new block in blockchain.
202  LogPrint(BCLog::POW,"Valid block found!\n");
203  return true;
204  }
205  }
206  //free(indices);
207  }
208 
209  return false;
210 
211 }
#define function(a, b, c, d, k, s)
#define DIGITBITS_S
Definition: libgpusolver.h:48
std::vector< unsigned char > GetMinimalFromIndices(std::vector< eh_index > indices, size_t cBitLen)
Definition: equihash.cpp:195
void run(uint8_t *header, size_t header_len, uint256 nonce, sols_t *indices, uint32_t *n_sol, uint256 *ptr)
bool run(unsigned int n, unsigned int k, uint8_t *header, size_t header_len, uint256 nonce, const std::function< bool(std::vector< unsigned char >)> validBlock, const std::function< bool(GPUSolverCancelCheck)> cancelled, crypto_generichash_blake2b_state base_state)
sols_t * indices
Definition: libgpusolver.h:80
bool GPUSolve(unsigned int n, unsigned int k, uint8_t *header, size_t header_len, uint256 &nonce, const std::function< bool(std::vector< unsigned char >)> validBlock, const std::function< bool(GPUSolverCancelCheck)> cancelled, crypto_generichash_blake2b_state base_state)
uint32_t n_sol
Definition: libgpusolver.h:81
uint8_t valid[MAX_SOLS]
Definition: libclwrapper.h:17
#define a(i)
bool init(unsigned _platformId, unsigned _deviceId, std::vector< std::string > _kernels)
GPUSolverCancelCheck
Definition: libgpusolver.h:57
#define EhIsValidSolution(n, k, base_state, soln, ret)
Definition: equihash.h:271
static const uint32_t PROOFSIZE
Definition: libgpusolver.h:78
#define LogPrint(category,...)
Definition: util.h:164
cl_gpuminer * miner
Definition: libgpusolver.h:75
256-bit opaque blob.
Definition: uint256.h:132
uint values[MAX_SOLS][512]
Definition: libclwrapper.h:18
char * s_hexdump(const void *_a, uint32_t a_len)
bool initOK
Definition: libgpusolver.h:77
static bool configureGPU(unsigned _platformId, unsigned _localWorkSize, unsigned _globalWorkSize)