From 8b2f9503c95aa7c124d8df387c313b9fb2250384 Mon Sep 17 00:00:00 2001 From: Simon B Date: Fri, 12 Jan 2018 19:35:37 +0100 Subject: [PATCH] Make total_difficulty the sum of network difficulty [testnet2] (#523) * Make total_difficulty the sum of network difficulty, not whatever the miner happened to mine. - Only for Testnet2 / Mainnet (hardforks Testnet1) - update chain::pipe validate_header to validate according to Testnet2 rules for cumulative difference Fixes #280 * tests that should ignore (network) difficulty * fn new_block is explained as "utility to create a block without worrying about the key or previous header" so it gets network difficulty := 0 too * update tx pool tests (going with "minimum" for network difficulty for now) * add ERR outputs about bannable offences (#406 should know about these) * whitespace fix * mine_simple_chain: Probably DON'T overwrite difficulty (?) * core/mod tests "reward_empty_block" and "reward_with_tx_block" tests set to use lowest network difficulty possible --- chain/src/pipe.rs | 24 +++++++++++++++---- chain/tests/mine_simple_chain.rs | 14 ++++++++---- chain/tests/store_indices.rs | 9 +++++++- chain/tests/test_coinbase_maturity.rs | 33 +++++++++++++++++++++++---- core/src/core/block.rs | 14 +++++++++--- core/src/core/mod.rs | 20 ++++++++++++++-- grin/src/miner.rs | 16 +++++++------ pool/src/pool.rs | 12 ++++++++-- 8 files changed, 114 insertions(+), 28 deletions(-) diff --git a/chain/src/pipe.rs b/chain/src/pipe.rs index 1c6804b1b..3267c0ec2 100644 --- a/chain/src/pipe.rs +++ b/chain/src/pipe.rs @@ -213,18 +213,32 @@ fn validate_header(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(), E return Err(Error::DifficultyTooLow); } + let diff_iter = store::DifficultyIter::from(header.previous, ctx.store.clone()); + let difficulty = + consensus::next_difficulty(diff_iter).map_err(|e| Error::Other(e.to_string()))?; + // explicit check to ensure total_difficulty has increased by exactly - // the difficulty of the previous block - if header.total_difficulty != prev.total_difficulty.clone() + prev.pow.to_difficulty() { + // the _network_ difficulty of the previous block + // (during testnet1 we use _block_ difficulty here) + if header.total_difficulty != prev.total_difficulty.clone() + difficulty.clone() { + error!( + LOGGER, + "validate_header: BANNABLE OFFENCE: header cumulative difficulty {} != {}", + header.difficulty.into_num(), + prev.total_difficulty.into_num() + difficulty.into_num() + ); return Err(Error::WrongTotalDifficulty); } // now check that the difficulty is not less than that calculated by the // difficulty iterator based on the previous block - let diff_iter = store::DifficultyIter::from(header.previous, ctx.store.clone()); - let difficulty = - consensus::next_difficulty(diff_iter).map_err(|e| Error::Other(e.to_string()))?; if header.difficulty < difficulty { + error!( + LOGGER, + "validate_header: BANNABLE OFFENCE: header difficulty {} < {}", + header.difficulty.into_num(), + difficulty.into_num() + ); return Err(Error::DifficultyTooLow); } } diff --git a/chain/tests/mine_simple_chain.rs b/chain/tests/mine_simple_chain.rs index eeab5771e..19dd165d1 100644 --- a/chain/tests/mine_simple_chain.rs +++ b/chain/tests/mine_simple_chain.rs @@ -74,12 +74,18 @@ fn mine_empty_chain() { ); for n in 1..4 { let prev = chain.head_header().unwrap(); + let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); let pk = keychain.derive_key_id(n as u32).unwrap(); - let mut b = core::core::Block::new(&prev, vec![], &keychain, &pk).unwrap(); + let mut b = core::core::Block::new( + &prev, + vec![], + &keychain, + &pk, + difficulty.clone() + ).unwrap(); b.header.timestamp = prev.timestamp + time::Duration::seconds(60); - let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); - b.header.difficulty = difficulty.clone(); + b.header.difficulty = difficulty.clone(); // TODO: overwrite here? really? chain.set_sumtree_roots(&mut b, false).unwrap(); pow::pow_size( @@ -335,7 +341,7 @@ fn prepare_fork_block_tx(kc: &Keychain, prev: &BlockHeader, chain: &Chain, diff: fn prepare_block_nosum(kc: &Keychain, prev: &BlockHeader, diff: u64, txs: Vec<&Transaction>) -> Block { let key_id = kc.derive_key_id(diff as u32).unwrap(); - let mut b = match core::core::Block::new(prev, txs, kc, &key_id) { + let mut b = match core::core::Block::new(prev, txs, kc, &key_id, Difficulty::from_num(diff)) { Err(e) => panic!("{:?}",e), Ok(b) => b }; diff --git a/chain/tests/store_indices.rs b/chain/tests/store_indices.rs index 2d35867ee..bc84658a2 100644 --- a/chain/tests/store_indices.rs +++ b/chain/tests/store_indices.rs @@ -24,6 +24,7 @@ use std::fs; use chain::{ChainStore, Tip}; use core::core::hash::Hashed; use core::core::Block; +use core::core::target::Difficulty; use keychain::Keychain; use core::global; use core::global::ChainTypes; @@ -47,7 +48,13 @@ fn test_various_store_indices() { chain_store.save_block(&genesis).unwrap(); chain_store.setup_height(&genesis.header, &Tip::new(genesis.hash())).unwrap(); - let block = Block::new(&genesis.header, vec![], &keychain, &key_id).unwrap(); + let block = Block::new( + &genesis.header, + vec![], + &keychain, + &key_id, + Difficulty::minimum() + ).unwrap(); let commit = block.outputs[0].commitment(); let block_hash = block.hash(); diff --git a/chain/tests/test_coinbase_maturity.rs b/chain/tests/test_coinbase_maturity.rs index dab4bea5f..f9e68df6a 100644 --- a/chain/tests/test_coinbase_maturity.rs +++ b/chain/tests/test_coinbase_maturity.rs @@ -25,6 +25,7 @@ use std::sync::Arc; use chain::types::*; use core::core::build; +use core::core::target::Difficulty; use core::core::transaction; use core::consensus; use core::global; @@ -74,7 +75,13 @@ fn test_coinbase_maturity() { let key_id3 = keychain.derive_key_id(3).unwrap(); let key_id4 = keychain.derive_key_id(4).unwrap(); - let mut block = core::core::Block::new(&prev, vec![], &keychain, &key_id1).unwrap(); + let mut block = core::core::Block::new( + &prev, + vec![], + &keychain, + &key_id1, + Difficulty::minimum() + ).unwrap(); block.header.timestamp = prev.timestamp + time::Duration::seconds(60); let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); @@ -110,7 +117,13 @@ fn test_coinbase_maturity() { ).unwrap(); let mut block = - core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, &key_id3).unwrap(); + core::core::Block::new( + &prev, + vec![&coinbase_txn], + &keychain, + &key_id3, + Difficulty::minimum() + ).unwrap(); block.header.timestamp = prev.timestamp + time::Duration::seconds(60); let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); @@ -138,7 +151,13 @@ fn test_coinbase_maturity() { let keychain = Keychain::from_random_seed().unwrap(); let pk = keychain.derive_key_id(1).unwrap(); - let mut block = core::core::Block::new(&prev, vec![], &keychain, &pk).unwrap(); + let mut block = core::core::Block::new( + &prev, + vec![], + &keychain, + &pk, + Difficulty::minimum() + ).unwrap(); block.header.timestamp = prev.timestamp + time::Duration::seconds(60); let difficulty = consensus::next_difficulty(chain.difficulty_iter()).unwrap(); @@ -158,7 +177,13 @@ fn test_coinbase_maturity() { let prev = chain.head_header().unwrap(); let mut block = - core::core::Block::new(&prev, vec![&coinbase_txn], &keychain, &key_id4).unwrap(); + core::core::Block::new( + &prev, + vec![&coinbase_txn], + &keychain, + &key_id4, + Difficulty::minimum() + ).unwrap(); block.header.timestamp = prev.timestamp + time::Duration::seconds(60); diff --git a/core/src/core/block.rs b/core/src/core/block.rs index 4d89a39c7..e5137139f 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -292,10 +292,11 @@ impl Block { txs: Vec<&Transaction>, keychain: &keychain::Keychain, key_id: &keychain::Identifier, + difficulty: Difficulty, ) -> Result { let fees = txs.iter().map(|tx| tx.fee).sum(); let (reward_out, reward_proof) = Block::reward_output(keychain, key_id, fees)?; - let block = Block::with_reward(prev, txs, reward_out, reward_proof)?; + let block = Block::with_reward(prev, txs, reward_out, reward_proof, difficulty)?; Ok(block) } @@ -307,6 +308,7 @@ impl Block { txs: Vec<&Transaction>, reward_out: Output, reward_kern: TxKernel, + difficulty: Difficulty, ) -> Result { let mut kernels = vec![]; let mut inputs = vec![]; @@ -350,7 +352,7 @@ impl Block { ..time::now_utc() }, previous: prev.hash(), - total_difficulty: prev.pow.clone().to_difficulty() + + total_difficulty: difficulty + prev.total_difficulty.clone(), ..Default::default() }, @@ -615,7 +617,13 @@ mod test { // header fn new_block(txs: Vec<&Transaction>, keychain: &Keychain) -> Block { let key_id = keychain.derive_key_id(1).unwrap(); - Block::new(&BlockHeader::default(), txs, keychain, &key_id).unwrap() + Block::new( + &BlockHeader::default(), + txs, + keychain, + &key_id, + Difficulty::minimum() + ).unwrap() } // utility producing a transaction that spends an output with the provided diff --git a/core/src/core/mod.rs b/core/src/core/mod.rs index 798da30a3..e299bc0db 100644 --- a/core/src/core/mod.rs +++ b/core/src/core/mod.rs @@ -28,6 +28,7 @@ use std::cmp::Ordering; use std::num::ParseFloatError; use consensus::GRIN_BASE; +use core::target::Difficulty; use util::{secp, static_secp_instance}; use util::secp::pedersen::*; @@ -388,7 +389,13 @@ mod test { let keychain = keychain::Keychain::from_random_seed().unwrap(); let key_id = keychain.derive_key_id(1).unwrap(); - let b = Block::new(&BlockHeader::default(), vec![], &keychain, &key_id).unwrap(); + let b = Block::new( + &BlockHeader::default(), + vec![], + &keychain, + &key_id, + Difficulty::minimum(), + ).unwrap(); b.compact().validate().unwrap(); } @@ -400,7 +407,13 @@ mod test { let mut tx1 = tx2i1o(); tx1.verify_sig().unwrap(); - let b = Block::new(&BlockHeader::default(), vec![&mut tx1], &keychain, &key_id).unwrap(); + let b = Block::new( + &BlockHeader::default(), + vec![&mut tx1], + &keychain, + &key_id, + Difficulty::minimum(), + ).unwrap(); b.compact().validate().unwrap(); } @@ -417,6 +430,7 @@ mod test { vec![&mut tx1, &mut tx2], &keychain, &key_id, + Difficulty::minimum(), ).unwrap(); b.validate().unwrap(); } @@ -447,6 +461,7 @@ mod test { vec![&tx1], &keychain, &key_id3.clone(), + Difficulty::minimum(), ).unwrap(); b.validate().unwrap(); @@ -467,6 +482,7 @@ mod test { vec![&tx1], &keychain, &key_id3.clone(), + Difficulty::minimum(), ).unwrap(); match b.validate() { Err(KernelLockHeight { lock_height: height }) => { diff --git a/grin/src/miner.rs b/grin/src/miner.rs index 73fa692dd..7668fd547 100644 --- a/grin/src/miner.rs +++ b/grin/src/miner.rs @@ -542,7 +542,7 @@ impl Miner { head: &core::BlockHeader, key_id: Option, ) -> Result<(core::Block, BlockFees), Error> { - + // prepare the block header timestamp let mut now_sec = time::get_time().sec; let head_sec = head.timestamp.to_timespec().sec; @@ -571,15 +571,16 @@ impl Miner { }; let (output, kernel, block_fees) = self.get_coinbase(block_fees)?; - let mut b = core::Block::with_reward(head, txs, output, kernel)?; + let mut b = core::Block::with_reward(head, txs, output, kernel, difficulty.clone())?; debug!( LOGGER, - "(Server ID: {}) Built new block with {} inputs and {} outputs, difficulty: {}", + "(Server ID: {}) Built new block with {} inputs and {} outputs, network difficulty: {}, block cumulative difficulty {}", self.debug_output_id, b.inputs.len(), b.outputs.len(), - difficulty + difficulty.clone().into_num(), + b.header.clone().difficulty.clone().into_num(), ); // making sure we're not spending time mining a useless block @@ -590,18 +591,19 @@ impl Miner { b.header.difficulty = difficulty; b.header.timestamp = time::at_utc(time::Timespec::new(now_sec, 0)); trace!(LOGGER, "Block: {:?}", b); - + let roots_result = self.chain.set_sumtree_roots(&mut b, false); + match roots_result { Ok(_) => Ok((b, block_fees)), - + // If it's a duplicate commitment, it's likely trying to use // a key that's already been derived but not in the wallet // for some reason, allow caller to retry Err(chain::Error::DuplicateCommitment(e)) => { Err(Error::Chain(chain::Error::DuplicateCommitment(e))) } - + //Some other issue, possibly duplicate kernel Err(e) => { error!(LOGGER, "Error setting sumtree root to build a block: {:?}", e); diff --git a/pool/src/pool.rs b/pool/src/pool.rs index 08d6edab7..bd4aa1ab8 100644 --- a/pool/src/pool.rs +++ b/pool/src/pool.rs @@ -20,6 +20,7 @@ pub use graph; use core::core::transaction; use core::core::block; use core::core::hash; +use core::core::target::Difficulty; use core::global; use util::secp::pedersen::Commitment; @@ -930,6 +931,7 @@ mod tests { txs.iter().collect(), &keychain, &key_id, + Difficulty::minimum(), ).unwrap(); // now apply the block to ensure the chainstate is updated before we reconcile @@ -1060,6 +1062,7 @@ mod tests { block_transactions, &keychain, &key_id, + Difficulty::minimum(), ).unwrap(); chain_ref.apply_block(&block); @@ -1183,8 +1186,13 @@ mod tests { let keychain = Keychain::from_random_seed().unwrap(); let key_id = keychain.derive_key_id(1).unwrap(); - block = block::Block::new(&block::BlockHeader::default(), tx_refs, &keychain, &key_id) - .unwrap(); + block = block::Block::new( + &block::BlockHeader::default(), + tx_refs, + &keychain, + &key_id, + Difficulty::minimum() + ).unwrap(); } chain_ref.apply_block(&block);