diff --git a/ethcore/benches/builtin.rs b/ethcore/benches/builtin.rs index 11df5028df9..ec703dd24e5 100644 --- a/ethcore/benches/builtin.rs +++ b/ethcore/benches/builtin.rs @@ -25,12 +25,10 @@ extern crate ethereum_types; extern crate parity_bytes as bytes; extern crate rustc_hex; -use std::collections::BTreeMap; - use bytes::BytesRef; use ethcore::builtin::Builtin; use ethcore::machine::EthereumMachine; -use ethereum_types::{Address, U256}; +use ethereum_types::U256; use ethcore::ethereum::new_byzantium_test_machine; use rustc_hex::FromHex; use self::test::Bencher; diff --git a/ethcore/evm/src/evm.rs b/ethcore/evm/src/evm.rs index 29f1b294b9f..ce2263e8fd5 100644 --- a/ethcore/evm/src/evm.rs +++ b/ethcore/evm/src/evm.rs @@ -63,7 +63,7 @@ impl Finalize for Error { /// Cost calculation type. For low-gas usage we calculate costs using usize instead of U256 pub trait CostType: Sized + From + Copy + Send - + ops::Mul + ops::Div + ops::Add +ops::Sub + + ops::Mul + ops::Div + ops::Add + ops::Sub + ops::Shr + ops::Shl + cmp::Ord + fmt::Debug { /// Converts this cost into `U256` diff --git a/ethcore/evm/src/interpreter/gasometer.rs b/ethcore/evm/src/interpreter/gasometer.rs index db67556e38c..524791fe95c 100644 --- a/ethcore/evm/src/interpreter/gasometer.rs +++ b/ethcore/evm/src/interpreter/gasometer.rs @@ -176,9 +176,8 @@ impl Gasometer { Request::GasMem(default_gas, mem_needed(stack.peek(0), stack.peek(1))?) }, instructions::SHA3 => { - let w = overflowing!(add_gas_usize(Gas::from_u256(*stack.peek(1))?, 31)); - let words = w >> 5; - let gas = Gas::from(schedule.sha3_gas) + (Gas::from(schedule.sha3_word_gas) * words); + let words = overflowing!(to_word_size(Gas::from_u256(*stack.peek(1))?)); + let gas = overflowing!(Gas::from(schedule.sha3_gas).overflow_add(overflowing!(Gas::from(schedule.sha3_word_gas).overflow_mul(words)))); Request::GasMem(gas, mem_needed(stack.peek(0), stack.peek(1))?) }, instructions::CALLDATACOPY | instructions::CODECOPY | instructions::RETURNDATACOPY => { @@ -231,9 +230,24 @@ impl Gasometer { Request::GasMemProvide(gas, mem, Some(requested)) }, - instructions::CREATE | instructions::CREATE2 => { + instructions::CREATE => { + let start = stack.peek(1); + let len = stack.peek(2); + let gas = Gas::from(schedule.create_gas); - let mem = mem_needed(stack.peek(1), stack.peek(2))?; + let mem = mem_needed(start, len)?; + + Request::GasMemProvide(gas, mem, None) + }, + instructions::CREATE2 => { + let start = stack.peek(1); + let len = stack.peek(2); + + let base = Gas::from(schedule.create_gas); + let word = overflowing!(to_word_size(Gas::from_u256(*len)?)); + let word_gas = overflowing!(Gas::from(schedule.sha3_word_gas).overflow_mul(word)); + let gas = overflowing!(base.overflow_add(word_gas)); + let mem = mem_needed(start, len)?; Request::GasMemProvide(gas, mem, None) }, @@ -283,8 +297,8 @@ impl Gasometer { }, Request::GasMemCopy(gas, mem_size, copy) => { let (mem_gas_cost, new_mem_gas, new_mem_size) = self.mem_gas_cost(schedule, current_mem_size, &mem_size)?; - let copy = overflowing!(add_gas_usize(copy, 31)) >> 5; - let copy_gas = Gas::from(schedule.copy_gas) * copy; + let copy = overflowing!(to_word_size(copy)); + let copy_gas = overflowing!(Gas::from(schedule.copy_gas).overflow_mul(copy)); let gas = overflowing!(gas.overflow_add(copy_gas)); let gas = overflowing!(gas.overflow_add(mem_gas_cost)); @@ -311,7 +325,7 @@ impl Gasometer { }; let current_mem_size = Gas::from(current_mem_size); - let req_mem_size_rounded = (overflowing!(mem_size.overflow_add(Gas::from(31 as usize))) >> 5) << 5; + let req_mem_size_rounded = overflowing!(to_word_size(*mem_size)) << 5; let (mem_gas_cost, new_mem_gas) = if req_mem_size_rounded > current_mem_size { let new_mem_gas = gas_for_mem(req_mem_size_rounded)?; @@ -343,6 +357,16 @@ fn add_gas_usize(value: Gas, num: usize) -> (Gas, bool) { value.overflow_add(Gas::from(num)) } +#[inline] +fn to_word_size(value: Gas) -> (Gas, bool) { + let (gas, overflow) = add_gas_usize(value, 31); + if overflow { + return (gas, overflow); + } + + (gas >> 5, false) +} + #[inline] fn calculate_eip1283_sstore_gas(schedule: &Schedule, original: &U256, current: &U256, new: &U256) -> Gas { Gas::from( diff --git a/ethcore/evm/src/interpreter/mod.rs b/ethcore/evm/src/interpreter/mod.rs index 7da3d2a1aab..d1661532029 100644 --- a/ethcore/evm/src/interpreter/mod.rs +++ b/ethcore/evm/src/interpreter/mod.rs @@ -385,8 +385,7 @@ impl Interpreter { match result { InstructionResult::JumpToPosition(position) => { if self.valid_jump_destinations.is_none() { - let code_hash = self.params.code_hash.clone().unwrap_or_else(|| keccak(self.reader.code.as_ref())); - self.valid_jump_destinations = Some(self.cache.jump_destinations(&code_hash, &self.reader.code)); + self.valid_jump_destinations = Some(self.cache.jump_destinations(&self.params.code_hash, &self.reader.code)); } let jump_destinations = self.valid_jump_destinations.as_ref().expect("jump_destinations are initialized on first jump; qed"); let pos = self.verify_jump(position, jump_destinations)?; diff --git a/ethcore/evm/src/interpreter/shared_cache.rs b/ethcore/evm/src/interpreter/shared_cache.rs index f4a7f47f90f..63c4f507d82 100644 --- a/ethcore/evm/src/interpreter/shared_cache.rs +++ b/ethcore/evm/src/interpreter/shared_cache.rs @@ -50,17 +50,22 @@ impl SharedCache { } /// Get jump destinations bitmap for a contract. - pub fn jump_destinations(&self, code_hash: &H256, code: &[u8]) -> Arc { - if code_hash == &KECCAK_EMPTY { - return Self::find_jump_destinations(code); - } + pub fn jump_destinations(&self, code_hash: &Option, code: &[u8]) -> Arc { + if let Some(ref code_hash) = code_hash { + if code_hash == &KECCAK_EMPTY { + return Self::find_jump_destinations(code); + } - if let Some(d) = self.jump_destinations.lock().get_mut(code_hash) { - return d.0.clone(); + if let Some(d) = self.jump_destinations.lock().get_mut(code_hash) { + return d.0.clone(); + } } let d = Self::find_jump_destinations(code); - self.jump_destinations.lock().insert(code_hash.clone(), Bits(d.clone())); + + if let Some(ref code_hash) = code_hash { + self.jump_destinations.lock().insert(*code_hash, Bits(d.clone())); + } d } diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs index e97d92589e0..0ea8983b966 100644 --- a/ethcore/light/src/client/mod.rs +++ b/ethcore/light/src/client/mod.rs @@ -207,7 +207,7 @@ impl Client { /// Import a header to the queue for additional verification. pub fn import_header(&self, header: Header) -> EthcoreResult { - self.queue.import(header).map_err(Into::into) + self.queue.import(header).map_err(|(_, e)| e) } /// Inquire about the status of a given header. diff --git a/ethcore/res/ethereum/ropsten.json b/ethcore/res/ethereum/ropsten.json index 09ebce8b278..9adb5f4a263 100644 --- a/ethcore/res/ethereum/ropsten.json +++ b/ethcore/res/ethereum/ropsten.json @@ -10,13 +10,13 @@ "blockReward": { "0": "0x4563918244F40000", "1700000": "0x29A2241AF62C0000", - "4200000": "0x1BC16D674EC80000" + "4230000": "0x1BC16D674EC80000" }, "homesteadTransition": 0, "eip100bTransition": 1700000, "difficultyBombDelays": { "1700000": 3000000, - "4200000": 2000000 + "4230000": 2000000 } } } @@ -42,10 +42,10 @@ "eip211Transition": 1700000, "eip214Transition": 1700000, "eip658Transition": 1700000, - "eip145Transition": 4200000, - "eip1014Transition": 4200000, - "eip1052Transition": 4200000, - "eip1283Transition": 4200000 + "eip145Transition": 4230000, + "eip1014Transition": 4230000, + "eip1052Transition": 4230000, + "eip1283Transition": 4230000 }, "genesis": { "seal": { diff --git a/ethcore/res/ethereum/tests-issues/currents.json b/ethcore/res/ethereum/tests-issues/currents.json index 371211cab82..b6be610eb92 100644 --- a/ethcore/res/ethereum/tests-issues/currents.json +++ b/ethcore/res/ethereum/tests-issues/currents.json @@ -365,6 +365,104 @@ "chain": "Constantinople (test)" } } + }, + { + "reference": "9590", + "failing": "stCreate2Test", + "subtests": { + "call_then_create2_successful_then_returndatasize": { + "subnumbers": ["1"], + "chain": "Constantinople (test)" + }, + "returndatacopy_afterFailing_create": { + "subnumbers": ["1"], + "chain": "Constantinople (test)" + }, + "create2checkFieldsInInitcode": { + "subnumbers": ["1","2","3","5","6","7"], + "chain": "Constantinople (test)" + }, + "Create2Recursive": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + }, + "create2collisionBalance": { + "subnumbers": ["2","3"], + "chain": "Constantinople (test)" + }, + "create2InitCodes": { + "subnumbers": ["1","5","6","7","8","9"], + "chain": "Constantinople (test)" + }, + "Create2OOGafterInitCode": { + "subnumbers": ["2"], + "chain": "Constantinople (test)" + }, + "CreateMessageRevertedOOGInInit": { + "subnumbers": ["2"], + "chain": "Constantinople (test)" + }, + "returndatacopy_following_revert_in_create": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + }, + "create2collisionSelfdestructed": { + "subnumbers": ["2"], + "chain": "Constantinople (test)" + }, + "returndatacopy_0_0_following_successful_create": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + }, + "Create2OnDepth1023": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + }, + "Create2OOGafterInitCodeReturndata2": { + "subnumbers": ["2"], + "chain": "Constantinople (test)" + }, + "RevertOpcodeInCreateReturns": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + }, + "CREATE2_ContractSuicideDuringInit_ThenStoreThenReturn": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + }, + "returndatasize_following_successful_create": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + }, + "call_outsize_then_create2_successful_then_returndatasize": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + }, + "CreateMessageReverted": { + "subnumbers": ["2"], + "chain": "Constantinople (test)" + }, + "CREATE2_Suicide": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + }, + "Create2OOGafterInitCodeRevert": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + }, + "Create2OnDepth1024": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + }, + "create2collisionStorage": { + "subnumbers": ["2","3"], + "chain": "Constantinople (test)" + }, + "create2callPrecompiles": { + "subnumbers": ["*"], + "chain": "Constantinople (test)" + } + } } ] } diff --git a/ethcore/src/builtin.rs b/ethcore/src/builtin.rs index ab02fbbcf0c..0257f8fe787 100644 --- a/ethcore/src/builtin.rs +++ b/ethcore/src/builtin.rs @@ -311,35 +311,51 @@ impl Impl for Ripemd160 { } } -// calculate modexp: exponentiation by squaring. the `num` crate has pow, but not modular. -fn modexp(mut base: BigUint, mut exp: BigUint, modulus: BigUint) -> BigUint { - use num::Integer; +// calculate modexp: left-to-right binary exponentiation to keep multiplicands lower +fn modexp(mut base: BigUint, exp: Vec, modulus: BigUint) -> BigUint { + const BITS_PER_DIGIT: usize = 8; - if modulus <= BigUint::one() { // n^m % 0 || n^m % 1 + // n^m % 0 || n^m % 1 + if modulus <= BigUint::one() { return BigUint::zero(); } - if exp.is_zero() { // n^0 % m + // normalize exponent + let mut exp = exp.into_iter().skip_while(|d| *d == 0).peekable(); + + // n^0 % m + if let None = exp.peek() { return BigUint::one(); } - if base.is_zero() { // 0^n % m, n>0 + // 0^n % m, n > 0 + if base.is_zero() { return BigUint::zero(); } - let mut result = BigUint::one(); base = base % &modulus; - // fast path for base divisible by modulus. + // Fast path for base divisible by modulus. if base.is_zero() { return BigUint::zero() } - while !exp.is_zero() { - if exp.is_odd() { - result = (result * &base) % &modulus; - } - exp = exp >> 1; - base = (base.clone() * base) % &modulus; + // Left-to-right binary exponentiation (Handbook of Applied Cryptography - Algorithm 14.79). + // http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf + let mut result = BigUint::one(); + + for digit in exp { + let mut mask = 1 << (BITS_PER_DIGIT - 1); + + for _ in 0..BITS_PER_DIGIT { + result = &result * &result % &modulus; + + if digit & mask > 0 { + result = result * &base % &modulus; + } + + mask >>= 1; + } } + result } @@ -366,15 +382,19 @@ impl Impl for ModexpImpl { } else { // read the numbers themselves. let mut buf = vec![0; max(mod_len, max(base_len, exp_len))]; - let mut read_num = |len| { + let mut read_num = |reader: &mut io::Chain<&[u8], io::Repeat>, len: usize| { reader.read_exact(&mut buf[..len]).expect("reading from zero-extended memory cannot fail; qed"); BigUint::from_bytes_be(&buf[..len]) }; - let base = read_num(base_len); - let exp = read_num(exp_len); - let modulus = read_num(mod_len); - modexp(base, exp, modulus) + let base = read_num(&mut reader, base_len); + + let mut exp_buf = vec![0; exp_len]; + reader.read_exact(&mut exp_buf[..exp_len]).expect("reading from zero-extended memory cannot fail; qed"); + + let modulus = read_num(&mut reader, mod_len); + + modexp(base, exp_buf, modulus) }; // write output to given memory, left padded and same length as the modulus. @@ -551,31 +571,31 @@ mod tests { let mut base = BigUint::parse_bytes(b"12345", 10).unwrap(); let mut exp = BigUint::zero(); let mut modulus = BigUint::parse_bytes(b"789", 10).unwrap(); - assert_eq!(me(base, exp, modulus), BigUint::one()); + assert_eq!(me(base, exp.to_bytes_be(), modulus), BigUint::one()); // 0^n % m == 0 base = BigUint::zero(); exp = BigUint::parse_bytes(b"12345", 10).unwrap(); modulus = BigUint::parse_bytes(b"789", 10).unwrap(); - assert_eq!(me(base, exp, modulus), BigUint::zero()); + assert_eq!(me(base, exp.to_bytes_be(), modulus), BigUint::zero()); // n^m % 1 == 0 base = BigUint::parse_bytes(b"12345", 10).unwrap(); exp = BigUint::parse_bytes(b"789", 10).unwrap(); modulus = BigUint::one(); - assert_eq!(me(base, exp, modulus), BigUint::zero()); + assert_eq!(me(base, exp.to_bytes_be(), modulus), BigUint::zero()); // if n % d == 0, then n^m % d == 0 base = BigUint::parse_bytes(b"12345", 10).unwrap(); exp = BigUint::parse_bytes(b"789", 10).unwrap(); modulus = BigUint::parse_bytes(b"15", 10).unwrap(); - assert_eq!(me(base, exp, modulus), BigUint::zero()); + assert_eq!(me(base, exp.to_bytes_be(), modulus), BigUint::zero()); // others base = BigUint::parse_bytes(b"12345", 10).unwrap(); exp = BigUint::parse_bytes(b"789", 10).unwrap(); modulus = BigUint::parse_bytes(b"97", 10).unwrap(); - assert_eq!(me(base, exp, modulus), BigUint::parse_bytes(b"55", 10).unwrap()); + assert_eq!(me(base, exp.to_bytes_be(), modulus), BigUint::parse_bytes(b"55", 10).unwrap()); } #[test] diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index cc7d2af2111..127f0f9eb5f 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -1405,15 +1405,14 @@ impl ImportBlock for Client { bail!(EthcoreErrorKind::Block(BlockError::UnknownParent(unverified.parent_hash()))); } - let raw = unverified.bytes.clone(); match self.importer.block_queue.import(unverified) { Ok(res) => Ok(res), // we only care about block errors (not import errors) - Err(EthcoreError(EthcoreErrorKind::Block(err), _))=> { - self.importer.bad_blocks.report(raw, format!("{:?}", err)); + Err((block, EthcoreError(EthcoreErrorKind::Block(err), _))) => { + self.importer.bad_blocks.report(block.bytes, format!("{:?}", err)); bail!(EthcoreErrorKind::Block(err)) }, - Err(e) => Err(e), + Err((_, e)) => Err(e), } } } @@ -2382,14 +2381,13 @@ impl ProvingBlockChainClient for Client { env_info.gas_limit = transaction.gas.clone(); let mut jdb = self.state_db.read().journal_db().boxed_clone(); - state::prove_transaction( + state::prove_transaction_virtual( jdb.as_hashdb_mut(), header.state_root().clone(), &transaction, self.engine.machine(), &env_info, self.factories.clone(), - false, ) } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 530fde32bf6..5a4eaa642ef 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -18,7 +18,7 @@ use engines::{Engine, Seal}; use parity_machine::{Machine, Transactions, TotalScoredHeader}; /// `InstantSeal` params. -#[derive(Debug, PartialEq)] +#[derive(Default, Debug, PartialEq)] pub struct InstantSealParams { /// Whether to use millisecond timestamp pub millisecond_timestamp: bool, diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 11507c206e2..0f5a9f4ccc0 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -32,7 +32,7 @@ pub mod epoch; pub use self::authority_round::AuthorityRound; pub use self::basic_authority::BasicAuthority; pub use self::epoch::{EpochVerifier, Transition as EpochTransition}; -pub use self::instant_seal::InstantSeal; +pub use self::instant_seal::{InstantSeal, InstantSealParams}; pub use self::null_engine::NullEngine; pub use self::tendermint::Tendermint; diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs index aa5d9cd9b7d..00ef71459aa 100644 --- a/ethcore/src/spec/spec.rs +++ b/ethcore/src/spec/spec.rs @@ -33,7 +33,10 @@ use vm::{EnvInfo, CallType, ActionValue, ActionParams, ParamsType}; use builtin::Builtin; use encoded; -use engines::{EthEngine, NullEngine, InstantSeal, BasicAuthority, AuthorityRound, Tendermint, DEFAULT_BLOCKHASH_CONTRACT}; +use engines::{ + EthEngine, NullEngine, InstantSeal, InstantSealParams, BasicAuthority, + AuthorityRound, Tendermint, DEFAULT_BLOCKHASH_CONTRACT +}; use error::Error; use executive::Executive; use factory::Factories; @@ -596,7 +599,8 @@ impl Spec { match engine_spec { ethjson::spec::Engine::Null(null) => Arc::new(NullEngine::new(null.params.into(), machine)), ethjson::spec::Engine::Ethash(ethash) => Arc::new(::ethereum::Ethash::new(spec_params.cache_dir, ethash.params.into(), machine, spec_params.optimization_setting)), - ethjson::spec::Engine::InstantSeal(instant_seal) => Arc::new(InstantSeal::new(instant_seal.params.into(), machine)), + ethjson::spec::Engine::InstantSeal(Some(instant_seal)) => Arc::new(InstantSeal::new(instant_seal.params.into(), machine)), + ethjson::spec::Engine::InstantSeal(None) => Arc::new(InstantSeal::new(InstantSealParams::default(), machine)), ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(basic_authority.params.into(), machine)), ethjson::spec::Engine::AuthorityRound(authority_round) => AuthorityRound::new(authority_round.params.into(), machine) .expect("Failed to start AuthorityRound consensus engine."), @@ -873,14 +877,13 @@ impl Spec { data: d, }.fake_sign(from); - let res = ::state::prove_transaction( + let res = ::state::prove_transaction_virtual( db.as_hashdb_mut(), *genesis.state_root(), &tx, self.engine.machine(), &env_info, factories.clone(), - true, ); res.map(|(out, proof)| { diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 0fde1d8fb39..1e5af2e9f6b 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -224,17 +224,16 @@ pub fn check_proof( } } -/// Prove a transaction on the given state. +/// Prove a `virtual` transaction on the given state. /// Returns `None` when the transacion could not be proved, /// and a proof otherwise. -pub fn prove_transaction + Send + Sync>( +pub fn prove_transaction_virtual + Send + Sync>( db: H, root: H256, transaction: &SignedTransaction, machine: &Machine, env_info: &EnvInfo, factories: Factories, - virt: bool, ) -> Option<(Bytes, Vec)> { use self::backend::Proving; @@ -252,7 +251,7 @@ pub fn prove_transaction + Send + Sync>( }; let options = TransactOptions::with_no_tracing().dont_check_nonce().save_output_from_contract(); - match state.execute(env_info, machine, transaction, options, virt) { + match state.execute(env_info, machine, transaction, options, true) { Err(ExecutionError::Internal(_)) => None, Err(e) => { trace!(target: "state", "Proved call failed: {}", e); diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index c356d66ff40..7d98aa94323 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -58,7 +58,7 @@ pub trait Kind: 'static + Sized + Send + Sync { type Verified: Sized + Send + BlockLike + HeapSizeOf; /// Attempt to create the `Unverified` item from the input. - fn create(input: Self::Input, engine: &EthEngine, check_seal: bool) -> Result; + fn create(input: Self::Input, engine: &EthEngine, check_seal: bool) -> Result; /// Attempt to verify the `Unverified` item using the given engine. fn verify(unverified: Self::Unverified, engine: &EthEngine, check_seal: bool) -> Result; @@ -86,16 +86,16 @@ pub mod blocks { type Unverified = Unverified; type Verified = PreverifiedBlock; - fn create(input: Self::Input, engine: &EthEngine, check_seal: bool) -> Result { + fn create(input: Self::Input, engine: &EthEngine, check_seal: bool) -> Result { match verify_block_basic(&input, engine, check_seal) { Ok(()) => Ok(input), Err(Error(ErrorKind::Block(BlockError::TemporarilyInvalid(oob)), _)) => { debug!(target: "client", "Block received too early {}: {:?}", input.hash(), oob); - Err(BlockError::TemporarilyInvalid(oob).into()) + Err((input, BlockError::TemporarilyInvalid(oob).into())) }, Err(e) => { warn!(target: "client", "Stage 1 block verification failed for {}: {:?}", input.hash(), e); - Err(e) + Err((input, e)) } } } @@ -209,8 +209,11 @@ pub mod headers { type Unverified = Header; type Verified = Header; - fn create(input: Self::Input, engine: &EthEngine, _check_seal: bool) -> Result { - verify_header_params(&input, engine, true).map(|_| input) + fn create(input: Self::Input, engine: &EthEngine, _check_seal: bool) -> Result { + match verify_header_params(&input, engine, true) { + Ok(_) => Ok(input), + Err(err) => Err((input, err)) + } } fn verify(unverified: Self::Unverified, engine: &EthEngine, check_seal: bool) -> Result { diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index 2d5f50c5d03..9b1597439b0 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -26,7 +26,7 @@ use heapsize::HeapSizeOf; use ethereum_types::{H256, U256}; use parking_lot::{Condvar, Mutex, RwLock}; use io::*; -use error::*; +use error::{BlockError, ImportErrorKind, ErrorKind, Error}; use engines::EthEngine; use client::ClientIoMessage; @@ -469,21 +469,21 @@ impl VerificationQueue { } /// Add a block to the queue. - pub fn import(&self, input: K::Input) -> EthcoreResult { + pub fn import(&self, input: K::Input) -> Result { let hash = input.hash(); { if self.processing.read().contains_key(&hash) { - bail!(ErrorKind::Import(ImportErrorKind::AlreadyQueued)); + bail!((input, ErrorKind::Import(ImportErrorKind::AlreadyQueued).into())); } let mut bad = self.verification.bad.lock(); if bad.contains(&hash) { - bail!(ErrorKind::Import(ImportErrorKind::KnownBad)); + bail!((input, ErrorKind::Import(ImportErrorKind::KnownBad).into())); } if bad.contains(&input.parent_hash()) { bad.insert(hash); - bail!(ErrorKind::Import(ImportErrorKind::KnownBad)); + bail!((input, ErrorKind::Import(ImportErrorKind::KnownBad).into())); } } @@ -500,7 +500,7 @@ impl VerificationQueue { self.more_to_verify.notify_all(); Ok(hash) }, - Err(err) => { + Err((input, err)) => { match err { // Don't mark future blocks as bad. Error(ErrorKind::Block(BlockError::TemporarilyInvalid(_)), _) => {}, @@ -508,7 +508,7 @@ impl VerificationQueue { self.verification.bad.lock().insert(hash); } } - Err(err) + Err((input, err)) } } } @@ -784,7 +784,7 @@ mod tests { let duplicate_import = queue.import(new_unverified(get_good_dummy_block())); match duplicate_import { - Err(e) => { + Err((_, e)) => { match e { Error(ErrorKind::Import(ImportErrorKind::AlreadyQueued), _) => {}, _ => { panic!("must return AlreadyQueued error"); } diff --git a/ethcore/sync/src/chain/mod.rs b/ethcore/sync/src/chain/mod.rs index 4e7b3076220..412f699d6ea 100644 --- a/ethcore/sync/src/chain/mod.rs +++ b/ethcore/sync/src/chain/mod.rs @@ -507,8 +507,9 @@ impl ChainSync { self.peers.clear(); } - /// Reset sync. Clear all downloaded data but keep the queue - fn reset(&mut self, io: &mut SyncIo) { + /// Reset sync. Clear all downloaded data but keep the queue. + /// Set sync state to the given state or to the initial state if `None` is provided. + fn reset(&mut self, io: &mut SyncIo, state: Option) { self.new_blocks.reset(); let chain_info = io.chain().chain_info(); for (_, ref mut p) in &mut self.peers { @@ -520,7 +521,7 @@ impl ChainSync { } } } - self.state = ChainSync::get_init_state(self.warp_sync, io.chain()); + self.state = state.unwrap_or_else(|| ChainSync::get_init_state(self.warp_sync, io.chain())); // Reactivate peers only if some progress has been made // since the last sync round of if starting fresh. self.active_peers = self.peers.keys().cloned().collect(); @@ -534,7 +535,7 @@ impl ChainSync { io.snapshot_service().abort_restore(); } self.snapshot.clear(); - self.reset(io); + self.reset(io, None); self.continue_sync(io); } @@ -699,7 +700,7 @@ impl ChainSync { /// Called after all blocks have been downloaded fn complete_sync(&mut self, io: &mut SyncIo) { trace!(target: "sync", "Sync complete"); - self.reset(io); + self.reset(io, Some(SyncState::Idle)); } /// Enter waiting state diff --git a/json/src/spec/engine.rs b/json/src/spec/engine.rs index f8476757c3f..020cc1fd0ba 100644 --- a/json/src/spec/engine.rs +++ b/json/src/spec/engine.rs @@ -26,7 +26,7 @@ pub enum Engine { Null(NullEngine), /// Instantly sealing engine. #[serde(rename="instantSeal")] - InstantSeal(InstantSeal), + InstantSeal(Option), /// Ethash engine. Ethash(Ethash), /// BasicAuthority engine. @@ -71,6 +71,17 @@ mod tests { _ => panic!(), }; + let s = r#"{ + "instantSeal": null + }"#; + + let deserialized: Engine = serde_json::from_str(s).unwrap(); + match deserialized { + Engine::InstantSeal(_) => {}, // instant seal is unit tested in its own file. + _ => panic!(), + }; + + let s = r#"{ "Ethash": { "params": { diff --git a/parity-clib/src/lib.rs b/parity-clib/src/lib.rs index 28b212acd69..7791f97bd5e 100644 --- a/parity-clib/src/lib.rs +++ b/parity-clib/src/lib.rs @@ -191,7 +191,7 @@ pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_configFromCli(env: }, Err(err) => { let _ = env.throw_new("java/lang/Exception", err.to_string()); - 0 + return 0 } }; } diff --git a/rpc/src/v1/helpers/light_fetch.rs b/rpc/src/v1/helpers/light_fetch.rs index ade100baa5a..df46d59166e 100644 --- a/rpc/src/v1/helpers/light_fetch.rs +++ b/rpc/src/v1/helpers/light_fetch.rs @@ -191,7 +191,7 @@ impl LightFetch { } /// Helper for getting proved execution. - pub fn proved_execution(&self, req: CallRequest, num: Trailing) -> impl Future + Send { + pub fn proved_read_only_execution(&self, req: CallRequest, num: Trailing) -> impl Future + Send { const DEFAULT_GAS_PRICE: u64 = 21_000; // starting gas when gas not provided. const START_GAS: u64 = 50_000; @@ -256,14 +256,14 @@ impl LightFetch { _ => return Either::A(future::err(errors::unknown_block())), }; - Either::B(execute_tx(gas_known, ExecuteParams { - from: from, - tx: tx, - hdr: hdr, - env_info: env_info, + Either::B(execute_read_only_tx(gas_known, ExecuteParams { + from, + tx, + hdr, + env_info, engine: client.engine().clone(), - on_demand: on_demand, - sync: sync, + on_demand, + sync, })) })) } @@ -608,10 +608,10 @@ struct ExecuteParams { // has a peer execute the transaction with given params. If `gas_known` is false, // this will double the gas on each `OutOfGas` error. -fn execute_tx(gas_known: bool, params: ExecuteParams) -> impl Future + Send { +fn execute_read_only_tx(gas_known: bool, params: ExecuteParams) -> impl Future + Send { if !gas_known { Box::new(future::loop_fn(params, |mut params| { - execute_tx(true, params.clone()).and_then(move |res| { + execute_read_only_tx(true, params.clone()).and_then(move |res| { match res { Ok(executed) => { // TODO: how to distinguish between actual OOG and diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index d03b2c002fb..34b89ac9f6b 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -381,7 +381,7 @@ impl Eth for EthClient { } fn call(&self, req: CallRequest, num: Trailing) -> BoxFuture { - Box::new(self.fetcher().proved_execution(req, num).and_then(|res| { + Box::new(self.fetcher().proved_read_only_execution(req, num).and_then(|res| { match res { Ok(exec) => Ok(exec.output.into()), Err(e) => Err(errors::execution(e)), @@ -391,7 +391,7 @@ impl Eth for EthClient { fn estimate_gas(&self, req: CallRequest, num: Trailing) -> BoxFuture { // TODO: binary chop for more accurate estimates. - Box::new(self.fetcher().proved_execution(req, num).and_then(|res| { + Box::new(self.fetcher().proved_read_only_execution(req, num).and_then(|res| { match res { Ok(exec) => Ok((exec.refunded + exec.gas_used).into()), Err(e) => Err(errors::execution(e)),