Merge remote-tracking branch 'origin/master' into vmtracing

This commit is contained in:
Gav Wood 2016-05-31 12:05:23 +02:00
commit 649767b911
24 changed files with 428 additions and 230 deletions

38
Cargo.lock generated
View File

@ -299,7 +299,7 @@ version = "1.2.0"
dependencies = [
"ethcore-devtools 1.2.0",
"ethcore-util 1.2.0",
"nanomsg 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
"semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -321,7 +321,7 @@ dependencies = [
"ethcore-ipc 1.2.0",
"jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
]
[[package]]
@ -356,6 +356,7 @@ dependencies = [
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethcore-rpc 1.2.0",
"ethcore-util 1.2.0",
"jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@ -389,7 +390,7 @@ dependencies = [
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rocksdb 0.4.3 (git+https://github.com/ethcore/rust-rocksdb)",
"rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)",
"rust-crypto 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
@ -578,7 +579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "json-ipc-server"
version = "0.1.0"
source = "git+https://github.com/ethcore/json-ipc-server.git#fdcba83d00b127c7419fe21406a5b81998f686eb"
source = "git+https://github.com/ethcore/json-ipc-server.git#4f9226c4f84dcce2385a188374e3b5fc66b63e68"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 2.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -659,14 +660,6 @@ name = "libc"
version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "librocksdb-sys"
version = "0.2.3"
source = "git+https://github.com/ethcore/rust-rocksdb#6b6ce93e2828182691e00da57fdfb2926226f1f1"
dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "log"
version = "0.3.6"
@ -742,8 +735,8 @@ dependencies = [
[[package]]
name = "nanomsg"
version = "0.5.0"
source = "git+https://github.com/ethcore/nanomsg.rs.git#9c81fb3b0f71714b173d0abf14bfd30addf8c7b1"
version = "0.5.1"
source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00"
dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"nanomsg-sys 0.5.0 (git+https://github.com/ethcore/nanomsg.rs.git)",
@ -752,7 +745,7 @@ dependencies = [
[[package]]
name = "nanomsg-sys"
version = "0.5.0"
source = "git+https://github.com/ethcore/nanomsg.rs.git#9c81fb3b0f71714b173d0abf14bfd30addf8c7b1"
source = "git+https://github.com/ethcore/nanomsg.rs.git#c40fe442c9afaea5b38009a3d992ca044dcceb00"
dependencies = [
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1073,11 +1066,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rocksdb"
version = "0.4.3"
source = "git+https://github.com/ethcore/rust-rocksdb#6b6ce93e2828182691e00da57fdfb2926226f1f1"
version = "0.4.5"
source = "git+https://github.com/ethcore/rust-rocksdb#9140e37ce0fdb748097f85653c01b0f7e3736ea9"
dependencies = [
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"librocksdb-sys 0.2.3 (git+https://github.com/ethcore/rust-rocksdb)",
"rocksdb-sys 0.3.0 (git+https://github.com/ethcore/rust-rocksdb)",
]
[[package]]
name = "rocksdb-sys"
version = "0.3.0"
source = "git+https://github.com/ethcore/rust-rocksdb#9140e37ce0fdb748097f85653c01b0f7e3736ea9"
dependencies = [
"gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]

View File

@ -254,7 +254,7 @@ impl<V> Client<V> where V: Verifier {
/// This is triggered by a message coming from a block queue when the block is ready for insertion
pub fn import_verified_blocks(&self, io: &IoChannel<NetSyncMessage>) -> usize {
let max_blocks_to_import = 128;
let max_blocks_to_import = 64;
let mut imported_blocks = Vec::with_capacity(max_blocks_to_import);
let mut invalid_blocks = HashSet::new();

View File

@ -115,7 +115,7 @@ fn can_collect_garbage() {
fn can_handle_long_fork() {
let client_result = generate_dummy_client(1200);
let client = client_result.reference();
for _ in 0..10 {
for _ in 0..20 {
client.import_verified_blocks(&IoChannel::disconnected());
}
assert_eq!(1200, client.chain_info().best_block_number);
@ -124,7 +124,7 @@ fn can_handle_long_fork() {
push_blocks_to_client(client, 49, 1201, 800);
push_blocks_to_client(client, 53, 1201, 600);
for _ in 0..20 {
for _ in 0..40 {
client.import_verified_blocks(&IoChannel::disconnected());
}
assert_eq!(2000, client.chain_info().best_block_number);

View File

@ -396,6 +396,7 @@ impl MinerService for Miner {
Err(ref e) => {
trace!(target: "own_tx", "Failed to import transaction {:?} (hash: {:?})", e, hash);
trace!(target: "own_tx", "Status: {:?}", transaction_queue.status());
warn!(target: "own_tx", "Error importing transaction: {:?}", e);
},
}
import

View File

@ -242,6 +242,11 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
port: conf.args.flag_signer_port,
}, signer::Dependencies {
panic_handler: panic_handler.clone(),
client: client.clone(),
sync: sync.clone(),
secret_store: account_service.clone(),
miner: miner.clone(),
external_miner: external_miner.clone(),
});
// Register IO handler

View File

@ -15,6 +15,10 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use ethcore::client::Client;
use ethsync::EthSync;
use ethminer::{Miner, ExternalMiner};
use util::keys::store::AccountService;
use util::panics::{PanicHandler, ForwardPanic};
use die::*;
@ -32,36 +36,51 @@ pub struct Configuration {
pub struct Dependencies {
pub panic_handler: Arc<PanicHandler>,
pub client: Arc<Client>,
pub sync: Arc<EthSync>,
pub secret_store: Arc<AccountService>,
pub miner: Arc<Miner>,
pub external_miner: Arc<ExternalMiner>,
}
pub fn start(conf: Configuration, deps: Dependencies) -> Option<SignerServer> {
if !conf.enabled {
None
} else {
Some(do_start(conf, deps))
}
}
#[cfg(feature = "ethcore-signer")]
pub fn start(conf: Configuration, deps: Dependencies) -> Option<SignerServer> {
if !conf.enabled {
return None;
}
fn do_start(conf: Configuration, deps: Dependencies) -> SignerServer {
let addr = format!("127.0.0.1:{}", conf.port).parse().unwrap_or_else(|_| {
die!("Invalid port specified: {}", conf.port)
});
let addr = format!("127.0.0.1:{}", conf.port).parse().unwrap_or_else(|_| die!("Invalid port specified: {}", conf.port));
let start_result = signer::Server::start(addr);
let start_result = {
use ethcore_rpc::v1::*;
let server = signer::ServerBuilder::new();
server.add_delegate(Web3Client::new().to_delegate());
server.add_delegate(NetClient::new(&deps.sync).to_delegate());
server.add_delegate(EthClient::new(&deps.client, &deps.sync, &deps.secret_store, &deps.miner, &deps.external_miner).to_delegate());
server.add_delegate(EthFilterClient::new(&deps.client, &deps.miner).to_delegate());
server.add_delegate(PersonalClient::new(&deps.secret_store, &deps.client, &deps.miner).to_delegate());
server.start(addr)
};
match start_result {
Err(signer::ServerError::IoError(err)) => die_with_io_error("Trusted Signer", err),
Err(e) => die!("Trusted Signer: {:?}", e),
Ok(server) => {
deps.panic_handler.forward_from(&server);
Some(server)
server
},
}
}
#[cfg(not(feature = "ethcore-signer"))]
pub fn start(conf: Configuration) -> Option<SignerServer> {
if !conf.enabled {
return None;
}
fn do_start(conf: Configuration) -> ! {
die!("Your Parity version has been compiled without Trusted Signer support.")
}

View File

@ -27,6 +27,7 @@ use jsonrpc_core::*;
use util::numbers::*;
use util::sha3::*;
use util::rlp::{encode, decode, UntrustedRlp, View};
use util::keys::store::AccountProvider;
use ethcore::client::{BlockChainClient, BlockID, TransactionID, UncleID};
use ethcore::block::IsBlock;
use ethcore::views::*;
@ -39,7 +40,6 @@ use v1::traits::{Eth, EthFilter};
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, CallRequest, OptionalValue, Index, Filter, Log, Receipt};
use v1::helpers::{PollFilter, PollManager};
use v1::impls::{dispatch_transaction, sign_and_dispatch};
use util::keys::store::AccountProvider;
use serde;
/// Eth rpc implementation.
@ -244,12 +244,14 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where
let res = match status.state {
SyncState::Idle => SyncStatus::None,
SyncState::Waiting | SyncState::Blocks | SyncState::NewBlocks | SyncState::ChainHead => {
let current_block = U256::from(take_weak!(self.client).chain_info().best_block_number);
let info = SyncInfo {
starting_block: U256::from(status.start_block_number),
current_block: U256::from(take_weak!(self.client).chain_info().best_block_number),
current_block: current_block,
highest_block: U256::from(status.highest_block_number.unwrap_or(status.start_block_number))
};
match info.highest_block > info.starting_block + U256::from(6) {
match info.highest_block > info.current_block + U256::from(6) {
true => SyncStatus::Info(info),
false => SyncStatus::None,
}
@ -494,6 +496,12 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where
})
}
fn sign(&self, params: Params) -> Result<Value, Error> {
from_params::<(Address, H256)>(params).and_then(|(addr, msg)| {
to_value(&take_weak!(self.accounts).sign(&addr, &msg).unwrap_or(H520::zero()))
})
}
fn send_transaction(&self, params: Params) -> Result<Value, Error> {
from_params::<(TransactionRequest, )>(params)
.and_then(|(request, )| {
@ -542,6 +550,18 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM> where
to_value(&r.map(|res| res.gas_used + res.refunded).unwrap_or(From::from(0)))
})
}
fn compile_lll(&self, _: Params) -> Result<Value, Error> {
rpc_unimplemented!()
}
fn compile_serpent(&self, _: Params) -> Result<Value, Error> {
rpc_unimplemented!()
}
fn compile_solidity(&self, _: Params) -> Result<Value, Error> {
rpc_unimplemented!()
}
}
/// Eth filter rpc implementation.

View File

@ -25,6 +25,10 @@ macro_rules! take_weak {
}
}
macro_rules! rpc_unimplemented {
() => (Err(Error::internal_error()))
}
mod web3;
mod eth;
mod net;
@ -55,22 +59,14 @@ fn dispatch_transaction<C, M>(client: &C, miner: &M, signed_transaction: SignedT
where C: BlockChainClient, M: MinerService {
let hash = signed_transaction.hash();
let import = {
miner.import_own_transaction(client, signed_transaction, |a: &Address| {
AccountDetails {
nonce: client.latest_nonce(&a),
balance: client.latest_balance(&a),
}
})
};
match import {
Ok(_) => to_value(&hash),
Err(e) => {
warn!("Error sending transaction: {:?}", e);
to_value(&H256::zero())
let import = miner.import_own_transaction(client, signed_transaction, |a: &Address| {
AccountDetails {
nonce: client.latest_nonce(&a),
balance: client.latest_balance(&a),
}
}
});
to_value(&import.map(|_| hash).unwrap_or(H256::zero()))
}
fn sign_and_dispatch<C, M>(client: &Weak<C>, miner: &Weak<M>, request: TransactionRequest, secret: H256) -> Result<Value, Error>

View File

@ -27,7 +27,7 @@ use ethcore::transaction::{Transaction, Action};
use ethminer::{MinerService, ExternalMiner};
use devtools::RandomTempPath;
use util::io::IoChannel;
use util::hash::{Address, FixedHash};
use util::hash::Address;
use util::numbers::{Uint, U256};
use util::keys::{AccountProvider, TestAccount, TestAccountProvider};
use jsonrpc_core::IoHandler;

View File

@ -20,14 +20,16 @@ use std::sync::{Arc, RwLock};
use jsonrpc_core::IoHandler;
use util::hash::{Address, H256, FixedHash};
use util::numbers::{Uint, U256};
use util::keys::{TestAccount, TestAccountProvider};
use util::keys::{AccountProvider, TestAccount, TestAccountProvider};
use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionID};
use ethcore::log_entry::{LocalizedLogEntry, LogEntry};
use ethcore::receipt::LocalizedReceipt;
use ethcore::transaction::{Transaction, Action};
use ethminer::ExternalMiner;
use ethminer::{ExternalMiner, MinerService};
use ethsync::SyncState;
use v1::{Eth, EthClient};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService};
use rustc_serialize::hex::ToHex;
fn blockchain_client() -> Arc<TestBlockChainClient> {
let client = TestBlockChainClient::new();
@ -92,9 +94,39 @@ fn rpc_eth_protocol_version() {
}
#[test]
#[ignore]
fn rpc_eth_syncing() {
unimplemented!()
let request = r#"{"jsonrpc": "2.0", "method": "eth_syncing", "params": [], "id": 1}"#;
let tester = EthTester::default();
let false_res = r#"{"jsonrpc":"2.0","result":false,"id":1}"#;
assert_eq!(tester.io.handle_request(request), Some(false_res.to_owned()));
{
let mut status = tester.sync.status.write().unwrap();
status.state = SyncState::Blocks;
status.highest_block_number = Some(2500);
// "sync" to 1000 blocks.
// causes TestBlockChainClient to return 1000 for its best block number.
let mut blocks = tester.client.blocks.write().unwrap();
for i in 0..1000 {
blocks.insert(H256::from(i), Vec::new());
}
}
let true_res = r#"{"jsonrpc":"2.0","result":{"currentBlock":"0x03e8","highestBlock":"0x09c4","startingBlock":"0x00"},"id":1}"#;
assert_eq!(tester.io.handle_request(request), Some(true_res.to_owned()));
{
// finish "syncing"
let mut blocks = tester.client.blocks.write().unwrap();
for i in 0..1500 {
blocks.insert(H256::from(i + 1000), Vec::new());
}
}
assert_eq!(tester.io.handle_request(request), Some(false_res.to_owned()));
}
#[test]
@ -130,9 +162,47 @@ fn rpc_eth_submit_hashrate() {
}
#[test]
#[ignore]
fn rpc_eth_sign() {
let tester = EthTester::default();
let account = tester.accounts_provider.new_account("abcd").unwrap();
let message = H256::from("0x0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f");
let signed = tester.accounts_provider.sign(&account, &message).unwrap();
let req = r#"{
"jsonrpc": "2.0",
"method": "eth_sign",
"params": [
""#.to_owned() + &format!("0x{:?}", account) + r#"",
"0x0cc175b9c0f1b6a831c399e26977266192eb5ffee6ae2fec3ad71c777531578f"
],
"id": 1
}"#;
let res = r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", signed) + r#"","id":1}"#;
assert_eq!(tester.io.handle_request(&req), Some(res));
}
#[test]
fn rpc_eth_author() {
unimplemented!()
let make_res = |addr| r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", addr) + r#"","id":1}"#;
let tester = EthTester::default();
let req = r#"{
"jsonrpc": "2.0",
"method": "eth_coinbase",
"params": [],
"id": 1
}"#;
assert_eq!(tester.io.handle_request(req), Some(make_res(Address::zero())));
for i in 0..20 {
let addr = tester.accounts_provider.new_account(&format!("{}", i)).unwrap();
tester.miner.set_author(addr.clone());
assert_eq!(tester.io.handle_request(req), Some(make_res(addr)));
}
}
#[test]
@ -193,18 +263,22 @@ fn rpc_eth_balance() {
assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
}
#[ignore] //TODO: propert test
#[test]
fn rpc_eth_balance_pending() {
let tester = EthTester::default();
tester.client.set_balance(Address::from(1), U256::from(5));
let request = r#"{
"jsonrpc": "2.0",
"method": "eth_getBalance",
"params": ["0x0000000000000000000000000000000000000001", "latest"],
"params": ["0x0000000000000000000000000000000000000001", "pending"],
"id": 1
}"#;
let response = r#"{"jsonrpc":"2.0","result":"0x","id":1}"#;
// the TestMinerService doesn't communicate with the the TestBlockChainClient in any way.
// if this returns zero, we know that the "pending" call is being properly forwarded to the
// miner.
let response = r#"{"jsonrpc":"2.0","result":"0x00","id":1}"#;
assert_eq!(tester.io.handle_request(request), Some(response.to_owned()));
}
@ -507,7 +581,7 @@ fn rpc_eth_send_transaction() {
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
assert_eq!(tester.io.handle_request(request.as_ref()), Some(response));
assert_eq!(tester.io.handle_request(&request), Some(response));
tester.miner.last_nonces.write().unwrap().insert(address.clone(), U256::zero());
@ -522,19 +596,38 @@ fn rpc_eth_send_transaction() {
let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#;
assert_eq!(tester.io.handle_request(request.as_ref()), Some(response));
assert_eq!(tester.io.handle_request(&request), Some(response));
}
#[test]
#[ignore]
fn rpc_eth_send_raw_transaction() {
unimplemented!()
}
let tester = EthTester::default();
let address = tester.accounts_provider.new_account("abcd").unwrap();
let secret = tester.accounts_provider.account_secret(&address).unwrap();
#[test]
#[ignore]
fn rpc_eth_sign() {
unimplemented!()
let t = Transaction {
nonce: U256::zero(),
gas_price: U256::from(0x9184e72a000u64),
gas: U256::from(0x76c0),
action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()),
value: U256::from(0x9184e72au64),
data: vec![]
}.sign(&secret);
let rlp = ::util::rlp::encode(&t).to_vec().to_hex();
let req = r#"{
"jsonrpc": "2.0",
"method": "eth_sendRawTransaction",
"params": [
"0x"#.to_owned() + &rlp + r#""
],
"id": 1
}"#;
let res = r#"{"jsonrpc":"2.0","result":""#.to_owned() + &format!("0x{:?}", t.hash()) + r#"","id":1}"#;
assert_eq!(tester.io.handle_request(&req), Some(res));
}
#[test]

View File

@ -21,115 +21,115 @@ use jsonrpc_core::*;
/// Eth rpc interface.
pub trait Eth: Sized + Send + Sync + 'static {
/// Returns protocol version.
fn protocol_version(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn protocol_version(&self, _: Params) -> Result<Value, Error>;
/// Returns an object with data about the sync status or false. (wtf?)
fn syncing(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn syncing(&self, _: Params) -> Result<Value, Error>;
/// Returns the number of hashes per second that the node is mining with.
fn hashrate(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn hashrate(&self, _: Params) -> Result<Value, Error>;
/// Returns block author.
fn author(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn author(&self, _: Params) -> Result<Value, Error>;
/// Returns true if client is actively mining new blocks.
fn is_mining(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn is_mining(&self, _: Params) -> Result<Value, Error>;
/// Returns current gas_price.
fn gas_price(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn gas_price(&self, _: Params) -> Result<Value, Error>;
/// Returns accounts list.
fn accounts(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn accounts(&self, _: Params) -> Result<Value, Error>;
/// Returns highest block number.
fn block_number(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn block_number(&self, _: Params) -> Result<Value, Error>;
/// Returns balance of the given account.
fn balance(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn balance(&self, _: Params) -> Result<Value, Error>;
/// Returns content of the storage at given address.
fn storage_at(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn storage_at(&self, _: Params) -> Result<Value, Error>;
/// Returns block with given hash.
fn block_by_hash(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn block_by_hash(&self, _: Params) -> Result<Value, Error>;
/// Returns block with given number.
fn block_by_number(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn block_by_number(&self, _: Params) -> Result<Value, Error>;
/// Returns the number of transactions sent from given address at given time (block number).
fn transaction_count(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn transaction_count(&self, _: Params) -> Result<Value, Error>;
/// Returns the number of transactions in a block with given hash.
fn block_transaction_count_by_hash(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn block_transaction_count_by_hash(&self, _: Params) -> Result<Value, Error>;
/// Returns the number of transactions in a block with given block number.
fn block_transaction_count_by_number(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn block_transaction_count_by_number(&self, _: Params) -> Result<Value, Error>;
/// Returns the number of uncles in a block with given hash.
fn block_uncles_count_by_hash(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn block_uncles_count_by_hash(&self, _: Params) -> Result<Value, Error>;
/// Returns the number of uncles in a block with given block number.
fn block_uncles_count_by_number(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn block_uncles_count_by_number(&self, _: Params) -> Result<Value, Error>;
/// Returns the code at given address at given time (block number).
fn code_at(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn code_at(&self, _: Params) -> Result<Value, Error>;
/// Signs the data with given address signature.
fn sign(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn sign(&self, _: Params) -> Result<Value, Error>;
/// Sends transaction.
fn send_transaction(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn send_transaction(&self, _: Params) -> Result<Value, Error>;
/// Sends signed transaction.
fn send_raw_transaction(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn send_raw_transaction(&self, _: Params) -> Result<Value, Error>;
/// Call contract.
fn call(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn call(&self, _: Params) -> Result<Value, Error>;
/// Estimate gas needed for execution of given contract.
fn estimate_gas(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn estimate_gas(&self, _: Params) -> Result<Value, Error>;
/// Get transaction by it's hash.
fn transaction_by_hash(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn transaction_by_hash(&self, _: Params) -> Result<Value, Error>;
/// Returns transaction at given block hash and index.
fn transaction_by_block_hash_and_index(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn transaction_by_block_hash_and_index(&self, _: Params) -> Result<Value, Error>;
/// Returns transaction by given block number and index.
fn transaction_by_block_number_and_index(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn transaction_by_block_number_and_index(&self, _: Params) -> Result<Value, Error>;
/// Returns transaction receipt.
fn transaction_receipt(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn transaction_receipt(&self, _: Params) -> Result<Value, Error>;
/// Returns an uncles at given block and index.
fn uncle_by_block_hash_and_index(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn uncle_by_block_hash_and_index(&self, _: Params) -> Result<Value, Error>;
/// Returns an uncles at given block and index.
fn uncle_by_block_number_and_index(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn uncle_by_block_number_and_index(&self, _: Params) -> Result<Value, Error>;
/// Returns available compilers.
fn compilers(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn compilers(&self, _: Params) -> Result<Value, Error>;
/// Compiles lll code.
fn compile_lll(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn compile_lll(&self, _: Params) -> Result<Value, Error>;
/// Compiles solidity.
fn compile_solidity(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn compile_solidity(&self, _: Params) -> Result<Value, Error>;
/// Compiles serpent.
fn compile_serpent(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn compile_serpent(&self, _: Params) -> Result<Value, Error>;
/// Returns logs matching given filter object.
fn logs(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn logs(&self, _: Params) -> Result<Value, Error>;
/// Returns the hash of the current block, the seedHash, and the boundary condition to be met.
fn work(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn work(&self, _: Params) -> Result<Value, Error>;
/// Used for submitting a proof-of-work solution.
fn submit_work(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn submit_work(&self, _: Params) -> Result<Value, Error>;
/// Used for submitting mining hashrate.
fn submit_hashrate(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn submit_hashrate(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {
@ -179,22 +179,22 @@ pub trait Eth: Sized + Send + Sync + 'static {
// TODO: do filters api properly
pub trait EthFilter: Sized + Send + Sync + 'static {
/// Returns id of new filter.
fn new_filter(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn new_filter(&self, _: Params) -> Result<Value, Error>;
/// Returns id of new block filter.
fn new_block_filter(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn new_block_filter(&self, _: Params) -> Result<Value, Error>;
/// Returns id of new block filter.
fn new_pending_transaction_filter(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn new_pending_transaction_filter(&self, _: Params) -> Result<Value, Error>;
/// Returns filter changes since last poll.
fn filter_changes(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn filter_changes(&self, _: Params) -> Result<Value, Error>;
/// Returns all logs matching given filter (in a range 'from' - 'to').
fn filter_logs(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn filter_logs(&self, _: Params) -> Result<Value, Error>;
/// Uninstalls filter.
fn uninstall_filter(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn uninstall_filter(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {

View File

@ -22,55 +22,55 @@ use jsonrpc_core::*;
pub trait Ethcore: Sized + Send + Sync + 'static {
/// Sets new minimal gas price for mined blocks.
fn set_min_gas_price(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn set_min_gas_price(&self, _: Params) -> Result<Value, Error>;
/// Sets new gas floor target for mined blocks.
fn set_gas_floor_target(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn set_gas_floor_target(&self, _: Params) -> Result<Value, Error>;
/// Sets new extra data for mined blocks.
fn set_extra_data(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn set_extra_data(&self, _: Params) -> Result<Value, Error>;
/// Sets new author for mined block.
fn set_author(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn set_author(&self, _: Params) -> Result<Value, Error>;
/// Sets the limits for transaction queue.
fn set_transactions_limit(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn set_transactions_limit(&self, _: Params) -> Result<Value, Error>;
/// Returns current transactions limit.
fn transactions_limit(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn transactions_limit(&self, _: Params) -> Result<Value, Error>;
/// Returns mining extra data.
fn extra_data(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn extra_data(&self, _: Params) -> Result<Value, Error>;
/// Returns mining gas floor target.
fn gas_floor_target(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn gas_floor_target(&self, _: Params) -> Result<Value, Error>;
/// Returns minimal gas price for transaction to be included in queue.
fn min_gas_price(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn min_gas_price(&self, _: Params) -> Result<Value, Error>;
/// Returns latest logs
fn dev_logs(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn dev_logs(&self, _: Params) -> Result<Value, Error>;
/// Returns logs levels
fn dev_logs_levels(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn dev_logs_levels(&self, _: Params) -> Result<Value, Error>;
/// Returns chain name
fn net_chain(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn net_chain(&self, _: Params) -> Result<Value, Error>;
/// Returns max peers
fn net_max_peers(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn net_max_peers(&self, _: Params) -> Result<Value, Error>;
/// Returns network port
fn net_port(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn net_port(&self, _: Params) -> Result<Value, Error>;
/// Returns rpc settings
fn rpc_settings(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn rpc_settings(&self, _: Params) -> Result<Value, Error>;
/// Returns node name
fn node_name(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn node_name(&self, _: Params) -> Result<Value, Error>;
/// Returns default extra data
fn default_extra_data(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn default_extra_data(&self, _: Params) -> Result<Value, Error>;
/// Executes the given call and returns the VM trace for it.
fn vm_trace_call(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }

View File

@ -16,10 +16,6 @@
//! Ethereum rpc interfaces.
macro_rules! rpc_unimplemented {
() => (Err(Error::internal_error()))
}
pub mod web3;
pub mod eth;
pub mod net;

View File

@ -21,14 +21,14 @@ use jsonrpc_core::*;
/// Net rpc interface.
pub trait Net: Sized + Send + Sync + 'static {
/// Returns protocol version.
fn version(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn version(&self, _: Params) -> Result<Value, Error>;
/// Returns number of peers connected to node.
fn peer_count(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn peer_count(&self, _: Params) -> Result<Value, Error>;
/// Returns true if client is actively listening for network connections.
/// Otherwise false.
fn is_listening(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn is_listening(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {

View File

@ -22,16 +22,16 @@ use jsonrpc_core::*;
pub trait Personal: Sized + Send + Sync + 'static {
/// Lists all stored accounts
fn accounts(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn accounts(&self, _: Params) -> Result<Value, Error>;
/// Creates new account (it becomes new current unlocked account)
fn new_account(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn new_account(&self, _: Params) -> Result<Value, Error>;
/// Unlocks specified account for use (can only be one unlocked account at one moment)
fn unlock_account(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn unlock_account(&self, _: Params) -> Result<Value, Error>;
/// Sends transaction and signs it in single call. The account is not unlocked in such case.
fn sign_and_send_transaction(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn sign_and_send_transaction(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {

View File

@ -23,10 +23,10 @@ use jsonrpc_core::*;
pub trait Rpc: Sized + Send + Sync + 'static {
/// Returns supported modules for Geth 1.3.6
fn modules(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn modules(&self, _: Params) -> Result<Value, Error>;
/// Returns supported modules for Geth 1.4.0
fn rpc_modules(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn rpc_modules(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {

View File

@ -21,16 +21,16 @@ use jsonrpc_core::*;
/// Traces specific rpc interface.
pub trait Traces: Sized + Send + Sync + 'static {
/// Returns traces matching given filter.
fn filter(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn filter(&self, _: Params) -> Result<Value, Error>;
/// Returns transaction trace at given index.
fn trace(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn trace(&self, _: Params) -> Result<Value, Error>;
/// Returns all traces of given transaction.
fn transaction_traces(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn transaction_traces(&self, _: Params) -> Result<Value, Error>;
/// Returns all traces produced at given block.
fn block_traces(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn block_traces(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {

View File

@ -21,10 +21,10 @@ use jsonrpc_core::*;
/// Web3 rpc interface.
pub trait Web3: Sized + Send + Sync + 'static {
/// Returns current client version.
fn client_version(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn client_version(&self, _: Params) -> Result<Value, Error>;
/// Returns sha3 of the given data
fn sha3(&self, _: Params) -> Result<Value, Error> { rpc_unimplemented!() }
fn sha3(&self, _: Params) -> Result<Value, Error>;
/// Should be used to convert object to io delegate.
fn to_delegate(self) -> IoDelegate<Self> {

View File

@ -16,6 +16,7 @@ syntex = "^0.32.0"
serde = "0.7.0"
serde_json = "0.7.0"
rustc-serialize = "0.3"
jsonrpc-core = "2.0"
log = "0.3"
env_logger = "0.3"
ws = "0.4.7"

View File

@ -33,10 +33,11 @@
//! ```
//! extern crate ethcore_signer;
//!
//! use ethcore_signer::Server;
//! use ethcore_signer::ServerBuilder;
//!
//! fn main() {
//! let _server = Server::start("127.0.0.1:8084".parse().unwrap());
//! let builder = ServerBuilder::new();
//! let _server = builder.start("127.0.0.1:8084".parse().unwrap()).unwrap();
//! }
//! ```
@ -50,6 +51,7 @@ extern crate rustc_serialize;
extern crate ethcore_util as util;
extern crate ethcore_rpc as rpc;
extern crate jsonrpc_core;
extern crate ws;
mod signing_queue;

View File

@ -19,11 +19,14 @@
use ws;
use std;
use std::thread;
use std::default::Default;
use std::ops::Drop;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::net::SocketAddr;
use util::panics::{PanicHandler, OnPanicListener, MayPanic};
use jsonrpc_core::{IoHandler, IoDelegate};
mod session;
/// Signer startup error
#[derive(Debug)]
@ -43,9 +46,40 @@ impl From<ws::Error> for ServerError {
}
}
/// Builder for `WebSockets` server
pub struct ServerBuilder {
handler: Arc<IoHandler>,
}
impl Default for ServerBuilder {
fn default() -> Self {
ServerBuilder::new()
}
}
impl ServerBuilder {
/// Creates new `ServerBuilder`
pub fn new() -> Self {
ServerBuilder {
handler: Arc::new(IoHandler::new())
}
}
/// Adds rpc delegate
pub fn add_delegate<D>(&self, delegate: IoDelegate<D>) where D: Send + Sync + 'static {
self.handler.add_delegate(delegate);
}
/// Starts a new `WebSocket` server in separate thread.
/// Returns a `Server` handle which closes the server when droped.
pub fn start(self, addr: SocketAddr) -> Result<Server, ServerError> {
Server::start(addr, self.handler)
}
}
/// `WebSockets` server implementation.
pub struct Server {
handle: Option<thread::JoinHandle<ws::WebSocket<Factory>>>,
handle: Option<thread::JoinHandle<ws::WebSocket<session::Factory>>>,
broadcaster: ws::Sender,
panic_handler: Arc<PanicHandler>,
}
@ -53,7 +87,7 @@ pub struct Server {
impl Server {
/// Starts a new `WebSocket` server in separate thread.
/// Returns a `Server` handle which closes the server when droped.
pub fn start(addr: SocketAddr) -> Result<Server, ServerError> {
pub fn start(addr: SocketAddr, handler: Arc<IoHandler>) -> Result<Server, ServerError> {
let config = {
let mut config = ws::Settings::default();
config.max_connections = 5;
@ -62,10 +96,7 @@ impl Server {
};
// Create WebSocket
let session_id = Arc::new(AtomicUsize::new(1));
let ws = try!(ws::Builder::new().with_settings(config).build(Factory {
session_id: session_id,
}));
let ws = try!(ws::Builder::new().with_settings(config).build(session::Factory::new(handler)));
let panic_handler = PanicHandler::new_in_arc();
let ph = panic_handler.clone();
@ -98,31 +129,3 @@ impl Drop for Server {
self.handle.take().unwrap().join().unwrap();
}
}
struct Session {
id: usize,
out: ws::Sender,
}
impl ws::Handler for Session {
fn on_open(&mut self, _shake: ws::Handshake) -> ws::Result<()> {
try!(self.out.send(format!("Hello client no: {}. We are not implemented yet.", self.id)));
try!(self.out.close(ws::CloseCode::Normal));
Ok(())
}
}
struct Factory {
session_id: Arc<AtomicUsize>,
}
impl ws::Factory for Factory {
type Handler = Session;
fn connection_made(&mut self, sender: ws::Sender) -> Self::Handler {
Session {
id: self.session_id.fetch_add(1, Ordering::SeqCst),
out: sender,
}
}
}

View File

@ -0,0 +1,59 @@
// Copyright 2015, 2016 Ethcore (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 <http://www.gnu.org/licenses/>.
//! Session handlers factory.
use ws;
use std::sync::Arc;
use jsonrpc_core::IoHandler;
pub struct Session {
out: ws::Sender,
handler: Arc<IoHandler>,
}
impl ws::Handler for Session {
fn on_message(&mut self, msg: ws::Message) -> ws::Result<()> {
let req = try!(msg.as_text());
match self.handler.handle_request(req) {
Some(res) => self.out.send(res),
None => Ok(()),
}
}
}
pub struct Factory {
handler: Arc<IoHandler>,
}
impl Factory {
pub fn new(handler: Arc<IoHandler>) -> Self {
Factory {
handler: handler,
}
}
}
impl ws::Factory for Factory {
type Handler = Session;
fn connection_made(&mut self, sender: ws::Sender) -> Self::Handler {
Session {
out: sender,
handler: self.handler.clone(),
}
}
}

View File

@ -113,11 +113,12 @@ const MAX_HEADERS_TO_SEND: usize = 512;
const MAX_NODE_DATA_TO_SEND: usize = 1024;
const MAX_RECEIPTS_TO_SEND: usize = 1024;
const MAX_RECEIPTS_HEADERS_TO_SEND: usize = 256;
const MAX_HEADERS_TO_REQUEST: usize = 256;
const MAX_HEADERS_TO_REQUEST: usize = 128;
const MAX_BODIES_TO_REQUEST: usize = 64;
const MIN_PEERS_PROPAGATION: usize = 4;
const MAX_PEERS_PROPAGATION: usize = 128;
const MAX_PEER_LAG_PROPAGATION: BlockNumber = 20;
const SUBCHAIN_SIZE: usize = 64;
const STATUS_PACKET: u8 = 0x00;
const NEW_BLOCK_HASHES_PACKET: u8 = 0x01;
@ -133,7 +134,7 @@ const NODE_DATA_PACKET: u8 = 0x0e;
const GET_RECEIPTS_PACKET: u8 = 0x0f;
const RECEIPTS_PACKET: u8 = 0x10;
const CONNECTION_TIMEOUT_SEC: f64 = 10f64;
const CONNECTION_TIMEOUT_SEC: f64 = 15f64;
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
/// Sync state
@ -639,7 +640,7 @@ impl ChainSync {
self.sync_peer(io, p, false);
}
}
if !self.peers.values().any(|p| p.asking != PeerAsking::Nothing) {
if self.state != SyncState::Waiting && !self.peers.values().any(|p| p.asking != PeerAsking::Nothing) {
self.complete_sync();
}
}
@ -665,7 +666,7 @@ impl ChainSync {
return;
}
if self.state == SyncState::Waiting {
trace!(target: "sync", "Waiting for block queue");
trace!(target: "sync", "Waiting for the block queue");
return;
}
(peer.latest_hash.clone(), peer.difficulty.clone())
@ -689,7 +690,7 @@ impl ChainSync {
// Request subchain headers
trace!(target: "sync", "Starting sync with better chain");
let last = self.last_imported_hash.clone();
self.request_headers_by_hash(io, peer_id, &last, 128, 255, false, PeerAsking::Heads);
self.request_headers_by_hash(io, peer_id, &last, SUBCHAIN_SIZE, MAX_HEADERS_TO_REQUEST - 1, false, PeerAsking::Heads);
},
SyncState::Blocks | SyncState::NewBlocks => {
if io.chain().block_status(BlockID::Hash(peer_latest)) == BlockStatus::Unknown {
@ -704,6 +705,8 @@ impl ChainSync {
fn start_sync_round(&mut self, io: &mut SyncIo) {
self.state = SyncState::ChainHead;
trace!(target: "sync", "Starting round (last imported count = {:?}, block = {:?}", self.imported_this_round, self.last_imported_block);
// Check if need to retract to find the common block. The problem is that the peers still return headers by hash even
// from the non-canonical part of the tree. So we also retract if nothing has been imported last round.
if self.imported_this_round.is_some() && self.imported_this_round.unwrap() == 0 && self.last_imported_block > 0 {
match io.chain().block_hash(BlockID::Number(self.last_imported_block - 1)) {
Some(h) => {
@ -781,9 +784,13 @@ impl ChainSync {
match io.chain().import_block(block) {
Err(Error::Import(ImportError::AlreadyInChain)) => {
self.last_imported_block = number;
self.last_imported_hash = h.clone();
trace!(target: "sync", "Block already in chain {:?}", h);
},
Err(Error::Import(ImportError::AlreadyQueued)) => {
self.last_imported_block = number;
self.last_imported_hash = h.clone();
trace!(target: "sync", "Block already queued {:?}", h);
},
Ok(_) => {
@ -856,22 +863,15 @@ impl ChainSync {
/// Generic request sender
fn send_request(&mut self, sync: &mut SyncIo, peer_id: PeerId, asking: PeerAsking, packet_id: PacketId, packet: Bytes) {
{
let peer = self.peers.get_mut(&peer_id).unwrap();
if peer.asking != PeerAsking::Nothing {
warn!(target:"sync", "Asking {:?} while requesting {:?}", peer.asking, asking);
}
let peer = self.peers.get_mut(&peer_id).unwrap();
if peer.asking != PeerAsking::Nothing {
warn!(target:"sync", "Asking {:?} while requesting {:?}", peer.asking, asking);
}
match sync.send(peer_id, packet_id, packet) {
Err(e) => {
debug!(target:"sync", "Error sending request: {:?}", e);
sync.disable_peer(peer_id);
}
Ok(_) => {
let mut peer = self.peers.get_mut(&peer_id).unwrap();
peer.asking = asking;
peer.ask_time = time::precise_time_s();
}
peer.asking = asking;
peer.ask_time = time::precise_time_s();
if let Err(e) = sync.send(peer_id, packet_id, packet) {
debug!(target:"sync", "Error sending request: {:?}", e);
sync.disable_peer(peer_id);
}
}
@ -1099,6 +1099,7 @@ impl ChainSync {
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 {
trace!(target:"sync", "Timeouted {}", peer_id);
io.disconnect_peer(*peer_id);
}
}
@ -1164,24 +1165,23 @@ impl ChainSync {
.collect::<Vec<_>>()
}
fn select_lagging_peers(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> Vec<(PeerId, BlockNumber)> {
use rand::Rng;
let mut lagging_peers = self.get_lagging_peers(chain_info, io);
// take sqrt(x) peers
let mut count = (self.peers.len() as f64).powf(0.5).round() as usize;
count = min(count, MAX_PEERS_PROPAGATION);
count = max(count, MIN_PEERS_PROPAGATION);
::rand::thread_rng().shuffle(&mut lagging_peers);
lagging_peers.into_iter().take(count).collect::<Vec<_>>()
}
/// propagates latest block to lagging peers
fn propagate_blocks(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> usize {
let updated_peers = {
let lagging_peers = self.get_lagging_peers(chain_info, io);
// sqrt(x)/x scaled to max u32
let fraction = (self.peers.len() as f64).powf(-0.5).mul(u32::max_value() as f64).round() as u32;
let lucky_peers = match lagging_peers.len() {
0 ... MIN_PEERS_PROPAGATION => lagging_peers,
_ => lagging_peers.into_iter().filter(|_| ::rand::random::<u32>() < fraction).collect::<Vec<_>>()
};
// taking at max of MAX_PEERS_PROPAGATION
lucky_peers.iter().map(|&(id, _)| id.clone()).take(min(lucky_peers.len(), MAX_PEERS_PROPAGATION)).collect::<Vec<PeerId>>()
};
let lucky_peers = self.select_lagging_peers(chain_info, io);
let mut sent = 0;
for peer_id in updated_peers {
for (peer_id, _) in lucky_peers {
let rlp = ChainSync::create_latest_block_rlp(io.chain());
self.send_packet(io, peer_id, NEW_BLOCK_PACKET, rlp);
self.peers.get_mut(&peer_id).unwrap().latest_hash = chain_info.best_block_hash.clone();
@ -1193,12 +1193,12 @@ impl ChainSync {
/// propagates new known hashes to all peers
fn propagate_new_hashes(&mut self, chain_info: &BlockChainInfo, io: &mut SyncIo) -> usize {
let updated_peers = self.get_lagging_peers(chain_info, io);
let lucky_peers = self.select_lagging_peers(chain_info, io);
let mut sent = 0;
let last_parent = HeaderView::new(&io.chain().block_header(BlockID::Hash(chain_info.best_block_hash.clone())).unwrap()).parent_hash();
for (peer_id, peer_number) in updated_peers {
for (peer_id, peer_number) in lucky_peers {
let mut peer_best = self.peers.get(&peer_id).unwrap().latest_hash.clone();
if chain_info.best_block_number - peer_number > MAX_PEERS_PROPAGATION as BlockNumber {
if chain_info.best_block_number - peer_number > MAX_PEER_LAG_PROPAGATION as BlockNumber {
// If we think peer is too far behind just send one latest hash
peer_best = last_parent.clone();
}
@ -1259,15 +1259,15 @@ impl ChainSync {
}
fn propagate_latest_blocks(&mut self, io: &mut SyncIo) {
self.propagate_new_transactions(io);
let chain_info = io.chain().chain_info();
if (((chain_info.best_block_number as i64) - (self.last_sent_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION {
let blocks = self.propagate_blocks(&chain_info, io);
let hashes = self.propagate_new_hashes(&chain_info, io);
let blocks = self.propagate_blocks(&chain_info, io);
if blocks != 0 || hashes != 0 {
trace!(target: "sync", "Sent latest {} blocks and {} hashes to peers.", blocks, hashes);
}
}
self.propagate_new_transactions(io);
self.last_sent_block_number = chain_info.best_block_number;
}

View File

@ -159,7 +159,7 @@ fn propagate_hashes() {
#[test]
fn propagate_blocks() {
let mut net = TestNet::new(2);
let mut net = TestNet::new(20);
net.peer_mut(1).chain.add_blocks(10, EachBlockWith::Uncle);
net.sync();
@ -169,7 +169,8 @@ fn propagate_blocks() {
assert!(!net.peer(0).queue.is_empty());
// NEW_BLOCK_PACKET
assert_eq!(0x07, net.peer(0).queue[0].packet_id);
let blocks = net.peer(0).queue.iter().filter(|p| p.packet_id == 0x7).count();
assert!(blocks > 0);
}
#[test]