Merge branch 'master' into json_tests_split

This commit is contained in:
debris 2016-02-02 22:50:53 +01:00
commit 7aba3032c8
19 changed files with 1016 additions and 63 deletions

View File

@ -4,11 +4,13 @@ language: rust
branches:
only:
- master
- /^beta-.*$/
- /^stable-.*$/
matrix:
fast_finish: true
include:
- rust: nightly
env: FEATURES="--features ethcore/json-tests" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity"
env: FEATURES="--features ethcore/json-tests" KCOV_FEATURES="" TARGETS="-p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" ARCHIVE_SUFFIX="-${TRAVIS_OS_NAME}-${TRAVIS_TAG}"
cache:
apt: true
directories:
@ -30,6 +32,7 @@ script:
- cargo build --release --verbose ${FEATURES}
- cargo test --release --verbose ${FEATURES} ${TARGETS}
- cargo bench --no-run ${FEATURES} ${TARGETS}
- tar cvzf parity${ARCHIVE_SUFFIX}.tar.gz -C target/release parity
after_success: |
wget https://github.com/SimonKagstrom/kcov/archive/master.tar.gz &&
tar xzf master.tar.gz && mkdir kcov-master/build && cd kcov-master/build && cmake .. && make && make install DESTDIR=../tmp && cd ../.. &&
@ -53,3 +56,12 @@ env:
global:
- secure: 3sUjNi9mhdL5h1GTm8LONnDN/SYvUHT+WSkMl93h3nYiLCQXk8eZaPS98AS7oOaTsfW4UvnwckVFCFl49ttInsv4cd/TkAxmrJHe6kPyS9/4NWUdmP8BjicbBvL/ioSdXMECMEYzPDLV+I3KhtC2LcB6ceDEl/XwMOJlzbGf7RbtcXGVQgMLqSYY1YKjQA4vbT5nFgIS/sZu3Z9yFgN0GafnihKcizqoHhdJjs/zxmX+qJepnC6o3V6KcFnS7QHhM1JOr85twE6S422UlvNaEb5ovwLPqmOl5+fA+6shbx4AxFTY6E9Iors+OVY/JliFhrqOdCt0i2P1FUHN4kbGZQkf0rphN/ZOI2uKNFTOyXiPvppfo/ZemKmcqkwkqP9+lf5QqYmtE6hsAYagxn49xJZILl8tAYbdqxF5gxa+TEVrfsBFtz/Sv3q8QhKQNPAmjEcKyMatyEreLUIFEpFTGIco8jN4eXeSoLRdJ+Z75ihttfQWhNfUDgNL30iQLy0AgFSsh/cyb5M8y9lxrGDzDTogvaiKGwr/V45sPkcXWCkmOgMdINqBB6ZtdL3bGHdyjmYj+y3btjf3aP11k++BL0fXIaKn25aS/p/9iyGb1FyGCM03o4ZRQ3YhTOvfMRfRGf6nWbaMx9upv8o5ShSdysewhrnh3082r7u896ny1Ho=
- secure: 0/FeVvFl3AhBW0TCPoujY9zOAYoUNMlAz3XjC04vlc4Ksfx0lGU3KFi97LlALxMWV0lfwQc7ixSe2vTgQVQuLVSU9XEW40fQgEjJlmLca2RcRx1kfzJDypuWSiCME7MWmLPH0ac4COdTDS1z5WGggv5YB7GQPCzFvcmOOaPYtF29ngCtkyB2HmNkY/W3omHFEk7Si6bsmOSHZiOAhivPl6ixnGpFyTEKPyraMMqPIj5rbEGkzgeLTiXf2ur143n/tnSr8tmP1MfQi9yS8/ONidMqnxUeuLkeNnb82zj9pVJhVXq0xF44WXJ8Za1jm0ByiTakgqpm8Juk822qjvtNulJ1XZW/fyZQZaN1dy3uq5Ud3W8wS9M7VIVl8CoXozzDpIsdPeUAtkAxeHBsZqL1vAH2yC1YJA7HPySMYzCjYqkJ2r62xYk0gXmNXphfU+F/X/rHzHsTMJPONJ54HQwu12m7zVlKIYBGHgEXg/HAM/g4ljUzl6WWR/nHH/tQM8ND/8FpHluJSZJWacq/1QNhVdTq2x6cqws2fs5A7nVpccR9+6RRgYgv6+YS2LxvFzByuZveGGoKif+uMECXN876j40araUqU528Yz9i8bHJlnM3coRBndaLNWByLcUyXCB9r9IUosUu41rr+L2mVzkSDm0GicuNCzqvzYQ9Q6QY4uQ=
deploy:
provider: releases
api_key:
secure: 3sUjNi9mhdL5h1GTm8LONnDN/SYvUHT+WSkMl93h3nYiLCQXk8eZaPS98AS7oOaTsfW4UvnwckVFCFl49ttInsv4cd/TkAxmrJHe6kPyS9/4NWUdmP8BjicbBvL/ioSdXMECMEYzPDLV+I3KhtC2LcB6ceDEl/XwMOJlzbGf7RbtcXGVQgMLqSYY1YKjQA4vbT5nFgIS/sZu3Z9yFgN0GafnihKcizqoHhdJjs/zxmX+qJepnC6o3V6KcFnS7QHhM1JOr85twE6S422UlvNaEb5ovwLPqmOl5+fA+6shbx4AxFTY6E9Iors+OVY/JliFhrqOdCt0i2P1FUHN4kbGZQkf0rphN/ZOI2uKNFTOyXiPvppfo/ZemKmcqkwkqP9+lf5QqYmtE6hsAYagxn49xJZILl8tAYbdqxF5gxa+TEVrfsBFtz/Sv3q8QhKQNPAmjEcKyMatyEreLUIFEpFTGIco8jN4eXeSoLRdJ+Z75ihttfQWhNfUDgNL30iQLy0AgFSsh/cyb5M8y9lxrGDzDTogvaiKGwr/V45sPkcXWCkmOgMdINqBB6ZtdL3bGHdyjmYj+y3btjf3aP11k++BL0fXIaKn25aS/p/9iyGb1FyGCM03o4ZRQ3YhTOvfMRfRGf6nWbaMx9upv8o5ShSdysewhrnh3082r7u896ny1Ho=
skip_cleanup: true
file: parity${ARCHIVE_SUFFIX}.tar.gz
on:
tags: true

