mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 08:51:08 +03:00
Test for chain forks and head switching.
This commit is contained in:
parent
dda223f25b
commit
cc9690ee8c
3 changed files with 84 additions and 22 deletions
|
@ -14,4 +14,5 @@ grin_store = { path = "../store" }
|
|||
secp256k1zkp = { path = "../secp256k1zkp" }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger="^0.3.5"
|
||||
rand = "^0.3"
|
||||
|
|
|
@ -32,8 +32,8 @@ bitflags! {
|
|||
/// Options for block validation
|
||||
pub flags Options: u32 {
|
||||
const NONE = 0b00000001,
|
||||
/// Runs with the easier version of the Proof of Work, mostly to make testing easier.
|
||||
const EASY_POW = 0b00000010,
|
||||
/// Runs without checking the Proof of Work, mostly to make testing easier.
|
||||
const SKIP_POW = 0b00000010,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,28 +140,26 @@ fn validate_header(b: &Block, ctx: &mut BlockContext) -> Result<(), Error> {
|
|||
return Err(Error::InvalidBlockTime);
|
||||
}
|
||||
|
||||
if header.total_difficulty != prev.total_difficulty.clone() + prev.pow.to_difficulty() {
|
||||
return Err(Error::WrongTotalDifficulty);
|
||||
}
|
||||
if !ctx.opts.intersects(SKIP_POW) {
|
||||
// verify the proof of work and related parameters
|
||||
|
||||
// verify the proof of work and related parameters
|
||||
let (difficulty, cuckoo_sz) = consensus::next_target(header.timestamp.to_timespec().sec,
|
||||
prev.timestamp.to_timespec().sec,
|
||||
prev.difficulty,
|
||||
prev.cuckoo_len);
|
||||
if header.difficulty < difficulty {
|
||||
return Err(Error::DifficultyTooLow);
|
||||
}
|
||||
if header.cuckoo_len != cuckoo_sz && !ctx.opts.intersects(EASY_POW) {
|
||||
return Err(Error::WrongCuckooSize);
|
||||
}
|
||||
if header.total_difficulty != prev.total_difficulty.clone() + prev.pow.to_difficulty() {
|
||||
return Err(Error::WrongTotalDifficulty);
|
||||
}
|
||||
|
||||
if ctx.opts.intersects(EASY_POW) {
|
||||
if !pow::verify_size(b, 16) {
|
||||
let (difficulty, cuckoo_sz) = consensus::next_target(header.timestamp.to_timespec().sec,
|
||||
prev.timestamp.to_timespec().sec,
|
||||
prev.difficulty,
|
||||
prev.cuckoo_len);
|
||||
if header.difficulty < difficulty {
|
||||
return Err(Error::DifficultyTooLow);
|
||||
}
|
||||
if header.cuckoo_len != cuckoo_sz {
|
||||
return Err(Error::WrongCuckooSize);
|
||||
}
|
||||
if !pow::verify(b) {
|
||||
return Err(Error::InvalidPow);
|
||||
}
|
||||
} else if !pow::verify(b) {
|
||||
return Err(Error::InvalidPow);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -196,6 +194,7 @@ fn update_head(b: &Block, ctx: &mut BlockContext) -> Result<Option<Tip>, Error>
|
|||
if tip.total_difficulty > ctx.head.total_difficulty {
|
||||
try!(ctx.store.save_head(&tip).map_err(&Error::StoreErr));
|
||||
ctx.head = tip.clone();
|
||||
info!("Updated head to {} at {}.", b.hash(), b.header.height);
|
||||
Ok(Some(tip))
|
||||
} else {
|
||||
Ok(None)
|
||||
|
|
|
@ -14,21 +14,25 @@
|
|||
|
||||
extern crate grin_core;
|
||||
extern crate grin_chain;
|
||||
extern crate rand;
|
||||
extern crate env_logger;
|
||||
extern crate time;
|
||||
extern crate rand;
|
||||
extern crate secp256k1zkp as secp;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
use rand::os::OsRng;
|
||||
|
||||
use grin_chain::types::*;
|
||||
use grin_core::core::hash::Hashed;
|
||||
use grin_core::core::target::Difficulty;
|
||||
use grin_core::pow;
|
||||
use grin_core::core;
|
||||
use grin_core::consensus;
|
||||
|
||||
#[test]
|
||||
fn mine_empty_chain() {
|
||||
env_logger::init().unwrap();
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
let store = grin_chain::store::ChainKVStore::new(".grin".to_string()).unwrap();
|
||||
|
||||
|
@ -64,7 +68,7 @@ fn mine_empty_chain() {
|
|||
grin_chain::pipe::process_block(&b,
|
||||
arc_store.clone(),
|
||||
adapter.clone(),
|
||||
grin_chain::pipe::EASY_POW)
|
||||
grin_chain::pipe::NONE)
|
||||
.unwrap();
|
||||
|
||||
// checking our new head
|
||||
|
@ -75,3 +79,61 @@ fn mine_empty_chain() {
|
|||
prev = b;
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mine_forks() {
|
||||
env_logger::init().unwrap();
|
||||
let mut rng = OsRng::new().unwrap();
|
||||
let store = grin_chain::store::ChainKVStore::new(".grin2".to_string()).unwrap();
|
||||
|
||||
// save a genesis block
|
||||
let mut gen = grin_core::genesis::genesis();
|
||||
store.save_block(&gen).unwrap();
|
||||
|
||||
// setup a new head tip
|
||||
let tip = Tip::new(gen.hash());
|
||||
store.save_head(&tip).unwrap();
|
||||
|
||||
// mine and add a few blocks
|
||||
let mut prev = gen;
|
||||
let secp = secp::Secp256k1::with_caps(secp::ContextFlag::Commit);
|
||||
let reward_key = secp::key::SecretKey::new(&secp, &mut rng);
|
||||
let arc_store = Arc::new(store);
|
||||
let adapter = Arc::new(NoopAdapter {});
|
||||
|
||||
for n in 1..4 {
|
||||
let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
|
||||
b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);
|
||||
b.header.total_difficulty = Difficulty::from_num(2*n);
|
||||
grin_chain::pipe::process_block(&b,
|
||||
arc_store.clone(),
|
||||
adapter.clone(),
|
||||
grin_chain::pipe::SKIP_POW)
|
||||
.unwrap();
|
||||
|
||||
// checking our new head
|
||||
thread::sleep(::std::time::Duration::from_millis(50));
|
||||
let head = arc_store.clone().head().unwrap();
|
||||
assert_eq!(head.height, n as u64);
|
||||
assert_eq!(head.last_block_h, b.hash());
|
||||
assert_eq!(head.prev_block_h, prev.hash());
|
||||
|
||||
let mut b = core::Block::new(&prev.header, vec![], reward_key).unwrap();
|
||||
b.header.timestamp = prev.header.timestamp + time::Duration::seconds(60);
|
||||
b.header.total_difficulty = Difficulty::from_num(2*n+1);
|
||||
grin_chain::pipe::process_block(&b,
|
||||
arc_store.clone(),
|
||||
adapter.clone(),
|
||||
grin_chain::pipe::SKIP_POW)
|
||||
.unwrap();
|
||||
|
||||
// checking our new head
|
||||
thread::sleep(::std::time::Duration::from_millis(50));
|
||||
let head = arc_store.clone().head().unwrap();
|
||||
assert_eq!(head.height, n as u64);
|
||||
assert_eq!(head.last_block_h, b.hash());
|
||||
assert_eq!(head.prev_block_h, prev.hash());
|
||||
|
||||
prev = b;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue