Cuckoo miner integration, Queue implementation (#84)
* Adding ability to serialise parts of the header, pre-nonce and post-nonce * Some test integration of queueing functions in cuckoo-miner * more cuckoo-miner async mode integration, now more or less working * integrating async miner workflow * rocksdb update * u64 internal difficulty representation, and integration of latest Cuckoo-miner API * change to cuckoo-miner notify function * Issue in testing, and if use_async value is None in grin.toml * making async mode explicit in tests - 2 * fiddle with port numbers for CI * update tag to ensure cuckoo-miner build doesn't fail on windows * change the order in which tests are run
This commit is contained in:
committed by
Ignotus Peverell
parent
c994c7cba2
commit
cdf4203dd1
+25
-20
@@ -30,7 +30,7 @@ pub const REWARD: u64 = 1_000_000_000;
|
||||
/// that we may reduce this value in the future as we get more data on mining
|
||||
/// with Cuckoo Cycle, networks improve and block propagation is optimized
|
||||
/// (adjusting the reward accordingly).
|
||||
pub const BLOCK_TIME_SEC: i64 = 60;
|
||||
pub const BLOCK_TIME_SEC: u64 = 60;
|
||||
|
||||
/// Cuckoo-cycle proof size (cycle length)
|
||||
pub const PROOFSIZE: usize = 42;
|
||||
@@ -61,22 +61,22 @@ pub const CUT_THROUGH_HORIZON: u32 = 48 * 3600 / (BLOCK_TIME_SEC as u32);
|
||||
pub const MAX_MSG_LEN: u64 = 20_000_000;
|
||||
|
||||
/// The minimum mining difficulty we'll allow
|
||||
pub const MINIMUM_DIFFICULTY: u32 = 10;
|
||||
pub const MINIMUM_DIFFICULTY: u64 = 10;
|
||||
|
||||
/// Time window in blocks to calculate block time median
|
||||
pub const MEDIAN_TIME_WINDOW: u32 = 11;
|
||||
pub const MEDIAN_TIME_WINDOW: u64 = 11;
|
||||
|
||||
/// Number of blocks used to calculate difficulty adjustments
|
||||
pub const DIFFICULTY_ADJUST_WINDOW: u32 = 23;
|
||||
pub const DIFFICULTY_ADJUST_WINDOW: u64 = 23;
|
||||
|
||||
/// Average time span of the difficulty adjustment window
|
||||
pub const BLOCK_TIME_WINDOW: i64 = (DIFFICULTY_ADJUST_WINDOW as i64) * BLOCK_TIME_SEC;
|
||||
pub const BLOCK_TIME_WINDOW: u64 = DIFFICULTY_ADJUST_WINDOW * BLOCK_TIME_SEC;
|
||||
|
||||
/// Maximum size time window used for difficutly adjustments
|
||||
pub const UPPER_TIME_BOUND: i64 = BLOCK_TIME_WINDOW * 4 / 3;
|
||||
pub const UPPER_TIME_BOUND: u64 = BLOCK_TIME_WINDOW * 4 / 3;
|
||||
|
||||
/// Minimum size time window used for difficutly adjustments
|
||||
pub const LOWER_TIME_BOUND: i64 = BLOCK_TIME_WINDOW * 5 / 6;
|
||||
pub const LOWER_TIME_BOUND: u64 = BLOCK_TIME_WINDOW * 5 / 6;
|
||||
|
||||
/// Error when computing the next difficulty adjustment.
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -100,7 +100,7 @@ impl fmt::Display for TargetError {
|
||||
/// difference between the median timestamps at the beginning and the end
|
||||
/// of the window.
|
||||
pub fn next_difficulty<T>(cursor: T) -> Result<Difficulty, TargetError>
|
||||
where T: IntoIterator<Item = Result<(i64, Difficulty), TargetError>>
|
||||
where T: IntoIterator<Item = Result<(u64, Difficulty), TargetError>>
|
||||
{
|
||||
|
||||
// Block times at the begining and end of the adjustment window, used to
|
||||
@@ -113,7 +113,7 @@ pub fn next_difficulty<T>(cursor: T) -> Result<Difficulty, TargetError>
|
||||
|
||||
// Enumerating backward over blocks
|
||||
for (n, head_info) in cursor.into_iter().enumerate() {
|
||||
let m = n as u32;
|
||||
let m = n as u64;
|
||||
let (ts, diff) = head_info?;
|
||||
|
||||
// Sum each element in the adjustment window. In addition, retain
|
||||
@@ -156,10 +156,13 @@ pub fn next_difficulty<T>(cursor: T) -> Result<Difficulty, TargetError>
|
||||
ts_damp
|
||||
};
|
||||
|
||||
Ok(diff_avg * Difficulty::from_num(BLOCK_TIME_WINDOW as u32) /
|
||||
Difficulty::from_num(adj_ts as u32))
|
||||
Ok(diff_avg * Difficulty::from_num(BLOCK_TIME_WINDOW) /
|
||||
Difficulty::from_num(adj_ts))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use std;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use core::target::Difficulty;
|
||||
@@ -168,18 +171,20 @@ mod test {
|
||||
|
||||
// Builds an iterator for next difficulty calculation with the provided
|
||||
// constant time interval, difficulty and total length.
|
||||
fn repeat(interval: i64, diff: u32, len: u32) -> Vec<Result<(i64, Difficulty), TargetError>> {
|
||||
fn repeat(interval: u64, diff: u64, len: u64) -> Vec<Result<(u64, Difficulty), TargetError>> {
|
||||
//watch overflow here, length shouldn't be ridiculous anyhow
|
||||
assert!(len < std::usize::MAX as u64);
|
||||
let diffs = vec![Difficulty::from_num(diff); len as usize];
|
||||
let times = (0..(len as usize)).map(|n| (n as i64) * interval).rev();
|
||||
let times = (0..(len as usize)).map(|n| n * interval as usize).rev();
|
||||
let pairs = times.zip(diffs.iter());
|
||||
pairs.map(|(t, d)| Ok((t, d.clone()))).collect::<Vec<_>>()
|
||||
pairs.map(|(t, d)| Ok((t as u64, d.clone()))).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn repeat_offs(from: i64,
|
||||
interval: i64,
|
||||
diff: u32,
|
||||
len: u32)
|
||||
-> Vec<Result<(i64, Difficulty), TargetError>> {
|
||||
fn repeat_offs(from: u64,
|
||||
interval: u64,
|
||||
diff: u64,
|
||||
len: u64)
|
||||
-> Vec<Result<(u64, Difficulty), TargetError>> {
|
||||
map_vec!(repeat(interval, diff, len), |e| {
|
||||
match e.clone() {
|
||||
Err(e) => Err(e),
|
||||
@@ -209,7 +214,7 @@ mod test {
|
||||
// checking averaging works, window length is odd so need to compensate a little
|
||||
let sec = DIFFICULTY_ADJUST_WINDOW / 2 + 1 + MEDIAN_TIME_WINDOW;
|
||||
let mut s1 = repeat(60, 500, sec);
|
||||
let mut s2 = repeat_offs((sec * 60) as i64, 60, 1545, DIFFICULTY_ADJUST_WINDOW / 2);
|
||||
let mut s2 = repeat_offs((sec * 60) as u64, 60, 1545, DIFFICULTY_ADJUST_WINDOW / 2);
|
||||
s2.append(&mut s1);
|
||||
assert_eq!(next_difficulty(s2).unwrap(), Difficulty::from_num(999));
|
||||
|
||||
|
||||
+29
-30
@@ -15,60 +15,61 @@
|
||||
//! Definition of the maximum target value a proof-of-work block hash can have
|
||||
//! and
|
||||
//! the related difficulty, defined as the maximum target divided by the hash.
|
||||
//!
|
||||
//! Note this is now wrapping a simple U64 now, but it's desirable to keep the
|
||||
//! wrapper in case the internal representation needs to change again
|
||||
|
||||
use std::fmt;
|
||||
use std::ops::{Add, Mul, Div, Sub};
|
||||
use std::io::Cursor;
|
||||
use std::u64::MAX;
|
||||
|
||||
use bigint::BigUint;
|
||||
use serde::{Serialize, Serializer, Deserialize, Deserializer, de};
|
||||
use byteorder::{ByteOrder, ReadBytesExt, BigEndian};
|
||||
|
||||
use core::hash::Hash;
|
||||
use ser::{self, Reader, Writer, Writeable, Readable};
|
||||
|
||||
/// The target is the 32-bytes hash block hashes must be lower than.
|
||||
pub const MAX_TARGET: [u8; 32] = [0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
|
||||
pub const MAX_TARGET: [u8; 8] = [0xf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff];
|
||||
|
||||
/// The difficulty is defined as the maximum target divided by the block hash.
|
||||
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord)]
|
||||
pub struct Difficulty {
|
||||
num: BigUint,
|
||||
num: u64,
|
||||
}
|
||||
|
||||
impl Difficulty {
|
||||
/// Difficulty of zero, which is practically invalid (not target can be
|
||||
/// calculated from it) but very useful as a start for additions.
|
||||
pub fn zero() -> Difficulty {
|
||||
Difficulty { num: BigUint::new(vec![0]) }
|
||||
Difficulty { num: 0 }
|
||||
}
|
||||
|
||||
/// Difficulty of one, which is the minumum difficulty (when the hash
|
||||
/// equals the max target)
|
||||
pub fn one() -> Difficulty {
|
||||
Difficulty { num: BigUint::new(vec![1]) }
|
||||
Difficulty { num: 1 }
|
||||
}
|
||||
|
||||
/// Convert a `u32` into a `Difficulty`
|
||||
pub fn from_num(num: u32) -> Difficulty {
|
||||
Difficulty { num: BigUint::new(vec![num]) }
|
||||
}
|
||||
|
||||
/// Convert a `BigUint` into a `Difficulty`
|
||||
pub fn from_biguint(num: BigUint) -> Difficulty {
|
||||
pub fn from_num(num: u64) -> Difficulty {
|
||||
Difficulty { num: num }
|
||||
}
|
||||
|
||||
/// Computes the difficulty from a hash. Divides the maximum target by the
|
||||
/// provided hash.
|
||||
pub fn from_hash(h: &Hash) -> Difficulty {
|
||||
let max_target = BigUint::from_bytes_be(&MAX_TARGET);
|
||||
let h_num = BigUint::from_bytes_be(&h[..]);
|
||||
Difficulty { num: max_target / h_num }
|
||||
let max_target = BigEndian::read_u64(&MAX_TARGET);
|
||||
//Use the first 64 bits of the given hash
|
||||
let mut in_vec=h.to_vec();
|
||||
in_vec.truncate(8);
|
||||
let num = BigEndian::read_u64(&in_vec);
|
||||
Difficulty { num: max_target / num }
|
||||
}
|
||||
|
||||
/// Converts the difficulty into a bignum
|
||||
pub fn into_biguint(self) -> BigUint {
|
||||
/// Converts the difficulty into a u64
|
||||
pub fn into_num(&self) -> u64 {
|
||||
self.num
|
||||
}
|
||||
}
|
||||
@@ -109,17 +110,14 @@ impl Div<Difficulty> for Difficulty {
|
||||
|
||||
impl Writeable for Difficulty {
|
||||
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ser::Error> {
|
||||
let data = self.num.to_bytes_be();
|
||||
try!(writer.write_u8(data.len() as u8));
|
||||
writer.write_fixed_bytes(&data)
|
||||
writer.write_u64(self.num)
|
||||
}
|
||||
}
|
||||
|
||||
impl Readable for Difficulty {
|
||||
fn read(reader: &mut Reader) -> Result<Difficulty, ser::Error> {
|
||||
let dlen = try!(reader.read_u8());
|
||||
let data = try!(reader.read_fixed_bytes(dlen as usize));
|
||||
Ok(Difficulty { num: BigUint::from_bytes_be(&data[..]) })
|
||||
let data = try!(reader.read_u64());
|
||||
Ok(Difficulty { num: data })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +125,7 @@ impl Serialize for Difficulty {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where S: Serializer
|
||||
{
|
||||
serializer.serialize_str(self.num.to_str_radix(10).as_str())
|
||||
serializer.serialize_u64(self.num)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +133,7 @@ impl<'de> Deserialize<'de> for Difficulty {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Difficulty, D::Error>
|
||||
where D: Deserializer<'de>
|
||||
{
|
||||
deserializer.deserialize_i32(DiffVisitor)
|
||||
deserializer.deserialize_u64(DiffVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,9 +149,10 @@ impl<'de> de::Visitor<'de> for DiffVisitor {
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where E: de::Error
|
||||
{
|
||||
let bigui = BigUint::parse_bytes(s.as_bytes(), 10).ok_or_else(|| {
|
||||
de::Error::invalid_value(de::Unexpected::Str(s), &"a value number")
|
||||
})?;
|
||||
Ok(Difficulty { num: bigui })
|
||||
let num_in = s.parse::<u64>();
|
||||
if let Err(e)=num_in {
|
||||
return Err(de::Error::invalid_value(de::Unexpected::Str(s), &"a value number"));
|
||||
};
|
||||
Ok(Difficulty { num: num_in.unwrap() })
|
||||
}
|
||||
}
|
||||
|
||||
+68
-14
@@ -387,18 +387,72 @@ impl Writeable for [u8; 4] {
|
||||
}
|
||||
|
||||
/// Useful marker trait on types that can be sized byte slices
|
||||
pub trait AsFixedBytes: Sized + AsRef<[u8]> {}
|
||||
pub trait AsFixedBytes: Sized + AsRef<[u8]> {
|
||||
fn len(&self) -> usize;
|
||||
}
|
||||
|
||||
impl<'a> AsFixedBytes for &'a [u8] {}
|
||||
impl AsFixedBytes for Vec<u8> {}
|
||||
impl AsFixedBytes for [u8; 1] {}
|
||||
impl AsFixedBytes for [u8; 2] {}
|
||||
impl AsFixedBytes for [u8; 4] {}
|
||||
impl AsFixedBytes for [u8; 8] {}
|
||||
impl AsFixedBytes for [u8; 32] {}
|
||||
impl AsFixedBytes for String {}
|
||||
impl AsFixedBytes for ::core::hash::Hash {}
|
||||
impl AsFixedBytes for ::secp::pedersen::RangeProof {}
|
||||
impl AsFixedBytes for ::secp::key::SecretKey {}
|
||||
impl AsFixedBytes for ::secp::Signature {}
|
||||
impl AsFixedBytes for ::secp::pedersen::Commitment {}
|
||||
impl<'a> AsFixedBytes for &'a [u8] {
|
||||
fn len(&self) -> usize {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for Vec<u8> {
|
||||
fn len(&self) -> usize {
|
||||
return self.len();
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for [u8; 1] {
|
||||
fn len(&self) -> usize {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for [u8; 2] {
|
||||
fn len(&self) -> usize {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for [u8; 4] {
|
||||
fn len(&self) -> usize {
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for [u8; 8] {
|
||||
fn len(&self) -> usize {
|
||||
return 8;
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for [u8; 32] {
|
||||
fn len(&self) -> usize {
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for String {
|
||||
fn len(&self) -> usize {
|
||||
return self.len();
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for ::core::hash::Hash {
|
||||
fn len(&self) -> usize {
|
||||
return 32;
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for ::secp::pedersen::RangeProof {
|
||||
fn len(&self) -> usize {
|
||||
return self.plen;
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for ::secp::key::SecretKey {
|
||||
fn len(&self) -> usize {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for ::secp::Signature {
|
||||
fn len(&self) -> usize {
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
impl AsFixedBytes for ::secp::pedersen::Commitment {
|
||||
fn len(&self) -> usize {
|
||||
return PEDERSEN_COMMITMENT_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user