grin/core/src/consensus.rs

153 lines
6 KiB
Rust
Raw Normal View History

2016-11-11 03:02:47 +03:00
// 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.
//! All the rules required for a cryptocurrency to have reach consensus across
//! the whole network are complex and hard to completely isolate. Some can be
//! simple parameters (like block reward), others complex algorithms (like
//! Merkle sum trees or reorg rules). However, as long as they're simple
2016-11-14 22:21:18 +03:00
//! enough, consensus-relevant constants and short functions should be kept
2016-11-11 03:02:47 +03:00
//! here.
use std::cmp;
use bigint::{BigInt, Sign};
use core::target::Difficulty;
2016-11-11 03:02:47 +03:00
/// The block subsidy amount
pub const REWARD: u64 = 1_000_000_000;
/// 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;
2016-11-11 03:02:47 +03:00
/// Cuckoo-cycle proof size (cycle length)
pub const PROOFSIZE: usize = 42;
/// 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;
2016-11-11 03:02:47 +03:00
/// 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_diff: Difficulty,
prev_cuckoo_sz: u8)
-> (Difficulty, u8) {
let one = BigInt::new(Sign::Plus, vec![1]);
let two = BigInt::new(Sign::Plus, vec![2]);
let ten = BigInt::new(Sign::Plus, vec![10]);
// 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 = one.clone() <<
(((prev_cuckoo_sz - cmp::min(DEFAULT_SIZESHIFT, prev_cuckoo_sz)) *
8 + 16) as usize);
let prev_diff = BigInt::from_biguint(Sign::Plus, prev_diff.into_biguint());
let (pdiff, clen) = if prev_diff > soft_min && prev_cuckoo_sz < MAX_SIZESHIFT {
(prev_diff / two, prev_cuckoo_sz + 1)
} else {
(prev_diff, prev_cuckoo_sz)
};
// signed deviation from desired value divided by ten and bounded in [-6, 6]
let delta = cmp::max(cmp::min((ts - prev_ts - (BLOCK_TIME_SEC as i64)), 60), -60);
let delta_bigi = BigInt::new(if delta >= 0 { Sign::Plus } else { Sign::Minus },
vec![delta.abs() as u32]);
let new_diff = pdiff.clone() - ((pdiff >> 10) + one.clone()) * delta_bigi / ten;
// cannot be lower than one
if new_diff < one {
(Difficulty::one(), clen)
} else {
(Difficulty::from_biguint(new_diff.to_biguint().unwrap()), clen)
}
}
2016-11-11 04:19:03 +03:00
/// 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
2016-11-11 04:19:03 +03:00
/// 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);
2016-12-14 06:21:49 +03:00
/// The maximum size we're willing to accept for any message. Enforced by the
/// peer-to-peer networking layer only for DoS protection.
pub const MAX_MSG_LEN: u64 = 20_000_000;
#[cfg(test)]
mod test {
use core::target::Difficulty;
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, Difficulty::one(), 26),
(Difficulty::one(), 26));
assert_eq!(next_target(90, 30, Difficulty::one(), 26),
(Difficulty::one(), 26));
assert_eq!(next_target(60, 0, Difficulty::one(), 26),
(Difficulty::one(), 26));
// lower next_target if gap too short
assert_eq!(next_target(30, 0, Difficulty::one(), 26).0,
Difficulty::from_num(4));
assert_eq!(next_target(50, 0, Difficulty::one(), 26).0,
Difficulty::from_num(2));
assert_eq!(next_target(40, 0, Difficulty::from_num(1024 * 8), 26).0,
Difficulty::from_num(1024 * 8 + 18));
// lower difficulty if gap too wide
assert_eq!(next_target(70, 0, Difficulty::from_num(10), 26).0,
Difficulty::from_num(9));
assert_eq!(next_target(90, 0, Difficulty::from_num(1024 * 8), 26).0,
Difficulty::from_num(1024 * 8 - 9 * 3));
// identical, no adjustment
assert_eq!(next_target(60, 0, Difficulty::from_num(1024 * 8), 26).0,
Difficulty::from_num(1024 * 8));
// increase cuckoo size if next_target goes above soft max, target is doubled,
// up to 29
assert_eq!(next_target(60, 0, Difficulty::from_num(1 << 16), 25),
(Difficulty::from_num(1 << 16), 25));
assert_eq!(next_target(60, 0, Difficulty::from_num((1 << 16) + 1), 25),
(Difficulty::from_num(1 << 15), 26));
assert_eq!(next_target(60, 0, Difficulty::from_num((1 << 24) + 1), 26),
(Difficulty::from_num(1 << 23), 27));
}
}