View File

@ -9,6 +9,7 @@ use engine::Engine;
use views::*;
use header::*;
use service::*;
use client::BlockStatus;
/// Block queue status
#[derive(Debug)]
@ -41,7 +42,7 @@ pub struct BlockQueue {
deleting: Arc<AtomicBool>,
ready_signal: Arc<QueueSignal>,
empty: Arc<Condvar>,
processing: HashSet<H256>
processing: RwLock<HashSet<H256>>
}
struct UnVerifiedBlock {
@ -106,7 +107,7 @@ impl BlockQueue {
verification: verification.clone(),
verifiers: verifiers,
deleting: deleting.clone(),
processing: HashSet::new(),
processing: RwLock::new(HashSet::new()),
empty: empty.clone(),
}
}
@ -196,11 +197,22 @@ impl BlockQueue {
}
}
/// Check if the block is currently in the queue
pub fn block_status(&self, hash: &H256) -> BlockStatus {
if self.processing.read().unwrap().contains(&hash) {
return BlockStatus::Queued;
}
if self.verification.lock().unwrap().bad.contains(&hash) {
return BlockStatus::Bad;
}
BlockStatus::Unknown
}
/// Add a block to the queue.
pub fn import_block(&mut self, bytes: Bytes) -> ImportResult {
let header = BlockView::new(&bytes).header();
let h = header.hash();
if self.processing.contains(&h) {
if self.processing.read().unwrap().contains(&h) {
return Err(ImportError::AlreadyQueued);
}
{
@ -217,7 +229,7 @@ impl BlockQueue {
match verify_block_basic(&header, &bytes, self.engine.deref().deref()) {
Ok(()) => {
self.processing.insert(h.clone());
self.processing.write().unwrap().insert(h.clone());
self.verification.lock().unwrap().unverified.push_back(UnVerifiedBlock { header: header, bytes: bytes });
self.more_to_verify.notify_all();
Ok(h)
@ -235,10 +247,12 @@ impl BlockQueue {
let mut verification_lock = self.verification.lock().unwrap();
let mut verification = verification_lock.deref_mut();
verification.bad.insert(hash.clone());
self.processing.write().unwrap().remove(&hash);
let mut new_verified = VecDeque::new();
for block in verification.verified.drain(..) {
if verification.bad.contains(&block.header.parent_hash) {
verification.bad.insert(block.header.hash());
self.processing.write().unwrap().remove(&block.header.hash());
}
else {
new_verified.push_back(block);
@ -247,6 +261,15 @@ impl BlockQueue {
verification.verified = new_verified;
}
/// Mark given block as processed
pub fn mark_as_good(&mut self, hashes: &[H256]) {
let mut processing = self.processing.write().unwrap();
for h in hashes {
processing.remove(&h);
}
//TODO: reward peers
}
/// Removes up to `max` verified blocks from the queue
pub fn drain(&mut self, max: usize) -> Vec<PreVerifiedBlock> {
let mut verification = self.verification.lock().unwrap();
@ -254,7 +277,6 @@ impl BlockQueue {
let mut result = Vec::with_capacity(count);
for _ in 0..count {
let block = verification.verified.pop_front().unwrap();
self.processing.remove(&block.header.hash());
result.push(block);
}
self.ready_signal.reset();
@ -294,6 +316,7 @@ mod tests {
use block_queue::*;
use tests::helpers::*;
use error::*;
use views::*;
fn get_test_queue() -> BlockQueue {
let spec = get_test_spec();
@ -339,11 +362,14 @@ mod tests {
#[test]
fn returns_ok_for_drained_duplicates() {
let mut queue = get_test_queue();
if let Err(e) = queue.import_block(get_good_dummy_block()) {
let block = get_good_dummy_block();
let hash = BlockView::new(&block).header().hash().clone();
if let Err(e) = queue.import_block(block) {
panic!("error importing block that is valid by definition({:?})", e);
}
queue.flush();
queue.drain(10);
queue.mark_as_good(&[ hash ]);
if let Err(e) = queue.import_block(get_good_dummy_block()) {
panic!("error importing block that has already been drained ({:?})", e);

View File

@ -17,7 +17,7 @@ use verification::*;
use block::*;
/// General block status
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub enum BlockStatus {
/// Part of the blockchain.
InChain,
@ -206,6 +206,7 @@ impl Client {
let mut bad = HashSet::new();
let _import_lock = self.import_lock.lock();
let blocks = self.block_queue.write().unwrap().drain(128);
let mut good_blocks = Vec::with_capacity(128);
for block in blocks {
if bad.contains(&block.header.parent_hash) {
self.block_queue.write().unwrap().mark_as_bad(&block.header.hash());
@ -258,6 +259,8 @@ impl Client {
break;
}
good_blocks.push(header.hash().clone());
self.chain.write().unwrap().insert_block(&block.bytes); //TODO: err here?
let ancient = if header.number() >= HISTORY { Some(header.number() - HISTORY) } else { None };
match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.read().unwrap().block_hash(n).unwrap()))) {
@ -271,6 +274,7 @@ impl Client {
trace!(target: "client", "Imported #{} ({})", header.number(), header.hash());
ret += 1;
}
self.block_queue.write().unwrap().mark_as_good(&good_blocks);
ret
}
@ -325,7 +329,11 @@ impl BlockChainClient for Client {
}
fn block_status(&self, hash: &H256) -> BlockStatus {
if self.chain.read().unwrap().is_known(&hash) { BlockStatus::InChain } else { BlockStatus::Unknown }
if self.chain.read().unwrap().is_known(&hash) {
BlockStatus::InChain
} else {
self.block_queue.read().unwrap().block_status(hash)
}
}
fn block_total_difficulty(&self, hash: &H256) -> Option<U256> {
@ -372,6 +380,9 @@ impl BlockChainClient for Client {
if self.chain.read().unwrap().is_known(&header.hash()) {
return Err(ImportError::AlreadyInChain);
}
if self.block_status(&header.parent_hash) == BlockStatus::Unknown {
return Err(ImportError::UnknownParent);
}
self.block_queue.write().unwrap().import_block(bytes)
}

View File

@ -130,14 +130,16 @@ pub enum BlockError {
}
#[derive(Debug)]
/// TODO [arkpar] Please document me
/// Import to the block queue result
pub enum ImportError {
/// TODO [arkpar] Please document me
/// Bad block detected
Bad(Option<Error>),
/// TODO [arkpar] Please document me
/// Already in the block chain
AlreadyInChain,
/// TODO [arkpar] Please document me
/// Already in the block queue
AlreadyQueued,
/// Unknown parent
UnknownParent,
}
impl From<Error> for ImportError {

View File

@ -15,31 +15,30 @@ pub enum Error {
/// `BadJumpDestination` is returned when execution tried to move
/// to position that wasn't marked with JUMPDEST instruction
BadJumpDestination {
/// TODO [Tomusdrw] Please document me
/// Position the code tried to jump to.
destination: usize
},
/// `BadInstructions` is returned when given instruction is not supported
BadInstruction {
/// TODO [Tomusdrw] Please document me
/// Unrecognized opcode
instruction: u8,
},
/// `StackUnderflow` when there is not enough stack elements to execute instruction
/// First parameter says how many elements were needed and the second how many were actually on Stack
StackUnderflow {
/// TODO [Tomusdrw] Please document me
/// Invoked instruction
instruction: &'static str,
/// TODO [Tomusdrw] Please document me
/// How many stack elements was requested by instruction
wanted: usize,
/// TODO [Tomusdrw] Please document me
/// How many elements were on stack
on_stack: usize
},
/// When execution would exceed defined Stack Limit
OutOfStack {
/// TODO [Tomusdrw] Please document me
/// Invoked instruction
instruction: &'static str,
/// TODO [Tomusdrw] Please document me
wanted: usize,
/// TODO [Tomusdrw] Please document me
/// How many stack elements instruction wanted to push
wanted: usize,
/// What was the stack limit
limit: usize
},
/// Returned on evm internal error. Should never be ignored during development.

View File

@ -5,12 +5,12 @@ use std::fmt;
use evm::Evm;
#[derive(Clone)]
/// TODO [Tomusdrw] Please document me
/// Type of EVM to use.
pub enum VMType {
/// TODO [Tomusdrw] Please document me
#[allow(dead_code)] // crated only by jit
/// JIT EVM
Jit,
/// TODO [Tomusdrw] Please document me
/// RUST EVM
Interpreter
}

View File

@ -1,11 +1,10 @@
///! Rust VM implementation
use common::*;
use evm;
use super::instructions as instructions;
use super::instructions::Instruction;
use std::marker::Copy;
use evm::{MessageCallResult, ContractCreateResult};
use evm::{self, MessageCallResult, ContractCreateResult};
#[cfg(not(feature = "evm-debug"))]
macro_rules! evm_debug {

View File

@ -150,7 +150,7 @@ fn test_add(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_988));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe").unwrap());
assert_store(&ext, 0, "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe");
}
evm_test!{test_sha3: test_sha3_jit, test_sha3_int}
@ -170,7 +170,7 @@ fn test_sha3(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_961));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470").unwrap());
assert_store(&ext, 0, "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
}
evm_test!{test_address: test_address_jit, test_address_int}
@ -190,7 +190,7 @@ fn test_address(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap());
assert_store(&ext, 0, "0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6");
}
evm_test!{test_origin: test_origin_jit, test_origin_int}
@ -212,7 +212,7 @@ fn test_origin(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap());
assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681");
}
// TODO [todr] Fails with Signal 11 on JIT
@ -235,7 +235,7 @@ fn test_sender(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681").unwrap());
assert_store(&ext, 0, "000000000000000000000000cd1722f2947def4cf144679da39c4c32bdc35681");
}
evm_test!{test_extcodecopy: test_extcodecopy_jit, test_extcodecopy_int}
@ -270,7 +270,7 @@ fn test_extcodecopy(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_935));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("6005600055000000000000000000000000000000000000000000000000000000").unwrap());
assert_store(&ext, 0, "6005600055000000000000000000000000000000000000000000000000000000");
}
evm_test!{test_log_empty: test_log_empty_jit, test_log_empty_int}
@ -369,7 +369,7 @@ fn test_calldataload(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_991));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("23ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23").unwrap());
assert_store(&ext, 0, "23ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff23");
}
@ -390,7 +390,7 @@ fn test_author(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap());
assert_store(&ext, 0, "0000000000000000000000000f572e5295c57f15886f9b263e2f6d2d6c7b5ec6");
}
evm_test!{test_timestamp: test_timestamp_jit, test_timestamp_int}
@ -410,7 +410,7 @@ fn test_timestamp(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap());
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234");
}
evm_test!{test_number: test_number_jit, test_number_int}
@ -430,7 +430,7 @@ fn test_number(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap());
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234");
}
evm_test!{test_difficulty: test_difficulty_jit, test_difficulty_int}
@ -450,7 +450,7 @@ fn test_difficulty(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap());
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234");
}
evm_test!{test_gas_limit: test_gas_limit_jit, test_gas_limit_int}
@ -470,6 +470,321 @@ fn test_gas_limit(factory: super::Factory) {
};
assert_eq!(gas_left, U256::from(79_995));
assert_eq!(ext.store.get(&H256::new()).unwrap(), &H256::from_str("0000000000000000000000000000000000000000000000000000000000001234").unwrap());
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000001234");
}
evm_test!{test_mul: test_mul_jit, test_mul_int}
fn test_mul(factory: super::Factory) {
let code = "65012365124623626543219002600055".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "000000000000000000000000000000000000000000000000734349397b853383");
assert_eq!(gas_left, U256::from(79_983));
}
evm_test!{test_sub: test_sub_jit, test_sub_int}
fn test_sub(factory: super::Factory) {
let code = "65012365124623626543219003600055".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000012364ad0302");
assert_eq!(gas_left, U256::from(79_985));
}
evm_test!{test_div: test_div_jit, test_div_int}
fn test_div(factory: super::Factory) {
let code = "65012365124623626543219004600055".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "000000000000000000000000000000000000000000000000000000000002e0ac");
assert_eq!(gas_left, U256::from(79_983));
}
evm_test!{test_div_zero: test_div_zero_jit, test_div_zero_int}
fn test_div_zero(factory: super::Factory) {
let code = "6501236512462360009004600055".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000");
assert_eq!(gas_left, U256::from(94_983));
}
evm_test!{test_mod: test_mod_jit, test_mod_int}
fn test_mod(factory: super::Factory) {
let code = "650123651246236265432290066000556501236512462360009006600155".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000076b4b");
assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000000");
assert_eq!(gas_left, U256::from(74_966));
}
evm_test!{test_smod: test_smod_jit, test_smod_int}
fn test_smod(factory: super::Factory) {
let code = "650123651246236265432290076000556501236512462360009007600155".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000076b4b");
assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000000");
assert_eq!(gas_left, U256::from(74_966));
}
evm_test!{test_sdiv: test_sdiv_jit, test_sdiv_int}
fn test_sdiv(factory: super::Factory) {
let code = "650123651246236265432290056000556501236512462360009005600155".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "000000000000000000000000000000000000000000000000000000000002e0ac");
assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000000");
assert_eq!(gas_left, U256::from(74_966));
}
evm_test!{test_exp: test_exp_jit, test_exp_int}
fn test_exp(factory: super::Factory) {
let code = "6016650123651246230a6000556001650123651246230a6001556000650123651246230a600255".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "90fd23767b60204c3d6fc8aec9e70a42a3f127140879c133a20129a597ed0c59");
assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000012365124623");
assert_store(&ext, 2, "0000000000000000000000000000000000000000000000000000000000000001");
assert_eq!(gas_left, U256::from(39_923));
}
evm_test!{test_comparison: test_comparison_jit, test_comparison_int}
fn test_comparison(factory: super::Factory) {
let code = "601665012365124623818181811060005511600155146002556415235412358014600355".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000");
assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000001");
assert_store(&ext, 2, "0000000000000000000000000000000000000000000000000000000000000000");
assert_store(&ext, 3, "0000000000000000000000000000000000000000000000000000000000000001");
assert_eq!(gas_left, U256::from(49_952));
}
evm_test!{test_signed_comparison: test_signed_comparison_jit, test_signed_comparison_int}
fn test_signed_comparison(factory: super::Factory) {
let code = "60106000036010818112600055136001556010601060000381811260025513600355".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000");
assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000001");
assert_store(&ext, 2, "0000000000000000000000000000000000000000000000000000000000000001");
assert_store(&ext, 3, "0000000000000000000000000000000000000000000000000000000000000000");
assert_eq!(gas_left, U256::from(49_940));
}
evm_test!{test_bitops: test_bitops_jit, test_bitops_int}
fn test_bitops(factory: super::Factory) {
let code = "60ff610ff08181818116600055176001551860025560008015600355198015600455600555".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(150_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "00000000000000000000000000000000000000000000000000000000000000f0");
assert_store(&ext, 1, "0000000000000000000000000000000000000000000000000000000000000fff");
assert_store(&ext, 2, "0000000000000000000000000000000000000000000000000000000000000f0f");
assert_store(&ext, 3, "0000000000000000000000000000000000000000000000000000000000000001");
assert_store(&ext, 4, "0000000000000000000000000000000000000000000000000000000000000000");
assert_store(&ext, 5, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
assert_eq!(gas_left, U256::from(44_937));
}
evm_test!{test_addmod_mulmod: test_addmod_mulmod_jit, test_addmod_mulmod_int}
fn test_addmod_mulmod(factory: super::Factory) {
let code = "60ff60f060108282820860005509600155600060f0601082828208196002550919600355".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000001");
assert_store(&ext, 1, "000000000000000000000000000000000000000000000000000000000000000f");
assert_store(&ext, 2, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
assert_store(&ext, 3, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
assert_eq!(gas_left, U256::from(19_914));
}
evm_test!{test_byte: test_byte_jit, test_byte_int}
fn test_byte(factory: super::Factory) {
let code = "60f061ffff1a600055610fff601f1a600155".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000000");
assert_store(&ext, 1, "00000000000000000000000000000000000000000000000000000000000000ff");
assert_eq!(gas_left, U256::from(74_976));
}
evm_test!{test_signextend: test_signextend_jit, test_signextend_int}
fn test_signextend(factory: super::Factory) {
let code = "610fff60020b60005560ff60200b600155".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "0000000000000000000000000000000000000000000000000000000000000fff");
assert_store(&ext, 1, "00000000000000000000000000000000000000000000000000000000000000ff");
assert_eq!(gas_left, U256::from(59_972));
}
evm_test!{test_badinstruction: test_badinstruction_jit, test_badinstruction_int}
fn test_badinstruction(factory: super::Factory) {
let code = "af".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let err = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap_err()
};
match err {
evm::Error::BadInstruction { instruction: 0xaf } => (),
_ => assert!(false, "Expected bad instruction")
}
}
evm_test!{test_pop: test_pop_jit, test_pop_int}
fn test_pop(factory: super::Factory) {
let code = "60f060aa50600055".from_hex().unwrap();
let mut params = ActionParams::default();
params.gas = U256::from(100_000);
params.code = Some(code);
let mut ext = FakeExt::new();
let gas_left = {
let vm = factory.create();
vm.exec(params, &mut ext).unwrap()
};
assert_store(&ext, 0, "00000000000000000000000000000000000000000000000000000000000000f0");
assert_eq!(gas_left, U256::from(79_989));
}
fn assert_store(ext: &FakeExt, pos: u64, val: &str) {
assert_eq!(ext.store.get(&H256::from(pos)).unwrap(), &H256::from_str(val).unwrap());
}

466
install-deps.sh Executable file
View File

@ -0,0 +1,466 @@
#!/usr/bin/env bash
function run_installer()
{
####### Init vars
HOMEBREW_PREFIX=/usr/local
HOMEBREW_CACHE=/Library/Caches/Homebrew
HOMEBREW_REPO=https://github.com/Homebrew/homebrew
OSX_REQUIERED_VERSION="10.7.0"
declare OS_TYPE
declare OSX_VERSION
declare GIT_PATH
declare RUBY_PATH
declare BREW_PATH
declare INSTALL_FILES=""
errorMessages=""
isOsVersion=false
isGit=false
isRuby=false
isBrew=false
canContinue=true
depCount=0
depFound=0
####### Setup colors
red=`tput setaf 1`
green=`tput setaf 2`
yellow=`tput setaf 3`
blue=`tput setaf 4`
magenta=`tput setaf 5`
cyan=`tput setaf 6`
white=`tput setaf 7`
b=`tput bold`
u=`tput sgr 0 1`
ul=`tput smul`
xl=`tput rmul`
stou=`tput smso`
xtou=`tput rmso`
dim=`tput dim`
reverse=`tput rev`
reset=`tput sgr0`
function head() {
echo "${blue}${b}==>${white} $1${reset}"
}
function info() {
echo "${blue}${b}==>${reset} $1"
}
function successHeading() {
echo "${green}${b}==> $1${reset}"
}
function success() {
echo "${green}${b}==>${reset}${green} $1${reset}"
}
function error() {
echo "${red}==> ${u}${b}${red}$1${reset}"
}
function smallError() {
echo "${red}==>${reset} $1"
}
function green() {
echo "${green}$1${reset}"
}
function red() {
echo "${red}$1${reset}"
}
function check() {
echo "${green}${bold}${reset} $1${reset}"
}
function uncheck() {
echo "${red}${bold}${reset} $1${reset}"
}
####### Setup methods
function wait_for_user() {
while :
do
read -p "${blue}==>${reset} $1 [Y/n] " imp
case $imp in
[yY] ) echo; break ;;
'' ) echo; break ;;
[nN] ) abortInstall "${red}==>${reset} Process stopped by user. To resume the install run the one-liner command again." ;;
* ) echo "Unrecognized option provided. Please provide either 'Y' or 'N'";
esac
done
}
function exe() {
echo "\$ $@"; "$@"
}
function detectOS() {
if [[ "$OSTYPE" == "linux-gnu" ]]
then
OS_TYPE="linux"
get_linux_dependencies
elif [[ "$OSTYPE" == "darwin"* ]]
then
OS_TYPE="osx"
get_osx_dependencies
else
OS_TYPE="win"
abortInstall "${red}==>${reset} ${b}OS not supported:${reset} parity one-liner currently support OS X and Linux.\nFor instructions on installing parity on other platforms please visit ${u}${blue}http://ethcore.io/${reset}"
fi
echo
if [[ $depCount == $depFound ]]
then
green "Found all dependencies ($depFound/$depCount)"
else
if [[ $canContinue == true ]]
then
red "Some dependencies are missing ($depFound/$depCount)"
elif [[ $canContinue == false && $depFound == 0 ]]
then
red "All dependencies are missing and cannot be auto-installed ($depFound/$depCount)"
abortInstall "$errorMessages";
elif [[ $canContinue == false ]]
then
red "Some dependencies which cannot be auto-installed are missing ($depFound/$depCount)"
abortInstall "$errorMessages";
fi
fi
}
function get_osx_dependencies()
{
macos_version
find_git
find_ruby
find_brew
}
function macos_version()
{
declare -a reqVersion
declare -a localVersion
depCount=$((depCount+1))
OSX_VERSION=`/usr/bin/sw_vers -productVersion 2>/dev/null`
if [ -z "$OSX_VERSION" ]
then
uncheck "OS X version not supported 🔥"
isOsVersion=false
canContinue=false
else
IFS='.' read -a localVersion <<< "$OSX_VERSION"
IFS='.' read -a reqVersion <<< "$OSX_REQUIERED_VERSION"
if (( ${reqVersion[0]} <= ${localVersion[0]} )) && (( ${reqVersion[1]} <= ${localVersion[1]} ))
then
check "OS X Version ${OSX_VERSION}"
isOsVersion=true
depFound=$((depFound+1))
return
else
uncheck "OS X version not supported"
isOsVersion=false
canContinue=false
fi
fi
errorMessages+="${red}==>${reset} ${b}Mac OS version too old:${reset} eth requires OS X version ${red}$OSX_REQUIERED_VERSION${reset} at least in order to run.\n"
errorMessages+=" Please update the OS and reload the install process.\n"
}
function find_eth()
{
ETH_PATH=`which eth 2>/dev/null`
if [[ -f $ETH_PATH ]]
then
check "Found eth: $ETH_PATH"
echo "$($ETH_PATH -V)"
isEth=true
else
uncheck "Eth is missing"
isEth=false
fi
}
function find_git()
{
depCount=$((depCount+1))
GIT_PATH=`which git 2>/dev/null`
if [[ -f $GIT_PATH ]]
then
check "$($GIT_PATH --version)"
isGit=true
depFound=$((depFound+1))
else
uncheck "Git is missing"
isGit=false
fi
}
function find_ruby()
{
depCount=$((depCount+1))
RUBY_PATH=`which ruby 2>/dev/null`
if [[ -f $RUBY_PATH ]]
then
RUBY_VERSION=`ruby -e "print RUBY_VERSION"`
check "Ruby ${RUBY_VERSION}"
isRuby=true
depFound=$((depFound+1))
else
uncheck "Ruby is missing 🔥"
isRuby=false
canContinue=false
errorMessages+="${red}==>${reset} ${b}Couldn't find Ruby:${reset} Brew requires Ruby which could not be found.\n"
errorMessages+=" Please install Ruby using these instructions ${u}${blue}https://www.ruby-lang.org/en/documentation/installation/${reset}.\n"
fi
}
function find_brew()
{
BREW_PATH=`which brew 2>/dev/null`
if [[ -f $BREW_PATH ]]
then
check "$($BREW_PATH -v)"
isBrew=true
depFound=$((depFound+1))
else
uncheck "Homebrew is missing"
isBrew=false
INSTALL_FILES+="${blue}${dim}==> Homebrew:${reset}\n"
INSTALL_FILES+=" ${blue}${dim}${reset} $HOMEBREW_PREFIX/bin/brew\n"
INSTALL_FILES+=" ${blue}${dim}${reset} $HOMEBREW_PREFIX/Library\n"
INSTALL_FILES+=" ${blue}${dim}${reset} $HOMEBREW_PREFIX/share/man/man1/brew.1\n"
fi
depCount=$((depCount+1))
}
function install_brew()
{
if [[ $isBrew == false ]]
then
head "Installing Homebrew"
if [[ $isRuby == true ]]
then
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
else
cd /usr
if [[ ! -d $HOMEBREW_PREFIX ]]
then
sudo mkdir $HOMEBREW_PREFIX
sudo chmod g+rwx $HOMEBREW_PREFIX
fi
if [[ ! -d $HOMEBREW_CACHE ]]
then
sudo mkdir $HOMEBREW_CACHE
sudo chmod g+rwx $HOMEBREW_CACHE
fi
DEVELOPER_DIR=`/usr/bin/xcode-select -print-path 2>/dev/null`
if [[ ! $(ls -A $DEVELOPER_DIR) || ! -f $DEVELOPER_DIR/usr/bin/git ]]
then
info "Installing the Command Line Tools (expect a GUI popup):"
sudo /usr/bin/xcode-select --install
echo "Press any key when the installation has completed"
fi
cd $HOMEBREW_PREFIX
bash -o pipefail -c "curl -fsSL ${HOMEBREW_REPO}/tarball/master | tar xz -m --strip 1"
fi
find_brew
echo
if [[ $isBrew == false ]]
then
abortInstall "Couldn't install brew"
fi
fi
}
function osx_installer()
{
osx_dependency_installer
info "Updating brew"
exe brew update
echo
info "Installing rocksdb"
exe brew install rocksdb
info "Installing multirust"
exe brew install multirust
sudo multirust update nightly
sudo multirust default nightly
echo
}
function osx_dependency_installer()
{
if [[ $isGit == false ]];
then
echo "Installing Git"
fi
if [[ $isRuby == false ]];
then
echo "Installing Ruby"
fi
if [[ $isBrew == false ]];
then
install_brew
fi
}
function get_linux_dependencies()
{
find_apt
}
function find_apt()
{
APT_PATH=`which apt-get 2>/dev/null`
if [[ -f $APT_PATH ]]
then
check "apt-get"
echo "$($APT_PATH -v)"
isApt=true
else
uncheck "apt-get is missing"
isApt=false
fi
}
function linux_rocksdb_installer()
{
oldpwd=`pwd`
cd /tmp
exe git clone --branch v4.1 --depth=1 https://github.com/facebook/rocksdb.git
cd rocksdb
exe make shared_lib
sudo cp -a librocksdb.so* /usr/lib
sudo ldconfig
cd /tmp
rm -rf /tmp/rocksdb
cd $oldpwd
}
function linux_installer()
{
info "Installing git"
sudo apt-get install -q -y git
echo
info "Installing rocksdb"
linux_rocksdb_installer
echo
info "Installing multirust"
curl -sf https://raw.githubusercontent.com/brson/multirust/master/blastoff.sh | sudo sh -s -- --yes
sudo multirust update nightly
sudo multirust default nightly
echo
}
function install()
{
echo
head "Installing Parity build dependencies"
if [[ $OS_TYPE == "osx" ]]
then
osx_installer
elif [[ $OS_TYPE == "linux" ]]
then
linux_installer
fi
}
function verify_installation()
{
info "Verifying installation"
# find_eth
# if [[ $isEth == false ]]
# then
# abortInstall
# fi
}
function abortInstall()
{
echo
error "Installation failed"
echo -e "$1"
echo
exit 0
}
function finish()
{
# echo
# successHeading "Installation successful!"
# head "Next steps"
# info "Run ${cyan}\`\`${reset} to get started.${reset}"
# echo
exit 0
}
# Check dependencies
head "Checking OS dependencies"
detectOS
echo
head "In addition to the parity build dependencies, this script will install:"
echo "$INSTALL_FILES"
echo
# Prompt user to continue or abort
wait_for_user "${b}OK,${reset} let's go!"
# Install dependencies and eth
install
# Check installation
verify_installation
# Display goodby message
finish
}
run_installer

