diff --git a/ethcore/res/ethereum/kovan.json b/ethcore/res/ethereum/kovan.json index 325b7cdf6..7ce019ee8 100644 --- a/ethcore/res/ethereum/kovan.json +++ b/ethcore/res/ethereum/kovan.json @@ -23,7 +23,9 @@ ] }, "validateScoreTransition": 1000000, - "validateStepTransition": 1500000 + "validateStepTransition": 1500000, + "maximumUncleCountTransition": 10000000, + "maximumUncleCount": 2 } } }, diff --git a/ethcore/res/wasm-tests b/ethcore/res/wasm-tests index 9a1fcbf0d..d6185ea16 160000 --- a/ethcore/res/wasm-tests +++ b/ethcore/res/wasm-tests @@ -1 +1 @@ -Subproject commit 9a1fcbf0d4e73bea437577e807bc38c7ba243d80 +Subproject commit d6185ea16eaba7ff685c069c2064819f9549c4d7 diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index d701a17eb..ddf72be2c 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -380,8 +380,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 785d9782f..3cca37679 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1230,12 +1230,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. @@ -1256,9 +1256,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)); @@ -1871,7 +1869,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; @@ -1886,7 +1884,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 27bd678a9..c0d607e98 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -65,6 +65,10 @@ pub struct AuthorityRoundParams { pub immediate_transitions: bool, /// Block reward in base units. pub block_reward: U256, + /// 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 { @@ -77,6 +81,8 @@ impl From for AuthorityRoundParams { validate_step_transition: p.validate_step_transition.map_or(0, Into::into), immediate_transitions: p.immediate_transitions.unwrap_or(false), block_reward: p.block_reward.map_or_else(Default::default, Into::into), + 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), } } } @@ -218,6 +224,8 @@ pub struct AuthorityRound { epoch_manager: Mutex, immediate_transitions: bool, block_reward: U256, + maximum_uncle_count_transition: u64, + maximum_uncle_count: usize, machine: EthereumMachine, } @@ -365,6 +373,8 @@ impl AuthorityRound { epoch_manager: Mutex::new(EpochManager::blank()), immediate_transitions: our_params.immediate_transitions, block_reward: our_params.block_reward, + maximum_uncle_count_transition: our_params.maximum_uncle_count_transition, + maximum_uncle_count: our_params.maximum_uncle_count, machine: machine, }); @@ -436,6 +446,15 @@ 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) { // 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(); @@ -949,6 +968,8 @@ mod tests { validate_score_transition: 0, validate_step_transition: 0, immediate_transitions: true, + maximum_uncle_count_transition: 0, + maximum_uncle_count: 0, block_reward: Default::default(), }; @@ -976,4 +997,31 @@ mod tests { assert!(aura.verify_block_family(&header, &parent_header).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 { + step_duration: Default::default(), + start_step: Some(1), + validators: Box::new(TestSet::new(Default::default(), last_benign.clone())), + validate_score_transition: 0, + validate_step_transition: 0, + immediate_transitions: true, + maximum_uncle_count_transition: 1, + maximum_uncle_count: 0, + block_reward: Default::default(), + }; + + let aura = { + let mut c_params = ::spec::CommonParams::default(); + c_params.gas_limit_bound_divisor = 5.into(); + let machine = ::machine::EthereumMachine::regular(c_params, Default::default()); + AuthorityRound::new(params, machine).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/mod.rs b/ethcore/src/engines/mod.rs index 2e583b179..5ec1b77ac 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -192,7 +192,8 @@ pub trait Engine: Sync + Send { fn extra_info(&self, _header: &M::Header) -> BTreeMap { BTreeMap::new() } /// 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 } @@ -363,7 +364,7 @@ pub trait EthEngine: Engine<::machine::EthereumMachine> { } /// The nonce with which accounts begin at given block. - fn account_start_nonce(&self, block: u64) -> U256 { + fn account_start_nonce(&self, block: BlockNumber) -> U256 { self.machine().account_start_nonce(block) } diff --git a/ethcore/src/engines/null_engine.rs b/ethcore/src/engines/null_engine.rs index 1c7edc99b..cc48a225a 100644 --- a/ethcore/src/engines/null_engine.rs +++ b/ethcore/src/engines/null_engine.rs @@ -16,6 +16,7 @@ use bigint::prelude::U256; use engines::Engine; +use header::BlockNumber; use parity_machine::{Header, LiveBlock, WithBalances}; /// Params for a null engine. @@ -95,6 +96,8 @@ impl Engine for NullEngine { self.machine.note_rewards(block, &[(author, result_block_reward)], &uncle_rewards) } + fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 } + fn verify_local_seal(&self, _header: &M::Header) -> Result<(), M::Error> { Ok(()) } diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 3ccc79baa..ac43acc09 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -450,7 +450,7 @@ impl Engine for Tendermint { fn machine(&self) -> &EthereumMachine { &self.machine } - fn maximum_uncle_count(&self) -> usize { 0 } + fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 0 } fn maximum_uncle_age(&self) -> usize { 0 } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index a49ba2e2a..55f0d58de 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -26,7 +26,7 @@ use util::Address; use unexpected::{OutOfBounds, Mismatch}; use block::*; use error::{BlockError, Error}; -use header::Header; +use header::{Header, BlockNumber}; use engines::{self, Engine}; use ethjson; use rlp::{self, UntrustedRlp}; @@ -181,6 +181,8 @@ impl Engine for Arc { } } + fn maximum_uncle_count(&self, _block: BlockNumber) -> usize { 2 } + fn populate_from_parent(&self, header: &mut Header, parent: &Header) { let difficulty = self.calculate_difficulty(header, parent); header.set_difficulty(difficulty); @@ -447,9 +449,12 @@ fn ecip1017_eras_block_reward(era_rounds: u64, mut reward: U256, block_number:u6 } else { block_number / era_rounds }; + let mut divi = U256::from(1); for _ in 0..eras { - reward = reward / U256::from(5) * U256::from(4); + reward = reward * U256::from(4); + divi = divi * U256::from(5); } + reward = reward / divi; (eras, reward) } @@ -515,6 +520,11 @@ mod tests { let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number); assert_eq!(15, eras); assert_eq!(U256::from_str("271000000000000").unwrap(), reward); + + let block_number = 250000000; + let (eras, reward) = ecip1017_eras_block_reward(eras_rounds, start_reward, block_number); + assert_eq!(49, eras); + assert_eq!(U256::from_str("51212FFBAF0A").unwrap(), reward); } #[test] diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index c56641916..2978774b0 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -137,9 +137,14 @@ pub fn verify_block_family(header: &Header, parent: &Header, engine: &EthEngine, fn verify_uncles(header: &Header, bytes: &[u8], bc: &BlockProvider, engine: &EthEngine) -> Result<(), Error> { 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(); @@ -653,7 +658,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/ethcore/wasm/src/env.rs b/ethcore/wasm/src/env.rs index 1a2f5fd3b..ed4bda68b 100644 --- a/ethcore/wasm/src/env.rs +++ b/ethcore/wasm/src/env.rs @@ -25,12 +25,12 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[ Static( "_storage_read", &[I32; 2], - Some(I32), + None, ), Static( "_storage_write", &[I32; 2], - Some(I32), + None, ), Static( "_balance", @@ -115,7 +115,7 @@ pub const SIGNATURES: &'static [UserFunctionDescriptor] = &[ Static( "_blockhash", &[I64, I32], - Some(I32), + None, ), Static( "_coinbase", diff --git a/ethcore/wasm/src/lib.rs b/ethcore/wasm/src/lib.rs index 70601144d..30ce03665 100644 --- a/ethcore/wasm/src/lib.rs +++ b/ethcore/wasm/src/lib.rs @@ -31,6 +31,7 @@ mod result; #[cfg(test)] mod tests; mod env; +mod panic_payload; const DEFAULT_STACK_SPACE: u32 = 5 * 1024 * 1024; diff --git a/ethcore/wasm/src/panic_payload.rs b/ethcore/wasm/src/panic_payload.rs new file mode 100644 index 000000000..dc95f53fb --- /dev/null +++ b/ethcore/wasm/src/panic_payload.rs @@ -0,0 +1,168 @@ +// Copyright 2015-2017 Parity Technologies (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use byteorder::{LittleEndian, ReadBytesExt}; +use std::io::{self, Read}; + +#[derive(Debug, PartialEq, Eq)] +pub struct PanicPayload { + pub msg: Option, + pub file: Option, + pub line: Option, + pub col: Option, +} + +fn read_string(rdr: &mut io::Cursor<&[u8]>) -> io::Result> { + let string_len = rdr.read_u32::()?; + let string = if string_len == 0 { + None + } else { + let mut content = vec![0; string_len as usize]; + rdr.read_exact(&mut content)?; + Some(String::from_utf8_lossy(&content).into_owned()) + }; + Ok(string) +} + +pub fn decode(raw: &[u8]) -> PanicPayload { + let mut rdr = io::Cursor::new(raw); + let msg = read_string(&mut rdr).ok().and_then(|x| x); + let file = read_string(&mut rdr).ok().and_then(|x| x); + let line = rdr.read_u32::().ok(); + let col = rdr.read_u32::().ok(); + PanicPayload { + msg: msg, + file: file, + line: line, + col: col, + } +} + +#[cfg(test)] +mod tests { + use super::*; + use byteorder::WriteBytesExt; + + fn write_u32(payload: &mut Vec, val: u32) { + payload.write_u32::(val).unwrap(); + } + + fn write_bytes(payload: &mut Vec, bytes: &[u8]) { + write_u32(payload, bytes.len() as u32); + payload.extend(bytes); + } + + #[test] + fn it_works() { + let mut raw = Vec::new(); + write_bytes(&mut raw, b"msg"); + write_bytes(&mut raw, b"file"); + write_u32(&mut raw, 1); + write_u32(&mut raw, 2); + + let payload = decode(&raw); + + assert_eq!( + payload, + PanicPayload { + msg: Some("msg".to_string()), + file: Some("file".to_string()), + line: Some(1), + col: Some(2), + } + ); + } + + #[test] + fn only_msg() { + let mut raw = Vec::new(); + write_bytes(&mut raw, b"msg"); + + let payload = decode(&raw); + + assert_eq!( + payload, + PanicPayload { + msg: Some("msg".to_string()), + file: None, + line: None, + col: None, + } + ); + } + + #[test] + fn invalid_utf8() { + let mut raw = Vec::new(); + write_bytes(&mut raw, b"\xF0\x90\x80msg"); + write_bytes(&mut raw, b"file"); + write_u32(&mut raw, 1); + write_u32(&mut raw, 2); + + let payload = decode(&raw); + + assert_eq!( + payload, + PanicPayload { + msg: Some("�msg".to_string()), + file: Some("file".to_string()), + line: Some(1), + col: Some(2), + } + ); + } + + #[test] + fn trailing_data() { + let mut raw = Vec::new(); + write_bytes(&mut raw, b"msg"); + write_bytes(&mut raw, b"file"); + write_u32(&mut raw, 1); + write_u32(&mut raw, 2); + write_u32(&mut raw, 0xdeadbeef); + + let payload = decode(&raw); + + assert_eq!( + payload, + PanicPayload { + msg: Some("msg".to_string()), + file: Some("file".to_string()), + line: Some(1), + col: Some(2), + } + ); + } + + #[test] + fn empty_str_is_none() { + let mut raw = Vec::new(); + write_bytes(&mut raw, b"msg"); + write_bytes(&mut raw, b""); + + let payload = decode(&raw); + + assert_eq!( + payload, + PanicPayload { + msg: Some("msg".to_string()), + file: None, + line: None, + col: None, + } + ); + } +} diff --git a/ethcore/wasm/src/runtime.rs b/ethcore/wasm/src/runtime.rs index e5a6dc910..bad325fbf 100644 --- a/ethcore/wasm/src/runtime.rs +++ b/ethcore/wasm/src/runtime.rs @@ -21,6 +21,7 @@ use std::sync::Arc; use byteorder::{LittleEndian, ByteOrder}; use vm; +use panic_payload; use parity_wasm::interpreter; use wasm_utils::rules; use bigint::prelude::U256; @@ -167,7 +168,7 @@ impl<'a, 'b> Runtime<'a, 'b> { self.ext.set_storage(key, val).map_err(|_| UserTrap::StorageUpdateError)?; - Ok(Some(0i32.into())) + Ok(None) } /// Read from the storage to wasm memory @@ -183,7 +184,7 @@ impl<'a, 'b> Runtime<'a, 'b> { self.memory.set(val_ptr as u32, &*val)?; - Ok(Some(0.into())) + Ok(None) } /// Fetches balance for address @@ -626,12 +627,26 @@ impl<'a, 'b> Runtime<'a, 'b> { fn user_panic(&mut self, context: InterpreterCallerContext) -> Result, InterpreterError> { - let msg_len = context.value_stack.pop_as::()? as u32; - let msg_ptr = context.value_stack.pop_as::()? as u32; - - let msg = String::from_utf8(self.memory.get(msg_ptr, msg_len as usize)?) - .map_err(|_| UserTrap::BadUtf8)?; + let payload_len = context.value_stack.pop_as::()? as u32; + let payload_ptr = context.value_stack.pop_as::()? as u32; + let raw_payload = self.memory.get(payload_ptr, payload_len as usize)?; + let payload = panic_payload::decode(&raw_payload); + let msg = format!( + "{msg}, {file}:{line}:{col}", + msg = payload + .msg + .as_ref() + .map(String::as_ref) + .unwrap_or(""), + file = payload + .file + .as_ref() + .map(String::as_ref) + .unwrap_or(""), + line = payload.line.unwrap_or(0), + col = payload.col.unwrap_or(0) + ); trace!(target: "wasm", "Contract custom panic message: {}", msg); Err(UserTrap::Panic(msg).into()) @@ -650,7 +665,7 @@ impl<'a, 'b> Runtime<'a, 'b> { self.memory.set(return_ptr, &*hash)?; - Ok(Some(0i32.into())) + Ok(None) } fn return_address_ptr(&mut self, ptr: u32, val: Address) -> Result<(), InterpreterError> diff --git a/ethcore/wasm/src/tests.rs b/ethcore/wasm/src/tests.rs index 0a93be11c..a387f9292 100644 --- a/ethcore/wasm/src/tests.rs +++ b/ethcore/wasm/src/tests.rs @@ -112,7 +112,7 @@ fn logger() { U256::from(1_000_000_000), "Logger sets 0x04 key to the trasferred value" ); - assert_eq!(gas_left, U256::from(19_143)); + assert_eq!(gas_left, U256::from(19_147)); } // This test checks if the contract can allocate memory and pass pointer to the result stream properly. @@ -180,7 +180,7 @@ fn dispersion() { result, vec![0u8, 0, 125, 11, 197, 7, 255, 8, 19, 0] ); - assert_eq!(gas_left, U256::from(99_469)); + assert_eq!(gas_left, U256::from(96_393)); } #[test] @@ -208,7 +208,7 @@ fn suicide_not() { result, vec![0u8] ); - assert_eq!(gas_left, U256::from(99_724)); + assert_eq!(gas_left, U256::from(96_725)); } #[test] @@ -240,7 +240,7 @@ fn suicide() { }; assert!(ext.suicides.contains(&refund)); - assert_eq!(gas_left, U256::from(99_663)); + assert_eq!(gas_left, U256::from(96_687)); } #[test] @@ -270,7 +270,7 @@ fn create() { assert!(ext.calls.contains( &FakeCall { call_type: FakeCallType::Create, - gas: U256::from(65_903), + gas: U256::from(65_899), sender_address: None, receive_address: None, value: Some(1_000_000_000.into()), @@ -278,7 +278,7 @@ fn create() { code_address: None, } )); - assert_eq!(gas_left, U256::from(65_896)); + assert_eq!(gas_left, U256::from(65_892)); } @@ -312,7 +312,7 @@ fn call_code() { assert!(ext.calls.contains( &FakeCall { call_type: FakeCallType::Call, - gas: U256::from(98_709), + gas: U256::from(98_713), sender_address: Some(sender), receive_address: Some(receiver), value: None, @@ -324,7 +324,7 @@ fn call_code() { // siphash result let res = LittleEndian::read_u32(&result[..]); assert_eq!(res, 4198595614); - assert_eq!(gas_left, U256::from(93_851)); + assert_eq!(gas_left, U256::from(93_855)); } #[test] @@ -357,7 +357,7 @@ fn call_static() { assert!(ext.calls.contains( &FakeCall { call_type: FakeCallType::Call, - gas: U256::from(98_709), + gas: U256::from(98_713), sender_address: Some(sender), receive_address: Some(receiver), value: None, @@ -370,7 +370,7 @@ fn call_static() { let res = LittleEndian::read_u32(&result[..]); assert_eq!(res, 317632590); - assert_eq!(gas_left, U256::from(93_851)); + assert_eq!(gas_left, U256::from(93_855)); } // Realloc test @@ -393,7 +393,7 @@ fn realloc() { } }; assert_eq!(result, vec![0u8; 2]); - assert_eq!(gas_left, U256::from(99_787)); + assert_eq!(gas_left, U256::from(96_723)); } // Tests that contract's ability to read from a storage @@ -419,7 +419,7 @@ fn storage_read() { }; assert_eq!(Address::from(&result[12..32]), address); - assert_eq!(gas_left, U256::from(99_702)); + assert_eq!(gas_left, U256::from(99_767)); } // Tests keccak calculation @@ -445,7 +445,7 @@ fn keccak() { }; assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87")); - assert_eq!(gas_left, U256::from(84_520)); + assert_eq!(gas_left, U256::from(81_446)); } // memcpy test. @@ -477,7 +477,7 @@ fn memcpy() { }; assert_eq!(result, test_payload); - assert_eq!(gas_left, U256::from(75_324)); + assert_eq!(gas_left, U256::from(72_216)); } // memmove test. @@ -509,7 +509,7 @@ fn memmove() { }; assert_eq!(result, test_payload); - assert_eq!(gas_left, U256::from(75_324)); + assert_eq!(gas_left, U256::from(72_216)); } // memset test @@ -534,7 +534,7 @@ fn memset() { }; assert_eq!(result, vec![228u8; 8192]); - assert_eq!(gas_left, U256::from(75_324)); + assert_eq!(gas_left, U256::from(72_196)); } macro_rules! reqrep_test { @@ -591,7 +591,7 @@ fn math_add() { U256::from_dec_str("1888888888888888888888888888887").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(98_576)); + assert_eq!(gas_left, U256::from(95_524)); } // multiplication @@ -613,7 +613,7 @@ fn math_mul() { U256::from_dec_str("888888888888888888888888888887111111111111111111111111111112").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(97_726)); + assert_eq!(gas_left, U256::from(94_674)); } // subtraction @@ -635,7 +635,7 @@ fn math_sub() { U256::from_dec_str("111111111111111111111111111111").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(98_568)); + assert_eq!(gas_left, U256::from(95_516)); } // subtraction with overflow @@ -677,7 +677,7 @@ fn math_div() { U256::from_dec_str("1125000").unwrap(), (&result[..]).into() ); - assert_eq!(gas_left, U256::from(91_564)); + assert_eq!(gas_left, U256::from(88_514)); } // This test checks the ability of wasm contract to invoke @@ -765,7 +765,7 @@ fn externs() { "Gas limit requested and returned does not match" ); - assert_eq!(gas_left, U256::from(97_740)); + assert_eq!(gas_left, U256::from(94_858)); } #[test] @@ -791,7 +791,7 @@ fn embedded_keccak() { }; assert_eq!(H256::from_slice(&result), H256::from("68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87")); - assert_eq!(gas_left, U256::from(84_520)); + assert_eq!(gas_left, U256::from(81_446)); } /// This test checks the correctness of log extern @@ -826,5 +826,5 @@ fn events() { assert_eq!(&log_entry.data, b"gnihtemos"); assert_eq!(&result, b"gnihtemos"); - assert_eq!(gas_left, U256::from(82_721)); + assert_eq!(gas_left, U256::from(79_637)); } diff --git a/json/src/spec/authority_round.rs b/json/src/spec/authority_round.rs index 984e2eff2..f39db7344 100644 --- a/json/src/spec/authority_round.rs +++ b/json/src/spec/authority_round.rs @@ -43,6 +43,12 @@ pub struct AuthorityRoundParams { /// Reward per block in wei. #[serde(rename="blockReward")] pub block_reward: 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. @@ -71,7 +77,9 @@ mod tests { }, "startStep" : 24, "validateStepTransition": 150, - "blockReward": 5000000 + "blockReward": 5000000, + "maximumUncleCountTransition": 10000000, + "maximumUncleCount": 5 } }"#; @@ -80,6 +88,8 @@ mod tests { assert_eq!(deserialized.params.validators, ValidatorSet::List(vec![Address(H160::from("0xc6d9d2cd449a754c494264e1809c50e34d64562b"))])); assert_eq!(deserialized.params.start_step, Some(Uint(U256::from(24)))); 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/parity/dapps.rs b/parity/dapps.rs index 364f563c5..2c3f0049b 100644 --- a/parity/dapps.rs +++ b/parity/dapps.rs @@ -195,9 +195,7 @@ mod server { pub struct Middleware; impl RequestMiddleware for Middleware { - fn on_request( - &self, _req: &hyper::server::Request, _control: &hyper::Control - ) -> RequestMiddlewareAction { + fn on_request(&self, _req: hyper::Request) -> RequestMiddlewareAction { unreachable!() } } diff --git a/test.sh b/test.sh index 1613530cb..69204fef2 100755 --- a/test.sh +++ b/test.sh @@ -24,6 +24,10 @@ esac set -e +# Validate chainspecs ./scripts/validate_chainspecs.sh cargo test -j 8 $OPTIONS --features "$FEATURES" --all --exclude evmjit $1 + +# Validate --no-default-features build +cargo check --no-default-features