diff --git a/ethcore/res/ethereum/expanse.json b/ethcore/res/ethereum/expanse.json
new file mode 100644
index 000000000..9b005096b
--- /dev/null
+++ b/ethcore/res/ethereum/expanse.json
@@ -0,0 +1,69 @@
+{
+ "name": "Expanse",
+ "forkName": "expanse",
+ "engine": {
+ "Ethash": {
+ "params": {
+ "gasLimitBoundDivisor": "0x0400",
+ "minimumDifficulty": "0x020000",
+ "difficultyBoundDivisor": "0x0800",
+ "difficultyIncrementDivisor": "60",
+ "durationLimit": "0x3C",
+ "blockReward": "0x6f05b59d3b200000",
+ "registrar" : "0x6c221ca53705f3497ec90ca7b84c59ae7382fc21",
+ "frontierCompatibilityModeLimit": "0x30d40",
+ "difficultyHardforkTransition": "0x59d9",
+ "difficultyHardforkBoundDivisor": "0x0200",
+ "bombDefuseTransition": "0x30d40"
+ }
+ }
+ },
+ "params": {
+ "accountStartNonce": "0x00",
+ "maximumExtraDataSize": "0x20",
+ "minGasLimit": "0x1388",
+ "networkID": "0x1",
+ "subprotocolName": "exp"
+ },
+ "genesis": {
+ "seal": {
+ "ethereum": {
+ "nonce": "0x214652414e4b4f21",
+ "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000"
+ }
+ },
+ "difficulty": "0x40000000",
+ "author": "0x93decab0cd745598860f782ac1e8f046cb99e898",
+ "timestamp": "0x00",
+ "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
+ "extraData": "0x4672616e6b6f497346726565646f6d",
+ "gasLimit": "0x1388"
+ },
+ "nodes": [
+ "enode://7f335a047654f3e70d6f91312a7cf89c39704011f1a584e2698250db3d63817e74b88e26b7854111e16b2c9d0c7173c05419aeee2d0321850227b126d8b1be3f@46.101.156.249:42786",
+ "enode://df872f81e25f72356152b44cab662caf1f2e57c3a156ecd20e9ac9246272af68a2031b4239a0bc831f2c6ab34733a041464d46b3ea36dce88d6c11714446e06b@178.62.208.109:42786",
+ "enode://96d3919b903e7f5ad59ac2f73c43be9172d9d27e2771355db03fd194732b795829a31fe2ea6de109d0804786c39a807e155f065b4b94c6fce167becd0ac02383@45.55.22.34:42786",
+ "enode://5f6c625bf287e3c08aad568de42d868781e961cbda805c8397cfb7be97e229419bef9a5a25a75f97632787106bba8a7caf9060fab3887ad2cfbeb182ab0f433f@46.101.182.53:42786",
+ "enode://d33a8d4c2c38a08971ed975b750f21d54c927c0bf7415931e214465a8d01651ecffe4401e1db913f398383381413c78105656d665d83f385244ab302d6138414@128.199.183.48:42786",
+ "enode://df872f81e25f72356152b44cab662caf1f2e57c3a156ecd20e9ac9246272af68a2031b4239a0bc831f2c6ab34733a041464d46b3ea36dce88d6c11714446e06b@178.62.208.109:42786",
+ "enode://f6f0d6b9b7d02ec9e8e4a16e38675f3621ea5e69860c739a65c1597ca28aefb3cec7a6d84e471ac927d42a1b64c1cbdefad75e7ce8872d57548ddcece20afdd1@159.203.64.95:42786"
+ ],
+ "accounts": {
+ "0000000000000000000000000000000000000001": { "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } },
+ "0000000000000000000000000000000000000002": { "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } },
+ "0000000000000000000000000000000000000003": { "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } },
+ "0000000000000000000000000000000000000004": { "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } },
+ "bb94f0ceb32257275b2a7a9c094c13e469b4563e": {
+ "balance": "10000000000000000000000000"
+ },
+ "15656715068ab0dbdf0ab00748a8a19e40f28192": {
+ "balance": "1000000000000000000000000"
+ },
+ "c075fa11f85bda3aaba67106226aaf086ac16f4e": {
+ "balance": "100000000000000000000000"
+ },
+ "93decab0cd745598860f782ac1e8f046cb99e898": {
+ "balance": "10000000000000000000000"
+ }
+ }
+}
diff --git a/ethcore/res/ethereum/frontier.json b/ethcore/res/ethereum/frontier.json
index 2f91809fc..903e87cc7 100644
--- a/ethcore/res/ethereum/frontier.json
+++ b/ethcore/res/ethereum/frontier.json
@@ -157,6 +157,9 @@
"stateRoot": "0xd7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544"
},
"nodes": [
+ "enode://cd6611461840543d5b9c56fbf088736154c699c43973b3a1a32390cf27106f87e58a818a606ccb05f3866de95a4fe860786fea71bf891ea95f234480d3022aa3@136.243.154.245:30303",
+ "enode://bcc7240543fe2cf86f5e9093d05753dd83343f8fda7bf0e833f65985c73afccf8f981301e13ef49c4804491eab043647374df1c4adf85766af88a624ecc3330e@136.243.154.244:30303",
+ "enode://ed4227681ca8c70beb2277b9e870353a9693f12e7c548c35df6bca6a956934d6f659999c2decb31f75ce217822eefca149ace914f1cbe461ed5a2ebaf9501455@88.212.206.70:30303",
"enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303",
"enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303",
"enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303",
diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs
index 249a3e851..acfba3634 100644
--- a/ethcore/src/ethereum/ethash.rs
+++ b/ethcore/src/ethereum/ethash.rs
@@ -32,6 +32,8 @@ pub struct EthashParams {
pub minimum_difficulty: U256,
/// Difficulty bound divisor.
pub difficulty_bound_divisor: U256,
+ /// Difficulty increment divisor.
+ pub difficulty_increment_divisor: u64,
/// Block duration.
pub duration_limit: u64,
/// Block reward.
@@ -46,6 +48,12 @@ pub struct EthashParams {
pub dao_hardfork_beneficiary: Address,
/// DAO hard-fork DAO accounts list (L)
pub dao_hardfork_accounts: Vec
,
+ /// Transition block for a change of difficulty params (currently just bound_divisor).
+ pub difficulty_hardfork_transition: u64,
+ /// Difficulty param after the difficulty transition.
+ pub difficulty_hardfork_bound_divisor: U256,
+ /// Block on which there is no additional difficulty from the exponential bomb.
+ pub bomb_defuse_transition: u64,
}
impl From for EthashParams {
@@ -54,6 +62,7 @@ impl From for EthashParams {
gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(),
minimum_difficulty: p.minimum_difficulty.into(),
difficulty_bound_divisor: p.difficulty_bound_divisor.into(),
+ difficulty_increment_divisor: p.difficulty_increment_divisor.map_or(10, Into::into),
duration_limit: p.duration_limit.into(),
block_reward: p.block_reward.into(),
registrar: p.registrar.map_or_else(Address::new, Into::into),
@@ -61,6 +70,9 @@ impl From for EthashParams {
dao_hardfork_transition: p.dao_hardfork_transition.map_or(0x7fffffffffffffff, Into::into),
dao_hardfork_beneficiary: p.dao_hardfork_beneficiary.map_or_else(Address::new, Into::into),
dao_hardfork_accounts: p.dao_hardfork_accounts.unwrap_or_else(Vec::new).into_iter().map(Into::into).collect(),
+ difficulty_hardfork_transition: p.difficulty_hardfork_transition.map_or(0x7fffffffffffffff, Into::into),
+ difficulty_hardfork_bound_divisor: p.difficulty_hardfork_bound_divisor.map_or(p.difficulty_bound_divisor.into(), Into::into),
+ bomb_defuse_transition: p.bomb_defuse_transition.map_or(0x7fffffffffffffff, Into::into),
}
}
}
@@ -267,7 +279,11 @@ impl Ethash {
}
let min_difficulty = self.ethash_params.minimum_difficulty;
- let difficulty_bound_divisor = self.ethash_params.difficulty_bound_divisor;
+ let difficulty_hardfork = header.number() >= self.ethash_params.difficulty_hardfork_transition;
+ let difficulty_bound_divisor = match difficulty_hardfork {
+ true => self.ethash_params.difficulty_hardfork_bound_divisor,
+ false => self.ethash_params.difficulty_bound_divisor,
+ };
let duration_limit = self.ethash_params.duration_limit;
let frontier_limit = self.ethash_params.frontier_compatibility_mode_limit;
@@ -281,17 +297,19 @@ impl Ethash {
else {
trace!(target: "ethash", "Calculating difficulty parent.difficulty={}, header.timestamp={}, parent.timestamp={}", parent.difficulty(), header.timestamp(), parent.timestamp());
//block_diff = parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)
- let diff_inc = (header.timestamp() - parent.timestamp()) / 10;
+ let diff_inc = (header.timestamp() - parent.timestamp()) / self.ethash_params.difficulty_increment_divisor;
if diff_inc <= 1 {
- parent.difficulty().clone() + parent.difficulty().clone() / From::from(2048) * From::from(1 - diff_inc)
+ parent.difficulty().clone() + parent.difficulty().clone() / From::from(difficulty_bound_divisor) * From::from(1 - diff_inc)
} else {
- parent.difficulty().clone() - parent.difficulty().clone() / From::from(2048) * From::from(min(diff_inc - 1, 99))
+ parent.difficulty().clone() - parent.difficulty().clone() / From::from(difficulty_bound_divisor) * From::from(min(diff_inc - 1, 99))
}
};
target = max(min_difficulty, target);
- let period = ((parent.number() + 1) / EXP_DIFF_PERIOD) as usize;
- if period > 1 {
- target = max(min_difficulty, target + (U256::from(1) << (period - 2)));
+ if header.number() < self.ethash_params.bomb_defuse_transition {
+ let period = ((parent.number() + 1) / EXP_DIFF_PERIOD) as usize;
+ if period > 1 {
+ target = max(min_difficulty, target + (U256::from(1) << (period - 2)));
+ }
}
target
}
diff --git a/ethcore/src/ethereum/mod.rs b/ethcore/src/ethereum/mod.rs
index 01ef81c75..6d4502d2d 100644
--- a/ethcore/src/ethereum/mod.rs
+++ b/ethcore/src/ethereum/mod.rs
@@ -42,6 +42,9 @@ pub fn new_frontier() -> Spec { load(include_bytes!("../../res/ethereum/frontier
/// Create a new Frontier mainnet chain spec without the DAO hardfork.
pub fn new_classic() -> Spec { load(include_bytes!("../../res/ethereum/classic.json")) }
+/// Create a new Frontier mainnet chain spec without the DAO hardfork.
+pub fn new_expanse() -> Spec { load(include_bytes!("../../res/ethereum/expanse.json")) }
+
/// Create a new Frontier chain spec as though it never changes to Homestead.
pub fn new_frontier_test() -> Spec { load(include_bytes!("../../res/ethereum/frontier_test.json")) }
diff --git a/ethcore/src/spec/spec.rs b/ethcore/src/spec/spec.rs
index aeb50a0ef..b133c7181 100644
--- a/ethcore/src/spec/spec.rs
+++ b/ethcore/src/spec/spec.rs
@@ -37,6 +37,8 @@ pub struct CommonParams {
pub maximum_extra_data_size: usize,
/// Network id.
pub network_id: U256,
+ /// Main subprotocol name.
+ pub subprotocol_name: String,
/// Minimum gas limit.
pub min_gas_limit: U256,
/// Fork block to check.
@@ -49,6 +51,7 @@ impl From for CommonParams {
account_start_nonce: p.account_start_nonce.into(),
maximum_extra_data_size: p.maximum_extra_data_size.into(),
network_id: p.network_id.into(),
+ subprotocol_name: p.subprotocol_name.unwrap_or_else(|| "eth".to_owned()),
min_gas_limit: p.min_gas_limit.into(),
fork_block: if let (Some(n), Some(h)) = (p.fork_block, p.fork_hash) { Some((n.into(), h.into())) } else { None },
}
@@ -156,6 +159,9 @@ impl Spec {
/// Get the configured Network ID.
pub fn network_id(&self) -> U256 { self.params.network_id }
+ /// Get the configured Network ID.
+ pub fn subprotocol_name(&self) -> String { self.params.subprotocol_name.clone() }
+
/// Get the configured network fork block.
pub fn fork_block(&self) -> Option<(BlockNumber, H256)> { self.params.fork_block }
@@ -169,7 +175,7 @@ impl Spec {
header.set_transactions_root(self.transactions_root.clone());
header.set_uncles_hash(RlpStream::new_list(0).out().sha3());
header.set_extra_data(self.extra_data.clone());
- header.set_state_root(self.state_root().clone());
+ header.set_state_root(self.state_root());
header.set_receipts_root(self.receipts_root.clone());
header.set_log_bloom(H2048::new().clone());
header.set_gas_used(self.gas_used.clone());
@@ -184,6 +190,7 @@ impl Spec {
let r = Rlp::new(&seal);
(0..self.seal_fields).map(|i| r.at(i).as_raw().to_vec()).collect()
});
+ trace!(target: "spec", "Header hash is {}", header.hash());
header
}
@@ -229,13 +236,16 @@ impl Spec {
/// Ensure that the given state DB has the trie nodes in for the genesis state.
pub fn ensure_db_good(&self, db: &mut StateDB) -> Result> {
if !db.as_hashdb().contains(&self.state_root()) {
+ trace!(target: "spec", "ensure_db_good: Fresh database? Cannot find state root {}", self.state_root());
let mut root = H256::new();
+
{
let mut t = SecTrieDBMut::new(db.as_hashdb_mut(), &mut root);
for (address, account) in self.genesis_state.get().iter() {
try!(t.insert(&**address, &account.rlp()));
}
}
+ trace!(target: "spec", "ensure_db_good: Populated sec trie; root is {}", root);
for (address, account) in self.genesis_state.get().iter() {
account.insert_additional(&mut AccountDBMut::new(db.as_hashdb_mut(), address));
}
diff --git a/json/src/spec/ethash.rs b/json/src/spec/ethash.rs
index 10d4f84ee..d20ab3992 100644
--- a/json/src/spec/ethash.rs
+++ b/json/src/spec/ethash.rs
@@ -32,6 +32,9 @@ pub struct EthashParams {
#[serde(rename="difficultyBoundDivisor")]
pub difficulty_bound_divisor: Uint,
/// See main EthashParams docs.
+ #[serde(rename="difficultyIncrementDivisor")]
+ pub difficulty_increment_divisor: Option,
+ /// See main EthashParams docs.
#[serde(rename="durationLimit")]
pub duration_limit: Uint,
/// See main EthashParams docs.
@@ -39,9 +42,11 @@ pub struct EthashParams {
pub block_reward: Uint,
/// See main EthashParams docs.
pub registrar: Option,
+
/// See main EthashParams docs.
#[serde(rename="frontierCompatibilityModeLimit")]
pub frontier_compatibility_mode_limit: Option,
+
/// See main EthashParams docs.
#[serde(rename="daoHardforkTransition")]
pub dao_hardfork_transition: Option,
@@ -51,6 +56,16 @@ pub struct EthashParams {
/// See main EthashParams docs.
#[serde(rename="daoHardforkAccounts")]
pub dao_hardfork_accounts: Option>,
+
+ /// See main EthashParams docs.
+ #[serde(rename="difficultyHardforkTransition")]
+ pub difficulty_hardfork_transition: Option,
+ /// See main EthashParams docs.
+ #[serde(rename="difficultyHardforkBoundDivisor")]
+ pub difficulty_hardfork_bound_divisor: Option,
+ /// See main EthashParams docs.
+ #[serde(rename="bombDefuseTransition")]
+ pub bomb_defuse_transition: Option,
}
/// Ethash engine deserialization.
@@ -99,7 +114,10 @@ mod tests {
"0x7602b46df5390e432ef1c307d4f2c9ff6d65cc97",
"0xbb9bc244d798123fde783fcc1c72d3bb8c189413",
"0x807640a13483f8ac783c557fcdf27be11ea4ac7a"
- ]
+ ],
+ "difficultyHardforkTransition": "0x59d9",
+ "difficultyHardforkBoundDivisor": "0x0200",
+ "bombDefuseTransition": "0x42"
}
}"#;
diff --git a/json/src/spec/params.rs b/json/src/spec/params.rs
index 62c63d6b5..676feff93 100644
--- a/json/src/spec/params.rs
+++ b/json/src/spec/params.rs
@@ -31,6 +31,9 @@ pub struct Params {
/// Network id.
#[serde(rename="networkID")]
pub network_id: Uint,
+ /// Name of the main ("eth") subprotocol.
+ #[serde(rename="subprotocolName")]
+ pub subprotocol_name: Option,
/// Minimum gas limit.
#[serde(rename="minGasLimit")]
pub min_gas_limit: Uint,
@@ -53,6 +56,7 @@ mod tests {
"frontierCompatibilityModeLimit": "0x118c30",
"maximumExtraDataSize": "0x20",
"networkID" : "0x1",
+ "subprotocolName" : "exp",
"minGasLimit": "0x1388",
"accountStartNonce": "0x00"
}"#;
diff --git a/parity/params.rs b/parity/params.rs
index 71f702cfb..160b50866 100644
--- a/parity/params.rs
+++ b/parity/params.rs
@@ -29,6 +29,7 @@ pub enum SpecType {
Testnet,
Olympic,
Classic,
+ Expanse,
Custom(String),
}
@@ -47,6 +48,7 @@ impl str::FromStr for SpecType {
"frontier-dogmatic" | "homestead-dogmatic" | "classic" => SpecType::Classic,
"morden" | "testnet" => SpecType::Testnet,
"olympic" => SpecType::Olympic,
+ "expanse" => SpecType::Expanse,
other => SpecType::Custom(other.into()),
};
Ok(spec)
@@ -60,6 +62,7 @@ impl SpecType {
SpecType::Testnet => Ok(ethereum::new_morden()),
SpecType::Olympic => Ok(ethereum::new_olympic()),
SpecType::Classic => Ok(ethereum::new_classic()),
+ SpecType::Expanse => Ok(ethereum::new_expanse()),
SpecType::Custom(ref filename) => {
let file = try!(fs::File::open(filename).map_err(|_| "Could not load specification file."));
Spec::load(file)
diff --git a/parity/run.rs b/parity/run.rs
index e95b5c9f5..4b458d4a6 100644
--- a/parity/run.rs
+++ b/parity/run.rs
@@ -148,6 +148,11 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> {
Some(id) => id,
None => spec.network_id(),
};
+ if spec.subprotocol_name().len() != 3 {
+ warn!("Your chain specification's subprotocol length is not 3. Ignoring.");
+ } else {
+ sync_config.subprotocol_name.clone_from_slice(spec.subprotocol_name().as_bytes());
+ }
sync_config.fork_block = spec.fork_block();
// prepare account provider
diff --git a/sync/src/api.rs b/sync/src/api.rs
index de1769d9c..961a70cd3 100644
--- a/sync/src/api.rs
+++ b/sync/src/api.rs
@@ -15,6 +15,7 @@
// along with Parity. If not, see .
use std::sync::Arc;
+use std::str;
use network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId,
NetworkConfiguration as BasicNetworkConfiguration, NonReservedPeerMode, NetworkError};
use util::{U256, H256};
@@ -29,9 +30,6 @@ use ipc::{BinaryConvertable, BinaryConvertError, IpcConfig};
use std::str::FromStr;
use parking_lot::RwLock;
-/// Ethereum sync protocol
-pub const ETH_PROTOCOL: &'static str = "eth";
-
/// Sync configuration
#[derive(Debug, Clone, Copy)]
pub struct SyncConfig {
@@ -39,6 +37,8 @@ pub struct SyncConfig {
pub max_download_ahead_blocks: usize,
/// Network ID
pub network_id: U256,
+ /// Main "eth" subprotocol name.
+ pub subprotocol_name: [u8; 3],
/// Fork block to check
pub fork_block: Option<(BlockNumber, H256)>,
}
@@ -48,6 +48,7 @@ impl Default for SyncConfig {
SyncConfig {
max_download_ahead_blocks: 20000,
network_id: U256::from(1),
+ subprotocol_name: *b"eth",
fork_block: None,
}
}
@@ -68,6 +69,8 @@ pub struct EthSync {
network: NetworkService,
/// Protocol handler
handler: Arc,
+ /// The main subprotocol name
+ subprotocol_name: [u8; 3],
}
impl EthSync {
@@ -78,6 +81,7 @@ impl EthSync {
let sync = Arc::new(EthSync{
network: service,
handler: Arc::new(SyncProtocolHandler { sync: RwLock::new(chain_sync), chain: chain, snapshot_service: snapshot_service }),
+ subprotocol_name: config.subprotocol_name,
});
Ok(sync)
@@ -135,7 +139,7 @@ impl ChainNotify for EthSync {
sealed: Vec,
_duration: u64)
{
- self.network.with_context(ETH_PROTOCOL, |context| {
+ self.network.with_context(self.subprotocol_name, |context| {
let mut sync_io = NetSyncIo::new(context, &*self.handler.chain, &*self.handler.snapshot_service);
self.handler.sync.write().chain_new_blocks(
&mut sync_io,
@@ -149,7 +153,7 @@ impl ChainNotify for EthSync {
fn start(&self) {
self.network.start().unwrap_or_else(|e| warn!("Error starting network: {:?}", e));
- self.network.register_protocol(self.handler.clone(), ETH_PROTOCOL, &[62u8, 63u8, 64u8])
+ self.network.register_protocol(self.handler.clone(), self.subprotocol_name, &[62u8, 63u8, 64u8])
.unwrap_or_else(|e| warn!("Error registering ethereum protocol: {:?}", e));
}
@@ -204,7 +208,7 @@ impl ManageNetwork for EthSync {
}
fn stop_network(&self) {
- self.network.with_context(ETH_PROTOCOL, |context| {
+ self.network.with_context(self.subprotocol_name, |context| {
let mut sync_io = NetSyncIo::new(context, &*self.handler.chain, &*self.handler.snapshot_service);
self.handler.sync.write().abort(&mut sync_io);
});
diff --git a/sync/src/sync_io.rs b/sync/src/sync_io.rs
index fa95941ea..445939399 100644
--- a/sync/src/sync_io.rs
+++ b/sync/src/sync_io.rs
@@ -17,7 +17,6 @@
use network::{NetworkContext, PeerId, PacketId, NetworkError};
use ethcore::client::BlockChainClient;
use ethcore::snapshot::SnapshotService;
-use api::ETH_PROTOCOL;
/// IO interface for the syning handler.
/// Provides peer connection management and an interface to the blockchain client.
@@ -101,7 +100,7 @@ impl<'s, 'h> SyncIo for NetSyncIo<'s, 'h> {
}
fn eth_protocol_version(&self, peer_id: PeerId) -> u8 {
- self.network.protocol_version(peer_id, ETH_PROTOCOL).unwrap_or(0)
+ self.network.protocol_version(peer_id, self.network.subprotocol_name()).unwrap_or(0)
}
}
diff --git a/util/network/src/host.rs b/util/network/src/host.rs
index ebc10324f..f530503c6 100644
--- a/util/network/src/host.rs
+++ b/util/network/src/host.rs
@@ -137,7 +137,7 @@ const SYS_TIMER: usize = LAST_SESSION + 1;
/// Protocol handler level packet id
pub type PacketId = u8;
/// Protocol / handler id
-pub type ProtocolId = &'static str;
+pub type ProtocolId = [u8; 3];
/// Messages used to communitate with the event loop from other threads.
#[derive(Clone)]
@@ -185,7 +185,7 @@ pub struct CapabilityInfo {
impl Encodable for CapabilityInfo {
fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(2);
- s.append(&self.protocol);
+ s.append(&&self.protocol[..]);
s.append(&self.version);
}
}
@@ -284,10 +284,13 @@ impl<'s> NetworkContext<'s> {
}
/// Returns max version for a given protocol.
- pub fn protocol_version(&self, peer: PeerId, protocol: &str) -> Option {
+ pub fn protocol_version(&self, peer: PeerId, protocol: ProtocolId) -> Option {
let session = self.resolve_session(peer);
session.and_then(|s| s.lock().capability_version(protocol))
}
+
+ /// Returns this object's subprotocol name.
+ pub fn subprotocol_name(&self) -> ProtocolId { self.protocol }
}
/// Shared host information
@@ -801,8 +804,8 @@ impl Host {
}
}
for (p, _) in self.handlers.read().iter() {
- if s.have_capability(p) {
- ready_data.push(p);
+ if s.have_capability(*p) {
+ ready_data.push(*p);
}
}
},
@@ -811,7 +814,7 @@ impl Host {
protocol,
packet_id,
}) => {
- match self.handlers.read().get(protocol) {
+ match self.handlers.read().get(&protocol) {
None => { warn!(target: "network", "No handler found for protocol: {:?}", protocol) },
Some(_) => packet_data.push((protocol, packet_id, data)),
}
@@ -826,13 +829,13 @@ impl Host {
}
let handlers = self.handlers.read();
for p in ready_data {
- let h = handlers.get(p).unwrap().clone();
+ let h = handlers.get(&p).unwrap().clone();
self.stats.inc_sessions();
let reserved = self.reserved_nodes.read();
h.connected(&NetworkContext::new(io, p, session.clone(), self.sessions.clone(), &reserved), &token);
}
for (p, packet_id, data) in packet_data {
- let h = handlers.get(p).unwrap().clone();
+ let h = handlers.get(&p).unwrap().clone();
let reserved = self.reserved_nodes.read();
h.read(&NetworkContext::new(io, p, session.clone(), self.sessions.clone(), &reserved), &token, packet_id, &data[1..]);
}
@@ -857,8 +860,8 @@ impl Host {
if s.is_ready() {
self.num_sessions.fetch_sub(1, AtomicOrdering::SeqCst);
for (p, _) in self.handlers.read().iter() {
- if s.have_capability(p) {
- to_disconnect.push(p);
+ if s.have_capability(*p) {
+ to_disconnect.push(*p);
}
}
}
@@ -874,7 +877,7 @@ impl Host {
}
}
for p in to_disconnect {
- let h = self.handlers.read().get(p).unwrap().clone();
+ let h = self.handlers.read().get(&p).unwrap().clone();
let reserved = self.reserved_nodes.read();
h.disconnected(&NetworkContext::new(io, p, expired_session.clone(), self.sessions.clone(), &reserved), &token);
}
@@ -980,7 +983,7 @@ impl IoHandler for Host {
self.nodes.write().clear_useless();
},
_ => match self.timers.read().get(&token).cloned() {
- Some(timer) => match self.handlers.read().get(timer.protocol).cloned() {
+ Some(timer) => match self.handlers.read().get(&timer.protocol).cloned() {
None => { warn!(target: "network", "No handler found for protocol: {:?}", timer.protocol) },
Some(h) => {
let reserved = self.reserved_nodes.read();
@@ -1004,11 +1007,11 @@ impl IoHandler for Host {
} => {
let h = handler.clone();
let reserved = self.reserved_nodes.read();
- h.initialize(&NetworkContext::new(io, protocol, None, self.sessions.clone(), &reserved));
- self.handlers.write().insert(protocol, h);
+ h.initialize(&NetworkContext::new(io, *protocol, None, self.sessions.clone(), &reserved));
+ self.handlers.write().insert(*protocol, h);
let mut info = self.info.write();
for v in versions {
- info.capabilities.push(CapabilityInfo { protocol: protocol, version: *v, packet_count:0 });
+ info.capabilities.push(CapabilityInfo { protocol: *protocol, version: *v, packet_count:0 });
}
},
NetworkIoMessage::AddTimer {
@@ -1023,7 +1026,7 @@ impl IoHandler for Host {
*counter += 1;
handler_token
};
- self.timers.write().insert(handler_token, ProtocolTimer { protocol: protocol, token: *token });
+ self.timers.write().insert(handler_token, ProtocolTimer { protocol: *protocol, token: *token });
io.register_timer(handler_token, *delay).unwrap_or_else(|e| debug!("Error registering timer {}: {:?}", token, e));
},
NetworkIoMessage::Disconnect(ref peer) => {
diff --git a/util/network/src/lib.rs b/util/network/src/lib.rs
index bfcd49cea..cd0336823 100644
--- a/util/network/src/lib.rs
+++ b/util/network/src/lib.rs
@@ -45,7 +45,7 @@
//!
//! fn main () {
//! let mut service = NetworkService::new(NetworkConfiguration::new_local()).expect("Error creating network service");
-//! service.register_protocol(Arc::new(MyHandler), "myproto", &[1u8]);
+//! service.register_protocol(Arc::new(MyHandler), *b"myp", &[1u8]);
//! service.start().expect("Error starting service");
//!
//! // Wait for quit condition
diff --git a/util/network/src/session.rs b/util/network/src/session.rs
index 164248d62..fdba12fff 100644
--- a/util/network/src/session.rs
+++ b/util/network/src/session.rs
@@ -14,8 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see .
+use std::{str, io};
use std::net::SocketAddr;
-use std::io;
use std::sync::*;
use mio::*;
use mio::tcp::*;
@@ -63,7 +63,7 @@ pub enum SessionData {
/// Packet data
data: Vec,
/// Packet protocol ID
- protocol: &'static str,
+ protocol: [u8; 3],
/// Zero based packet ID
packet_id: u8,
},
@@ -89,15 +89,21 @@ pub struct SessionInfo {
#[derive(Debug, PartialEq, Eq)]
pub struct PeerCapabilityInfo {
- pub protocol: String,
+ pub protocol: ProtocolId,
pub version: u8,
}
impl Decodable for PeerCapabilityInfo {
fn decode(decoder: &D) -> Result where D: Decoder {
let c = decoder.as_rlp();
+ let p: Vec = try!(c.val_at(0));
+ if p.len() != 3 {
+ return Err(DecoderError::Custom("Invalid subprotocol string length. Should be 3"));
+ }
+ let mut p2: ProtocolId = [0u8; 3];
+ p2.clone_from_slice(&p);
Ok(PeerCapabilityInfo {
- protocol: try!(c.val_at(0)),
+ protocol: p2,
version: try!(c.val_at(1))
})
}
@@ -105,7 +111,7 @@ impl Decodable for PeerCapabilityInfo {
#[derive(Debug)]
struct SessionCapabilityInfo {
- pub protocol: &'static str,
+ pub protocol: [u8; 3],
pub version: u8,
pub packet_count: u8,
pub id_offset: u8,
@@ -239,12 +245,12 @@ impl Session {
}
/// Checks if peer supports given capability
- pub fn have_capability(&self, protocol: &str) -> bool {
+ pub fn have_capability(&self, protocol: [u8; 3]) -> bool {
self.info.capabilities.iter().any(|c| c.protocol == protocol)
}
/// Checks if peer supports given capability
- pub fn capability_version(&self, protocol: &str) -> Option {
+ pub fn capability_version(&self, protocol: [u8; 3]) -> Option {
self.info.capabilities.iter().filter_map(|c| if c.protocol == protocol { Some(c.version) } else { None }).max()
}
@@ -270,10 +276,10 @@ impl Session {
}
/// Send a protocol packet to peer.
- pub fn send_packet(&mut self, io: &IoContext, protocol: &str, packet_id: u8, data: &[u8]) -> Result<(), NetworkError>
+ pub fn send_packet(&mut self, io: &IoContext, protocol: [u8; 3], packet_id: u8, data: &[u8]) -> Result<(), NetworkError>
where Message: Send + Sync + Clone {
if self.info.capabilities.is_empty() || !self.had_hello {
- debug!(target: "network", "Sending to unconfirmed session {}, protocol: {}, packet: {}", self.token(), protocol, packet_id);
+ debug!(target: "network", "Sending to unconfirmed session {}, protocol: {}, packet: {}", self.token(), str::from_utf8(&protocol[..]).unwrap_or("??"), packet_id);
return Err(From::from(NetworkError::BadProtocol));
}
if self.expired() {
diff --git a/util/network/src/tests.rs b/util/network/src/tests.rs
index 4186e549a..97a641c81 100644
--- a/util/network/src/tests.rs
+++ b/util/network/src/tests.rs
@@ -41,7 +41,7 @@ impl TestProtocol {
/// Creates and register protocol with the network service
pub fn register(service: &mut NetworkService, drop_session: bool) -> Arc {
let handler = Arc::new(TestProtocol::new(drop_session));
- service.register_protocol(handler.clone(), "test", &[42u8, 43u8]).expect("Error registering test protocol handler");
+ service.register_protocol(handler.clone(), *b"tst", &[42u8, 43u8]).expect("Error registering test protocol handler");
handler
}
@@ -93,7 +93,7 @@ impl NetworkProtocolHandler for TestProtocol {
fn net_service() {
let service = NetworkService::new(NetworkConfiguration::new_local()).expect("Error creating network service");
service.start().unwrap();
- service.register_protocol(Arc::new(TestProtocol::new(false)), "myproto", &[1u8]).unwrap();
+ service.register_protocol(Arc::new(TestProtocol::new(false)), *b"myp", &[1u8]).unwrap();
}
#[test]