mirror of
https://github.com/mimblewimble/grin.git
synced 2025-01-20 19:11:08 +03:00
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
This commit is contained in:
parent
5edc63f617
commit
8b2f9503c9
8 changed files with 114 additions and 28 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -292,10 +292,11 @@ impl Block {
|
|||
txs: Vec<&Transaction>,
|
||||
keychain: &keychain::Keychain,
|
||||
key_id: &keychain::Identifier,
|
||||
difficulty: Difficulty,
|
||||
) -> Result<Block, Error> {
|
||||
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<Block, Error> {
|
||||
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
|
||||
|
|
|
@ -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 }) => {
|
||||
|
|
|
@ -542,7 +542,7 @@ impl Miner {
|
|||
head: &core::BlockHeader,
|
||||
key_id: Option<Identifier>,
|
||||
) -> 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);
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue