diff --git a/Cargo.lock b/Cargo.lock index c0a683173..1a6538407 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,7 +1,3 @@ -[root] -name = "using_queue" -version = "0.1.0" - [[package]] name = "advapi32-sys" version = "0.2.0" @@ -277,7 +273,7 @@ dependencies = [ name = "common-types" version = "0.1.0" dependencies = [ - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "ethjson 0.1.0", "rlp 0.2.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -476,7 +472,7 @@ dependencies = [ "ethcore-ipc-nano 1.7.0", "ethcore-logger 1.7.0", "ethcore-stratum 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "ethjson 0.1.0", "ethkey 0.2.0", "ethstore 0.1.0", @@ -545,7 +541,7 @@ name = "ethcore-ipc" version = "1.7.0" dependencies = [ "ethcore-devtools 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -594,7 +590,7 @@ dependencies = [ "ethcore-ipc 1.7.0", "ethcore-ipc-codegen 1.7.0", "ethcore-ipc-nano 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -611,7 +607,7 @@ dependencies = [ "ethcore-ipc 1.7.0", "ethcore-ipc-codegen 1.7.0", "ethcore-network 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "evm 0.1.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -650,7 +646,7 @@ dependencies = [ "ethcore-devtools 1.7.0", "ethcore-io 1.7.0", "ethcore-logger 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "ethcrypto 0.1.0", "ethkey 0.2.0", "igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -681,7 +677,7 @@ dependencies = [ "ethcore-ipc-codegen 1.7.0", "ethcore-ipc-nano 1.7.0", "ethcore-logger 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "ethcrypto 0.1.0", "ethkey 0.2.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -711,7 +707,7 @@ dependencies = [ "ethcore-ipc-codegen 1.7.0", "ethcore-ipc-nano 1.7.0", "ethcore-logger 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -724,7 +720,7 @@ dependencies = [ [[package]] name = "ethcore-util" -version = "1.7.9" +version = "1.7.10" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", @@ -774,7 +770,7 @@ name = "ethjson" version = "0.1.0" dependencies = [ "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -855,7 +851,7 @@ dependencies = [ "ethcore-ipc-nano 1.7.0", "ethcore-light 1.7.0", "ethcore-network 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "ethkey 0.2.0", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -874,7 +870,7 @@ dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "ethjson 0.1.0", "evmjit 1.7.0", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -891,7 +887,7 @@ version = "0.1.0" dependencies = [ "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "ethjson 0.1.0", "evm 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1136,7 +1132,7 @@ version = "1.7.0" dependencies = [ "ethcore-ipc 1.7.0", "ethcore-ipc-codegen 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1530,7 +1526,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "native-contract-generator 0.1.0", ] @@ -1735,7 +1731,7 @@ dependencies = [ [[package]] name = "parity" -version = "1.7.9" +version = "1.7.10" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1755,7 +1751,7 @@ dependencies = [ "ethcore-logger 1.7.0", "ethcore-secretstore 1.0.0", "ethcore-stratum 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "ethkey 0.2.0", "ethsync 1.7.0", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1801,7 +1797,7 @@ dependencies = [ "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-devtools 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "fetch 0.1.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1845,7 +1841,7 @@ name = "parity-hash-fetch" version = "1.7.0" dependencies = [ "ethabi 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "fetch 0.1.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1863,7 +1859,7 @@ version = "1.7.0" dependencies = [ "cid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "multihash 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1876,7 +1872,7 @@ version = "0.1.0" dependencies = [ "ethcore 1.7.0", "ethcore-io 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "ethkey 0.2.0", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0", @@ -1906,7 +1902,7 @@ dependencies = [ "ethcore-ipc 1.7.0", "ethcore-light 1.7.0", "ethcore-logger 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "ethcrypto 0.1.0", "ethjson 0.1.0", "ethkey 0.2.0", @@ -1948,7 +1944,7 @@ dependencies = [ name = "parity-rpc-client" version = "1.4.0" dependencies = [ - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-ws-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -2011,7 +2007,7 @@ dependencies = [ "ethcore 1.7.0", "ethcore-ipc 1.7.0", "ethcore-ipc-codegen 1.7.0", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "ethsync 1.7.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-common-types 1.7.0", @@ -2367,7 +2363,7 @@ name = "rpc-cli" version = "1.4.0" dependencies = [ "bigint 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-util 1.7.9", + "ethcore-util 1.7.10", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-rpc 1.7.0", "parity-rpc-client 1.4.0", @@ -2997,6 +2993,10 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "using_queue" +version = "0.1.0" + [[package]] name = "utf8-ranges" version = "1.0.0" diff --git a/Cargo.toml b/Cargo.toml index 5e7d16af6..a4420eafa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Parity Ethereum client" name = "parity" -version = "1.7.9" +version = "1.7.10" license = "GPL-3.0" authors = ["Parity Technologies "] build = "build.rs" diff --git a/dapps/node-health/src/time.rs b/dapps/node-health/src/time.rs index 588af6659..157682fe9 100644 --- a/dapps/node-health/src/time.rs +++ b/dapps/node-health/src/time.rs @@ -193,7 +193,7 @@ const UPDATE_TIMEOUT_ERR_SECS: u64 = 60; const UPDATE_TIMEOUT_INCOMPLETE_SECS: u64 = 10; /// Maximal valid time drift. -pub const MAX_DRIFT: i64 = 500; +pub const MAX_DRIFT: i64 = 10_000; #[derive(Debug, Clone)] /// A time checker. diff --git a/ethcore/res/ethereum/kovan.json b/ethcore/res/ethereum/kovan.json index 7cdb79e16..83226a463 100644 --- a/ethcore/res/ethereum/kovan.json +++ b/ethcore/res/ethereum/kovan.json @@ -26,15 +26,21 @@ }, "validateScoreTransition": 1000000, "eip155Transition": 1000000, - "validateStepTransition": 1500000 - } + "validateStepTransition": 1500000, + "maximumUncleCountTransition": 5100000, + "maximumUncleCount": 0 + } } }, "params": { "maximumExtraDataSize": "0x20", "minGasLimit": "0x1388", "networkID" : "0x2A", - "validateReceiptsTransition" : 1000000 + "validateReceiptsTransition" : 1000000, + "eip140Transition": 5100000, + "eip211Transition": 5100000, + "eip214Transition": 5100000, + "eip658Transition": 5100000 }, "genesis": { "seal": { @@ -49,8 +55,12 @@ "accounts": { "0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, "0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, - "0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, - "0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, + "0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, + "0x0000000000000000000000000000000000000005": { "builtin": { "name": "modexp", "activate_at": 5100000, "pricing": { "modexp": { "divisor": 20 } } } }, + "0x0000000000000000000000000000000000000006": { "builtin": { "name": "alt_bn128_add", "activate_at": 5100000, "pricing": { "linear": { "base": 500, "word": 0 } } } }, + "0x0000000000000000000000000000000000000007": { "builtin": { "name": "alt_bn128_mul", "activate_at": 5100000, "pricing": { "linear": { "base": 40000, "word": 0 } } } }, + "0x0000000000000000000000000000000000000008": { "builtin": { "name": "alt_bn128_pairing", "activate_at": 5100000, "pricing": { "alt_bn128_pairing": { "base": 100000, "pair": 80000 } } } }, "0x00521965e7bd230323c423d96c657db5b79d099f": { "balance": "1606938044258990275541962092341162602522202993782792835301376" } }, "nodes": [ diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 6d3e406fc..c3b475cbc 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -324,8 +324,13 @@ impl<'x> OpenBlock<'x> { /// NOTE Will check chain constraints and the uncle number but will NOT check /// that the header itself is actually valid. pub fn push_uncle(&mut self, valid_uncle_header: Header) -> Result<(), BlockError> { - if self.block.uncles.len() + 1 > self.engine.maximum_uncle_count() { - return Err(BlockError::TooManyUncles(OutOfBounds{min: None, max: Some(self.engine.maximum_uncle_count()), found: self.block.uncles.len() + 1})); + let max_uncles = self.engine.maximum_uncle_count(self.block.header().number()); + if self.block.uncles.len() + 1 > max_uncles { + return Err(BlockError::TooManyUncles(OutOfBounds{ + min: None, + max: Some(max_uncles), + found: self.block.uncles.len() + 1, + })); } // TODO: check number // TODO: check not a direct ancestor (use last_hashes for that) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 9d359aef6..3a2aa4425 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1192,12 +1192,12 @@ impl BlockChainClient for Client { } fn estimate_gas(&self, t: &SignedTransaction, block: BlockId) -> Result { - const UPPER_CEILING: u64 = 1_000_000_000_000u64; - let (mut upper, env_info) = { + let (mut upper, max_upper, env_info) = { let mut env_info = self.env_info(block).ok_or(CallError::StatePruned)?; - let initial_upper = env_info.gas_limit; - env_info.gas_limit = UPPER_CEILING.into(); - (initial_upper, env_info) + let init = env_info.gas_limit; + let max = init * U256::from(10); + env_info.gas_limit = max; + (init, max, env_info) }; // that's just a copy of the state. @@ -1218,9 +1218,7 @@ impl BlockChainClient for Client { }; if !cond(upper)? { - // impossible at block gas limit - try `UPPER_CEILING` instead. - // TODO: consider raising limit by powers of two. - upper = UPPER_CEILING.into(); + upper = max_upper; if !cond(upper)? { trace!(target: "estimate_gas", "estimate_gas failed with {}", upper); let err = ExecutionError::Internal(format!("Requires higher than upper limit of {}", upper)); @@ -1788,7 +1786,7 @@ impl MiningBlockChainClient for Client { .find_uncle_headers(&h, engine.maximum_uncle_age()) .unwrap_or_else(Vec::new) .into_iter() - .take(engine.maximum_uncle_count()) + .take(engine.maximum_uncle_count(open_block.header().number())) .foreach(|h| { open_block.push_uncle(h).expect("pushing maximum_uncle_count; open_block was just created; @@ -1803,7 +1801,7 @@ impl MiningBlockChainClient for Client { fn reopen_block(&self, block: ClosedBlock) -> OpenBlock { let engine = &*self.engine; let mut block = block.reopen(engine); - let max_uncles = engine.maximum_uncle_count(); + let max_uncles = engine.maximum_uncle_count(block.header().number()); if block.uncles().len() < max_uncles { let chain = self.chain.read(); let h = chain.best_block_hash(); diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 83eadc422..295ad9c23 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -67,6 +67,10 @@ pub struct AuthorityRoundParams { pub validate_step_transition: u64, /// Immediate transitions. pub immediate_transitions: bool, + /// Number of accepted uncles transition block. + pub maximum_uncle_count_transition: u64, + /// Number of accepted uncles. + pub maximum_uncle_count: usize, } impl From for AuthorityRoundParams { @@ -82,6 +86,8 @@ impl From for AuthorityRoundParams { eip155_transition: p.eip155_transition.map_or(0, Into::into), validate_step_transition: p.validate_step_transition.map_or(0, Into::into), immediate_transitions: p.immediate_transitions.unwrap_or(false), + maximum_uncle_count_transition: p.maximum_uncle_count_transition.map_or(0, Into::into), + maximum_uncle_count: p.maximum_uncle_count.map_or(0, Into::into), } } } @@ -125,6 +131,11 @@ impl Step { } } +// Chain scoring: total weight is sqrt(U256::max_value())*height - step +fn calculate_score(parent_step: U256, current_step: U256) -> U256 { + U256::from(U128::max_value()) + parent_step - current_step +} + struct EpochManager { epoch_transition_hash: H256, epoch_transition_number: BlockNumber, @@ -229,6 +240,8 @@ pub struct AuthorityRound { validate_step_transition: u64, epoch_manager: Mutex, immediate_transitions: bool, + maximum_uncle_count_transition: u64, + maximum_uncle_count: usize, } // header-chain validator. @@ -381,6 +394,8 @@ impl AuthorityRound { validate_step_transition: our_params.validate_step_transition, epoch_manager: Mutex::new(EpochManager::blank()), immediate_transitions: our_params.immediate_transitions, + maximum_uncle_count_transition: our_params.maximum_uncle_count_transition, + maximum_uncle_count: our_params.maximum_uncle_count, }); // Do not initialize timeouts for tests. @@ -455,10 +470,19 @@ impl Engine for AuthorityRound { ] } + fn maximum_uncle_count(&self, block: BlockNumber) -> usize { + if block >= self.maximum_uncle_count_transition { + self.maximum_uncle_count + } else { + // fallback to default value + 2 + } + } + fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) { - // Chain scoring: total weight is sqrt(U256::max_value())*height - step - let new_difficulty = U256::from(U128::max_value()) + header_step(parent).expect("Header has been verified; qed").into() - self.step.load().into(); - header.set_difficulty(new_difficulty); + let parent_step = header_step(parent).expect("Header has been verified; qed"); + let score = calculate_score(parent_step.into(), self.step.load().into()); + header.set_difficulty(score); header.set_gas_limit({ let gas_limit = parent.gas_limit().clone(); let bound_divisor = self.gas_limit_bound_divisor; @@ -471,20 +495,29 @@ impl Engine for AuthorityRound { } fn seals_internally(&self) -> Option { + // TODO: accept a `&Call` here so we can query the validator set. Some(self.signer.read().is_some()) } /// Attempt to seal the block internally. /// - /// This operation is synchronous and may (quite reasonably) not be available, in which `false` will - /// be returned. - fn generate_seal(&self, block: &ExecutedBlock) -> Seal { + /// This operation is synchronous and may (quite reasonably) not be available, in which case + /// `Seal::None` will be returned. + fn generate_seal(&self, block: &ExecutedBlock, parent: &Header) -> Seal { // first check to avoid generating signature most of the time // (but there's still a race to the `compare_and_swap`) if !self.can_propose.load(AtomicOrdering::SeqCst) { return Seal::None; } let header = block.header(); + let parent_step: U256 = header_step(parent) + .expect("Header has been verified; qed").into(); + let step = self.step.load(); + let expected_diff = calculate_score(parent_step, step.into()); + + if header.difficulty() != &expected_diff { + return Seal::None; + } // fetch correct validator set for current epoch, taking into account // finality of previous transitions. @@ -526,6 +559,7 @@ impl Engine for AuthorityRound { trace!(target: "engine", "generate_seal: {} not a proposer for step {}.", header.author(), step); } + Seal::None } @@ -924,17 +958,51 @@ mod tests { let b2 = b2.close_and_lock(); engine.set_signer(tap.clone(), addr1, "1".into()); - if let Seal::Regular(seal) = engine.generate_seal(b1.block()) { + if let Seal::Regular(seal) = engine.generate_seal(b1.block(), &genesis_header) { assert!(b1.clone().try_seal(engine, seal).is_ok()); // Second proposal is forbidden. - assert!(engine.generate_seal(b1.block()) == Seal::None); + assert!(engine.generate_seal(b1.block(), &genesis_header) == Seal::None); } engine.set_signer(tap, addr2, "2".into()); - if let Seal::Regular(seal) = engine.generate_seal(b2.block()) { + if let Seal::Regular(seal) = engine.generate_seal(b2.block(), &genesis_header) { assert!(b2.clone().try_seal(engine, seal).is_ok()); // Second proposal is forbidden. - assert!(engine.generate_seal(b2.block()) == Seal::None); + assert!(engine.generate_seal(b2.block(), &genesis_header) == Seal::None); + } + } + + #[test] + fn checks_difficulty_in_generate_seal() { + let tap = Arc::new(AccountProvider::transient_provider()); + let addr1 = tap.insert_account("1".sha3().into(), "1").unwrap(); + let addr2 = tap.insert_account("0".sha3().into(), "0").unwrap(); + + let spec = Spec::new_test_round(); + let engine = &*spec.engine; + + let genesis_header = spec.genesis_header(); + let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); + let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap(); + let last_hashes = Arc::new(vec![genesis_header.hash()]); + + let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b1 = b1.close_and_lock(); + let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap(); + let b2 = b2.close_and_lock(); + + engine.set_signer(tap.clone(), addr1, "1".into()); + match engine.generate_seal(b1.block(), &genesis_header) { + Seal::None | Seal::Proposal(_) => panic!("wrong seal"), + Seal::Regular(_) => { + engine.step(); + + engine.set_signer(tap.clone(), addr2, "0".into()); + match engine.generate_seal(b2.block(), &genesis_header) { + Seal::Regular(_) | Seal::Proposal(_) => panic!("sealed despite wrong difficulty"), + Seal::None => {} + } + } } } @@ -1027,7 +1095,10 @@ mod tests { validate_step_transition: 0, eip155_transition: 0, immediate_transitions: true, + maximum_uncle_count_transition: 0, + maximum_uncle_count: 0, }; + let aura = AuthorityRound::new(Default::default(), params, Default::default()).unwrap(); let mut parent_header: Header = Header::default(); @@ -1047,4 +1118,29 @@ mod tests { assert!(aura.verify_block_family(&header, &parent_header, None).is_ok()); assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 1); } + + #[test] + fn test_uncles_transition() { + let last_benign = Arc::new(AtomicUsize::new(0)); + let params = AuthorityRoundParams { + gas_limit_bound_divisor: 5.into(), + step_duration: Default::default(), + block_reward: Default::default(), + registrar: Default::default(), + start_step: Some(1), + validators: Box::new(TestSet::new(Default::default(), last_benign.clone())), + validate_score_transition: 0, + validate_step_transition: 0, + eip155_transition: 0, + immediate_transitions: true, + maximum_uncle_count_transition: 1, + maximum_uncle_count: 0, + }; + + let aura = AuthorityRound::new(Default::default(), params, Default::default()).unwrap(); + + assert_eq!(aura.maximum_uncle_count(0), 2); + assert_eq!(aura.maximum_uncle_count(1), 0); + assert_eq!(aura.maximum_uncle_count(100), 0); + } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 68759131d..3431bbb07 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -133,7 +133,7 @@ impl Engine for BasicAuthority { } /// Attempt to seal the block internally. - fn generate_seal(&self, block: &ExecutedBlock) -> Seal { + fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal { let header = block.header(); let author = header.author(); if self.validators.contains(header.parent_hash(), author) { @@ -320,7 +320,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![], false).unwrap(); let b = b.close_and_lock(); - if let Seal::Regular(seal) = engine.generate_seal(b.block()) { + if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 38834622c..ebd0a10bc 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -18,6 +18,7 @@ use std::collections::BTreeMap; use util::{Address, HashMap}; use builtin::Builtin; use engines::{Engine, Seal}; +use header::Header; use spec::CommonParams; use block::ExecutedBlock; @@ -58,8 +59,8 @@ impl Engine for InstantSeal { fn seals_internally(&self) -> Option { Some(true) } - fn generate_seal(&self, _block: &ExecutedBlock) -> Seal { - Seal::Regular(Vec::new()) + fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal { + if block.fields().transactions.is_empty() { Seal::None } else { Seal::Regular(Vec::new()) } } } @@ -81,7 +82,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![], false).unwrap(); let b = b.close_and_lock(); - if let Seal::Regular(seal) = engine.generate_seal(b.block()) { + if let Seal::Regular(seal) = engine.generate_seal(b.block(), &genesis_header) { assert!(b.try_seal(engine, seal).is_ok()); } } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 412766200..59b2d4a35 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -203,7 +203,8 @@ pub trait Engine : Sync + Send { /// Some intrinsic operation parameters; by default they take their value from the `spec()`'s `engine_params`. fn maximum_extra_data_size(&self) -> usize { self.params().maximum_extra_data_size } /// Maximum number of uncles a block is allowed to declare. - fn maximum_uncle_count(&self) -> usize { 2 } + fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 0 } + /// The number of generations back that uncles can be. fn maximum_uncle_age(&self) -> usize { 6 } /// The nonce with which accounts begin at given block. @@ -242,7 +243,10 @@ pub trait Engine : Sync + Send { /// /// This operation is synchronous and may (quite reasonably) not be available, in which None will /// be returned. - fn generate_seal(&self, _block: &ExecutedBlock) -> Seal { Seal::None } + /// + /// It is fine to require access to state or a full client for this function, since + /// light clients do not generate seals. + fn generate_seal(&self, _block: &ExecutedBlock, _parent: &Header) -> Seal { Seal::None } /// Phase 1 quick block verification. Only does checks that are cheap. `block` (the header's full block) /// may be provided for additional checks. Returns either a null `Ok` or a general error detailing the problem with import. diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index 552154580..00b6000d6 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -57,6 +57,8 @@ impl Engine for NullEngine { &self.builtins } + fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 } + fn schedule(&self, _block_number: BlockNumber) -> Schedule { Schedule::new_homestead() } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index f40c7539e..4340f52a0 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -391,7 +391,7 @@ impl Engine for Tendermint { fn builtins(&self) -> &BTreeMap { &self.builtins } - fn maximum_uncle_count(&self) -> usize { 0 } + fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 0 } fn maximum_uncle_age(&self) -> usize { 0 } @@ -427,7 +427,10 @@ impl Engine for Tendermint { } /// Attempt to seal generate a proposal seal. - fn generate_seal(&self, block: &ExecutedBlock) -> Seal { + /// + /// This operation is synchronous and may (quite reasonably) not be available, in which case + /// `Seal::None` will be returned. + fn generate_seal(&self, block: &ExecutedBlock, _parent: &Header) -> Seal { let header = block.header(); let author = header.author(); // Only proposer can generate seal if None was generated. @@ -681,7 +684,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db.boxed_clone(), &genesis_header, last_hashes, proposer, (3141562.into(), 31415620.into()), vec![], false).unwrap(); let b = b.close(); - if let Seal::Proposal(seal) = spec.engine.generate_seal(b.block()) { + if let Seal::Proposal(seal) = spec.engine.generate_seal(b.block(), &genesis_header) { (b, seal) } else { panic!() diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 68c769c7c..4592753f9 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -217,7 +217,7 @@ impl Engine for Arc { } else if block_number < self.ethash_params.eip150_transition { Schedule::new_homestead() } else { - /// There's no max_code_size transition so we tie it to eip161abc + // There's no max_code_size transition so we tie it to eip161abc let max_code_size = if block_number >= self.ethash_params.eip161abc_transition { self.ethash_params.max_code_size as usize } else { usize::max_value() }; let mut schedule = Schedule::new_post_eip150( max_code_size, @@ -238,6 +238,8 @@ impl Engine for Arc { } } + fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 } + fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, mut gas_ceil_target: U256) { let difficulty = self.calculate_difficulty(header, parent); if header.number() >= self.ethash_params.max_gas_limit_transition && gas_ceil_target > self.ethash_params.max_gas_limit { diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index af173ec70..2f190b85e 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -499,7 +499,13 @@ impl Miner { fn seal_and_import_block_internally(&self, chain: &MiningBlockChainClient, block: ClosedBlock) -> bool { if !block.transactions().is_empty() || self.forced_sealing() || Instant::now() > *self.next_mandatory_reseal.read() { trace!(target: "miner", "seal_block_internally: attempting internal seal."); - match self.engine.generate_seal(block.block()) { + + let parent_header = match chain.block_header(BlockId::Hash(*block.header().parent_hash())) { + Some(hdr) => hdr.decode(), + None => return false, + }; + + match self.engine.generate_seal(block.block(), &parent_header) { // Save proposal for later seal submission and broadcast it. Seal::Proposal(seal) => { trace!(target: "miner", "Received a Proposal seal."); diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 0ff9612fa..a6e586c02 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -110,9 +110,14 @@ pub fn verify_block_family(header: &Header, bytes: &[u8], engine: &Engine, bc: & engine.verify_block_family(&header, &parent, Some(bytes))?; let num_uncles = UntrustedRlp::new(bytes).at(2)?.item_count()?; + let max_uncles = engine.maximum_uncle_count(header.number()); if num_uncles != 0 { - if num_uncles > engine.maximum_uncle_count() { - return Err(From::from(BlockError::TooManyUncles(OutOfBounds { min: None, max: Some(engine.maximum_uncle_count()), found: num_uncles }))); + if num_uncles > max_uncles { + return Err(From::from(BlockError::TooManyUncles(OutOfBounds { + min: None, + max: Some(max_uncles), + found: num_uncles, + }))); } let mut excluded = HashSet::new(); @@ -571,7 +576,7 @@ mod tests { let mut bad_uncles = good_uncles.clone(); bad_uncles.push(good_uncle1.clone()); check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc), - TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count()), min: None, found: bad_uncles.len() })); + TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count(header.number())), min: None, found: bad_uncles.len() })); header = good.clone(); bad_uncles = vec![ good_uncle1.clone(), good_uncle1.clone() ]; diff --git a/json/src/spec/authority_round.rs b/json/src/spec/authority_round.rs index 0fdbfbfb3..67a1d8a68 100644 --- a/json/src/spec/authority_round.rs +++ b/json/src/spec/authority_round.rs @@ -52,6 +52,12 @@ pub struct AuthorityRoundParams { /// Whether transitions should be immediate. #[serde(rename="immediateTransitions")] pub immediate_transitions: Option, + /// Block at which maximum uncle count should be considered. + #[serde(rename="maximumUncleCountTransition")] + pub maximum_uncle_count_transition: Option, + /// Maximum number of accepted uncles. + #[serde(rename="maximumUncleCount")] + pub maximum_uncle_count: Option, } /// Authority engine deserialization. @@ -84,6 +90,8 @@ mod tests { "startStep" : 24, "eip155Transition": "0x42", "validateStepTransition": 150 + "maximumUncleCountTransition": 10000000, + "maximumUncleCount": 5 } }"#; @@ -96,5 +104,8 @@ mod tests { assert_eq!(deserialized.params.start_step, Some(Uint(U256::from(24)))); assert_eq!(deserialized.params.eip155_transition, Some(Uint(U256::from(0x42)))); assert_eq!(deserialized.params.immediate_transitions, None); + + assert_eq!(deserialized.params.maximum_uncle_count_transition, Some(Uint(10_000_000.into()))); + assert_eq!(deserialized.params.maximum_uncle_count, Some(Uint(5.into()))); } } diff --git a/mac/Parity.pkgproj b/mac/Parity.pkgproj index 9cbb1bde3..fc9ffed06 100755 --- a/mac/Parity.pkgproj +++ b/mac/Parity.pkgproj @@ -462,7 +462,7 @@ OVERWRITE_PERMISSIONS VERSION - 1.7.9 + 1.7.10 UUID 2DCD5B81-7BAF-4DA1-9251-6274B089FD36 diff --git a/nsis/installer.nsi b/nsis/installer.nsi index 8b4a6d5b9..d1efdaa4e 100644 --- a/nsis/installer.nsi +++ b/nsis/installer.nsi @@ -10,7 +10,7 @@ !define DESCRIPTION "Fast, light, robust Ethereum implementation" !define VERSIONMAJOR 1 !define VERSIONMINOR 7 -!define VERSIONBUILD 9 +!define VERSIONBUILD 10 !define ARGS "--warp" !define FIRST_START_ARGS "ui --warp --mode=passive" diff --git a/util/Cargo.toml b/util/Cargo.toml index e78906f1d..5ca9fa4a5 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore utility library" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-util" -version = "1.7.9" +version = "1.7.10" authors = ["Parity Technologies "] build = "build.rs"