View File

@ -13,4 +13,5 @@ ethcore = { path = ".." }
clippy = "0.0.37"
log = "0.3"
env_logger = "0.3"
time = "0.1.34"

View File

@ -22,6 +22,7 @@ use range_collection::{RangeCollection, ToUsize, FromUsize};
use ethcore::error::*;
use ethcore::block::Block;
use io::SyncIo;
use time;
impl ToUsize for BlockNumber {
fn to_usize(&self) -> usize {
@ -61,6 +62,8 @@ const RECEIPTS_PACKET: u8 = 0x10;
const NETWORK_ID: U256 = ONE_U256; //TODO: get this from parent
const CONNECTION_TIMEOUT_SEC: f64 = 30f64;
struct Header {
/// Header data
data: Bytes,
@ -138,6 +141,8 @@ struct PeerInfo {
asking: PeerAsking,
/// A set of block numbers being requested
asking_blocks: Vec<BlockNumber>,
/// Request timestamp
ask_time: f64,
}
/// Blockchain sync handler.
@ -250,6 +255,7 @@ impl ChainSync {
genesis: try!(r.val_at(4)),
asking: PeerAsking::Nothing,
asking_blocks: Vec::new(),
ask_time: 0f64,
};
trace!(target: "sync", "New peer {} (protocol: {}, network: {:?}, difficulty: {:?}, latest:{}, genesis:{})", peer_id, peer.protocol_version, peer.network_id, peer.difficulty, peer.latest, peer.genesis);
@ -408,6 +414,7 @@ impl ChainSync {
trace!(target: "sync", "{} -> NewBlock ({})", peer_id, h);
let header_view = HeaderView::new(header_rlp.as_raw());
// TODO: Decompose block and add to self.headers and self.bodies instead
let mut unknown = false;
if header_view.number() == From::from(self.last_imported_block + 1) {
match io.chain().import_block(block_rlp.as_raw().to_vec()) {
Err(ImportError::AlreadyInChain) => {
@ -416,6 +423,10 @@ impl ChainSync {
Err(ImportError::AlreadyQueued) => {
trace!(target: "sync", "New block already queued {:?}", h);
},
Err(ImportError::UnknownParent) => {
unknown = true;
trace!(target: "sync", "New block with unknown parent {:?}", h);
},
Ok(_) => {
trace!(target: "sync", "New block queued {:?}", h);
},
@ -426,6 +437,9 @@ impl ChainSync {
};
}
else {
unknown = true;
}
if unknown {
trace!(target: "sync", "New block unknown {:?}", h);
//TODO: handle too many unknown blocks
let difficulty: U256 = try!(r.val_at(1));
@ -795,6 +809,7 @@ impl ChainSync {
Ok(_) => {
let mut peer = self.peers.get_mut(&peer_id).unwrap();
peer.asking = asking;
peer.ask_time = time::precise_time_s();
}
}
}
@ -969,6 +984,16 @@ impl ChainSync {
})
}
/// Handle peer timeouts
pub fn maintain_peers(&self, io: &mut SyncIo) {
let tick = time::precise_time_s();
for (peer_id, peer) in &self.peers {
if peer.asking != PeerAsking::Nothing && (tick - peer.ask_time) > CONNECTION_TIMEOUT_SEC {
io.disconnect_peer(*peer_id);
}
}
}
/// Maintain other peers. Send out any new blocks and transactions
pub fn _maintain_sync(&mut self, _io: &mut SyncIo) {
}

View File

@ -9,6 +9,8 @@ use ethcore::service::SyncMessage;
pub trait SyncIo {
/// Disable a peer
fn disable_peer(&mut self, peer_id: PeerId);
/// Disconnect peer
fn disconnect_peer(&mut self, peer_id: PeerId);
/// Respond to current request with a packet. Can be called from an IO handler for incoming packet.
fn respond(&mut self, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError>;
/// Send a packet to a peer.
@ -42,6 +44,10 @@ impl<'s, 'h> SyncIo for NetSyncIo<'s, 'h> {
self.network.disable_peer(peer_id);
}
fn disconnect_peer(&mut self, peer_id: PeerId) {
self.network.disconnect_peer(peer_id);
}
fn respond(&mut self, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError>{
self.network.respond(packet_id, data)
}

View File

@ -33,11 +33,13 @@ extern crate log;
extern crate ethcore_util as util;
extern crate ethcore;
extern crate env_logger;
extern crate time;
use std::ops::*;
use std::sync::*;
use ethcore::client::Client;
use util::network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId};
use util::io::TimerToken;
use chain::ChainSync;
use ethcore::service::SyncMessage;
use io::NetSyncIo;
@ -87,7 +89,8 @@ impl EthSync {
}
impl NetworkProtocolHandler<SyncMessage> for EthSync {
fn initialize(&self, _io: &NetworkContext<SyncMessage>) {
fn initialize(&self, io: &NetworkContext<SyncMessage>) {
io.register_timer(0, 1000).expect("Error registering sync timer");
}
fn read(&self, io: &NetworkContext<SyncMessage>, peer: &PeerId, packet_id: u8, data: &[u8]) {
@ -101,6 +104,10 @@ impl NetworkProtocolHandler<SyncMessage> for EthSync {
fn disconnected(&self, io: &NetworkContext<SyncMessage>, peer: &PeerId) {
self.sync.write().unwrap().on_peer_aborting(&mut NetSyncIo::new(io, self.chain.deref()), *peer);
}
fn timeout(&self, io: &NetworkContext<SyncMessage>, _timer: TimerToken) {
self.sync.write().unwrap().maintain_peers(&mut NetSyncIo::new(io, self.chain.deref()));
}
}

View File

@ -209,6 +209,9 @@ impl<'p> SyncIo for TestIo<'p> {
fn disable_peer(&mut self, _peer_id: PeerId) {
}
fn disconnect_peer(&mut self, _peer_id: PeerId) {
}
fn respond(&mut self, packet_id: PacketId, data: Vec<u8>) -> Result<(), UtilError> {
self.queue.push_back(TestPacket {
data: data,

View File

@ -207,6 +207,12 @@ pub struct EncryptedConnection {
}
impl EncryptedConnection {
/// Get socket token
pub fn token(&self) -> StreamToken {
self.connection.token
}
/// Create an encrypted connection out of the handshake. Consumes a handshake object.
pub fn new(mut handshake: Handshake) -> Result<EncryptedConnection, UtilError> {
let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_public));

View File

@ -5,17 +5,17 @@ use rlp::*;
pub enum DisconnectReason
{
DisconnectRequested,
//TCPError,
//BadProtocol,
_TCPError,
_BadProtocol,
UselessPeer,
//TooManyPeers,
//DuplicatePeer,
//IncompatibleProtocol,
//NullIdentity,
//ClientQuit,
//UnexpectedIdentity,
//LocalIdentity,
//PingTimeout,
_TooManyPeers,
_DuplicatePeer,
_IncompatibleProtocol,
_NullIdentity,
_ClientQuit,
_UnexpectedIdentity,
_LocalIdentity,
PingTimeout,
}
#[derive(Debug)]

View File

@ -19,6 +19,7 @@ use io::*;
use network::NetworkProtocolHandler;
use network::node::*;
use network::stats::NetworkStats;
use network::error::DisconnectReason;
type Slab<T> = ::slab::Slab<T, usize>;
@ -108,6 +109,8 @@ pub enum NetworkIoMessage<Message> where Message: Send + Sync + Clone {
/// Timer delay in milliseconds.
delay: u64,
},
/// Disconnect a peer
Disconnect(PeerId),
/// User message
User(Message),
}
@ -181,8 +184,14 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone
}
/// Disable current protocol capability for given peer. If no capabilities left peer gets disconnected.
pub fn disable_peer(&self, _peer: PeerId) {
pub fn disable_peer(&self, peer: PeerId) {
//TODO: remove capability, disconnect if no capabilities left
self.disconnect_peer(peer);
}
/// Disconnect peer. Reconnect can be attempted later.
pub fn disconnect_peer(&self, peer: PeerId) {
self.io.message(NetworkIoMessage::Disconnect(peer));
}
/// Register a new IO timer. 'IoHandler::timeout' will be called with the token.
@ -332,6 +341,7 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
}
fn maintain_network(&self, io: &IoContext<NetworkIoMessage<Message>>) {
self.keep_alive(io);
self.connect_peers(io);
}
@ -343,6 +353,21 @@ impl<Message> Host<Message> where Message: Send + Sync + Clone {
self.connections.read().unwrap().iter().any(|e| match *e.lock().unwrap().deref() { ConnectionEntry::Handshake(ref h) => h.id.eq(&id), _ => false })
}
fn keep_alive(&self, io: &IoContext<NetworkIoMessage<Message>>) {
let mut to_kill = Vec::new();
for e in self.connections.write().unwrap().iter_mut() {
if let ConnectionEntry::Session(ref mut s) = *e.lock().unwrap().deref_mut() {
if !s.keep_alive() {
s.disconnect(DisconnectReason::PingTimeout);
to_kill.push(s.token());
}
}
}
for p in to_kill {
self.kill_connection(p, io);
}
}
fn connect_peers(&self, io: &IoContext<NetworkIoMessage<Message>>) {
struct NodeInfo {
id: NodeId,
@ -684,6 +709,15 @@ impl<Message> IoHandler<NetworkIoMessage<Message>> for Host<Message> where Messa
self.timers.write().unwrap().insert(handler_token, ProtocolTimer { protocol: protocol, token: *token });
io.register_timer(handler_token, *delay).expect("Error registering timer");
},
NetworkIoMessage::Disconnect(ref peer) => {
if let Some(connection) = self.connections.read().unwrap().get(*peer).cloned() {
match *connection.lock().unwrap().deref_mut() {
ConnectionEntry::Handshake(_) => {},
ConnectionEntry::Session(ref mut s) => { s.disconnect(DisconnectReason::DisconnectRequested); }
}
}
self.kill_connection(*peer, io);
},
NetworkIoMessage::User(ref message) => {
for (p, h) in self.handlers.read().unwrap().iter() {
h.message(&NetworkContext::new(io, p, None, self.connections.clone()), &message);

View File

@ -21,7 +21,7 @@ impl<Message> NetworkService<Message> where Message: Send + Sync + Clone + 'stat
let host = Arc::new(Host::new(config));
let stats = host.stats().clone();
let host_info = host.client_version();
info!("NetworkService::start(): id={:?}", host.client_id());
info!("Host ID={:?}", host.client_id());
try!(io_service.register_handler(host));
Ok(NetworkService {
io_service: io_service,

View File

@ -4,10 +4,14 @@ use rlp::*;
use network::connection::{EncryptedConnection, Packet};
use network::handshake::Handshake;
use error::*;
use io::{IoContext};
use io::{IoContext, StreamToken};
use network::error::{NetworkError, DisconnectReason};
use network::host::*;
use network::node::NodeId;
use time;
const PING_TIMEOUT_SEC: u64 = 30;
const PING_INTERVAL_SEC: u64 = 30;
/// Peer session over encrypted connection.
/// When created waits for Hello packet exchange and signals ready state.
@ -19,6 +23,8 @@ pub struct Session {
connection: EncryptedConnection,
/// Session ready flag. Set after successfull Hello packet exchange
had_hello: bool,
ping_time_ns: u64,
pong_time_ns: Option<u64>,
}
/// Structure used to report various session events.
@ -47,6 +53,8 @@ pub struct SessionInfo {
pub protocol_version: u32,
/// Peer protocol capabilities
capabilities: Vec<SessionCapabilityInfo>,
/// Peer ping delay in milliseconds
pub ping_ms: Option<u64>,
}
#[derive(Debug, PartialEq, Eq)]
@ -95,10 +103,13 @@ impl Session {
client_version: String::new(),
protocol_version: 0,
capabilities: Vec::new(),
ping_ms: None,
},
ping_time_ns: 0,
pong_time_ns: None,
};
try!(session.write_hello(host));
try!(session.write_ping());
try!(session.send_ping());
Ok(session)
}
@ -141,7 +152,7 @@ impl Session {
while protocol != self.info.capabilities[i].protocol {
i += 1;
if i == self.info.capabilities.len() {
debug!(target: "net", "Unkown protocol: {:?}", protocol);
debug!(target: "net", "Unknown protocol: {:?}", protocol);
return Ok(())
}
}
@ -152,6 +163,26 @@ impl Session {
self.connection.send_packet(&rlp.out())
}
/// Keep this session alive. Returns false if ping timeout happened
pub fn keep_alive(&mut self) -> bool {
let timed_out = if let Some(pong) = self.pong_time_ns {
pong - self.ping_time_ns > PING_TIMEOUT_SEC * 1000_000_000
} else {
time::precise_time_ns() - self.ping_time_ns > PING_TIMEOUT_SEC * 1000_000_000
};
if !timed_out && time::precise_time_ns() - self.ping_time_ns > PING_INTERVAL_SEC * 1000_000_000 {
if let Err(e) = self.send_ping() {
debug!("Error sending ping message: {:?}", e);
}
}
!timed_out
}
pub fn token(&self) -> StreamToken {
self.connection.token()
}
fn read_packet(&mut self, packet: Packet, host: &HostInfo) -> Result<SessionData, UtilError> {
if packet.data.len() < 2 {
return Err(From::from(NetworkError::BadProtocol));
@ -168,7 +199,12 @@ impl Session {
},
PACKET_DISCONNECT => Err(From::from(NetworkError::Disconnect(DisconnectReason::DisconnectRequested))),
PACKET_PING => {
try!(self.write_pong());
try!(self.send_pong());
Ok(SessionData::None)
},
PACKET_PONG => {
self.pong_time_ns = Some(time::precise_time_ns());
self.info.ping_ms = Some((self.pong_time_ns.unwrap() - self.ping_time_ns) / 1000_000);
Ok(SessionData::None)
},
PACKET_GET_PEERS => Ok(SessionData::None), //TODO;
@ -178,7 +214,7 @@ impl Session {
while packet_id < self.info.capabilities[i].id_offset {
i += 1;
if i == self.info.capabilities.len() {
debug!(target: "net", "Unkown packet: {:?}", packet_id);
debug!(target: "net", "Unknown packet: {:?}", packet_id);
return Ok(SessionData::None)
}
}
@ -189,7 +225,7 @@ impl Session {
Ok(SessionData::Packet { data: packet.data, protocol: protocol, packet_id: pid } )
},
_ => {
debug!(target: "net", "Unkown packet: {:?}", packet_id);
debug!(target: "net", "Unknown packet: {:?}", packet_id);
Ok(SessionData::None)
}
}
@ -255,15 +291,20 @@ impl Session {
Ok(())
}
fn write_ping(&mut self) -> Result<(), UtilError> {
self.send(try!(Session::prepare(PACKET_PING)))
/// Senf ping packet
pub fn send_ping(&mut self) -> Result<(), UtilError> {
try!(self.send(try!(Session::prepare(PACKET_PING))));
self.ping_time_ns = time::precise_time_ns();
self.pong_time_ns = None;
Ok(())
}
fn write_pong(&mut self) -> Result<(), UtilError> {
fn send_pong(&mut self) -> Result<(), UtilError> {
self.send(try!(Session::prepare(PACKET_PONG)))
}
fn disconnect(&mut self, reason: DisconnectReason) -> NetworkError {
/// Disconnect this session
pub fn disconnect(&mut self, reason: DisconnectReason) -> NetworkError {
let mut rlp = RlpStream::new();
rlp.append(&(PACKET_DISCONNECT as u32));
rlp.begin_list(1);