mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 08:51:08 +03:00
Block now uses the new Target type. Consensus next_target calculation adjusting every block based on deviation and increasing Cuckoo size gradually. Block time of a minute until we learn more from mining ecosystem, so enough PoW attempts can be made even on CPUs.
This commit is contained in:
parent
44545525f4
commit
3c5e2b2958
7 changed files with 201 additions and 58 deletions
|
@ -19,40 +19,146 @@
|
|||
//! enough, consensus-relevant constants and short functions should be kept
|
||||
//! here.
|
||||
|
||||
use std::cmp;
|
||||
|
||||
use core::target::Target;
|
||||
|
||||
/// The block subsidy amount
|
||||
pub const REWARD: u64 = 1_000_000_000;
|
||||
|
||||
/// Block interval, in seconds, the network will tune its difficulty for. Note
|
||||
/// that contrarily to bitcoin, we may reduce this value in the future as
|
||||
/// networks improve and block propagation is optimized (adjusting the reward
|
||||
/// accordingly).
|
||||
pub const BLOCK_TIME_SEC: u8 = 30;
|
||||
/// Block interval, in seconds, the network will tune its next_target for. Note
|
||||
/// 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: u8 = 60;
|
||||
|
||||
/// Cuckoo-cycle proof size (cycle length)
|
||||
pub const PROOFSIZE: usize = 42;
|
||||
|
||||
/// Default Cuckoo Cycle size shift used is 28. We may decide to increase it
|
||||
/// when hashrate increases. May also start lower.
|
||||
pub const SIZESHIFT: u32 = 28;
|
||||
/// Origin Cuckoo Cycle size shift used by the genesis block.
|
||||
pub const DEFAULT_SIZESHIFT: u8 = 25;
|
||||
|
||||
/// Maximum Cuckoo Cycle size shift we'll ever use. We adopt a schedule that
|
||||
/// progressively increases the size as the target becomes lower.
|
||||
/// Start => 25
|
||||
/// MAX_TARGET >> 12 => 26
|
||||
/// MAX_TARGET >> 20 => 27
|
||||
/// MAX_TARGET >> 28 => 28
|
||||
/// MAX_TARGET >> 36 => 29
|
||||
pub const MAX_SIZESHIFT: u8 = 29;
|
||||
|
||||
/// Default Cuckoo Cycle easiness, high enough to have good likeliness to find
|
||||
/// a solution.
|
||||
pub const EASINESS: u32 = 50;
|
||||
|
||||
/// Difficulty adjustment somewhat inspired by Ethereum's. Tuned to add or
|
||||
/// remove 1/1024th of the target for each 10 seconds of deviation from the 30
|
||||
/// seconds block time. Increases Cuckoo size shift by one when next_target
|
||||
/// reaches soft max.
|
||||
pub fn next_target(ts: i64, prev_ts: i64, prev_target: Target, prev_cuckoo_sz: u8) -> (Target, u8) {
|
||||
// increase the cuckoo size when the target gets lower than the soft min as
|
||||
// long as we're not at the max size already; target gets 2x to compensate for
|
||||
// increased next_target
|
||||
let soft_min = SOFT_MIN_TARGET >> (((prev_cuckoo_sz - DEFAULT_SIZESHIFT) * 8) as usize);
|
||||
let (ptarget, clen) = if prev_target < soft_min && prev_cuckoo_sz < MAX_SIZESHIFT {
|
||||
(prev_target << 1, prev_cuckoo_sz + 1)
|
||||
} else {
|
||||
(prev_target, prev_cuckoo_sz)
|
||||
};
|
||||
|
||||
// target is increased/decreased by multiples of 1/1024th of itself
|
||||
let incdec = ptarget >> 10;
|
||||
// signed deviation from desired value divided by ten and bounded in [-3, 3]
|
||||
let delta = cmp::max(cmp::min((ts - prev_ts - (BLOCK_TIME_SEC as i64)) / 10, 3),
|
||||
-3);
|
||||
// increase or decrease the target based on the sign of delta by a shift of
|
||||
// |delta|-1; keep as-is for delta of zero
|
||||
let new_target = match delta {
|
||||
1...3 => ptarget + (incdec << ((delta - 1) as usize)),
|
||||
-3...-1 => ptarget - (incdec << ((-delta - 1) as usize)),
|
||||
_ => ptarget,
|
||||
};
|
||||
|
||||
// cannot exceed the maximum target
|
||||
if new_target > MAX_TARGET {
|
||||
(MAX_TARGET, clen)
|
||||
} else {
|
||||
(new_target, clen)
|
||||
}
|
||||
}
|
||||
|
||||
/// Max target hash, lowest next_target
|
||||
pub const MAX_TARGET: Target = Target([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]);
|
||||
|
||||
/// Target limit under which we start increasing the size shift on Cuckoo cycle.
|
||||
pub const SOFT_MIN_TARGET: Target = Target([0, 0, 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]);
|
||||
|
||||
/// Default number of blocks in the past when cross-block cut-through will start
|
||||
/// happening. Needs to be long enough to not overlap with a long reorg. Rational
|
||||
/// happening. Needs to be long enough to not overlap with a long reorg.
|
||||
/// Rational
|
||||
/// behind the value is the longest bitcoin fork was about 30 blocks, so 5h. We
|
||||
/// add an order of magnitude to be safe and round to 48h of blocks to make it
|
||||
/// easier to reason about.
|
||||
pub const CUT_THROUGH_HORIZON: u32 = 48 * 3600 / (BLOCK_TIME_SEC as u32);
|
||||
|
||||
/// Max target hash, lowest difficulty
|
||||
pub const MAX_TARGET: [u32; PROOFSIZE] =
|
||||
[0xfff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff];
|
||||
|
||||
/// The maximum number of inputs or outputs a transaction may have
|
||||
/// and be deserializable. Only for DoS protection.
|
||||
pub const MAX_IN_OUT_LEN: u64 = 50000;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
/// Checks different next_target adjustments and difficulty boundaries
|
||||
fn next_target_adjustment() {
|
||||
// can't do lower than min
|
||||
assert_eq!(next_target(60, 0, MAX_TARGET, 26), (MAX_TARGET, 26));
|
||||
assert_eq!(next_target(90, 30, MAX_TARGET, 26), (MAX_TARGET, 26));
|
||||
assert_eq!(next_target(60, 0, MAX_TARGET, 26), (MAX_TARGET, 26));
|
||||
|
||||
// lower next_target if gap too short, even negative
|
||||
assert_eq!(next_target(50, 0, MAX_TARGET, 26).0,
|
||||
MAX_TARGET - (MAX_TARGET >> 10));
|
||||
assert_eq!(next_target(40, 0, MAX_TARGET, 26).0,
|
||||
MAX_TARGET - ((MAX_TARGET >> 10) << 1));
|
||||
assert_eq!(next_target(0, 20, MAX_TARGET, 26).0,
|
||||
MAX_TARGET - ((MAX_TARGET >> 10) << 2));
|
||||
|
||||
// raise next_target if gap too wide
|
||||
let lower_target = MAX_TARGET >> 8;
|
||||
assert_eq!(next_target(70, 0, lower_target, 26).0,
|
||||
lower_target + (lower_target >> 10));
|
||||
assert_eq!(next_target(80, 0, lower_target, 26).0,
|
||||
lower_target + ((lower_target >> 10) << 1));
|
||||
assert_eq!(next_target(200, 0, lower_target, 26).0,
|
||||
lower_target + ((lower_target >> 10) << 2));
|
||||
|
||||
// close enough, no adjustment
|
||||
assert_eq!(next_target(65, 0, lower_target, 26).0, lower_target);
|
||||
assert_eq!(next_target(55, 0, lower_target, 26).0, lower_target);
|
||||
|
||||
// increase cuckoo size if next_target goes above soft max, target is doubled,
|
||||
// up to 29
|
||||
assert_eq!(next_target(60, 0, SOFT_MIN_TARGET >> 1, 25),
|
||||
((SOFT_MIN_TARGET >> 1) << 1, 26));
|
||||
assert_eq!(next_target(60, 0, SOFT_MIN_TARGET >> 9, 26),
|
||||
((SOFT_MIN_TARGET >> 9) << 1, 27));
|
||||
assert_eq!(next_target(60, 0, SOFT_MIN_TARGET >> 17, 27),
|
||||
((SOFT_MIN_TARGET >> 17) << 1, 28));
|
||||
assert_eq!(next_target(60, 0, SOFT_MIN_TARGET >> 25, 28),
|
||||
((SOFT_MIN_TARGET >> 25) << 1, 29));
|
||||
assert_eq!(next_target(60, 0, SOFT_MIN_TARGET >> 33, 29),
|
||||
(SOFT_MIN_TARGET >> 33, 29));
|
||||
|
||||
// should only increase on the according previous size
|
||||
assert_eq!(next_target(60, 0, SOFT_MIN_TARGET >> 1, 26),
|
||||
(SOFT_MIN_TARGET >> 1, 26));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,19 +23,28 @@ use std::collections::HashSet;
|
|||
use core::Committed;
|
||||
use core::{Input, Output, Proof, TxProof, Transaction};
|
||||
use core::transaction::merkle_inputs_outputs;
|
||||
use consensus::{PROOFSIZE, REWARD, MAX_IN_OUT_LEN};
|
||||
use consensus::{PROOFSIZE, REWARD, DEFAULT_SIZESHIFT, MAX_IN_OUT_LEN, MAX_TARGET};
|
||||
use core::hash::{Hash, Hashed, ZERO_HASH};
|
||||
use core::target::Target;
|
||||
use ser::{self, Readable, Reader, Writeable, Writer};
|
||||
|
||||
/// Block header, fairly standard compared to other blockchains.
|
||||
pub struct BlockHeader {
|
||||
/// Height of this block since the genesis block (height 0)
|
||||
pub height: u64,
|
||||
/// Hash of the block previous to this in the chain.
|
||||
pub previous: Hash,
|
||||
/// Timestamp at which the block was built.
|
||||
pub timestamp: time::Tm,
|
||||
pub td: u64, // total difficulty up to this block
|
||||
/// Length of the cuckoo cycle used to mine this block.
|
||||
pub cuckoo_len: u8,
|
||||
/// Difficulty used to mine the block.
|
||||
pub target: Target,
|
||||
pub utxo_merkle: Hash,
|
||||
pub tx_merkle: Hash,
|
||||
/// Nonce increment used to mine this block.
|
||||
pub nonce: u64,
|
||||
/// Proof of work data.
|
||||
pub pow: Proof,
|
||||
}
|
||||
|
||||
|
@ -45,7 +54,8 @@ impl Default for BlockHeader {
|
|||
height: 0,
|
||||
previous: ZERO_HASH,
|
||||
timestamp: time::at_utc(time::Timespec { sec: 0, nsec: 0 }),
|
||||
td: 0,
|
||||
cuckoo_len: 20, // only for tests
|
||||
target: MAX_TARGET,
|
||||
utxo_merkle: ZERO_HASH,
|
||||
tx_merkle: ZERO_HASH,
|
||||
nonce: 0,
|
||||
|
@ -62,6 +72,9 @@ impl Writeable for BlockHeader {
|
|||
[write_u64, self.height],
|
||||
[write_fixed_bytes, &self.previous],
|
||||
[write_i64, self.timestamp.to_timespec().sec],
|
||||
[write_u8, self.cuckoo_len]);
|
||||
try!(self.target.write(writer));
|
||||
ser_multiwrite!(writer,
|
||||
[write_fixed_bytes, &self.utxo_merkle],
|
||||
[write_fixed_bytes, &self.tx_merkle]);
|
||||
// make sure to not introduce any variable length data before the nonce to
|
||||
|
@ -71,7 +84,7 @@ impl Writeable for BlockHeader {
|
|||
for n in 0..42 {
|
||||
try!(writer.write_u32(self.pow.0[n]));
|
||||
}
|
||||
writer.write_u64(self.td)
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,13 +127,11 @@ impl Writeable for Block {
|
|||
/// from a binary stream.
|
||||
impl Readable<Block> for Block {
|
||||
fn read(reader: &mut Reader) -> Result<Block, ser::Error> {
|
||||
let (height, previous, timestamp, utxo_merkle, tx_merkle, nonce) = ser_multiread!(reader,
|
||||
read_u64,
|
||||
read_32_bytes,
|
||||
read_i64,
|
||||
read_32_bytes,
|
||||
read_32_bytes,
|
||||
read_u64);
|
||||
let (height, previous, timestamp, cuckoo_len) =
|
||||
ser_multiread!(reader, read_u64, read_32_bytes, read_i64, read_u8);
|
||||
let target = try!(Target::read(reader));
|
||||
let (utxo_merkle, tx_merkle, nonce) =
|
||||
ser_multiread!(reader, read_32_bytes, read_32_bytes, read_u64);
|
||||
|
||||
// cuckoo cycle of 42 nodes
|
||||
let mut pow = [0; PROOFSIZE];
|
||||
|
@ -148,7 +159,8 @@ impl Readable<Block> for Block {
|
|||
sec: timestamp,
|
||||
nsec: 0,
|
||||
}),
|
||||
td: td,
|
||||
cuckoo_len: cuckoo_len,
|
||||
target: target,
|
||||
utxo_merkle: Hash::from_vec(utxo_merkle),
|
||||
tx_merkle: Hash::from_vec(tx_merkle),
|
||||
pow: Proof(pow),
|
||||
|
|
|
@ -23,6 +23,8 @@ use tiny_keccak::Keccak;
|
|||
|
||||
use ser::{self, AsFixedBytes};
|
||||
|
||||
pub const ZERO_HASH: Hash = Hash([0; 32]);
|
||||
|
||||
/// A hash to uniquely (or close enough) identify one of the main blockchain
|
||||
/// constructs. Used pervasively for blocks, transactions and ouputs.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||
|
@ -56,15 +58,13 @@ impl Hash {
|
|||
}
|
||||
}
|
||||
|
||||
pub const ZERO_HASH: Hash = Hash([0; 32]);
|
||||
|
||||
/// Serializer that outputs a hash of the serialized object
|
||||
pub struct HashWriter {
|
||||
state: Keccak,
|
||||
}
|
||||
|
||||
impl HashWriter {
|
||||
fn finalize(self, output: &mut [u8]) {
|
||||
pub fn finalize(self, output: &mut [u8]) {
|
||||
self.state.finalize(output);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ use secp::pedersen::*;
|
|||
use consensus::PROOFSIZE;
|
||||
pub use self::block::{Block, BlockHeader};
|
||||
pub use self::transaction::{Transaction, Input, Output, TxProof};
|
||||
use self::hash::{Hash, Hashed, ZERO_HASH};
|
||||
use self::hash::{Hash, Hashed, HashWriter, ZERO_HASH};
|
||||
use ser::{Writeable, Writer, Error};
|
||||
|
||||
/// Implemented by types that hold inputs and outputs including Pedersen
|
||||
|
@ -109,11 +109,24 @@ impl Clone for Proof {
|
|||
}
|
||||
}
|
||||
|
||||
impl Hashed for Proof {
|
||||
fn hash(&self) -> Hash {
|
||||
let mut hasher = HashWriter::default();
|
||||
let mut ret = [0; 32];
|
||||
for p in self.0.iter() {
|
||||
hasher.write_u32(*p).unwrap();
|
||||
}
|
||||
hasher.finalize(&mut ret);
|
||||
Hash(ret)
|
||||
}
|
||||
}
|
||||
|
||||
impl Proof {
|
||||
/// Builds a proof with all bytes zeroed out
|
||||
pub fn zero() -> Proof {
|
||||
Proof([0; 42])
|
||||
}
|
||||
|
||||
/// Builds a proof from a vector of exactly PROOFSIZE (42) u32.
|
||||
pub fn from_vec(v: Vec<u32>) -> Proof {
|
||||
assert!(v.len() == PROOFSIZE);
|
||||
|
@ -123,6 +136,7 @@ impl Proof {
|
|||
}
|
||||
Proof(p)
|
||||
}
|
||||
|
||||
/// Converts the proof to a vector of u64s
|
||||
pub fn to_u64s(&self) -> Vec<u64> {
|
||||
let mut nonces = Vec::with_capacity(PROOFSIZE);
|
||||
|
@ -131,10 +145,17 @@ impl Proof {
|
|||
}
|
||||
nonces
|
||||
}
|
||||
|
||||
/// Converts the proof to a vector of u32s
|
||||
pub fn to_u32s(&self) -> Vec<u32> {
|
||||
self.0.to_vec()
|
||||
}
|
||||
|
||||
/// Converts the proof to a proof-of-work Target so they can be compared.
|
||||
/// Hashes the Cuckoo Proof data.
|
||||
pub fn to_target(self) -> target::Target {
|
||||
target::Target(self.hash().0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Two hashes that will get hashed together in a Merkle tree to build the next
|
||||
|
|
|
@ -244,14 +244,15 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn shift_truncate() {
|
||||
assert_eq!((Target::join(0, 0xffff).unwrap() >> 8) << 8, Target::join(0, 0xff00).unwrap());
|
||||
assert_eq!((Target::join(0, 0xffff).unwrap() >> 8) << 8,
|
||||
Target::join(0, 0xff00).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_fit() {
|
||||
let t = Target::join(10 * 8, ::std::u32::MAX).unwrap();
|
||||
let (exp, mant) = t.split();
|
||||
assert_eq!(exp, 10*8);
|
||||
assert_eq!(exp, 10 * 8);
|
||||
assert_eq!(mant, ::std::u32::MAX);
|
||||
}
|
||||
|
||||
|
@ -268,29 +269,29 @@ mod test {
|
|||
#[test]
|
||||
fn addition() {
|
||||
assert_eq!(Target::join(0, 10).unwrap() + Target::join(0, 20).unwrap(),
|
||||
Target::join(0, 30).unwrap());
|
||||
Target::join(0, 30).unwrap());
|
||||
// single overflow
|
||||
assert_eq!(Target::join(0, 250).unwrap() + Target::join(0, 250).unwrap(),
|
||||
Target::join(0, 500).unwrap());
|
||||
Target::join(0, 500).unwrap());
|
||||
// multiple overflows
|
||||
assert_eq!(Target::join(0, 300).unwrap() + Target::join(0, 300).unwrap(),
|
||||
Target::join(0, 600).unwrap());
|
||||
Target::join(0, 600).unwrap());
|
||||
assert_eq!(Target::join(10, 300).unwrap() + Target::join(10, 300).unwrap(),
|
||||
Target::join(10, 600).unwrap());
|
||||
Target::join(10, 600).unwrap());
|
||||
// cascading overflows
|
||||
assert_eq!(Target::join(8, 0xffff).unwrap() + Target::join(8, 0xffff).unwrap(),
|
||||
Target::join(8, 0x1fffe).unwrap());
|
||||
Target::join(8, 0x1fffe).unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn subtraction() {
|
||||
assert_eq!(Target::join(0, 40).unwrap() - Target::join(0, 10).unwrap(),
|
||||
Target::join(0, 30).unwrap());
|
||||
Target::join(0, 30).unwrap());
|
||||
assert_eq!(Target::join(0, 300).unwrap() - Target::join(0, 100).unwrap(),
|
||||
Target::join(0, 200).unwrap());
|
||||
Target::join(0, 200).unwrap());
|
||||
assert_eq!(Target::join(0, 0xffff).unwrap() - Target::join(0, 0xffff).unwrap(),
|
||||
Target::join(0, 0).unwrap());
|
||||
Target::join(0, 0).unwrap());
|
||||
assert_eq!(Target::join(0, 0xffff).unwrap() - Target::join(0, 0xff01).unwrap(),
|
||||
Target::join(0, 0xfe).unwrap());
|
||||
Target::join(0, 0xfe).unwrap());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
use time;
|
||||
|
||||
use core;
|
||||
use consensus::{DEFAULT_SIZESHIFT, MAX_TARGET};
|
||||
|
||||
use tiny_keccak::Keccak;
|
||||
|
||||
|
@ -38,7 +39,8 @@ pub fn genesis() -> core::Block {
|
|||
tm_mday: 4,
|
||||
..time::empty_tm()
|
||||
},
|
||||
td: 0,
|
||||
cuckoo_len: DEFAULT_SIZESHIFT,
|
||||
target: MAX_TARGET,
|
||||
utxo_merkle: core::hash::Hash::from_vec(empty_h.to_vec()),
|
||||
tx_merkle: core::hash::Hash::from_vec(empty_h.to_vec()),
|
||||
nonce: 0,
|
||||
|
|
|
@ -27,9 +27,10 @@ mod cuckoo;
|
|||
|
||||
use time;
|
||||
|
||||
use consensus::{SIZESHIFT, EASINESS};
|
||||
use consensus::EASINESS;
|
||||
use core::{Block, Proof};
|
||||
use core::hash::{Hash, Hashed};
|
||||
use core::target::Target;
|
||||
use pow::cuckoo::{Cuckoo, Miner, Error};
|
||||
|
||||
use ser;
|
||||
|
@ -87,21 +88,21 @@ impl PowHeader {
|
|||
}
|
||||
|
||||
/// Validates the proof of work of a given header.
|
||||
pub fn verify(b: &Block, target: Proof) -> bool {
|
||||
verify_size(b, target, SIZESHIFT)
|
||||
pub fn verify(b: &Block, target: Target) -> bool {
|
||||
verify_size(b, target, b.header.cuckoo_len as u32)
|
||||
}
|
||||
|
||||
/// Same as default verify function but uses the much easier Cuckoo20 (mostly
|
||||
/// for tests).
|
||||
pub fn verify20(b: &Block, target: Proof) -> bool {
|
||||
pub fn verify20(b: &Block, target: Target) -> bool {
|
||||
verify_size(b, target, 20)
|
||||
}
|
||||
|
||||
pub fn verify_size(b: &Block, target: Proof, sizeshift: u32) -> bool {
|
||||
pub fn verify_size(b: &Block, target: Target, sizeshift: u32) -> bool {
|
||||
let hash = PowHeader::from_block(b).hash();
|
||||
// make sure the hash is smaller than our target before going into more
|
||||
// expensive validation
|
||||
if target < b.header.pow {
|
||||
if target < b.header.pow.to_target() {
|
||||
return false;
|
||||
}
|
||||
Cuckoo::new(hash.to_slice(), sizeshift).verify(b.header.pow, EASINESS as u64)
|
||||
|
@ -110,17 +111,17 @@ pub fn verify_size(b: &Block, target: Proof, sizeshift: u32) -> bool {
|
|||
/// Runs a naive single-threaded proof of work computation over the provided
|
||||
/// block, until the required difficulty target is reached. May take a
|
||||
/// while for a low target...
|
||||
pub fn pow(b: &Block, target: Proof) -> Result<(Proof, u64), Error> {
|
||||
pow_size(b, target, SIZESHIFT)
|
||||
pub fn pow(b: &Block, target: Target) -> Result<(Proof, u64), Error> {
|
||||
pow_size(b, target, b.header.cuckoo_len as u32)
|
||||
}
|
||||
|
||||
/// Same as default pow function but uses the much easier Cuckoo20 (mostly for
|
||||
/// tests).
|
||||
pub fn pow20(b: &Block, target: Proof) -> Result<(Proof, u64), Error> {
|
||||
pub fn pow20(b: &Block, target: Target) -> Result<(Proof, u64), Error> {
|
||||
pow_size(b, target, 20)
|
||||
}
|
||||
|
||||
fn pow_size(b: &Block, target: Proof, sizeshift: u32) -> Result<(Proof, u64), Error> {
|
||||
fn pow_size(b: &Block, target: Target, sizeshift: u32) -> Result<(Proof, u64), Error> {
|
||||
let mut pow_header = PowHeader::from_block(b);
|
||||
let start_nonce = pow_header.nonce;
|
||||
|
||||
|
@ -133,7 +134,7 @@ fn pow_size(b: &Block, target: Proof, sizeshift: u32) -> Result<(Proof, u64), Er
|
|||
// if we found a cycle (not guaranteed) and the proof is lower that the target,
|
||||
// we're all good
|
||||
if let Ok(proof) = Miner::new(pow_hash.to_slice(), EASINESS, sizeshift).mine() {
|
||||
if proof <= target {
|
||||
if proof.to_target() <= target {
|
||||
return Ok((proof, pow_header.nonce));
|
||||
}
|
||||
}
|
||||
|
@ -159,11 +160,11 @@ mod test {
|
|||
#[test]
|
||||
fn genesis_pow() {
|
||||
let mut b = genesis::genesis();
|
||||
let (proof, nonce) = pow20(&b, Proof(MAX_TARGET)).unwrap();
|
||||
let (proof, nonce) = pow20(&b, MAX_TARGET).unwrap();
|
||||
assert!(nonce > 0);
|
||||
assert!(proof < Proof(MAX_TARGET));
|
||||
assert!(proof.to_target() < MAX_TARGET);
|
||||
b.header.pow = proof;
|
||||
b.header.nonce = nonce;
|
||||
assert!(verify20(&b, Proof(MAX_TARGET)));
|
||||
assert!(verify20(&b, MAX_TARGET));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue