POW refactor (#100)
* Adding output stats from plugin, when available * adding grin config * moving pow crate from core/pow to it's own crate * moving POW/mining stuff into pow module, and removing mining dependency from chain * refactored most of mining into pow module...miner.rs still in server * update grin tests * updating genesis block mining to use configured miner, if available * chain tests back into chain, done with pow refactor * use tag of cuckoo-miner for pr
This commit is contained in:
committed by
Ignotus Peverell
parent
6772d9f516
commit
045f5bb4da
+26
-1
@@ -94,6 +94,17 @@ pub fn is_automated_testing_mode() -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
/// Are we in production mode?
|
||||
pub fn is_production_mode() -> bool {
|
||||
let param_ref=MINING_PARAMETER_MODE.read().unwrap();
|
||||
if let MiningParameterMode::Production=*param_ref {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Helper function to get a nonce known to create a valid POW on
|
||||
/// the genesis block, to prevent it taking ages. Should be fine for now
|
||||
/// as the genesis block POW solution turns out to be the same for every new block chain
|
||||
@@ -104,6 +115,20 @@ pub fn get_genesis_nonce() -> u64 {
|
||||
match *param_ref {
|
||||
MiningParameterMode::AutomatedTesting => 0, //won't make a difference
|
||||
MiningParameterMode::UserTesting => 22141, //Magic nonce for current genesis block at cuckoo16
|
||||
MiningParameterMode::Production => 0, //TBD
|
||||
MiningParameterMode::Production => 1429942738856787200, //Magic nonce for current genesis at cuckoo30
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the genesis POW for production, because it takes far too long to mine at production values
|
||||
/// using the internal miner
|
||||
|
||||
pub fn get_genesis_pow() -> [u32;42]{
|
||||
//TODO: This is diff 26, probably just want a 10: mine one
|
||||
[7444824, 11926557, 28520390, 30594072, 50854023, 52797085, 57882033,
|
||||
59816511, 61404804, 84947619, 87779345, 115270337, 162618676,
|
||||
166860710, 178656003, 178971372, 200454733, 209197630, 221231015,
|
||||
228598741, 241012783, 245401183, 279080304, 295848517, 327300943,
|
||||
329741709, 366394532, 382493153, 389329248, 404353381, 406012911,
|
||||
418813499, 426573907, 452566575, 456930760, 463021458, 474340589,
|
||||
476248039, 478197093, 487576917, 495653489, 501862896]
|
||||
}
|
||||
|
||||
@@ -42,6 +42,5 @@ pub mod macros;
|
||||
pub mod consensus;
|
||||
pub mod core;
|
||||
pub mod genesis;
|
||||
pub mod pow;
|
||||
pub mod ser;
|
||||
pub mod global;
|
||||
|
||||
@@ -1,415 +0,0 @@
|
||||
// Copyright 2016 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Implementation of Cuckoo Cycle designed by John Tromp. Ported to Rust from
|
||||
//! the C and Java code at https://github.com/tromp/cuckoo. Note that only the
|
||||
//! simple miner is included, mostly for testing purposes. John Tromp's Tomato
|
||||
//! miner will be much faster in almost every environment.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::cmp;
|
||||
|
||||
use blake2;
|
||||
|
||||
use core::Proof;
|
||||
use pow::siphash::siphash24;
|
||||
use pow::MiningWorker;
|
||||
|
||||
const MAXPATHLEN: usize = 8192;
|
||||
|
||||
/// A cuckoo-cycle related error
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// Unable to find a short enough path
|
||||
Path,
|
||||
/// Unable to find a solution
|
||||
NoSolution,
|
||||
}
|
||||
|
||||
/// An edge in the Cuckoo graph, simply references two u64 nodes.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
struct Edge {
|
||||
u: u64,
|
||||
v: u64,
|
||||
}
|
||||
|
||||
/// Cuckoo cycle context
|
||||
pub struct Cuckoo {
|
||||
mask: u64,
|
||||
size: u64,
|
||||
v: [u64; 4],
|
||||
}
|
||||
|
||||
impl Cuckoo {
|
||||
/// Initializes a new Cuckoo Cycle setup, using the provided byte array to
|
||||
/// generate a seed. In practice for PoW applications the byte array is a
|
||||
/// serialized block header.
|
||||
pub fn new(header: &[u8], sizeshift: u32) -> Cuckoo {
|
||||
let size = 1 << sizeshift;
|
||||
let hashed=blake2::blake2b::blake2b(32, &[], header);
|
||||
let hashed=hashed.as_bytes();
|
||||
|
||||
let k0 = u8_to_u64(hashed, 0);
|
||||
let k1 = u8_to_u64(hashed, 8);
|
||||
let mut v = [0; 4];
|
||||
v[0] = k0 ^ 0x736f6d6570736575;
|
||||
v[1] = k1 ^ 0x646f72616e646f6d;
|
||||
v[2] = k0 ^ 0x6c7967656e657261;
|
||||
v[3] = k1 ^ 0x7465646279746573;
|
||||
Cuckoo {
|
||||
v: v,
|
||||
size: size,
|
||||
mask: (1 << sizeshift) / 2 - 1,
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates a node in the cuckoo graph generated from our seed. A node is
|
||||
/// simply materialized as a u64 from a nonce and an offset (generally 0 or
|
||||
/// 1).
|
||||
fn new_node(&self, nonce: u64, uorv: u64) -> u64 {
|
||||
return ((siphash24(self.v, 2 * nonce + uorv) & self.mask) << 1) | uorv;
|
||||
}
|
||||
|
||||
/// Creates a new edge in the cuckoo graph generated by our seed from a
|
||||
/// nonce. Generates two node coordinates from the nonce and links them
|
||||
/// together.
|
||||
fn new_edge(&self, nonce: u64) -> Edge {
|
||||
Edge {
|
||||
u: self.new_node(nonce, 0),
|
||||
v: self.new_node(nonce, 1),
|
||||
}
|
||||
}
|
||||
|
||||
/// Assuming increasing nonces all smaller than easiness, verifies the
|
||||
/// nonces form a cycle in a Cuckoo graph. Each nonce generates an edge, we
|
||||
/// build the nodes on both side of that edge and count the connections.
|
||||
pub fn verify(&self, proof: Proof, ease: u64) -> bool {
|
||||
let easiness = ease * (self.size as u64) / 100;
|
||||
let nonces = proof.to_u64s();
|
||||
let mut us = vec![0; proof.proof_size];
|
||||
let mut vs = vec![0; proof.proof_size];
|
||||
for n in 0..proof.proof_size {
|
||||
if nonces[n] >= easiness || (n != 0 && nonces[n] <= nonces[n - 1]) {
|
||||
return false;
|
||||
}
|
||||
us[n] = self.new_node(nonces[n], 0);
|
||||
vs[n] = self.new_node(nonces[n], 1);
|
||||
}
|
||||
let mut i = 0;
|
||||
let mut count = proof.proof_size;
|
||||
loop {
|
||||
let mut j = i;
|
||||
for k in 0..proof.proof_size {
|
||||
// find unique other j with same vs[j]
|
||||
if k != i && vs[k] == vs[i] {
|
||||
if j != i {
|
||||
return false;
|
||||
}
|
||||
j = k;
|
||||
}
|
||||
}
|
||||
if j == i {
|
||||
return false;
|
||||
}
|
||||
i = j;
|
||||
for k in 0..proof.proof_size {
|
||||
// find unique other i with same us[i]
|
||||
if k != j && us[k] == us[j] {
|
||||
if i != j {
|
||||
return false;
|
||||
}
|
||||
i = k;
|
||||
}
|
||||
}
|
||||
if i == j {
|
||||
return false;
|
||||
}
|
||||
count -= 2;
|
||||
if i == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
count == 0
|
||||
}
|
||||
}
|
||||
|
||||
/// Miner for the Cuckoo Cycle algorithm. While the verifier will work for
|
||||
/// graph sizes up to a u64, the miner is limited to u32 to be more memory
|
||||
/// compact (so shift <= 32). Non-optimized for now and and so mostly used for
|
||||
/// tests, being impractical with sizes greater than 2^22.
|
||||
pub struct Miner {
|
||||
easiness: u64,
|
||||
proof_size: usize,
|
||||
cuckoo: Option<Cuckoo>,
|
||||
graph: Vec<u32>,
|
||||
sizeshift: u32,
|
||||
}
|
||||
|
||||
impl MiningWorker for Miner {
|
||||
|
||||
/// Creates a new miner
|
||||
fn new(ease: u32,
|
||||
sizeshift: u32,
|
||||
proof_size: usize) -> Miner {
|
||||
let size = 1 << sizeshift;
|
||||
let graph = vec![0; size + 1];
|
||||
let easiness = (ease as u64) * (size as u64) / 100;
|
||||
Miner {
|
||||
easiness: easiness,
|
||||
cuckoo: None,
|
||||
graph: graph,
|
||||
sizeshift: sizeshift,
|
||||
proof_size: proof_size,
|
||||
}
|
||||
}
|
||||
|
||||
fn mine(&mut self, header: &[u8]) -> Result<Proof, Error> {
|
||||
let size = 1 << self.sizeshift;
|
||||
self.graph = vec![0; size + 1];
|
||||
self.cuckoo=Some(Cuckoo::new(header, self.sizeshift));
|
||||
self.mine_impl()
|
||||
}
|
||||
}
|
||||
|
||||
/// What type of cycle we have found?
|
||||
enum CycleSol {
|
||||
/// A cycle of the right length is a valid proof.
|
||||
ValidProof(Vec<u32>),
|
||||
/// A cycle of the wrong length is great, but not a proof.
|
||||
InvalidCycle(usize),
|
||||
/// No cycles have been found.
|
||||
NoCycle,
|
||||
}
|
||||
|
||||
impl Miner {
|
||||
|
||||
|
||||
/// Searches for a solution
|
||||
pub fn mine_impl(&mut self) -> Result<Proof, Error> {
|
||||
let mut us = [0; MAXPATHLEN];
|
||||
let mut vs = [0; MAXPATHLEN];
|
||||
for nonce in 0..self.easiness {
|
||||
us[0] = self.cuckoo.as_mut().unwrap().new_node(nonce, 0) as u32;
|
||||
vs[0] = self.cuckoo.as_mut().unwrap().new_node(nonce, 1) as u32;
|
||||
let u = self.graph[us[0] as usize];
|
||||
let v = self.graph[vs[0] as usize];
|
||||
if us[0] == 0 {
|
||||
continue; // ignore duplicate edges
|
||||
}
|
||||
let nu = try!(self.path(u, &mut us)) as usize;
|
||||
let nv = try!(self.path(v, &mut vs)) as usize;
|
||||
|
||||
let sol = self.find_sol(nu, &us, nv, &vs);
|
||||
match sol {
|
||||
CycleSol::ValidProof(res) => {
|
||||
return Ok(Proof::new(res.to_vec()));
|
||||
},
|
||||
CycleSol::InvalidCycle(_) => continue,
|
||||
CycleSol::NoCycle => {
|
||||
self.update_graph(nu, &us, nv, &vs);
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Error::NoSolution)
|
||||
}
|
||||
|
||||
fn path(&self, mut u: u32, us: &mut [u32]) -> Result<u32, Error> {
|
||||
let mut nu = 0;
|
||||
while u != 0 {
|
||||
nu += 1;
|
||||
if nu >= MAXPATHLEN {
|
||||
while nu != 0 && us[(nu - 1) as usize] != u {
|
||||
nu -= 1;
|
||||
}
|
||||
return Err(Error::Path);
|
||||
}
|
||||
us[nu as usize] = u;
|
||||
u = self.graph[u as usize];
|
||||
}
|
||||
Ok(nu as u32)
|
||||
}
|
||||
|
||||
fn update_graph(&mut self, mut nu: usize, us: &[u32], mut nv: usize, vs: &[u32]) {
|
||||
if nu < nv {
|
||||
while nu != 0 {
|
||||
nu -= 1;
|
||||
self.graph[us[nu + 1] as usize] = us[nu];
|
||||
}
|
||||
self.graph[us[0] as usize] = vs[0];
|
||||
} else {
|
||||
while nv != 0 {
|
||||
nv -= 1;
|
||||
self.graph[vs[nv + 1] as usize] = vs[nv];
|
||||
}
|
||||
self.graph[vs[0] as usize] = us[0];
|
||||
}
|
||||
}
|
||||
|
||||
fn find_sol(&mut self, mut nu: usize, us: &[u32], mut nv: usize, vs: &[u32]) -> CycleSol {
|
||||
if us[nu] == vs[nv] {
|
||||
let min = cmp::min(nu, nv);
|
||||
nu -= min;
|
||||
nv -= min;
|
||||
while us[nu] != vs[nv] {
|
||||
nu += 1;
|
||||
nv += 1;
|
||||
}
|
||||
if nu + nv + 1 == self.proof_size {
|
||||
self.solution(&us, nu as u32, &vs, nv as u32)
|
||||
} else {
|
||||
CycleSol::InvalidCycle(nu + nv + 1)
|
||||
}
|
||||
} else {
|
||||
CycleSol::NoCycle
|
||||
}
|
||||
}
|
||||
|
||||
fn solution(&mut self, us: &[u32], mut nu: u32, vs: &[u32], mut nv: u32) -> CycleSol {
|
||||
let mut cycle = HashSet::new();
|
||||
cycle.insert(Edge {
|
||||
u: us[0] as u64,
|
||||
v: vs[0] as u64,
|
||||
});
|
||||
while nu != 0 {
|
||||
// u's in even position; v's in odd
|
||||
nu -= 1;
|
||||
cycle.insert(Edge {
|
||||
u: us[((nu + 1) & !1) as usize] as u64,
|
||||
v: us[(nu | 1) as usize] as u64,
|
||||
});
|
||||
}
|
||||
while nv != 0 {
|
||||
// u's in odd position; v's in even
|
||||
nv -= 1;
|
||||
cycle.insert(Edge {
|
||||
u: vs[(nv | 1) as usize] as u64,
|
||||
v: vs[((nv + 1) & !1) as usize] as u64,
|
||||
});
|
||||
}
|
||||
let mut n = 0;
|
||||
let mut sol = vec![0; self.proof_size];
|
||||
for nonce in 0..self.easiness {
|
||||
let edge = self.cuckoo.as_mut().unwrap().new_edge(nonce);
|
||||
if cycle.contains(&edge) {
|
||||
sol[n] = nonce as u32;
|
||||
n += 1;
|
||||
cycle.remove(&edge);
|
||||
}
|
||||
}
|
||||
return if n == self.proof_size {
|
||||
CycleSol::ValidProof(sol)
|
||||
} else {
|
||||
CycleSol::NoCycle
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Utility to transform a 8 bytes of a byte array into a u64.
|
||||
fn u8_to_u64(p:&[u8], i: usize) -> u64 {
|
||||
(p[i] as u64) | (p[i + 1] as u64) << 8 | (p[i + 2] as u64) << 16 | (p[i + 3] as u64) << 24 |
|
||||
(p[i + 4] as u64) << 32 | (p[i + 5] as u64) << 40 |
|
||||
(p[i + 6] as u64) << 48 | (p[i + 7] as u64) << 56
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use core::Proof;
|
||||
|
||||
|
||||
static V1:[u32;42] = [0x1fe9, 0x2050, 0x4581, 0x6322, 0x65ab, 0xb3c1, 0xc1a4,
|
||||
0xe257, 0x106ae, 0x17b11, 0x202d4, 0x2705d, 0x2deb2, 0x2f80e,
|
||||
0x32298, 0x34782, 0x35c5a, 0x37458, 0x38f28, 0x406b2, 0x40e34,
|
||||
0x40fc6, 0x42220, 0x42d13, 0x46c0f, 0x4fd47, 0x55ad2, 0x598f7,
|
||||
0x5aa8f, 0x62aa3, 0x65725, 0x65dcb, 0x671c7, 0x6eb20, 0x752fe,
|
||||
0x7594f, 0x79b9c, 0x7f775, 0x81635, 0x8401c, 0x844e5, 0x89fa8];
|
||||
static V2:[u32;42] = [0x2a37, 0x7557, 0xa3c3, 0xfce6, 0x1248e, 0x15837, 0x1827f,
|
||||
0x18a93, 0x1a7dd, 0x1b56b, 0x1ceb4, 0x1f962, 0x1fe2a, 0x29cb9,
|
||||
0x2f30e, 0x2f771, 0x336bf, 0x34355, 0x391d7, 0x39495, 0x3be0c,
|
||||
0x463be, 0x4d0c2, 0x4eead, 0x50214, 0x520de, 0x52a86, 0x53818,
|
||||
0x53b3b, 0x54c0b, 0x572fa, 0x5d79c, 0x5e3c2, 0x6769e, 0x6a0fe,
|
||||
0x6d835, 0x6fc7c, 0x70f03, 0x79d4a, 0x7b03e, 0x81e09, 0x9bd44];
|
||||
static V3:[u32;42] = [0x8158, 0x9f18, 0xc4ba, 0x108c7, 0x11caa, 0x13b82, 0x1618f,
|
||||
0x1c83b, 0x1ec89, 0x24354, 0x28864, 0x2a0fb, 0x2ce50, 0x2e8fa,
|
||||
0x32b36, 0x343e6, 0x34dc9, 0x36881, 0x3ffca, 0x40f79, 0x42721,
|
||||
0x43b8c, 0x44b9d, 0x47ed3, 0x4cd34, 0x5278a, 0x5ab64, 0x5b4d4,
|
||||
0x5d842, 0x5fa33, 0x6464e, 0x676ee, 0x685d6, 0x69df0, 0x6a5fd,
|
||||
0x6bda3, 0x72544, 0x77974, 0x7908c, 0x80e67, 0x81ef4, 0x8d882];
|
||||
// cuckoo28 at 50% edges of letter 'u'
|
||||
static V4:[u32;42] = [0x1CBBFD, 0x2C5452, 0x520338, 0x6740C5, 0x8C6997, 0xC77150, 0xFD4972,
|
||||
0x1060FA7, 0x11BFEA0, 0x1343E8D, 0x14CE02A, 0x1533515, 0x1715E61, 0x1996D9B,
|
||||
0x1CB296B, 0x1FCA180, 0x209A367, 0x20AD02E, 0x23CD2E4, 0x2A3B360, 0x2DD1C0C,
|
||||
0x333A200, 0x33D77BC, 0x3620C78, 0x3DD7FB8, 0x3FBFA49, 0x41BDED2, 0x4A86FD9,
|
||||
0x570DE24, 0x57CAB86, 0x594B886, 0x5C74C94, 0x5DE7572, 0x60ADD6F, 0x635918B,
|
||||
0x6C9E120, 0x6EFA583, 0x7394ACA, 0x7556A23, 0x77F70AA, 0x7CF750A, 0x7F60790];
|
||||
|
||||
/// Find a 42-cycle on Cuckoo20 at 75% easiness and verifiy against a few
|
||||
/// known cycle proofs
|
||||
/// generated by other implementations.
|
||||
#[test]
|
||||
fn mine20_vectors() {
|
||||
let nonces1 = Miner::new(75, 20, 42).mine(&[49]).unwrap();
|
||||
assert_eq!(Proof::new(V1.to_vec()), nonces1);
|
||||
|
||||
let nonces2 = Miner::new(70, 20, 42).mine(&[50]).unwrap();
|
||||
assert_eq!(Proof::new(V2.to_vec()), nonces2);
|
||||
|
||||
let nonces3 = Miner::new(70, 20, 42).mine(&[51]).unwrap();
|
||||
assert_eq!(Proof::new(V3.to_vec()), nonces3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate20_vectors() {
|
||||
assert!(Cuckoo::new(&[49], 20).verify(Proof::new(V1.to_vec().clone()), 75));
|
||||
assert!(Cuckoo::new(&[50], 20).verify(Proof::new(V2.to_vec().clone()), 70));
|
||||
assert!(Cuckoo::new(&[51], 20).verify(Proof::new(V3.to_vec().clone()), 70));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate28_vectors() {
|
||||
let mut test_header=[0;32];
|
||||
test_header[0]=24;
|
||||
assert!(Cuckoo::new(&test_header, 28).verify(Proof::new(V4.to_vec().clone()), 50));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn validate_fail() {
|
||||
// edge checks
|
||||
assert!(!Cuckoo::new(&[49], 20).verify(Proof::new(vec![0; 42]), 75));
|
||||
assert!(!Cuckoo::new(&[49], 20).verify(Proof::new(vec![0xffff; 42]), 75));
|
||||
// wrong data for proof
|
||||
assert!(!Cuckoo::new(&[50], 20).verify(Proof::new(V1.to_vec().clone()), 75));
|
||||
let mut test_header=[0;32];
|
||||
test_header[0]=24;
|
||||
assert!(!Cuckoo::new(&test_header, 20).verify(Proof::new(V4.to_vec().clone()), 50));
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mine20_validate() {
|
||||
// cuckoo20
|
||||
for n in 1..5 {
|
||||
let h = [n; 32];
|
||||
let nonces = Miner::new(75, 20, 42).mine(&h).unwrap();
|
||||
assert!(Cuckoo::new(&h, 20).verify(nonces, 75));
|
||||
}
|
||||
// cuckoo18
|
||||
for n in 1..5 {
|
||||
let h = [n; 32];
|
||||
let nonces = Miner::new(75, 18, 42).mine(&h).unwrap();
|
||||
assert!(Cuckoo::new(&h, 18).verify(nonces, 75));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
// Copyright 2016 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! The proof of work needs to strike a balance between fast header
|
||||
//! verification to avoid DoS attacks and difficulty for block verifiers to
|
||||
//! build new blocks. In addition, mining new blocks should also be as
|
||||
//! difficult on high end custom-made hardware (ASICs) as on commodity hardware
|
||||
//! or smartphones. For this reason we use Cuckoo Cycle (see the cuckoo
|
||||
//! module for more information).
|
||||
//!
|
||||
//! Note that this miner implementation is here mostly for tests and
|
||||
//! reference. It's not optimized for speed.
|
||||
|
||||
mod siphash;
|
||||
pub mod cuckoo;
|
||||
|
||||
use time;
|
||||
|
||||
use consensus::EASINESS;
|
||||
use core::BlockHeader;
|
||||
use core::hash::Hashed;
|
||||
use core::Proof;
|
||||
use core::target::Difficulty;
|
||||
use pow::cuckoo::{Cuckoo, Error};
|
||||
|
||||
|
||||
/// Should be implemented by anything providing mining services
|
||||
///
|
||||
|
||||
pub trait MiningWorker {
|
||||
|
||||
/// This only sets parameters and does initialisation work now
|
||||
fn new(ease: u32, sizeshift: u32, proof_size:usize) -> Self;
|
||||
|
||||
/// Actually perform a mining attempt on the given input and
|
||||
/// return a proof if found
|
||||
fn mine(&mut self, header: &[u8]) -> Result<Proof, Error>;
|
||||
|
||||
}
|
||||
|
||||
/// Validates the proof of work of a given header, and that the proof of work
|
||||
/// satisfies the requirements of the header.
|
||||
pub fn verify_size(bh: &BlockHeader, cuckoo_sz: u32) -> bool {
|
||||
// make sure the pow hash shows a difficulty at least as large as the target
|
||||
// difficulty
|
||||
if bh.difficulty > bh.pow.clone().to_difficulty() {
|
||||
return false;
|
||||
}
|
||||
Cuckoo::new(&bh.hash()[..], cuckoo_sz).verify(bh.pow.clone(), EASINESS as u64)
|
||||
}
|
||||
|
||||
/// Uses the much easier Cuckoo20 (mostly for
|
||||
/// tests).
|
||||
pub fn pow20<T: MiningWorker>(miner:&mut T, bh: &mut BlockHeader, diff: Difficulty) -> Result<(), Error> {
|
||||
pow_size(miner, bh, diff, 20)
|
||||
}
|
||||
|
||||
/// Runs a proof of work computation over the provided block using the provided Mining Worker,
|
||||
/// until the required difficulty target is reached. May take a while for a low target...
|
||||
pub fn pow_size<T: MiningWorker>(miner:&mut T, bh: &mut BlockHeader,
|
||||
diff: Difficulty, _: u32) -> Result<(), Error> {
|
||||
let start_nonce = bh.nonce;
|
||||
|
||||
// try to find a cuckoo cycle on that header hash
|
||||
loop {
|
||||
// can be trivially optimized by avoiding re-serialization every time but this
|
||||
// is not meant as a fast miner implementation
|
||||
let pow_hash = bh.hash();
|
||||
|
||||
// if we found a cycle (not guaranteed) and the proof hash is higher that the
|
||||
// diff, we're all good
|
||||
|
||||
if let Ok(proof) = miner.mine(&pow_hash[..]) {
|
||||
if proof.clone().to_difficulty() >= diff {
|
||||
bh.pow = proof;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise increment the nonce
|
||||
bh.nonce += 1;
|
||||
|
||||
// and if we're back where we started, update the time (changes the hash as
|
||||
// well)
|
||||
if bh.nonce == start_nonce {
|
||||
bh.timestamp = time::at_utc(time::Timespec { sec: 0, nsec: 0 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use global;
|
||||
use core::target::Difficulty;
|
||||
use genesis;
|
||||
use consensus::MINIMUM_DIFFICULTY;
|
||||
use global::MiningParameterMode;
|
||||
|
||||
|
||||
#[test]
|
||||
fn genesis_pow() {
|
||||
global::set_mining_mode(MiningParameterMode::AutomatedTesting);
|
||||
let mut b = genesis::genesis();
|
||||
b.header.nonce = 310;
|
||||
let mut internal_miner = cuckoo::Miner::new(EASINESS, global::sizeshift() as u32, global::proofsize());
|
||||
pow_size(&mut internal_miner, &mut b.header, Difficulty::from_num(MINIMUM_DIFFICULTY), global::sizeshift() as u32).unwrap();
|
||||
assert!(b.header.nonce != 310);
|
||||
assert!(b.header.pow.clone().to_difficulty() >= Difficulty::from_num(MINIMUM_DIFFICULTY));
|
||||
assert!(verify_size(&b.header, global::sizeshift() as u32));
|
||||
}
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
// Copyright 2016 The Grin Developers
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//! Simple implementation of the siphash 2-4 hashing function from
|
||||
//! Jean-Philippe Aumasson and Daniel J. Bernstein.
|
||||
|
||||
/// Implements siphash 2-4 specialized for a 4 u64 array key and a u64 nonce
|
||||
pub fn siphash24(v: [u64; 4], nonce: u64) -> u64 {
|
||||
let mut v0 = v[0];
|
||||
let mut v1 = v[1];
|
||||
let mut v2 = v[2];
|
||||
let mut v3 = v[3] ^ nonce;
|
||||
|
||||
// macro for left rotation
|
||||
macro_rules! rotl {
|
||||
($num:ident, $shift:expr) => {
|
||||
$num = ($num << $shift) | ($num >> (64 - $shift));
|
||||
}
|
||||
}
|
||||
|
||||
// macro for a single siphash round
|
||||
macro_rules! round {
|
||||
() => {
|
||||
v0 = v0.wrapping_add(v1);
|
||||
v2 = v2.wrapping_add(v3);
|
||||
rotl!(v1, 13);
|
||||
rotl!(v3, 16);
|
||||
v1 ^= v0;
|
||||
v3 ^= v2;
|
||||
rotl!(v0, 32);
|
||||
v2 = v2.wrapping_add(v1);
|
||||
v0 = v0.wrapping_add(v3);
|
||||
rotl!(v1, 17);
|
||||
rotl!(v3, 21);
|
||||
v1 ^= v2;
|
||||
v3 ^= v0;
|
||||
rotl!(v2, 32);
|
||||
}
|
||||
}
|
||||
|
||||
// 2 rounds
|
||||
round!();
|
||||
round!();
|
||||
|
||||
v0 ^= nonce;
|
||||
v2 ^= 0xff;
|
||||
|
||||
// and then 4 rounds, hence siphash 2-4
|
||||
round!();
|
||||
round!();
|
||||
round!();
|
||||
round!();
|
||||
|
||||
return v0 ^ v1 ^ v2 ^ v3;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
/// Some test vectors hoisted from the Java implementation (adjusted from
|
||||
/// the fact that the Java impl uses a long, aka a signed 64 bits number).
|
||||
#[test]
|
||||
fn hash_some() {
|
||||
assert_eq!(siphash24([1, 2, 3, 4], 10), 928382149599306901);
|
||||
assert_eq!(siphash24([1, 2, 3, 4], 111), 10524991083049122233);
|
||||
assert_eq!(siphash24([9, 7, 6, 7], 12), 1305683875471634734);
|
||||
assert_eq!(siphash24([9, 7, 6, 7], 10), 11589833042187638814);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user