Skip to content

Commit

Permalink
[T4] tweaks and fixes (mimblewimble#1766)
Browse files Browse the repository at this point in the history
* refactor consensus.rs, tweaking some values
* move scale() there
* fix set_header_nonce bug
* remove maturity soft-fork code
* increase diff target precision
* fix weight comments and try resolve PR conflict
  • Loading branch information
tromp authored and ignopeverell committed Oct 16, 2018
1 parent 701f0b9 commit 8540e4f
Show file tree
Hide file tree
Showing 11 changed files with 65 additions and 69 deletions.
4 changes: 2 additions & 2 deletions chain/src/txhashset/txhashset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -821,14 +821,14 @@ impl<'a> Extension<'a> {
if pos > 0 {
// If we have not yet reached 1,000 / 1,440 blocks then
// we can fail immediately as coinbase cannot be mature.
if height < global::coinbase_maturity(height) {
if height < global::coinbase_maturity() {
return Err(ErrorKind::ImmatureCoinbase.into());
}

// Find the "cutoff" pos in the output MMR based on the
// header from 1,000 blocks ago.
let cutoff_height = height
.checked_sub(global::coinbase_maturity(height))
.checked_sub(global::coinbase_maturity())
.unwrap_or(0);
let cutoff_header = self.batch.get_header_by_height(cutoff_height)?;
let cutoff_pos = cutoff_header.output_mmr_size;
Expand Down
2 changes: 1 addition & 1 deletion chain/tests/test_coinbase_maturity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ fn test_coinbase_maturity() {

let amount = consensus::REWARD;

let lock_height = 1 + global::coinbase_maturity(1);
let lock_height = 1 + global::coinbase_maturity();
assert_eq!(lock_height, 4);

// here we build a tx that attempts to spend the earlier coinbase output
Expand Down
51 changes: 31 additions & 20 deletions core/src/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,30 +33,34 @@ pub const MICRO_GRIN: u64 = MILLI_GRIN / 1_000;
/// Nanogrin, smallest unit, takes a billion to make a grin
pub const NANO_GRIN: u64 = 1;

/// 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: u64 = 60;

/// The block subsidy amount, one grin per second on average
pub const REWARD: u64 = 60 * GRIN_BASE;
pub const REWARD: u64 = BLOCK_TIME_SEC * GRIN_BASE;

/// Actual block reward for a given total fee amount
pub fn reward(fee: u64) -> u64 {
REWARD + fee
}

/// 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: u64 = 60;
/// Nominal height for standard time intervals
pub const HOUR_HEIGHT: u64 = 3600 / BLOCK_TIME_SEC;
pub const DAY_HEIGHT: u64 = 24 * HOUR_HEIGHT;
pub const WEEK_HEIGHT: u64 = 7 * DAY_HEIGHT;
pub const YEAR_HEIGHT: u64 = 52 * WEEK_HEIGHT;

/// Number of blocks before a coinbase matures and can be spent
/// set to nominal number of block in one day (1440 with 1-minute blocks)
pub const COINBASE_MATURITY: u64 = 24 * 60 * 60 / BLOCK_TIME_SEC;
pub const COINBASE_MATURITY: u64 = DAY_HEIGHT;

/// Ratio the secondary proof of work should take over the primary, as a
/// function of block height (time). Starts at 90% losing a percent
/// approximately every week (10000 blocks). Represented as an integer
/// between 0 and 100.
/// approximately every week. Represented as an integer between 0 and 100.
pub fn secondary_pow_ratio(height: u64) -> u64 {
90u64.saturating_sub(height / 10000)
90u64.saturating_sub(height / WEEK_HEIGHT)
}

/// Cuckoo-cycle proof size (cycle length)
Expand All @@ -83,7 +87,7 @@ pub const MAX_SECONDARY_SCALING: u64 = 8 << 11;
/// 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 7x24h of blocks to make it
/// easier to reason about.
pub const CUT_THROUGH_HORIZON: u32 = 7 * 24 * 3600 / (BLOCK_TIME_SEC as u32);
pub const CUT_THROUGH_HORIZON: u32 = WEEK_HEIGHT as u32;

/// Weight of an input when counted against the max block weight capacity
pub const BLOCK_INPUT_WEIGHT: usize = 1;
Expand All @@ -106,12 +110,11 @@ pub const BLOCK_KERNEL_WEIGHT: usize = 2;
/// outputs and a single kernel).
///
/// A more "standard" block, filled with transactions of 2 inputs, 2 outputs
/// and one kernel, should be around 2_663_333 bytes.
/// and one kernel, should be around 2.66 MB
pub const MAX_BLOCK_WEIGHT: usize = 40_000;

/// Fork every 250,000 blocks for first 2 years, simple number and just a
/// little less than 6 months.
pub const HARD_FORK_INTERVAL: u64 = 250_000;
/// Fork every 6 months.
pub const HARD_FORK_INTERVAL: u64 = YEAR_HEIGHT / 2;

/// Check whether the block version is valid at a given height, implements
/// 6 months interval scheduled hard forks for the first 2 years.
Expand Down Expand Up @@ -139,7 +142,7 @@ pub const MEDIAN_TIME_WINDOW: u64 = 11;
pub const MEDIAN_TIME_INDEX: u64 = MEDIAN_TIME_WINDOW / 2;

/// Number of blocks used to calculate difficulty adjustments
pub const DIFFICULTY_ADJUST_WINDOW: u64 = 60;
pub const DIFFICULTY_ADJUST_WINDOW: u64 = HOUR_HEIGHT;

/// Average time span of the difficulty adjustment window
pub const BLOCK_TIME_WINDOW: u64 = DIFFICULTY_ADJUST_WINDOW * BLOCK_TIME_SEC;
Expand All @@ -153,12 +156,20 @@ pub const LOWER_TIME_BOUND: u64 = BLOCK_TIME_WINDOW / 2;
/// Dampening factor to use for difficulty adjustment
pub const DAMP_FACTOR: u64 = 3;

/// Compute difficulty scaling factor as number of siphash bits defining the graph
/// Must be made dependent on height to phase out smaller size over the years
/// This can wait until end of 2019 at latest
pub fn scale(edge_bits: u8) -> u64 {
(2 << (edge_bits - global::base_edge_bits()) as u64) * (edge_bits as u64)
}

/// The initial difficulty at launch. This should be over-estimated
/// and difficulty should come down at launch rather than up
/// Currently grossly over-estimated at 10% of current
/// ethereum GPUs (assuming 1GPU can solve a block at diff 1
/// in one block interval)
pub const INITIAL_DIFFICULTY: u64 = 1_000_000;
/// ethereum GPUs (assuming 1GPU can solve a block at diff 1 in one block interval)
/// Pick MUCH more modest value for TESTNET4; CHANGE FOR MAINNET
pub const INITIAL_DIFFICULTY: u64 = 1_000 * (2<<(29-24)) * 29; // scale(SECOND_POW_EDGE_BITS);
/// pub const INITIAL_DIFFICULTY: u64 = 1_000_000 * Difficulty::scale(SECOND_POW_EDGE_BITS);
/// Consensus errors
#[derive(Clone, Debug, Eq, PartialEq, Fail)]
Expand Down
25 changes: 8 additions & 17 deletions core/src/global.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use consensus::HeaderInfo;
use consensus::{
BASE_EDGE_BITS, BLOCK_TIME_SEC, COINBASE_MATURITY, CUT_THROUGH_HORIZON,
DIFFICULTY_ADJUST_WINDOW, INITIAL_DIFFICULTY, MEDIAN_TIME_WINDOW, PROOFSIZE,
SECOND_POW_EDGE_BITS,
SECOND_POW_EDGE_BITS, DAY_HEIGHT
};
use pow::{self, CuckatooContext, EdgeType, PoWContext};
/// An enum collecting sets of parameters used throughout the
Expand Down Expand Up @@ -50,12 +50,6 @@ pub const AUTOMATED_TESTING_COINBASE_MATURITY: u64 = 3;
/// User testing coinbase maturity
pub const USER_TESTING_COINBASE_MATURITY: u64 = 3;

/// Old coinbase maturity
/// TODO: obsolete for mainnet together with maturity code below
pub const OLD_COINBASE_MATURITY: u64 = 1_000;
/// soft-fork around Sep 17 2018 on testnet3
pub const COINBASE_MATURITY_FORK_HEIGHT: u64 = 100_000;

/// Testing cut through horizon in blocks
pub const TESTING_CUT_THROUGH_HORIZON: u32 = 20;

Expand All @@ -70,12 +64,13 @@ pub const TESTNET2_INITIAL_DIFFICULTY: u64 = 1000;
pub const TESTNET3_INITIAL_DIFFICULTY: u64 = 30000;

/// Testnet 4 initial block difficulty
pub const TESTNET4_INITIAL_DIFFICULTY: u64 = 1;
/// 1_000 times natural scale factor for cuckatoo29
pub const TESTNET4_INITIAL_DIFFICULTY: u64 = 1_000 * (2<<(29-24)) * 29;

/// Trigger compaction check on average every 1440 blocks (i.e. one day) for FAST_SYNC_NODE,
/// Trigger compaction check on average every day for FAST_SYNC_NODE,
/// roll the dice on every block to decide,
/// all blocks lower than (BodyHead.height - CUT_THROUGH_HORIZON) will be removed.
pub const COMPACTION_CHECK: u64 = 1440;
pub const COMPACTION_CHECK: u64 = DAY_HEIGHT;

/// Types of chain a server can run with, dictates the genesis block and
/// and mining parameters used.
Expand Down Expand Up @@ -180,17 +175,13 @@ pub fn proofsize() -> usize {
}
}

/// Coinbase maturity for coinbases to be spent at given height
pub fn coinbase_maturity(height: u64) -> u64 {
/// Coinbase maturity for coinbases to be spent
pub fn coinbase_maturity() -> u64 {
let param_ref = CHAIN_TYPE.read().unwrap();
match *param_ref {
ChainTypes::AutomatedTesting => AUTOMATED_TESTING_COINBASE_MATURITY,
ChainTypes::UserTesting => USER_TESTING_COINBASE_MATURITY,
_ => if height < COINBASE_MATURITY_FORK_HEIGHT {
OLD_COINBASE_MATURITY
} else {
COINBASE_MATURITY
},
_ => COINBASE_MATURITY,
}
}

Expand Down
12 changes: 4 additions & 8 deletions core/src/pow/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,10 @@ pub fn set_header_nonce(header: Vec<u8>, nonce: Option<u32>) -> Result<[u64; 4],
let mut header = header.clone();
header.truncate(len - mem::size_of::<u32>());
header.write_u32::<LittleEndian>(n)?;
create_siphash_keys(header)
} else {
create_siphash_keys(header)
}
create_siphash_keys(header)
}

pub fn create_siphash_keys(header: Vec<u8>) -> Result<[u64; 4], Error> {
Expand Down Expand Up @@ -165,15 +167,9 @@ where
/// Reset the main keys used for siphash from the header and nonce
pub fn reset_header_nonce(
&mut self,
mut header: Vec<u8>,
header: Vec<u8>,
nonce: Option<u32>,
) -> Result<(), Error> {
// THIS IF LOOKS REDUNDANT SINCE set_header_nonce DOES SAME THING
if let Some(n) = nonce {
let len = header.len();
header.truncate(len - mem::size_of::<u32>());
header.write_u32::<LittleEndian>(n)?;
}
self.siphash_keys = set_header_nonce(header, nonce)?;
Ok(())
}
Expand Down
20 changes: 9 additions & 11 deletions core/src/pow/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@

/// Types for a Cuck(at)oo proof of work and its encapsulation as a fully usable
/// proof of work within a block header.
use std::cmp::max;
use std::cmp::{min,max};
use std::ops::{Add, Div, Mul, Sub};
use std::{fmt, iter};

use rand::{thread_rng, Rng};
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

use consensus::SECOND_POW_EDGE_BITS;
use consensus::{self, SECOND_POW_EDGE_BITS};
use core::hash::Hashed;
use global;
use ser::{self, Readable, Reader, Writeable, Writer};
Expand Down Expand Up @@ -89,19 +89,16 @@ impl Difficulty {
/// provided hash and applies the Cuck(at)oo size adjustment factor (see
/// https://lists.launchpad.net/mimblewimble/msg00494.html).
fn from_proof_adjusted(proof: &Proof) -> Difficulty {
// Adjust the difficulty based on a 2^(N-M)*(N-1) factor, with M being
// the minimum edge_bits and N the provided edge_bits
let edge_bits = proof.edge_bits;

Difficulty::from_num(proof.raw_difficulty() * Difficulty::scale(edge_bits))
// scale with natural scaling factor
Difficulty::from_num(proof.scaled_difficulty(consensus::scale(proof.edge_bits)))
}

/// Same as `from_proof_adjusted` but instead of an adjustment based on
/// cycle size, scales based on a provided factor. Used by dual PoW system
/// to scale one PoW against the other.
fn from_proof_scaled(proof: &Proof, scaling: u32) -> Difficulty {
// Scaling between 2 proof of work algos
Difficulty::from_num(proof.raw_difficulty() * scaling as u64)
Difficulty::from_num(proof.scaled_difficulty(scaling as u64))
}

/// Converts the difficulty into a u64
Expand Down Expand Up @@ -383,9 +380,10 @@ impl Proof {
self.nonces.len()
}

/// Difficulty achieved by this proof
fn raw_difficulty(&self) -> u64 {
<u64>::max_value() / self.hash().to_u64()
/// Difficulty achieved by this proof with given scaling factor
fn scaled_difficulty(&self, scale: u64) -> u64 {
let diff = ((scale as u128) << 64) / (self.hash().to_u64() as u128);
min(diff, <u64>::max_value() as u128) as u64
}
}

Expand Down
10 changes: 5 additions & 5 deletions core/tests/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -581,12 +581,12 @@ fn hard_forks() {
assert!(valid_header_version(0, 1));
assert!(valid_header_version(10, 1));
assert!(!valid_header_version(10, 2));
assert!(valid_header_version(249_999, 1));
assert!(valid_header_version(YEAR_HEIGHT/2-1, 1));
// v2 not active yet
assert!(!valid_header_version(250_000, 2));
assert!(!valid_header_version(250_000, 1));
assert!(!valid_header_version(500_000, 1));
assert!(!valid_header_version(250_001, 2));
assert!(!valid_header_version(YEAR_HEIGHT/2, 2));
assert!(!valid_header_version(YEAR_HEIGHT/2, 1));
assert!(!valid_header_version(YEAR_HEIGHT, 1));
assert!(!valid_header_version(YEAR_HEIGHT/2+1, 2));
}

// #[test]
Expand Down
2 changes: 1 addition & 1 deletion wallet/src/libwallet/internal/restore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ where
);

let lock_height = if *is_coinbase {
*height + global::coinbase_maturity(*height) // ignores on/off spendability around soft fork height
*height + global::coinbase_maturity()
} else {
*height
};
Expand Down
2 changes: 1 addition & 1 deletion wallet/src/libwallet/internal/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ where
K: Keychain,
{
let height = block_fees.height;
let lock_height = height + global::coinbase_maturity(height); // ignores on/off spendability around soft fork height
let lock_height = height + global::coinbase_maturity();
let key_id = block_fees.key_id();
let parent_key_id = wallet.parent_key_id();

Expand Down
2 changes: 1 addition & 1 deletion wallet/tests/accounts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ fn accounts_test_impl(test_dir: &str) -> Result<(), libwallet::Error> {

// few values to keep things shorter
let reward = core::consensus::REWARD;
let cm = global::coinbase_maturity(0); // assume all testing precedes soft fork height
let cm = global::coinbase_maturity(); // assume all testing precedes soft fork height

// test default accounts exist
wallet::controller::owner_single_use(wallet1.clone(), |api| {
Expand Down
4 changes: 2 additions & 2 deletions wallet/tests/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ fn basic_transaction_api(test_dir: &str) -> Result<(), libwallet::Error> {

// few values to keep things shorter
let reward = core::consensus::REWARD;
let cm = global::coinbase_maturity(0); // assume all testing precedes soft fork height
let cm = global::coinbase_maturity(); // assume all testing precedes soft fork height
// mine a few blocks
let _ = common::award_blocks_to_wallet(&chain, wallet1.clone(), 10);

Expand Down Expand Up @@ -324,7 +324,7 @@ fn tx_rollback(test_dir: &str) -> Result<(), libwallet::Error> {

// few values to keep things shorter
let reward = core::consensus::REWARD;
let cm = global::coinbase_maturity(0); // assume all testing precedes soft fork height
let cm = global::coinbase_maturity(); // assume all testing precedes soft fork height
// mine a few blocks
let _ = common::award_blocks_to_wallet(&chain, wallet1.clone(), 5);

Expand Down

0 comments on commit 8540e4f

Please sign in to comment.