grin_miner_plugin/
lib.rs

1// Copyright 2017 The Grin Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Crate wrapping up the Grin miner plugins
16
17#![deny(non_upper_case_globals)]
18#![deny(non_camel_case_types)]
19#![deny(non_snake_case)]
20#![deny(unused_mut)]
21#![warn(missing_docs)]
22
23extern crate serde;
24#[macro_use]
25extern crate serde_derive;
26extern crate blake2_rfc as blake2;
27extern crate byteorder;
28extern crate libc;
29extern crate serde_json;
30
31use libc::*;
32use std::ffi::CString;
33use std::ptr::NonNull;
34use std::{cmp, fmt, marker};
35
36use blake2::blake2b::Blake2b;
37use byteorder::{BigEndian, ByteOrder};
38
39/// Size of proof
40pub const PROOFSIZE: usize = 42;
41/// Maximin length of plugin name w
42pub const MAX_NAME_LEN: usize = 256;
43/// Maximum number of solutions
44pub const MAX_SOLS: usize = 4;
45
46// Type definitions corresponding to each function that the plugin/solver implements
47/// Create solver function
48pub type CuckooCreateSolverCtx = unsafe extern "C" fn(*mut SolverParams) -> *mut SolverCtx;
49/// Destroy solver function
50pub type CuckooDestroySolverCtx = unsafe extern "C" fn(*mut SolverCtx);
51/// Run solver function
52pub type CuckooRunSolver = unsafe extern "C" fn(
53	*mut SolverCtx,       // Solver context
54	*const c_uchar,       // header
55	uint32_t,             // header length
56	uint64_t,             // nonce
57	uint32_t,             // range
58	*mut SolverSolutions, // reference to any found solutions
59	*mut SolverStats,     // solver stats
60) -> uint32_t;
61/// Stop solver function
62pub type CuckooStopSolver = unsafe extern "C" fn(*mut SolverCtx);
63/// Fill default params of solver
64pub type CuckooFillDefaultParams = unsafe extern "C" fn(*mut SolverParams);
65
66/// A solver context, opaque reference to C++ type underneath
67#[derive(Copy, Clone, Debug)]
68pub enum SolverCtx {}
69/// wrap ctx to send across threads
70pub struct SolverCtxWrapper(pub NonNull<SolverCtx>);
71unsafe impl marker::Send for SolverCtxWrapper {}
72
73/// Common parameters for a solver
74#[derive(Clone, Debug, Serialize, Deserialize)]
75#[repr(C)]
76pub struct SolverParams {
77	/// threads
78	pub nthreads: uint32_t,
79	/// trims
80	pub ntrims: uint32_t,
81	/// Whether to show cycle (should be true to get solutions)
82	pub showcycle: bool,
83	/// allrounds
84	pub allrounds: bool,
85	/// whether to apply the nonce to the header, or leave as is,
86	/// letting caller mutate nonce
87	pub mutate_nonce: bool,
88	/// reduce cpuload
89	pub cpuload: bool,
90
91	/// Common Cuda params
92	pub device: u32,
93
94	/// Lean cuda params
95	pub blocks: u32,
96	///
97	pub tpb: u32,
98
99	/// Mean cuda params
100	pub expand: u32,
101	///
102	pub genablocks: u32,
103	///
104	pub genatpb: u32,
105	///
106	pub genbtpb: u32,
107	///
108	pub trimtpb: u32,
109	///
110	pub tailtpb: u32,
111	///
112	pub recoverblocks: u32,
113	///
114	pub recovertpb: u32,
115	/// OCL platform ID, 0 - default, 1 - AMD, 2 - NVIDIA
116	pub platform: u32,
117	/// edge bits for OCL plugins
118	pub edge_bits: u32,
119}
120
121impl Default for SolverParams {
122	fn default() -> SolverParams {
123		SolverParams {
124			nthreads: 0,
125			ntrims: 0,
126			showcycle: true,
127			allrounds: false,
128			mutate_nonce: false,
129			cpuload: true,
130			device: 0,
131			blocks: 0,
132			tpb: 0,
133			expand: 0,
134			genablocks: 0,
135			genatpb: 0,
136			genbtpb: 0,
137			trimtpb: 0,
138			tailtpb: 0,
139			recoverblocks: 0,
140			recovertpb: 0,
141			platform: 0,
142			edge_bits: 31,
143		}
144	}
145}
146
147/// Common stats collected by solvers
148#[derive(Clone)]
149#[repr(C)]
150pub struct SolverStats {
151	/// device Id
152	pub device_id: uint32_t,
153	/// graph size
154	pub edge_bits: uint32_t,
155	/// plugin name
156	pub plugin_name: [c_uchar; MAX_NAME_LEN],
157	/// device name
158	pub device_name: [c_uchar; MAX_NAME_LEN],
159	/// whether device has reported an error
160	pub has_errored: bool,
161	/// reason for error
162	pub error_reason: [c_uchar; MAX_NAME_LEN],
163	/// number of searched completed by device
164	pub iterations: uint32_t,
165	/// last solution start time
166	pub last_start_time: uint64_t,
167	/// last solution end time
168	pub last_end_time: uint64_t,
169	/// last solution elapsed time
170	pub last_solution_time: uint64_t,
171}
172
173impl Default for SolverStats {
174	fn default() -> SolverStats {
175		SolverStats {
176			device_id: 0,
177			edge_bits: 0,
178			plugin_name: [0; MAX_NAME_LEN],
179			device_name: [0; MAX_NAME_LEN],
180			has_errored: false,
181			error_reason: [0; MAX_NAME_LEN],
182			iterations: 0,
183			last_start_time: 0,
184			last_end_time: 0,
185			last_solution_time: 0,
186		}
187	}
188}
189
190impl SolverStats {
191	fn get_name(&self, c_str: &[u8; MAX_NAME_LEN]) -> String {
192		// remove all null zeroes
193		let v = c_str.clone().to_vec();
194		let mut i = 0;
195		for j in 0..v.len() {
196			if v.get(j) == Some(&0) {
197				i = j;
198				break;
199			}
200		}
201		let v = v.split_at(i).0;
202		match CString::new(v) {
203			Ok(s) => s.to_str().unwrap().to_owned(),
204			Err(_) => String::from("Unknown Device Name"),
205		}
206	}
207	/// return device name as rust string
208	pub fn get_device_name(&self) -> String {
209		self.get_name(&self.device_name)
210	}
211	/// return plugin name as rust string
212	pub fn get_plugin_name(&self) -> String {
213		self.get_name(&self.plugin_name)
214	}
215	/// return plugin name as rust string
216	pub fn get_error_reason(&self) -> String {
217		self.get_name(&self.error_reason)
218	}
219	/// set plugin name
220	pub fn set_plugin_name(&mut self, name: &str) {
221		let c_vec = CString::new(name).unwrap().into_bytes();
222		for i in 0..c_vec.len() {
223			self.plugin_name[i] = c_vec[i];
224		}
225	}
226}
227
228/// A single solution
229#[repr(C)]
230#[derive(Clone, Copy)]
231pub struct Solution {
232	/// Optional ID
233	pub id: uint64_t,
234	/// Nonce
235	pub nonce: uint64_t,
236	/// Proof
237	pub proof: [uint64_t; PROOFSIZE],
238}
239
240impl Default for Solution {
241	fn default() -> Solution {
242		Solution {
243			id: 0,
244			nonce: 0,
245			proof: [0u64; PROOFSIZE],
246		}
247	}
248}
249
250impl fmt::Display for Solution {
251	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252		let mut comma_separated = String::new();
253
254		for num in &self.proof[0..self.proof.len()] {
255			comma_separated.push_str(&format!("0x{:X}", &num));
256			comma_separated.push_str(", ");
257		}
258		comma_separated.pop();
259		comma_separated.pop();
260
261		write!(f, "Nonce:{} [{}]", self.nonce, comma_separated)
262	}
263}
264
265impl fmt::Debug for Solution {
266	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267		write!(f, "{:?}", &self.proof[..])
268	}
269}
270
271impl cmp::PartialEq for Solution {
272	fn eq(&self, other: &Solution) -> bool {
273		for i in 0..PROOFSIZE {
274			if self.proof[i] != other.proof[i] {
275				return false;
276			}
277		}
278		return true;
279	}
280}
281
282impl Solution {
283	/// Converts the proof to a vector of u64s
284	pub fn to_u64s(&self) -> Vec<u64> {
285		let mut nonces = Vec::with_capacity(PROOFSIZE);
286		for n in self.proof.iter() {
287			nonces.push(*n as u64);
288		}
289		nonces
290	}
291
292	/// Returns the hash of the solution, as performed in
293	/// grin
294	/// TODO: Check whether grin sticks to u32s like this
295	pub fn hash(&self) -> [u8; 32] {
296		// Hash
297		let mut blake2b = Blake2b::new(32);
298		for n in 0..self.proof.len() {
299			let mut bytes = [0; 4];
300			BigEndian::write_u32(&mut bytes, self.proof[n] as u32);
301			blake2b.update(&bytes);
302		}
303		let mut ret = [0; 32];
304		ret.copy_from_slice(blake2b.finalize().as_bytes());
305		ret
306	}
307}
308
309/// All solutions returned
310#[derive(Clone, Copy)]
311#[repr(C)]
312pub struct SolverSolutions {
313	/// graph size
314	pub edge_bits: u32,
315	/// number of solutions
316	pub num_sols: u32,
317	/// solutions themselves
318	pub sols: [Solution; MAX_SOLS],
319}
320
321impl Default for SolverSolutions {
322	fn default() -> SolverSolutions {
323		SolverSolutions {
324			edge_bits: 0,
325			num_sols: 0,
326			sols: [Solution::default(); MAX_SOLS],
327		}
328	}
329}