diff --git a/Cargo.lock b/Cargo.lock index af7a7d9c13..1ce59fa078 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -262,12 +262,10 @@ dependencies = [ "codechain-merkle", "codechain-network", "codechain-state", - "codechain-stratum", "codechain-timer", "codechain-types", "codechain-vm", "crossbeam-channel", - "cuckoo", "hyper 0.10.0-a.0", "kvdb", "kvdb-memorydb", @@ -517,24 +515,6 @@ dependencies = [ "util-error", ] -[[package]] -name = "codechain-stratum" -version = "1.11.0" -dependencies = [ - "codechain-crypto", - "codechain-json", - "codechain-logger", - "env_logger 0.6.0", - "jsonrpc-core", - "jsonrpc-derive", - "jsonrpc-tcp-server", - "log 0.4.6", - "parking_lot 0.6.4", - "primitives", - "tokio-core", - "tokio-io", -] - [[package]] name = "codechain-sync" version = "0.1.0" @@ -726,15 +706,6 @@ dependencies = [ "winapi 0.2.8", ] -[[package]] -name = "cuckoo" -version = "0.1.0" -source = "git+https://github.com/CodeChain-io/rust-cuckoo.git?rev=280cab9c#280cab9c777ed4c736b9590ebf62b9fc440fadbd" -dependencies = [ - "byteorder", - "rust-crypto", -] - [[package]] name = "curl" version = "0.4.12" @@ -969,7 +940,6 @@ dependencies = [ "codechain-network", "codechain-rpc", "codechain-state", - "codechain-stratum", "codechain-sync", "codechain-timer", "codechain-types", @@ -1354,18 +1324,6 @@ dependencies = [ "unicase 2.1.0", ] -[[package]] -name = "jsonrpc-tcp-server" -version = "14.0.3" -source = "git+https://github.com/paritytech/jsonrpc.git?tag=v14.0.3#2135c25df57715238f1709365e3ea3bedc88e030" -dependencies = [ - "jsonrpc-core", - "jsonrpc-server-utils", - "log 0.4.6", - "parking_lot 0.9.0", - "tokio-service", -] - [[package]] name = "jsonrpc-ws-server" version = "14.0.3" diff --git a/Cargo.toml b/Cargo.toml index 27e729fc0d..7ff41e8b4e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,6 @@ codechain-sync = { path = "sync" } codechain-timer = { path = "util/timer" } codechain-types = { path = "types" } codechain-vm = { path = "vm" } -codechain-stratum = { path = "stratum" } ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" } fdlimit = "0.1" finally-block = "0.1" diff --git a/core/Cargo.toml b/core/Cargo.toml index d08eb40d6d..d20a8cf03a 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -17,10 +17,8 @@ codechain-network = { path = "../network" } codechain-state = { path = "../state" } codechain-timer = { path = "../util/timer" } codechain-types = { path = "../types" } -codechain-stratum = { path = "../stratum" } codechain-vm = { path = "../vm" } crossbeam-channel = "0.3" -cuckoo = { git = "https://github.com/CodeChain-io/rust-cuckoo.git", rev = "280cab9c" } hyper = { git = "https://github.com/paritytech/hyper", default-features = false } kvdb = "0.1" kvdb-rocksdb = "0.1" diff --git a/core/res/blake_pow.json b/core/res/blake_pow.json deleted file mode 100644 index 10a111a3cb..0000000000 --- a/core/res/blake_pow.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "name": "BlakePoW", - "engine": { - "blakePoW": { - "params": { - "blockReward": "0x0d", - "minScore": "0x020000", - "recommendedConfirmation": 12 - } - } - }, - "params": { - "maxAssetSchemeMetadataSize": "0x0400", - "maxTransferMetadataSize": "0x0100", - "maxTextContentSize": "0x0200", - "maxExtraDataSize": "0x20", - "networkID": "tc", - "minPayCost" : 10, - "minSetRegularKeyCost" : 10, - "minCreateShardCost" : 10, - "minSetShardOwnersCost" : 10, - "minSetShardUsersCost" : 10, - "minWrapCccCost" : 10, - "minCustomCost" : 10, - "minStoreCost" : 10, - "minRemoveCost" : 10, - "minMintAssetCost" : 10, - "minTransferAssetCost" : 10, - "minChangeAssetSchemeCost" : 10, - "minIncreaseAssetSupplyCost" : 10, - "minComposeAssetCost" : 10, - "minDecomposeAssetCost" : 10, - "minUnwrapCccCost" : 10, - "maxBodySize": 4194304, - "snapshotPeriod": 16384 - }, - "genesis": { - "seal": { - "generic": "0x0" - }, - "score": "0x20000", - "author": "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhhn9p3", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x" - }, - "accounts": { - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqyca3rwt": { "balance": "1000000", "seq": "0" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqgfrhflv": { "balance": "1000000", "seq": "0" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqvxf40sk": { "balance": "1000000", "seq": "0" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqszkma5z": { "balance": "1000000", "seq": "0" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq5duemmc": { "balance": "1000000" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqcuzl32l": { "balance": "1000000" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqungah99": { "balance": "1000000" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqc2ul2h": { "balance": "1000000" }, - "tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u": { "balance": "1000000" }, - "tccq9h7vnl68frvqapzv3tujrxtxtwqdnxw6yamrrgd": { "balance": "10000000000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u"], - "users": [] - } - } -} diff --git a/core/res/cuckoo.json b/core/res/cuckoo.json deleted file mode 100644 index 585bcb55dd..0000000000 --- a/core/res/cuckoo.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "Cuckoo", - "engine": { - "cuckoo": { - "params": { - "blockReward": "0x0d", - "minScore": "0x020000", - "maxVertex": "0x40000000", - "maxEdge": "0x20000000", - "cycleLength": "42", - "recommendedConfirmation": 6 - } - } - }, - "params": { - "maxAssetSchemeMetadataSize": "0x0400", - "maxTransferMetadataSize": "0x0100", - "maxTextContentSize": "0x0200", - "maxExtraDataSize": "0x20", - "networkID": "tc", - "minPayCost" : 10, - "minSetRegularKeyCost" : 10, - "minCreateShardCost" : 10, - "minSetShardOwnersCost" : 10, - "minSetShardUsersCost" : 10, - "minWrapCccCost" : 10, - "minCustomCost" : 10, - "minStoreCost" : 10, - "minRemoveCost" : 10, - "minMintAssetCost" : 10, - "minTransferAssetCost" : 10, - "minChangeAssetSchemeCost" : 10, - "minIncreaseAssetSupplyCost" : 10, - "minComposeAssetCost" : 10, - "minDecomposeAssetCost" : 10, - "minUnwrapCccCost" : 10, - "maxBodySize": 4194304, - "snapshotPeriod": 16384 - }, - "genesis": { - "seal": { - "generic": "0x0" - }, - "score": "0x20000", - "author": "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqhhn9p3", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x" - }, - "accounts": { - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqyca3rwt": { "balance": "1000000", "seq": "0" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqgfrhflv": { "balance": "1000000", "seq": "0" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqvxf40sk": { "balance": "1000000", "seq": "0" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqszkma5z": { "balance": "1000000", "seq": "0" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq5duemmc": { "balance": "1000000" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqcuzl32l": { "balance": "1000000" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqungah99": { "balance": "1000000" }, - "tccqyqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqpqc2ul2h": { "balance": "1000000" }, - "tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u": { "balance": "1000000" }, - "tccq9h7vnl68frvqapzv3tujrxtxtwqdnxw6yamrrgd": { "balance": "10000000000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["tccq8vapdlstar6ghmqgczp6j2e83njsqq0tsvaxm9u"], - "users": [] - } - } -} diff --git a/core/res/husky.json b/core/res/husky.json deleted file mode 100644 index 91dd4316d6..0000000000 --- a/core/res/husky.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "name": "Husky", - "engine": { - "cuckoo": { - "params": { - "blockReward": "0x2540be400", - "blockInterval": "30", - "minScore": "0x1050", - "maxVertex": "0x1000", - "maxEdge": "0x800", - "cycleLength": "8", - "recommendedConfirmation": 6 - } - } - }, - "params": { - "maxAssetSchemeMetadataSize": "0x0400", - "maxTransferMetadataSize": "0x0100", - "maxTextContentSize": "0x0200", - "maxExtraDataSize": "0x20", - "networkID": "tc", - "minPayCost" : 10, - "minSetRegularKeyCost" : 10, - "minCreateShardCost" : 10, - "minSetShardOwnersCost" : 10, - "minSetShardUsersCost" : 10, - "minWrapCccCost" : 10, - "minCustomCost" : 10, - "minStoreCost" : 10, - "minRemoveCost" : 10, - "minMintAssetCost" : 10, - "minTransferAssetCost" : 10, - "minChangeAssetSchemeCost" : 10, - "minIncreaseAssetSupplyCost" : 10, - "minComposeAssetCost" : 10, - "minDecomposeAssetCost" : 10, - "minUnwrapCccCost" : 10, - "maxBodySize": 4194304, - "snapshotPeriod": 16384 - }, - "genesis": { - "seal": { - "generic": "0x0" - }, - "score": "0x1050", - "author": "tccqynz79luhx4cfakvcqe29rwaajnkzz6aev5deztu", - "timestamp": "0x00", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "extraData": "0x" - }, - "accounts": { - "tccqynz79luhx4cfakvcqe29rwaajnkzz6aev5deztu": { "balance": "2100000000000000", "seq": "0" } - }, - "shards": { - "0": { - "seq": 0, - "owners": ["tccqynz79luhx4cfakvcqe29rwaajnkzz6aev5deztu"], - "users": [] - } - } -} diff --git a/core/src/block.rs b/core/src/block.rs index b1af5920fc..a93b5c95ee 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -375,19 +375,11 @@ impl LockedBlock { /// Provide a valid seal in order to turn this into a `SealedBlock`. /// This does check the validity of `seal` with the engine. /// Returns the `ClosedBlock` back again if the seal is no good. - pub fn try_seal( - mut self, - engine: &dyn CodeChainEngine, - seal: Vec, - ) -> Result { + pub fn seal_block(mut self, seal: Vec) -> SealedBlock { self.block.header.set_seal(seal); - // TODO: passing state context to avoid engines owning it? - match engine.verify_local_seal(&self.block.header) { - Err(e) => Err((e, self)), - _ => Ok(SealedBlock { - block: self.block, - }), + SealedBlock { + block: self.block, } } diff --git a/core/src/client/client.rs b/core/src/client/client.rs index 5f6ba75ace..29a24c92fd 100644 --- a/core/src/client/client.rs +++ b/core/src/client/client.rs @@ -315,8 +315,6 @@ impl Client { } } -/// When RESEAL_MAX_TIMER invoked, a block is created although the block is empty. -const RESEAL_MAX_TIMER_TOKEN: TimerToken = 0; /// The minimum time between blocks, the miner creates a block when RESEAL_MIN_TIMER is invoked. /// Do not create a block before RESEAL_MIN_TIMER event. const RESEAL_MIN_TIMER_TOKEN: TimerToken = 1; @@ -324,12 +322,6 @@ const RESEAL_MIN_TIMER_TOKEN: TimerToken = 1; impl TimeoutHandler for Client { fn on_timeout(&self, token: TimerToken) { match token { - RESEAL_MAX_TIMER_TOKEN => { - // Working in PoW only - if self.engine().seals_internally().is_none() && !self.importer.miner.prepare_work_sealing(self) { - self.update_sealing(BlockId::Latest, true); - } - } RESEAL_MIN_TIMER_TOKEN => { // Checking self.ready_transactions() for efficiency if !self.engine().engine_type().ignore_reseal_min_period() && !self.is_pending_queue_empty() { @@ -552,18 +544,6 @@ impl EngineClient for Client { } } - /// Submit a seal for a block in the mining queue. - fn submit_seal(&self, block_hash: BlockHash, seal: Vec) { - if self.importer.miner.submit_seal(self, block_hash, seal).is_err() { - cwarn!(CLIENT, "Wrong internal seal submission!") - } - } - - /// Convert PoW difficulty to target. - fn score_to_target(&self, score: &U256) -> U256 { - self.engine.score_to_target(score) - } - /// Update the best block as the given block hash. /// /// Used in Tendermint, when going to the commit step. @@ -690,20 +670,6 @@ impl ImportBlock for Client { Err(err) => unreachable!("Reseal min timer should not fail but failed with {:?}", err), } } - - fn set_max_timer(&self) { - self.reseal_timer.cancel(RESEAL_MAX_TIMER_TOKEN).expect("Reseal max timer clear succeeds"); - match self - .reseal_timer - .schedule_once(self.importer.miner.get_options().reseal_max_period, RESEAL_MAX_TIMER_TOKEN) - { - Ok(_) => {} - Err(TimerScheduleError::TokenAlreadyScheduled) => { - // Since set_max_timer could be called in multi thread, ignore the TokenAlreadyScheduled error - } - Err(err) => unreachable!("Reseal max timer should not fail but failed with {:?}", err), - } - } } diff --git a/core/src/client/mod.rs b/core/src/client/mod.rs index 7040860781..dd42b863d1 100644 --- a/core/src/client/mod.rs +++ b/core/src/client/mod.rs @@ -100,12 +100,6 @@ pub trait EngineClient: Sync + Send + BlockChainTrait + ImportBlock { /// Make a new block and seal it. fn update_sealing(&self, parent_block: BlockId, allow_empty_block: bool); - /// Submit a seal for a block in the mining queue. - fn submit_seal(&self, block_hash: BlockHash, seal: Vec); - - /// Convert PoW difficulty to target. - fn score_to_target(&self, score: &U256) -> U256; - /// Update the best block as the given block hash /// /// Used in Tendermint, when going to the commit step. @@ -206,8 +200,6 @@ pub trait ImportBlock { /// Set reseal min timer as reseal_min_period, for creating blocks with transactions which are pending because of reseal_min_period fn set_min_timer(&self); - /// Set reseal max timer as reseal_max_period, for creating empty blocks every reseal_max_period - fn set_max_timer(&self); } /// Blockchain database client. Owns and manages a blockchain and a block queue. diff --git a/core/src/client/test_client.rs b/core/src/client/test_client.rs index 80d816aabe..962aa73e16 100644 --- a/core/src/client/test_client.rs +++ b/core/src/client/test_client.rs @@ -514,8 +514,6 @@ impl ImportBlock for TestBlockChainClient { } fn set_min_timer(&self) {} - - fn set_max_timer(&self) {} } @@ -625,16 +623,6 @@ impl super::EngineClient for TestBlockChainClient { self.miner.update_sealing(self, parent_block, allow_empty_block) } - fn submit_seal(&self, block_hash: BlockHash, seal: Vec) { - if self.miner.submit_seal(self, block_hash, seal).is_err() { - cwarn!(CLIENT, "Wrong internal seal submission!") - } - } - - fn score_to_target(&self, _score: &U256) -> U256 { - U256::zero() - } - fn update_best_as_committed(&self, _block_hash: BlockHash) {} fn get_kvdb(&self) -> Arc { diff --git a/core/src/consensus/blake_pow/mod.rs b/core/src/consensus/blake_pow/mod.rs deleted file mode 100644 index 010fa35ae6..0000000000 --- a/core/src/consensus/blake_pow/mod.rs +++ /dev/null @@ -1,189 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -mod params; - -use std::cmp::{max, min}; - -use ccrypto::blake256; -use ckey::Address; -use ctypes::util::unexpected::{Mismatch, OutOfBounds}; -use ctypes::{CommonParams, Header}; -use primitives::U256; -use rlp::Rlp; - -use self::params::BlakePoWParams; -use super::ConsensusEngine; -use crate::block::ExecutedBlock; -use crate::codechain_machine::CodeChainMachine; -use crate::consensus::{EngineError, EngineType}; -use crate::error::{BlockError, Error}; - -/// BlakePoW specific seal -#[derive(Debug, PartialEq)] -pub struct Seal { - pub nonce: u64, -} - -impl Seal { - /// Tries to parse rlp as cuckoo seal. - pub fn parse_seal>(seal: &[T]) -> Result { - if seal.len() != 1 { - return Err(BlockError::InvalidSealArity(Mismatch { - expected: 1, - found: seal.len(), - }) - .into()) - } - - Ok(Seal { - nonce: Rlp::new(seal[0].as_ref()).as_val()?, - }) - } -} - -pub struct BlakePoW { - params: BlakePoWParams, - machine: CodeChainMachine, -} - -impl BlakePoW { - pub fn new(params: BlakePoWParams, machine: CodeChainMachine) -> Self { - Self { - params, - machine, - } - } - - fn calculate_score(&self, header: &Header, parent: &Header) -> U256 { - if header.number() == 0 { - panic!("Can't calculate genesis block score"); - } - - //score = parent_score + parent_score // 2048 * max(1 - (block_timestamp - parent_timestamp) // block_interval, -99) - let diff = (header.timestamp() - parent.timestamp()) / self.params.block_interval; - let target = if diff <= 1 { - parent.score().saturating_add(*parent.score() / 2048 * U256::from(1 - diff)) - } else { - parent.score().saturating_sub(*parent.score() / 2048 * U256::from(min(diff - 1, 99))) - }; - max(self.params.min_score, target) - } -} - -impl ConsensusEngine for BlakePoW { - fn name(&self) -> &str { - "BlakePoW" - } - - fn machine(&self) -> &CodeChainMachine { - &self.machine - } - - fn seal_fields(&self, _header: &Header) -> usize { - 1 - } - - fn engine_type(&self) -> EngineType { - EngineType::PoW - } - - fn verify_local_seal(&self, header: &Header) -> Result<(), Error> { - self.verify_header_basic(header).and_then(|_| self.verify_block_seal(header)) - } - - fn verify_header_basic(&self, header: &Header) -> Result<(), Error> { - if *header.score() < self.params.min_score { - return Err(From::from(BlockError::ScoreOutOfBounds(OutOfBounds { - min: Some(self.params.min_score), - max: None, - found: *header.score(), - }))) - } - - Ok(()) - } - - fn verify_block_seal(&self, header: &Header) -> Result<(), Error> { - let seal = Seal::parse_seal(header.seal())?; - - let mut message = header.bare_hash().0; - message[0..8].copy_from_slice(&seal.nonce.to_le_bytes()); - - let target = self.score_to_target(header.score()); - let hash = blake256(message); - if U256::from(hash) > target { - return Err(From::from(BlockError::PowOutOfBounds(OutOfBounds { - min: None, - max: Some(target), - found: U256::from(hash), - }))) - } - Ok(()) - } - - fn verify_block_family(&self, header: &Header, parent: &Header) -> Result<(), Error> { - if header.number() == 0 { - return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { - min: Some(1), - max: None, - found: header.number(), - }))) - } - - let expected_score = self.calculate_score(header, parent); - if header.score() != &expected_score { - return Err(From::from(BlockError::InvalidScore(Mismatch { - expected: expected_score, - found: U256::from(*header.hash()), - }))) - } - - Ok(()) - } - - fn populate_from_parent(&self, header: &mut Header, parent: &Header) { - let score = self.calculate_score(header, parent); - header.set_score(score); - } - - fn on_close_block( - &self, - block: &mut ExecutedBlock, - _term_common_params: Option<&CommonParams>, - ) -> Result<(), Error> { - let author = *block.header().author(); - let total_reward = self.block_reward(block.header().number()) - + self.block_fee(Box::new(block.transactions().to_owned().into_iter().map(Into::into))); - self.machine.add_balance(block, &author, total_reward) - } - - fn score_to_target(&self, score: &U256) -> U256 { - (U256::max_value() - *score) / *score - } - - fn block_reward(&self, _block_number: u64) -> u64 { - self.params.block_reward - } - - fn recommended_confirmation(&self) -> u32 { - self.params.recommmended_confirmation - } - - fn possible_authors(&self, _block_number: Option) -> Result>, EngineError> { - Ok(None) - } -} diff --git a/core/src/consensus/blake_pow/params.rs b/core/src/consensus/blake_pow/params.rs deleted file mode 100644 index be94eb016c..0000000000 --- a/core/src/consensus/blake_pow/params.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2018 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use cjson; -use primitives::U256; - -pub struct BlakePoWParams { - pub block_reward: u64, - pub min_score: U256, - pub block_interval: u64, - pub recommmended_confirmation: u32, -} - -impl From for BlakePoWParams { - fn from(p: cjson::scheme::BlakePoWParams) -> Self { - BlakePoWParams { - block_reward: p.block_reward.map_or(0, Into::into), - block_interval: p.block_interval.map_or(120, Into::into), - min_score: p.min_score.map_or(U256::from(0x0002_0000), Into::into), - recommmended_confirmation: p.recommended_confirmation.map_or(15, Into::into), - } - } -} diff --git a/core/src/consensus/cuckoo/mod.rs b/core/src/consensus/cuckoo/mod.rs deleted file mode 100644 index d904120d67..0000000000 --- a/core/src/consensus/cuckoo/mod.rs +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -mod params; - -use std::cmp::{max, min}; - -use ccrypto::blake256; -use ckey::Address; -use ctypes::util::unexpected::{Mismatch, OutOfBounds}; -use ctypes::{CommonParams, Header}; -use cuckoo::Cuckoo as CuckooVerifier; -use primitives::U256; -use rlp::Rlp; - -use self::params::CuckooParams; -use super::ConsensusEngine; -use crate::block::ExecutedBlock; -use crate::codechain_machine::CodeChainMachine; -use crate::consensus::{EngineError, EngineType}; -use crate::error::{BlockError, Error}; - -/// Cuckoo specific seal -#[derive(Debug, PartialEq)] -pub struct Seal { - pub nonce: u64, - pub proof: Vec, -} - -impl Seal { - /// Tries to parse rlp as cuckoo seal. - pub fn parse_seal>(seal: &[T]) -> Result { - if seal.len() != 2 { - return Err(BlockError::InvalidSealArity(Mismatch { - expected: 2, - found: seal.len(), - }) - .into()) - } - - Ok(Seal { - nonce: Rlp::new(seal[0].as_ref()).as_val()?, - proof: Rlp::new(seal[1].as_ref()).as_list()?, - }) - } -} - -pub struct Cuckoo { - params: CuckooParams, - machine: CodeChainMachine, - verifier: CuckooVerifier, -} - -impl Cuckoo { - pub fn new(params: CuckooParams, machine: CodeChainMachine) -> Self { - let verifier = CuckooVerifier::new(params.max_vertex, params.max_edge, params.cycle_length); - Self { - params, - machine, - verifier, - } - } - - fn calculate_score(&self, header: &Header, parent: &Header) -> U256 { - if header.number() == 0 { - panic!("Can't calculate genesis block score"); - } - - //score = parent_score + parent_score // 2048 * max(1 - (block_timestamp - parent_timestamp) // block_interval, -99) - let diff = (header.timestamp() - parent.timestamp()) / self.params.block_interval; - let target = if diff <= 1 { - parent.score().saturating_add(*parent.score() / 2048 * U256::from(1 - diff)) - } else { - parent.score().saturating_sub(*parent.score() / 2048 * U256::from(min(diff - 1, 99))) - }; - max(self.params.min_score, target) - } -} - -impl ConsensusEngine for Cuckoo { - fn name(&self) -> &str { - "Cuckoo" - } - - fn machine(&self) -> &CodeChainMachine { - &self.machine - } - - fn seal_fields(&self, _header: &Header) -> usize { - 2 - } - - fn engine_type(&self) -> EngineType { - EngineType::PoW - } - - fn verify_local_seal(&self, header: &Header) -> Result<(), Error> { - self.verify_header_basic(header).and_then(|_| self.verify_block_seal(header)) - } - - fn verify_header_basic(&self, header: &Header) -> Result<(), Error> { - if *header.score() < self.params.min_score { - return Err(From::from(BlockError::ScoreOutOfBounds(OutOfBounds { - min: Some(self.params.min_score), - max: None, - found: *header.score(), - }))) - } - - Ok(()) - } - - fn verify_block_seal(&self, header: &Header) -> Result<(), Error> { - let seal = Seal::parse_seal(header.seal())?; - - let mut message = header.bare_hash().0; - message[0..8].copy_from_slice(&seal.nonce.to_le_bytes()); - - if !self.verifier.verify(&message, &seal.proof) { - return Err(From::from(BlockError::InvalidProofOfWork)) - } - - let target = self.score_to_target(header.score()); - let hash = blake256(::rlp::encode_list(&seal.proof)); - if U256::from(hash) > target { - return Err(From::from(BlockError::PowOutOfBounds(OutOfBounds { - min: None, - max: Some(target), - found: U256::from(hash), - }))) - } - Ok(()) - } - - fn verify_block_family(&self, header: &Header, parent: &Header) -> Result<(), Error> { - if header.number() == 0 { - return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { - min: Some(1), - max: None, - found: header.number(), - }))) - } - - let expected_score = self.calculate_score(header, parent); - if header.score() != &expected_score { - return Err(From::from(BlockError::InvalidScore(Mismatch { - expected: expected_score, - found: U256::from(*header.hash()), - }))) - } - - Ok(()) - } - - fn populate_from_parent(&self, header: &mut Header, parent: &Header) { - let score = self.calculate_score(header, parent); - header.set_score(score); - } - - fn on_close_block( - &self, - block: &mut ExecutedBlock, - _term_common_params: Option<&CommonParams>, - ) -> Result<(), Error> { - let author = *block.header().author(); - let total_reward = self.block_reward(block.header().number()) - + self.block_fee(Box::new(block.transactions().to_owned().into_iter().map(Into::into))); - self.machine.add_balance(block, &author, total_reward) - } - - fn score_to_target(&self, score: &U256) -> U256 { - (U256::max_value() - *score) / *score - } - - fn block_reward(&self, _block_number: u64) -> u64 { - self.params.block_reward - } - - fn recommended_confirmation(&self) -> u32 { - self.params.recommmended_confirmation - } - - fn possible_authors(&self, _block_number: Option) -> Result>, EngineError> { - Ok(None) - } -} - -#[cfg(test)] -mod tests { - use ctypes::CommonParams; - - use crate::block::{IsBlock, OpenBlock}; - use crate::scheme::Scheme; - use crate::tests::helpers::get_temp_state_db; - - use super::*; - - #[test] - fn has_valid_metadata() { - let engine = Scheme::new_test_cuckoo().engine; - - assert_eq!(engine.name(), "Cuckoo"); - assert_eq!(engine.engine_type(), EngineType::PoW); - } - - #[test] - fn seal_fields() { - let engine = Scheme::new_test_cuckoo().engine; - let header = Header::default(); - - assert_eq!(engine.seal_fields(&header), 2); - } - - #[test] - fn verify_header_basic_err() { - let engine = Scheme::new_test_cuckoo().engine; - let default_header = Header::default(); - - assert!(engine.verify_header_basic(&default_header).is_err()); - } - - #[test] - fn verify_header_basic_ok() { - let scheme = Scheme::new_test_cuckoo(); - let engine = &*scheme.engine; - let genesis_header = scheme.genesis_header(); - - assert!(engine.verify_header_basic(&genesis_header).is_ok()); - } - - #[test] - fn verify_block_seal_err() { - let engine = Scheme::new_test_cuckoo().engine; - let default_header = Header::default(); - - assert!(engine.verify_block_seal(&default_header).is_err()); - } - - #[test] - fn score_to_target() { - let engine = Scheme::new_test_cuckoo().engine; - - assert_eq!(engine.score_to_target(&U256::max_value()), U256::from(0)); - } - - #[test] - fn on_close_block() { - let scheme = Scheme::new_test_cuckoo(); - let engine = &*scheme.engine; - let db = scheme.ensure_genesis_state(get_temp_state_db()).unwrap(); - let header = Header::default(); - let block = OpenBlock::try_new(engine, db, &header, Default::default(), vec![]).unwrap(); - let mut executed_block = block.block().clone(); - - assert!(engine.on_close_block(&mut executed_block, Some(&CommonParams::default_for_test())).is_ok()); - assert_eq!(0xd, engine.machine().balance(&executed_block, header.author()).unwrap()); - } - - #[test] - fn populate_from_parent() { - let scheme = Scheme::new_test_cuckoo(); - let engine = &*scheme.engine; - let mut header = Header::default(); - let genesis_header = scheme.genesis_header(); - header.set_number(1); - header.set_parent_hash(genesis_header.hash()); - - engine.populate_from_parent(&mut header, &genesis_header); - assert_eq!(*header.score(), U256::from(0x20040)); - } -} diff --git a/core/src/consensus/cuckoo/params.rs b/core/src/consensus/cuckoo/params.rs deleted file mode 100644 index 4f39b6f496..0000000000 --- a/core/src/consensus/cuckoo/params.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2018 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use cjson; -use primitives::U256; - -pub struct CuckooParams { - pub block_reward: u64, - pub block_interval: u64, - pub min_score: U256, - pub max_vertex: usize, - pub max_edge: usize, - pub cycle_length: usize, - pub recommmended_confirmation: u32, -} - -impl From for CuckooParams { - fn from(p: cjson::scheme::CuckooParams) -> Self { - CuckooParams { - block_reward: p.block_reward.map_or(0, Into::into), - block_interval: p.block_interval.map_or(120, Into::into), - min_score: p.min_score.map_or(U256::from(0x0002_0000), Into::into), - max_vertex: p.max_vertex.map_or(1 << 30, Into::into), - max_edge: p.max_edge.map_or(1 << 29, Into::into), - cycle_length: p.cycle_length.map_or(42, Into::into), - recommmended_confirmation: p.recommended_confirmation.map_or(15, Into::into), - } - } -} diff --git a/core/src/consensus/mod.rs b/core/src/consensus/mod.rs index c3eb46db6a..6d82c555e9 100644 --- a/core/src/consensus/mod.rs +++ b/core/src/consensus/mod.rs @@ -15,8 +15,6 @@ // along with this program. If not, see . mod bit_set; -mod blake_pow; -mod cuckoo; mod null_engine; mod signer; mod simple_poa; @@ -25,8 +23,6 @@ pub mod stake; mod tendermint; mod validator_set; -pub use self::blake_pow::BlakePoW; -pub use self::cuckoo::Cuckoo; pub use self::null_engine::NullEngine; pub use self::simple_poa::SimplePoA; pub use self::solo::Solo; @@ -46,7 +42,7 @@ use ctypes::errors::SyntaxError; use ctypes::transaction::Action; use ctypes::util::unexpected::{Mismatch, OutOfBounds}; use ctypes::{BlockHash, CommonParams, Header}; -use primitives::{Bytes, U256}; +use primitives::Bytes; use self::bit_set::BitSet; use crate::account_provider::AccountProvider; @@ -96,7 +92,6 @@ impl Seal { pub enum EngineType { PoA, PBFT, - PoW, Solo, } @@ -106,7 +101,6 @@ impl EngineType { EngineType::PoA => true, EngineType::PBFT => true, EngineType::Solo => false, - EngineType::PoW => false, } } @@ -115,7 +109,6 @@ impl EngineType { EngineType::PoA => false, EngineType::PBFT => true, EngineType::Solo => false, - EngineType::PoW => false, } } @@ -124,7 +117,6 @@ impl EngineType { EngineType::PoA => false, EngineType::PBFT => true, EngineType::Solo => false, - EngineType::PoW => false, } } @@ -133,7 +125,6 @@ impl EngineType { EngineType::PoA => false, EngineType::PBFT => true, EngineType::Solo => true, - EngineType::PoW => false, } } } @@ -151,12 +142,9 @@ pub trait ConsensusEngine: Sync + Send { 0 } - /// None means that it requires external input (e.g. PoW) to seal a block. - /// Some(true) means the engine is currently prime for seal generation (i.e. node is the current validator). - /// Some(false) means that the node might seal internally but is not qualified now. - fn seals_internally(&self) -> Option { - None - } + /// true means the engine is currently prime for seal generation (i.e. node is the current validator). + /// false means that the node might seal internally but is not qualified now. + fn seals_internally(&self) -> bool; /// The type of this engine. fn engine_type(&self) -> EngineType; @@ -176,20 +164,6 @@ pub trait ConsensusEngine: Sync + Send { fn proposal_generated(&self, _sealed_block: &SealedBlock) {} - /// Verify a locally-generated seal of a header. - /// - /// If this engine seals internally, - /// no checks have to be done here, since all internally generated seals - /// should be valid. - /// - /// Externally-generated seals (e.g. PoW) will need to be checked for validity. - /// - /// It is fine to require access to state or a full client for this function, since - /// light clients do not generate seals. - fn verify_local_seal(&self, _header: &Header) -> Result<(), Error> { - Ok(()) - } - /// Phase 1 quick block verification. Only does checks that are cheap. Returns either a null `Ok` or a general error detailing the problem with import. fn verify_header_basic(&self, _header: &Header) -> Result<(), Error> { Ok(()) @@ -247,10 +221,6 @@ pub trait ConsensusEngine: Sync + Send { fn register_time_gap_config_to_worker(&self, _time_gap_params: TimeGapParams) {} - fn score_to_target(&self, _score: &U256) -> U256 { - U256::zero() - } - fn block_reward(&self, block_number: u64) -> u64; fn block_fee(&self, transactions: Box>) -> u64 { @@ -265,7 +235,6 @@ pub trait ConsensusEngine: Sync + Send { header.hash() } - /// In PoW consensus, the higher scored block becomes the best block. /// In Tendermint consensus, the highest scored block may not be the best block. /// Only the descendant of the current best block could be the next best block in Tendermint consensus. fn can_change_canon_chain( diff --git a/core/src/consensus/null_engine/mod.rs b/core/src/consensus/null_engine/mod.rs index 26f40199d1..c05a9037f7 100644 --- a/core/src/consensus/null_engine/mod.rs +++ b/core/src/consensus/null_engine/mod.rs @@ -51,6 +51,10 @@ impl ConsensusEngine for NullEngine { &self.machine } + fn seals_internally(&self) -> bool { + true + } + fn engine_type(&self) -> EngineType { EngineType::Solo } diff --git a/core/src/consensus/simple_poa/mod.rs b/core/src/consensus/simple_poa/mod.rs index a6b72120b8..7192077bd8 100644 --- a/core/src/consensus/simple_poa/mod.rs +++ b/core/src/consensus/simple_poa/mod.rs @@ -88,8 +88,8 @@ impl ConsensusEngine for SimplePoA { 1 } - fn seals_internally(&self) -> Option { - Some(self.signer.read().is_some()) + fn seals_internally(&self) -> bool { + self.signer.read().is_some() } fn engine_type(&self) -> EngineType { @@ -186,14 +186,12 @@ mod tests { let b = OpenBlock::try_new(engine, db, &genesis_header, Default::default(), vec![]).unwrap(); let term_common_params = CommonParams::default_for_test(); let b = b.close_and_lock(&genesis_header, Some(&term_common_params)).unwrap(); - if let Some(seal) = engine.generate_seal(Some(b.block()), &genesis_header).seal_fields() { - assert!(b.try_seal(engine, seal).is_ok()); - } + assert_eq!(None, engine.generate_seal(Some(b.block()), &genesis_header).seal_fields()); } #[test] fn seals_internally() { let engine = Scheme::new_test_simple_poa().engine; - assert!(!engine.seals_internally().unwrap()); + assert!(!engine.seals_internally()); } } diff --git a/core/src/consensus/solo/mod.rs b/core/src/consensus/solo/mod.rs index 414e45a00f..ad147cb80f 100644 --- a/core/src/consensus/solo/mod.rs +++ b/core/src/consensus/solo/mod.rs @@ -71,8 +71,8 @@ impl ConsensusEngine for Solo { &self.machine } - fn seals_internally(&self) -> Option { - Some(true) + fn seals_internally(&self) -> bool { + true } fn engine_type(&self) -> EngineType { @@ -183,7 +183,7 @@ mod tests { let term_common_params = CommonParams::default_for_test(); let b = b.close_and_lock(&genesis_header, Some(&term_common_params)).unwrap(); if let Some(seal) = engine.generate_seal(Some(b.block()), &genesis_header).seal_fields() { - assert!(b.try_seal(&*engine, seal).is_ok()); + b.seal_block(seal); } } diff --git a/core/src/consensus/tendermint/engine.rs b/core/src/consensus/tendermint/engine.rs index 33c77e7fe8..a1d0566834 100644 --- a/core/src/consensus/tendermint/engine.rs +++ b/core/src/consensus/tendermint/engine.rs @@ -69,8 +69,8 @@ impl ConsensusEngine for Tendermint { } /// Should this node participate. - fn seals_internally(&self) -> Option { - Some(self.has_signer.load(AtomicOrdering::SeqCst)) + fn seals_internally(&self) -> bool { + self.has_signer.load(AtomicOrdering::SeqCst) } fn engine_type(&self) -> EngineType { diff --git a/core/src/consensus/tendermint/mod.rs b/core/src/consensus/tendermint/mod.rs index 721ce1cb34..8a69eaeb09 100644 --- a/core/src/consensus/tendermint/mod.rs +++ b/core/src/consensus/tendermint/mod.rs @@ -127,19 +127,16 @@ const SEAL_FIELDS: usize = 4; mod tests { use ccrypto::blake256; use ckey::Address; - use ctypes::{CommonParams, Header}; - use primitives::Bytes; + use ctypes::Header; use super::super::BitSet; use super::message::VoteStep; use crate::account_provider::AccountProvider; - use crate::block::{ClosedBlock, OpenBlock}; use crate::client::TestBlockChainClient; - use crate::consensus::{CodeChainEngine, EngineError, Seal}; + use crate::consensus::{EngineError, Seal}; use crate::error::BlockError; use crate::error::Error; use crate::scheme::Scheme; - use crate::tests::helpers::get_temp_state_db; use super::*; @@ -155,29 +152,12 @@ mod tests { (scheme, tap, test_client) } - fn propose_default(scheme: &Scheme, proposer: Address) -> (ClosedBlock, Vec) { - let db = get_temp_state_db(); - let db = scheme.ensure_genesis_state(db).unwrap(); - let genesis_header = scheme.genesis_header(); - let b = OpenBlock::try_new(scheme.engine.as_ref(), db, &genesis_header, proposer, vec![]).unwrap(); - let seal = scheme.engine.generate_seal(None, &genesis_header).seal_fields().unwrap(); - let term_common_params = CommonParams::default_for_test(); - let b = b.close(&genesis_header, Some(&term_common_params)).unwrap(); - (b, seal) - } - fn insert_and_unlock(tap: &Arc, acc: &str) -> Address { let addr = tap.insert_account(blake256(acc).into(), &acc.into()).unwrap(); tap.unlock_account_permanently(addr, acc.into()).unwrap(); addr } - fn insert_and_register(tap: &Arc, engine: &dyn CodeChainEngine, acc: &str) -> Address { - let addr = insert_and_unlock(tap, acc); - engine.set_signer(tap.clone(), addr); - addr - } - #[test] fn has_valid_metadata() { use std::time::Duration; @@ -209,17 +189,6 @@ mod tests { } } - #[test] - #[ignore] // FIXME - fn generate_seal() { - let (scheme, tap, _c) = setup(); - - let proposer = insert_and_register(&tap, scheme.engine.as_ref(), "1"); - - let (b, seal) = propose_default(&scheme, proposer); - assert!(b.lock().try_seal(scheme.engine.as_ref(), seal).is_ok()); - } - #[test] #[ignore] // FIXME fn parent_block_existence_checking() { diff --git a/core/src/error.rs b/core/src/error.rs index 0de2058746..5267f45af5 100644 --- a/core/src/error.rs +++ b/core/src/error.rs @@ -95,8 +95,6 @@ pub enum BlockError { InvalidScore(Mismatch), /// Proof-of-work aspect of seal is invalid. InvalidProofOfWork, - /// Score of proof-of-work is out of bound. - PowOutOfBounds(OutOfBounds), /// Some low-level aspect of the seal is incorrect. InvalidSeal, /// Timestamp header field is invalid. @@ -147,7 +145,6 @@ impl fmt::Display for BlockError { ScoreOutOfBounds(oob) => format!("Invalid block score: {}", oob), InvalidScore(oob) => format!("Invalid block score: {}", oob), InvalidProofOfWork => "Invalid proof of work.".into(), - PowOutOfBounds(oob) => format!("Invalid proof of work: {}", oob), InvalidSeal => "Block has invalid seal.".into(), InvalidTimestamp(oob) => format!("Invalid timestamp in header: {}", oob), TemporarilyInvalid(oob) => format!("Future timestamp in header: {}", oob), @@ -180,10 +177,6 @@ pub enum Error { Engine(EngineError), /// Key error. Key(KeyError), - /// PoW hash is invalid or out of date. - PowHashInvalid, - /// The value of the nonce or mishash is invalid. - PowInvalid, Scheme(SchemeError), /// Account Provider error. AccountProvider(AccountProviderError), @@ -203,8 +196,6 @@ impl fmt::Display for Error { Error::Import(err) => err.fmt(f), Error::Engine(err) => err.fmt(f), Error::Key(err) => err.fmt(f), - Error::PowHashInvalid => f.write_str("Invalid or out of date PoW hash."), - Error::PowInvalid => f.write_str("Invalid nonce or mishash"), Error::Scheme(err) => err.fmt(f), Error::AccountProvider(err) => err.fmt(f), Error::Trie(err) => err.fmt(f), diff --git a/core/src/lib.rs b/core/src/lib.rs index 104e7d4911..6056a35926 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -27,7 +27,6 @@ extern crate codechain_logger as clogger; extern crate codechain_merkle as cmerkle; extern crate codechain_network as cnetwork; extern crate codechain_state as cstate; -extern crate codechain_stratum as cstratum; extern crate codechain_timer as ctimer; extern crate codechain_types as ctypes; extern crate codechain_vm as cvm; @@ -71,7 +70,7 @@ pub use crate::client::{ pub use crate::consensus::{EngineType, TimeGapParams}; pub use crate::db::{COL_STATE, NUM_COLUMNS}; pub use crate::error::{BlockImportError, Error, ImportError}; -pub use crate::miner::{MemPoolFees, Miner, MinerOptions, MinerService, Stratum, StratumConfig, StratumError}; +pub use crate::miner::{MemPoolFees, Miner, MinerOptions, MinerService}; pub use crate::scheme::Scheme; pub use crate::service::ClientService; pub use crate::transaction::{ diff --git a/core/src/miner/mem_pool.rs b/core/src/miner/mem_pool.rs index 42c22fe87f..86e736a859 100644 --- a/core/src/miner/mem_pool.rs +++ b/core/src/miner/mem_pool.rs @@ -395,8 +395,6 @@ impl MemPool { .filter(|&(_, ref item)| !item.origin.is_local()) .map(|(hash, item)| (hash, item, current_block_number.saturating_sub(item.inserted_block_number))) .filter_map(|(hash, item, time_diff)| { - // FIXME: In PoW, current_timestamp can be roll-backed. - // In that case, transactions which are removed in here can be recovered. if let Some(expiration) = item.expiration() { if expiration < current_timestamp { return Some(*hash) @@ -948,11 +946,6 @@ impl MemPool { .collect() } - /// Returns true if there is at least one local transaction pending - pub fn has_local_pending_transactions(&self) -> bool { - self.current.queue.iter().any(|tx| tx.origin.is_local()) - } - /// Returns Some(true) if the given transaction is local and None for not found. pub fn is_local_transaction(&self, tx_hash: TxHash) -> Option { self.by_hash.get(&tx_hash).map(|found_item| found_item.origin.is_local()) diff --git a/core/src/miner/miner.rs b/core/src/miner/miner.rs index 08a2ba0a99..29cb422889 100644 --- a/core/src/miner/miner.rs +++ b/core/src/miner/miner.rs @@ -26,20 +26,18 @@ use ckey::{public_to_address, Address, Password, PlatformAddress, Public}; use cstate::{FindActionHandler, TopLevelState}; use ctypes::errors::{HistoryError, RuntimeError}; use ctypes::transaction::{Action, IncompleteTransaction, Timelock}; -use ctypes::{BlockHash, BlockNumber, Header, TxHash}; +use ctypes::{BlockHash, TxHash}; use cvm::ChainTimeInfo; use kvdb::KeyValueDB; use parking_lot::{Mutex, RwLock}; -use primitives::{Bytes, H256}; +use primitives::Bytes; use super::mem_pool::{Error as MemPoolError, MemPool}; pub use super::mem_pool_types::MemPoolFees; use super::mem_pool_types::{AccountDetails, MemPoolInput, TxOrigin, TxTimelock}; -use super::sealing_queue::SealingQueue; -use super::work_notify::{NotifyWork, WorkPoster}; use super::{MinerService, MinerStatus, TransactionImportResult}; use crate::account_provider::{AccountProvider, Error as AccountProviderError}; -use crate::block::{Block, ClosedBlock, IsBlock}; +use crate::block::{ClosedBlock, IsBlock}; use crate::client::{ AccountData, BlockChainTrait, BlockProducer, Client, EngineInfo, ImportBlock, MiningBlockChainClient, TermInfo, }; @@ -54,8 +52,6 @@ use std::borrow::Borrow; /// Configures the behaviour of the miner. #[derive(Debug, PartialEq)] pub struct MinerOptions { - /// URLs to notify when there is new work. - pub new_work_notify: Vec, /// Force the miner to reseal, even when nobody has asked for work. pub force_sealing: bool, /// Reseal on receipt of new external transactions. @@ -78,8 +74,6 @@ pub struct MinerOptions { /// Local transactions ignore this option. pub mem_pool_fee_bump_shift: usize, pub allow_create_shard: bool, - /// How many historical work packages can we store before running out? - pub work_queue_size: usize, /// Minimum fees configured by the machine. pub mem_pool_fees: MemPoolFees, } @@ -87,7 +81,6 @@ pub struct MinerOptions { impl Default for MinerOptions { fn default() -> Self { MinerOptions { - new_work_notify: vec![], force_sealing: false, reseal_on_external_transaction: true, reseal_on_own_transaction: true, @@ -98,7 +91,6 @@ impl Default for MinerOptions { mem_pool_memory_limit: Some(2 * 1024 * 1024), mem_pool_fee_bump_shift: 3, allow_create_shard: false, - work_queue_size: 20, mem_pool_fees: Default::default(), } } @@ -110,11 +102,6 @@ pub struct AuthoringParams { pub extra_data: Bytes, } -struct SealingWork { - queue: SealingQueue, - enabled: bool, -} - type TransactionListener = Box; pub struct Miner { @@ -122,8 +109,6 @@ pub struct Miner { transaction_listener: RwLock>, next_allowed_reseal: Mutex, next_mandatory_reseal: RwLock, - sealing_block_last_request: Mutex, - sealing_work: Mutex, params: RwLock, engine: Arc, options: MinerOptions, @@ -131,17 +116,11 @@ pub struct Miner { sealing_enabled: AtomicBool, accounts: Option>, - notifiers: RwLock>>, malicious_users: RwLock>, immune_users: RwLock>, } impl Miner { - /// Push listener that will handle new jobs - pub fn add_work_listener(&self, notifier: Box) { - self.notifiers.write().push(notifier); - } - pub fn new( options: MinerOptions, scheme: &Scheme, @@ -170,28 +149,16 @@ impl Miner { options.mem_pool_fees, ))); - let notifiers: Vec> = if options.new_work_notify.is_empty() { - Vec::new() - } else { - vec![Box::new(WorkPoster::new(&options.new_work_notify))] - }; - Self { mem_pool, transaction_listener: RwLock::new(vec![]), next_allowed_reseal: Mutex::new(Instant::now()), next_mandatory_reseal: RwLock::new(Instant::now() + options.reseal_max_period), params: RwLock::new(AuthoringParams::default()), - sealing_block_last_request: Mutex::new(0), - sealing_work: Mutex::new(SealingWork { - queue: SealingQueue::new(options.work_queue_size), - enabled: options.force_sealing || scheme.engine.seals_internally().is_some(), - }), engine: scheme.engine.clone(), options, sealing_enabled: AtomicBool::new(true), accounts, - notifiers: RwLock::new(notifiers), malicious_users: RwLock::new(HashSet::new()), immune_users: RwLock::new(HashSet::new()), } @@ -206,60 +173,10 @@ impl Miner { self.transaction_listener.write().push(f); } - /// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing. - pub fn pending_state(&self, latest_block_number: BlockNumber) -> Option { - self.map_pending_block(|b| b.state().clone(), latest_block_number) - } - - /// Get `Some` `clone()` of the current pending block or `None` if we're not sealing. - pub fn pending_block(&self, latest_block_number: BlockNumber) -> Option { - self.map_pending_block(IsBlock::to_base, latest_block_number) - } - - /// Get `Some` `clone()` of the current pending block header or `None` if we're not sealing. - pub fn pending_block_header(&self, latest_block_number: BlockNumber) -> Option
{ - self.map_pending_block(|b| b.header().clone(), latest_block_number) - } - pub fn get_options(&self) -> &MinerOptions { &self.options } - /// Check is reseal is allowed and necessary. - fn requires_reseal(&self, best_block: BlockNumber) -> bool { - let has_local_transactions = self.mem_pool.read().has_local_pending_transactions(); - let mut sealing_work = self.sealing_work.lock(); - if sealing_work.enabled { - ctrace!(MINER, "requires_reseal: sealing enabled"); - let last_request = *self.sealing_block_last_request.lock(); - let should_disable_sealing = !self.options.force_sealing - && !has_local_transactions - && self.engine.seals_internally().is_none() - && best_block > last_request - && best_block - last_request > SEALING_TIMEOUT_IN_BLOCKS; - - ctrace!( - MINER, - "requires_reseal: should_disable_sealing={}; best_block={}, last_request={}", - should_disable_sealing, - best_block, - last_request - ); - - if should_disable_sealing { - cdebug!(MINER, "Miner sleeping"); - sealing_work.enabled = false; - sealing_work.queue.reset(); - false - } else { - true - } - } else { - cdebug!(MINER, "requires_reseal: sealing is disabled"); - false - } - } - fn add_transactions_to_pool( &self, client: &C, @@ -429,54 +346,6 @@ impl Miner { }) } - /// Prepares work which has to be done to seal. - fn prepare_work(&self, block: ClosedBlock, original_work_hash: Option) { - let (work, is_new) = { - let mut sealing_work = self.sealing_work.lock(); - let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| pb.block().header().hash()); - ctrace!( - MINER, - "prepare_work: Checking whether we need to reseal: orig={:?} last={:?}, this={:?}", - original_work_hash, - last_work_hash, - block.block().header().hash() - ); - let (work, is_new) = if last_work_hash.map_or(true, |h| h != block.block().header().hash()) { - ctrace!( - MINER, - "prepare_work: Pushing a new, refreshed or borrowed pending {}...", - block.block().header().hash() - ); - let pow_hash = *block.block().header().hash(); - let number = block.block().header().number(); - let score = *block.block().header().score(); - let is_new = original_work_hash.map_or(true, |h| *block.block().header().hash() != h); - sealing_work.queue.push(block); - // If push notifications are enabled we assume all work items are used. - if !self.notifiers.read().is_empty() && is_new { - sealing_work.queue.use_last_ref(); - } - (Some((pow_hash, score, number)), is_new) - } else { - (None, false) - }; - ctrace!( - MINER, - "prepare_work: leaving (last={:?})", - sealing_work.queue.peek_last_ref().map(|b| b.block().header().hash()) - ); - (work, is_new) - }; - if is_new { - if let Some((pow_hash, score, _number)) = work { - let target = self.engine.score_to_target(&score); - for notifier in self.notifiers.read().iter() { - notifier.notify(pow_hash, target) - } - } - } - } - /// Prepares new block for sealing including top transactions from queue. fn prepare_block< C: AccountData + BlockChainTrait + BlockProducer + ChainTimeInfo + EngineInfo + FindActionHandler + TermInfo, @@ -484,11 +353,8 @@ impl Miner { &self, parent_block_id: BlockId, chain: &C, - ) -> Result)>, Error> { - let (transactions, mut open_block, original_work_hash, block_number) = { - let sealing_work = self.sealing_work.lock(); - - let last_work_hash = sealing_work.queue.peek_last_ref().map(|pb| *pb.block().header().hash()); + ) -> Result, Error> { + let (transactions, mut open_block, block_number) = { ctrace!(MINER, "prepare_block: No existing work - making new block"); let params = self.params.read().clone(); let open_block = chain.prepare_open_block(parent_block_id, params.author, params.extra_data); @@ -507,7 +373,7 @@ impl Miner { .top_transactions(max_body_size, Some(open_block.header().timestamp()), DEFAULT_RANGE) .transactions; - (transactions, open_block, last_work_hash, block_number) + (transactions, open_block, block_number) }; let parent_header = { @@ -515,11 +381,7 @@ impl Miner { chain.block_header(&BlockId::Hash(*parent_hash)).expect("Parent header MUST exist") }; if self.engine_type().is_seal_first() { - match self.engine.seals_internally() { - Some(false) => panic!("If a signer is not prepared, prepare_block should not be called"), - None => panic!("Exteranl sealing is not seals_first"), - Some(true) => {} - }; + assert!(self.engine.seals_internally(), "If a signer is not prepared, prepare_block should not be called"); let seal = self.engine.generate_seal(None, &parent_header.decode()); if let Some(seal_bytes) = seal.seal_fields() { open_block.seal(self.engine.borrow(), seal_bytes).expect("Sealing always success"); @@ -621,7 +483,7 @@ impl Miner { chain.chain_info().best_block_timestamp, ); } - Ok(Some((block, original_work_hash))) + Ok(Some(block)) } /// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the type of Seal. @@ -642,7 +504,7 @@ impl Miner { None => return false, }; - if self.engine.seals_internally() != Some(true) { + if !self.engine.seals_internally() { ctrace!(MINER, "No seal is generated."); return false } @@ -677,19 +539,6 @@ impl Miner { self.sealing_enabled.load(Ordering::Relaxed) && (Instant::now() > *self.next_allowed_reseal.lock()) } - fn map_pending_block(&self, f: F, latest_block_number: BlockNumber) -> Option - where - F: FnOnce(&ClosedBlock) -> T, { - let sealing_work = self.sealing_work.lock(); - sealing_work.queue.peek_last_ref().and_then(|b| { - if b.block().header().number() > latest_block_number { - Some(f(b)) - } else { - None - } - }) - } - fn is_allowed_transaction(&self, action: &Action) -> bool { if let Action::CreateShard { .. @@ -703,18 +552,14 @@ impl Miner { } } -const SEALING_TIMEOUT_IN_BLOCKS: u64 = 5; - impl MinerService for Miner { type State = TopLevelState; fn status(&self) -> MinerStatus { let status = self.mem_pool.read().status(); - let sealing_work = self.sealing_work.lock(); MinerStatus { transactions_in_pending_queue: status.pending, transactions_in_future_queue: status.future, - tranasction_in_pending_block: sealing_work.queue.peek_last_ref().map_or(0, |b| b.transactions().len()), } } @@ -725,16 +570,11 @@ impl MinerService for Miner { fn set_author(&self, address: Address) -> Result<(), AccountProviderError> { self.params.write().author = address; - if self.engine_type().need_signer_key() && self.engine.seals_internally().is_some() { + if self.engine_type().need_signer_key() { if let Some(ref ap) = self.accounts { ctrace!(MINER, "Set author to {:?}", address); // Sign test message ap.get_unlocked_account(&address)?.sign(&Default::default())?; - // Limit the scope of the locks. - { - let mut sealing_work = self.sealing_work.lock(); - sealing_work.enabled = true; - } self.engine.set_signer(ap.clone(), address); Ok(()) } else { @@ -803,65 +643,10 @@ impl MinerService for Miner { } } - fn can_produce_work_package(&self) -> bool { - self.engine.seals_internally().is_none() - } - fn engine_type(&self) -> EngineType { self.engine.engine_type() } - fn prepare_work_sealing< - C: AccountData + BlockChainTrait + BlockProducer + ChainTimeInfo + EngineInfo + FindActionHandler + TermInfo, - >( - &self, - client: &C, - ) -> bool { - ctrace!(MINER, "prepare_work_sealing: entering"); - let prepare_new = { - let mut sealing_work = self.sealing_work.lock(); - let have_work = sealing_work.queue.peek_last_ref().is_some(); - ctrace!(MINER, "prepare_work_sealing: have_work={}", have_work); - if !have_work { - sealing_work.enabled = true; - true - } else { - false - } - }; - if prepare_new { - // -------------------------------------------------------------------------- - // | NOTE Code below requires transaction_queue and sealing_work locks. | - // | Make sure to release the locks before calling that method. | - // -------------------------------------------------------------------------- - match self.prepare_block(BlockId::Latest, client) { - Ok(Some((block, original_work_hash))) => { - self.prepare_work(block, original_work_hash); - } - Ok(None) => { - ctrace!(MINER, "prepare_work_sealing: cannot prepare block"); - } - Err(err) => { - ctrace!(MINER, "prepare_work_sealing: cannot prepare block: {:?}", err); - } - } - } - let mut sealing_block_last_request = self.sealing_block_last_request.lock(); - let best_number = client.chain_info().best_block_number; - if *sealing_block_last_request != best_number { - ctrace!( - MINER, - "prepare_work_sealing: Miner received request (was {}, now {}) - waking up.", - *sealing_block_last_request, - best_number - ); - *sealing_block_last_request = best_number; - } - - // Return if we restarted - prepare_new - } - fn update_sealing(&self, chain: &C, parent_block: BlockId, allow_empty_block: bool) where C: AccountData @@ -874,94 +659,39 @@ impl MinerService for Miner { + TermInfo, { ctrace!(MINER, "update_sealing: preparing a block"); - let parent_block_number = chain.block_header(&parent_block).expect("Parent is always exist").number(); - if self.requires_reseal(parent_block_number) { - let (block, original_work_hash) = match self.prepare_block(parent_block, chain) { - Ok(Some((block, original_work_hash))) => { - if !allow_empty_block && block.block().transactions().is_empty() { - ctrace!(MINER, "update_sealing: block is empty, and allow_empty_block is false"); - return - } - (block, original_work_hash) - } - Ok(None) => { - ctrace!(MINER, "update_sealing: cannot prepare block"); - return - } - Err(err) => { - ctrace!(MINER, "update_sealing: cannot prepare block: {:?}", err); - return - } - }; - - match self.engine.seals_internally() { - Some(true) => { - ctrace!(MINER, "update_sealing: engine indicates internal sealing"); - if self.seal_and_import_block_internally(chain, block) { - ctrace!(MINER, "update_sealing: imported internally sealed block"); - } - } - Some(false) => { - ctrace!(MINER, "update_sealing: engine is not keen to seal internally right now"); + let block = match self.prepare_block(parent_block, chain) { + Ok(Some(block)) => { + if !allow_empty_block && block.block().transactions().is_empty() { + ctrace!(MINER, "update_sealing: block is empty, and allow_empty_block is false"); return } - None => { - ctrace!(MINER, "update_sealing: engine does not seal internally, preparing work"); - self.prepare_work(block, original_work_hash); - // Set the reseal max timer, for creating empty blocks every reseal_max_period - // Not related to next_mandatory_reseal, which is used in seal_and_import_block_internally - if !self.options.no_reseal_timer { - chain.set_max_timer(); - } - } + block } - - // Sealing successful - *self.next_allowed_reseal.lock() = Instant::now() + self.options.reseal_min_period; - if !self.options.no_reseal_timer { - chain.set_min_timer(); + Ok(None) => { + ctrace!(MINER, "update_sealing: cannot prepare block"); + return } - } - } + Err(err) => { + ctrace!(MINER, "update_sealing: cannot prepare block: {:?}", err); + return + } + }; - fn submit_seal(&self, chain: &C, block_hash: BlockHash, seal: Vec) -> Result<(), Error> { - let result = if let Some(b) = self.sealing_work.lock().queue.take_used_if(|b| b.hash() == *block_hash) { - ctrace!( - MINER, - "Submitted block {}={}={} with seal {:?}", - block_hash, - b.hash(), - b.header().bare_hash(), - seal - ); - b.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| { - cwarn!(MINER, "Mined solution rejected: {}", e); - Err(Error::PowInvalid) - }) + if self.engine.seals_internally() { + ctrace!(MINER, "update_sealing: engine indicates internal sealing"); + if self.seal_and_import_block_internally(chain, block) { + ctrace!(MINER, "update_sealing: imported internally sealed block"); + } } else { - cwarn!(MINER, "Submitted solution rejected: Block unknown or out of date."); - Err(Error::PowHashInvalid) - }; - result.and_then(|sealed| { - let n = sealed.header().number(); - let h = sealed.header().hash(); - chain.import_sealed_block(&sealed)?; - cinfo!(MINER, "Submitted block imported OK. #{}: {}", n, h); - Ok(()) - }) - } + ctrace!(MINER, "update_sealing: engine is not keen to seal internally right now"); + return + } - fn map_sealing_work(&self, client: &C, f: F) -> Option - where - C: AccountData + BlockChainTrait + BlockProducer + ChainTimeInfo + EngineInfo + FindActionHandler + TermInfo, - F: FnOnce(&ClosedBlock) -> T, { - ctrace!(MINER, "map_sealing_work: entering"); - self.prepare_work_sealing(client); - ctrace!(MINER, "map_sealing_work: sealing prepared"); - let mut sealing_work = self.sealing_work.lock(); - let ret = sealing_work.queue.use_last_ref(); - ctrace!(MINER, "map_sealing_work: leaving use_last_ref={:?}", ret.as_ref().map(|b| b.block().header().hash())); - ret.map(f) + // Sealing successful + *self.next_allowed_reseal.lock() = Instant::now() + self.options.reseal_min_period; + if !self.options.no_reseal_timer { + chain.set_min_timer(); + } } fn import_external_transactions( @@ -1024,7 +754,7 @@ impl MinerService for Miner { if imported.is_ok() && self.options.reseal_on_own_transaction && self.transaction_reseal_allowed() && !self.engine_type().ignore_reseal_on_transaction() // Make sure to do it after transaction is imported and lock is dropped. // We need to create pending block and enable sealing. - && (self.engine.seals_internally().unwrap_or(false) || !self.prepare_work_sealing(chain)) + && self.engine.seals_internally() { // If new block has not been prepared (means we already had one) // or Engine might be able to seal internally, @@ -1160,7 +890,7 @@ pub mod test { use ckey::{Private, Signature}; use ctimer::TimerLoop; use ctypes::transaction::Transaction; - use primitives::H512; + use primitives::{H256, H512}; use super::super::super::client::ClientConfig; use super::super::super::service::ClientIoMessage; diff --git a/core/src/miner/mod.rs b/core/src/miner/mod.rs index c732644a68..3363e010d5 100644 --- a/core/src/miner/mod.rs +++ b/core/src/miner/mod.rs @@ -19,9 +19,6 @@ mod mem_pool; mod mem_pool_types; #[cfg_attr(feature = "cargo-clippy", allow(clippy::module_inception))] mod miner; -mod sealing_queue; -mod stratum; -mod work_notify; use std::ops::Range; @@ -34,9 +31,7 @@ use primitives::Bytes; pub use self::mem_pool_types::MemPoolFees; pub use self::miner::{AuthoringParams, Miner, MinerOptions}; -pub use self::stratum::{Config as StratumConfig, Error as StratumError, Stratum}; use crate::account_provider::{AccountProvider, Error as AccountProviderError}; -use crate::block::ClosedBlock; use crate::client::{ AccountData, BlockChainTrait, BlockProducer, EngineInfo, ImportBlock, MiningBlockChainClient, TermInfo, }; @@ -79,17 +74,9 @@ pub trait MinerService: Send + Sync { ) where C: AccountData + BlockChainTrait + BlockProducer + EngineInfo + ImportBlock; - /// PoW chain - can produce work package - fn can_produce_work_package(&self) -> bool; - /// Get the type of consensus engine. fn engine_type(&self) -> EngineType; - /// Returns true if we had to prepare new pending block. - fn prepare_work_sealing(&self, _: &C) -> bool - where - C: AccountData + BlockChainTrait + BlockProducer + ChainTimeInfo + EngineInfo + FindActionHandler + TermInfo; - /// New chain head event. Restart mining operation. fn update_sealing(&self, chain: &C, parent_block: BlockId, allow_empty_block: bool) where @@ -102,17 +89,6 @@ pub trait MinerService: Send + Sync { + FindActionHandler + TermInfo; - /// Submit `seal` as a valid solution for the header of `pow_hash`. - /// Will check the seal, but not actually insert the block into the chain. - fn submit_seal(&self, chain: &C, pow_hash: BlockHash, seal: Vec) -> Result<(), Error>; - - /// Get the sealing work package and if `Some`, apply some transform. - fn map_sealing_work(&self, client: &C, f: F) -> Option - where - C: AccountData + BlockChainTrait + BlockProducer + ChainTimeInfo + EngineInfo + FindActionHandler + TermInfo, - F: FnOnce(&ClosedBlock) -> T, - Self: Sized; - /// Imports transactions to mem pool. fn import_external_transactions( &self, @@ -176,8 +152,6 @@ pub struct MinerStatus { pub transactions_in_pending_queue: usize, /// Number of transactions in queue with state `future` (not yet ready to be included in block) pub transactions_in_future_queue: usize, - /// Number of transactions included in currently mined block - pub tranasction_in_pending_block: usize, } /// Represents the result of importing tranasction. diff --git a/core/src/miner/sealing_queue.rs b/core/src/miner/sealing_queue.rs deleted file mode 100644 index 16f282367e..0000000000 --- a/core/src/miner/sealing_queue.rs +++ /dev/null @@ -1,207 +0,0 @@ -// Copyright 2018-2019 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use crate::block::ClosedBlock; - -pub struct SealingQueue { - /// Not yet being sealed by a miner, but if one asks for work, we'd prefer they do this. - pending: Option, - /// Currently being sealed by miners. - in_use: Vec, - /// The maximum allowable number of items in_use. - max_size: usize, -} - -impl SealingQueue { - pub fn new(max_size: usize) -> Self { - Self { - pending: None, - in_use: Vec::new(), - max_size, - } - } - - /// Return a reference to the item at the top of the queue (or `None` if the queue is empty); - /// it doesn't constitute noting that the item is used. - pub fn peek_last_ref(&self) -> Option<&ClosedBlock> { - self.pending.as_ref().or_else(|| self.in_use.last()) - } - - pub fn push(&mut self, b: ClosedBlock) { - self.pending = Some(b); - } - - /// Return a reference to the item at the top of the queue (or `None` if the queue is empty); - /// this constitutes using the item and will remain in the queue for at least another - /// `max_size` invocations of `push()`. - pub fn use_last_ref(&mut self) -> Option<&ClosedBlock> { - if let Some(x) = self.pending.take() { - self.in_use.push(x); - if self.in_use.len() > self.max_size { - self.in_use.remove(0); - } - } - self.in_use.last() - } - - /// Clears everything; the queue is entirely reset. - pub fn reset(&mut self) { - self.pending = None; - self.in_use.clear(); - } - - pub fn take_used_if

(&mut self, predicate: P) -> Option - where - P: Fn(&ClosedBlock) -> bool, { - self.in_use.iter().position(|r| predicate(r)).map(|i| self.in_use.remove(i)) - } -} - -#[cfg(test)] -mod tests { - use ckey::Address; - use ctypes::CommonParams; - - use super::SealingQueue; - use crate::block::{ClosedBlock, OpenBlock}; - use crate::scheme::Scheme; - use crate::tests::helpers::get_temp_state_db; - - const QUEUE_SIZE: usize = 2; - - fn create_closed_block(address: Address) -> ClosedBlock { - let scheme = Scheme::new_test(); - let genesis_header = scheme.genesis_header(); - let db = scheme.ensure_genesis_state(get_temp_state_db()).unwrap(); - let b = OpenBlock::try_new(&*scheme.engine, db, &genesis_header, address, vec![]).unwrap(); - let term_common_params = CommonParams::default_for_test(); - b.close(&genesis_header, Some(&term_common_params)).unwrap() - } - - #[test] - fn fail_to_find_when_pushed() { - let mut q = SealingQueue::new(QUEUE_SIZE); - let b = create_closed_block(Address::default()); - let h = b.hash(); - - q.push(b); - - assert!(q.take_used_if(|b| b.hash() == h).is_none()); - } - - #[test] - fn find_when_pushed_and_used() { - let mut q = SealingQueue::new(QUEUE_SIZE); - let b = create_closed_block(Address::default()); - let h = b.hash(); - - q.push(b); - q.use_last_ref(); - - assert!(q.take_used_if(|b| b.hash() == h).is_some()); - } - - #[test] - fn find_when_others_used() { - let mut q = SealingQueue::new(QUEUE_SIZE); - let b1 = create_closed_block(Address::from(1)); - let b2 = create_closed_block(Address::from(2)); - let h1 = b1.hash(); - - q.push(b1); - q.use_last_ref(); - q.push(b2); - q.use_last_ref(); - - assert!(q.take_used_if(|b| b.hash() == h1).is_some()); - } - - #[test] - fn fail_to_find_when_too_many_used() { - let mut q = SealingQueue::new(1); - let b1 = create_closed_block(Address::from(1)); - let b2 = create_closed_block(Address::from(2)); - let h1 = b1.hash(); - - q.push(b1); - q.use_last_ref(); - q.push(b2); - q.use_last_ref(); - - assert!(q.take_used_if(|b| b.hash() == h1).is_none()); - } - - #[test] - fn fail_to_find_when_not_used_and_then_pushed() { - let mut q = SealingQueue::new(QUEUE_SIZE); - let b1 = create_closed_block(Address::from(1)); - let b2 = create_closed_block(Address::from(2)); - let h1 = b1.hash(); - - q.push(b1); - q.push(b2); - q.use_last_ref(); - - assert!(q.take_used_if(|b| b.hash() == h1).is_none()); - } - - #[test] - fn peek_correctly_after_push() { - let mut q = SealingQueue::new(QUEUE_SIZE); - let b1 = create_closed_block(Address::from(1)); - let b2 = create_closed_block(Address::from(2)); - let h1 = b1.hash(); - let h2 = b2.hash(); - - q.push(b1); - assert_eq!(q.peek_last_ref().unwrap().hash(), h1); - - q.push(b2); - assert_eq!(q.peek_last_ref().unwrap().hash(), h2); - } - - #[test] - fn inspect_correctly() { - let mut q = SealingQueue::new(QUEUE_SIZE); - let b1 = create_closed_block(Address::from(1)); - let b2 = create_closed_block(Address::from(2)); - let h1 = b1.hash(); - let h2 = b2.hash(); - - q.push(b1); - assert_eq!(q.use_last_ref().unwrap().hash(), h1); - assert_eq!(q.peek_last_ref().unwrap().hash(), h1); - - q.push(b2); - assert_eq!(q.use_last_ref().unwrap().hash(), h2); - assert_eq!(q.peek_last_ref().unwrap().hash(), h2); - } - - #[test] - fn fail_to_find_when_not_used_peeked_and_then_pushed() { - let mut q = SealingQueue::new(QUEUE_SIZE); - let b1 = create_closed_block(Address::from(1)); - let b2 = create_closed_block(Address::from(2)); - let h = b1.hash(); - - q.push(b1); - q.peek_last_ref(); - q.push(b2); - q.use_last_ref(); - - assert!(q.take_used_if(|b| b.hash() == h).is_none()); - } -} diff --git a/core/src/miner/stratum.rs b/core/src/miner/stratum.rs deleted file mode 100644 index 4d43916229..0000000000 --- a/core/src/miner/stratum.rs +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright 2018 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -//! Client-side stratum job dispatcher and mining notifier handler - -use std::net::{AddrParseError, SocketAddr}; -use std::sync::Arc; - -use crate::error::Error as MinerError; -use cstratum::{Error as StratumServiceError, JobDispatcher, PushWorkHandler, Stratum as StratumService}; -use primitives::{Bytes, H256, U256}; - -use crate::client::Client; -use crate::miner::work_notify::NotifyWork; -use crate::miner::{Miner, MinerService}; - -/// Configures stratum server options. -#[derive(Debug, PartialEq, Clone)] -pub struct Config { - /// Network address - pub listen_addr: String, - /// Port - pub port: u16, - /// Secret for peers - pub secret: Option, -} - -/// Job dispatcher for stratum service -pub struct StratumJobDispatcher { - client: Arc, - miner: Arc, -} - -impl JobDispatcher for StratumJobDispatcher { - fn initial(&self) -> Option { - // initial payload may contain additional data, not in this case - self.job() - } - - fn submit(&self, payload: (H256, Vec)) -> Result<(), StratumServiceError> { - let (pow_hash, seal) = payload; - - ctrace!(STRATUM, "submit_work: Decoded: pow_hash={}, seal={:?}", pow_hash, seal); - - if !self.miner.can_produce_work_package() { - cwarn!(STRATUM, "Cannot get work package - engine seals internally."); - return Err(StratumServiceError::InternalError) - } - - match self.miner.submit_seal(&*self.client, pow_hash.into(), seal) { - Ok(_) => Ok(()), - Err(e) => { - cwarn!(STRATUM, "submit_seal error: {:?}", e); - Err(StratumServiceError::from(e)) - } - } - } -} - -impl StratumJobDispatcher { - /// New stratum job dispatcher given the miner and client - fn new(miner: Arc, client: Arc) -> StratumJobDispatcher { - StratumJobDispatcher { - client, - miner, - } - } - - /// Serializes payload for stratum service - fn payload(&self, pow_hash: H256, target: U256) -> String { - format!(r#"["0x{:x}","0x{:x}"]"#, pow_hash, target) - } -} -/// Wrapper for dedicated stratum service -pub struct Stratum { - dispatcher: Arc, - service: StratumService, -} - -#[derive(Debug)] -/// Stratum error -pub enum Error { - /// IPC sockets error - Service(StratumServiceError), - /// Invalid network address - Address(AddrParseError), -} - -impl From for StratumServiceError { - fn from(err: MinerError) -> Self { - match err { - MinerError::PowHashInvalid => StratumServiceError::PowHashInvalid, - MinerError::PowInvalid => StratumServiceError::PowInvalid, - _ => StratumServiceError::InternalError, - } - } -} - -impl From for Error { - fn from(service_err: StratumServiceError) -> Error { - Error::Service(service_err) - } -} - -impl From for Error { - fn from(err: AddrParseError) -> Error { - Error::Address(err) - } -} - -impl NotifyWork for Stratum { - fn notify(&self, pow_hash: H256, target: U256) { - ctrace!(STRATUM, "Notify work"); - - self.service - .push_work_all(self.dispatcher.payload(pow_hash, target)) - .unwrap_or_else(|e| cwarn!(STRATUM, "Error while pushing work: {:?}", e)); - } -} - -impl Stratum { - /// New stratum job dispatcher, given the miner, client and dedicated stratum service - pub fn start(config: &Config, miner: Arc, client: Arc) -> Result { - use std::net::IpAddr; - - let dispatcher = Arc::new(StratumJobDispatcher::new(miner, client)); - let stratum_svc = StratumService::start( - &SocketAddr::new(config.listen_addr.parse::()?, config.port), - dispatcher.clone(), - config.secret, - )?; - - Ok(Stratum { - dispatcher, - service: stratum_svc, - }) - } -} diff --git a/core/src/miner/work_notify.rs b/core/src/miner/work_notify.rs deleted file mode 100644 index 7b0967e375..0000000000 --- a/core/src/miner/work_notify.rs +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2018 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use std::io::Write; - -use hyper; -use parking_lot::Mutex; -use primitives::{H256, U256}; - -use self::hyper::client::{Client, Request, Response}; -use self::hyper::header::ContentType; -use self::hyper::method::Method; -use self::hyper::net::HttpStream; -use self::hyper::{Next, Url}; - -/// Trait for notifying about new mining work -pub trait NotifyWork: Send + Sync { - /// Fired when new mining job available - fn notify(&self, pow_hash: H256, target: U256); -} - -/// POSTs info about new work to given urls. -pub struct WorkPoster { - urls: Vec, - client: Mutex>, -} - -impl WorkPoster { - /// Create new `WorkPoster`. - pub fn new(urls: &[String]) -> Self { - let urls = urls - .iter() - .filter_map(|u| match Url::parse(u) { - Ok(url) => Some(url), - Err(e) => { - cwarn!(MINER, "Error parsing URL {} : {}", u, e); - None - } - }) - .collect(); - let client = WorkPoster::create_client(); - WorkPoster { - client: Mutex::new(client), - urls, - } - } - - fn create_client() -> Client { - Client::::configure().keep_alive(true).build().expect("Error creating HTTP client") - } -} - -impl NotifyWork for WorkPoster { - fn notify(&self, pow_hash: H256, target: U256) { - let body = format!(r#"{{ "result": ["0x{:x}","0x{:x}"] }}"#, pow_hash, target); - let mut client = self.client.lock(); - for u in &self.urls { - if let Err(e) = client.request(u.clone(), PostHandler { - body: body.clone(), - }) { - cwarn!(MINER, "Error sending HTTP notification to {} : {}, retrying", u, e); - // TODO: remove this once https://github.com/hyperium/hyper/issues/848 is fixed - *client = WorkPoster::create_client(); - if let Err(e) = client.request(u.clone(), PostHandler { - body: body.clone(), - }) { - cwarn!(MINER, "Error sending HTTP notification to {} : {}", u, e); - } - } - } - } -} - -struct PostHandler { - body: String, -} - -impl hyper::client::Handler for PostHandler { - fn on_request(&mut self, request: &mut Request<'_>) -> Next { - request.set_method(Method::Post); - request.headers_mut().set(ContentType::json()); - Next::write() - } - - fn on_request_writable(&mut self, encoder: &mut hyper::Encoder<'_, HttpStream>) -> Next { - if let Err(e) = encoder.write_all(self.body.as_bytes()) { - ctrace!(MINER, "Error posting work data: {}", e); - } - encoder.close(); - Next::read() - } - - fn on_response(&mut self, _response: Response) -> Next { - Next::end() - } - - fn on_response_readable(&mut self, _decoder: &mut hyper::Decoder<'_, HttpStream>) -> Next { - Next::end() - } - - fn on_error(&mut self, err: hyper::Error) -> Next { - ctrace!(MINER, "Error posting work data: {}", err); - Next::end() - } -} diff --git a/core/src/scheme/scheme.rs b/core/src/scheme/scheme.rs index 64c427131b..1ce540d60b 100644 --- a/core/src/scheme/scheme.rs +++ b/core/src/scheme/scheme.rs @@ -35,7 +35,7 @@ use super::pod_state::{PodAccounts, PodShards}; use super::seal::Generic as GenericSeal; use super::Genesis; use crate::codechain_machine::CodeChainMachine; -use crate::consensus::{BlakePoW, CodeChainEngine, Cuckoo, NullEngine, SimplePoA, Solo, Tendermint}; +use crate::consensus::{CodeChainEngine, NullEngine, SimplePoA, Solo, Tendermint}; use crate::error::{Error, SchemeError}; /// Parameters for a block chain; includes both those intrinsic to the design of the @@ -105,8 +105,6 @@ impl Scheme { cjson::scheme::Engine::Solo(solo) => Arc::new(Solo::new(solo.params.into(), machine)), cjson::scheme::Engine::SimplePoA(simple_poa) => Arc::new(SimplePoA::new(simple_poa.params.into(), machine)), cjson::scheme::Engine::Tendermint(tendermint) => Tendermint::new(tendermint.params.into(), machine), - cjson::scheme::Engine::Cuckoo(cuckoo) => Arc::new(Cuckoo::new(cuckoo.params.into(), machine)), - cjson::scheme::Engine::BlakePoW(blake_pow) => Arc::new(BlakePoW::new(blake_pow.params.into(), machine)), } } @@ -251,24 +249,10 @@ impl Scheme { load_bundled!("tendermint") } - /// Create a new Scheme with Cuckoo PoW consensus. - pub fn new_test_cuckoo() -> Self { - load_bundled!("cuckoo") - } - - /// Create a new Scheme with Blake PoW consensus. - pub fn new_test_blake_pow() -> Self { - load_bundled!("blake_pow") - } - pub fn new_mainnet() -> Self { load_bundled!("mainnet") } - pub fn new_husky() -> Self { - load_bundled!("husky") - } - pub fn new_saluki() -> Self { load_bundled!("saluki") } diff --git a/foundry/config/chain_type.rs b/foundry/config/chain_type.rs index 608e5141e3..32597a8d62 100644 --- a/foundry/config/chain_type.rs +++ b/foundry/config/chain_type.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Kodebox, Inc. +// Copyright 2018-2019 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -28,9 +28,6 @@ pub enum ChainType { Solo, SimplePoA, Tendermint, - Cuckoo, - BlakePoW, - Husky, Saluki, Corgi, Beagle, @@ -52,9 +49,6 @@ impl FromStr for ChainType { "solo" => ChainType::Solo, "simple_poa" => ChainType::SimplePoA, "tendermint" => ChainType::Tendermint, - "cuckoo" => ChainType::Cuckoo, - "blake_pow" => ChainType::BlakePoW, - "husky" => ChainType::Husky, "saluki" => ChainType::Saluki, "corgi" => ChainType::Corgi, "beagle" => ChainType::Beagle, @@ -101,9 +95,6 @@ impl fmt::Display for ChainType { ChainType::Solo => "solo", ChainType::SimplePoA => "simple_poa", ChainType::Tendermint => "tendermint", - ChainType::Cuckoo => "cuckoo", - ChainType::BlakePoW => "blake_pow", - ChainType::Husky => "husky", ChainType::Saluki => "saluki", ChainType::Corgi => "corgi", ChainType::Beagle => "beagle", @@ -119,9 +110,6 @@ impl ChainType { ChainType::Solo => Ok(Scheme::new_test_solo()), ChainType::SimplePoA => Ok(Scheme::new_test_simple_poa()), ChainType::Tendermint => Ok(Scheme::new_test_tendermint()), - ChainType::Cuckoo => Ok(Scheme::new_test_cuckoo()), - ChainType::BlakePoW => Ok(Scheme::new_test_blake_pow()), - ChainType::Husky => Ok(Scheme::new_husky()), ChainType::Saluki => Ok(Scheme::new_saluki()), ChainType::Corgi => Ok(Scheme::new_corgi()), ChainType::Beagle => Ok(Scheme::new_beagle()), diff --git a/foundry/config/mod.rs b/foundry/config/mod.rs index d8ffbf3f8e..0cbe1d9ce0 100644 --- a/foundry/config/mod.rs +++ b/foundry/config/mod.rs @@ -20,7 +20,7 @@ use std::fs; use std::str::{self, FromStr}; use std::time::Duration; -use ccore::{MemPoolFees, MinerOptions, StratumConfig, TimeGapParams}; +use ccore::{MemPoolFees, MinerOptions, TimeGapParams}; use cidr::IpCidr; use ckey::PlatformAddress; use clap; @@ -41,7 +41,6 @@ pub struct Config { pub rpc: Rpc, pub ws: Ws, pub snapshot: Snapshot, - pub stratum: Stratum, #[serde(default)] pub email_alarm: EmailAlarm, } @@ -55,7 +54,6 @@ impl Config { self.rpc.merge(&other.rpc); self.ws.merge(&other.ws); self.snapshot.merge(&other.snapshot); - self.stratum.merge(&other.stratum); self.email_alarm.merge(&other.email_alarm); } @@ -100,14 +98,12 @@ impl Config { }, mem_pool_fee_bump_shift: self.mining.mem_pool_fee_bump_shift.unwrap(), allow_create_shard: self.mining.allow_create_shard.unwrap_or(false), - new_work_notify: self.mining.notify_work.clone().unwrap(), force_sealing: self.mining.force_sealing.unwrap(), reseal_on_own_transaction, reseal_on_external_transaction, reseal_min_period: Duration::from_millis(self.mining.reseal_min_period.unwrap()), reseal_max_period: Duration::from_millis(self.mining.reseal_max_period.unwrap()), no_reseal_timer: self.mining.no_reseal_timer.unwrap(), - work_queue_size: self.mining.work_queue_size.unwrap(), mem_pool_fees, }) } @@ -198,17 +194,6 @@ impl Config { blacklist, }) } - - pub fn stratum_config(&self) -> StratumConfig { - debug_assert!(!self.stratum.disable.unwrap()); - - // FIXME: Add listen_addr and secret - StratumConfig { - listen_addr: "127.0.0.1".to_string(), - port: self.stratum.port.unwrap(), - secret: None, - } - } } #[derive(Deserialize)] @@ -239,13 +224,11 @@ pub struct Mining { pub mem_pool_mem_limit: Option, pub mem_pool_fee_bump_shift: Option, pub allow_create_shard: Option, - pub notify_work: Option>, pub force_sealing: Option, pub reseal_on_txs: Option, pub reseal_min_period: Option, pub reseal_max_period: Option, pub no_reseal_timer: Option, - pub work_queue_size: Option, pub allowed_past_gap: Option, pub allowed_future_gap: Option, pub min_pay_transaction_cost: Option, @@ -315,14 +298,6 @@ pub struct Snapshot { pub path: Option, } -#[derive(Deserialize)] -#[serde(deny_unknown_fields)] -pub struct Stratum { - pub disable: Option, - pub port: Option, -} - - #[derive(Deserialize)] #[serde(deny_unknown_fields)] pub struct EmailAlarm { @@ -421,9 +396,6 @@ impl Mining { if other.allow_create_shard.is_some() { self.allow_create_shard = other.allow_create_shard; } - if other.notify_work.is_some() { - self.notify_work = other.notify_work.clone(); - } if other.force_sealing.is_some() { self.force_sealing = other.force_sealing; } @@ -439,9 +411,6 @@ impl Mining { if other.no_reseal_timer.is_some() { self.no_reseal_timer = other.no_reseal_timer; } - if other.work_queue_size.is_some() { - self.work_queue_size = other.work_queue_size; - } if other.min_pay_transaction_cost.is_some() { self.min_pay_transaction_cost = other.min_pay_transaction_cost; } @@ -496,7 +465,7 @@ impl Mining { if matches.is_present("no-miner") { self.author = None; self.engine_signer = None; - println!("This option was deprecated. PoW type engine with no engine signer and PBFT or PoA type engine with no author implicitly means no-miner."); + println!("This option was deprecated. PBFT or PoA type engine with no author implicitly means no-miner."); } if let Some(mem_pool_fee_bump_shift) = matches.value_of("mem-pool-fee-bump-shift") { self.mem_pool_mem_limit = @@ -511,9 +480,6 @@ impl Mining { if matches.is_present("allow-create-shard") { self.allow_create_shard = Some(true) } - if let Some(notify_work) = matches.values_of("notify-work") { - self.notify_work = Some(notify_work.map(|a| a.into()).collect()); - } if matches.is_present("force-sealing") { self.force_sealing = Some(true); } @@ -529,9 +495,6 @@ impl Mining { if matches.is_present("no-reseal-timer") { self.no_reseal_timer = Some(true); } - if let Some(work_queue_size) = matches.value_of("work-queue-size") { - self.work_queue_size = Some(work_queue_size.parse().map_err(|_| "Invalid size")?); - } if let Some(allowed_past_gap) = matches.value_of("allowed-past-gap") { self.allowed_past_gap = Some(allowed_past_gap.parse().map_err(|_| "Invalid time gap")?); } @@ -753,28 +716,6 @@ impl Snapshot { } } -impl Stratum { - pub fn merge(&mut self, other: &Stratum) { - if other.disable.is_some() { - self.disable = other.disable; - } - if other.port.is_some() { - self.port = other.port; - } - } - - pub fn overwrite_with(&mut self, matches: &clap::ArgMatches<'_>) -> Result<(), String> { - if matches.is_present("no-stratum") { - self.disable = Some(true); - } - - if let Some(port) = matches.value_of("stratum-port") { - self.port = Some(port.parse().map_err(|_| "Invalid port")?); - } - Ok(()) - } -} - impl EmailAlarm { pub fn merge(&mut self, other: &EmailAlarm) { if other.disable.is_some() { @@ -845,7 +786,6 @@ pub fn load_config(matches: &clap::ArgMatches<'_>) -> Result { config.rpc.overwrite_with(&matches)?; config.ws.overwrite_with(&matches)?; config.snapshot.overwrite_with(&matches)?; - config.stratum.overwrite_with(&matches)?; config.email_alarm.overwrite_with(&matches)?; Ok(config) } diff --git a/foundry/config/presets/config.dev.toml b/foundry/config/presets/config.dev.toml index 2b8890b4f7..801e10840b 100644 --- a/foundry/config/presets/config.dev.toml +++ b/foundry/config/presets/config.dev.toml @@ -8,13 +8,11 @@ mem_pool_mem_limit = 4 # MB mem_pool_size = 32768 mem_pool_fee_bump_shift = 3 # 12.5% allow_create_shard = false -notify_work = [] force_sealing = false reseal_on_txs = "all" reseal_min_period = 0 reseal_max_period = 120000 no_reseal_timer = false -work_queue_size = 20 allowed_past_gap = 30000 allowed_future_gap = 5000 @@ -53,9 +51,5 @@ max_connections = 100 disable = false path = "snapshot" -[stratum] -disable = false -port = 8008 - [email_alarm] disable = true diff --git a/foundry/config/presets/config.prod.toml b/foundry/config/presets/config.prod.toml index b67e2746bb..2c45b38ccd 100644 --- a/foundry/config/presets/config.prod.toml +++ b/foundry/config/presets/config.prod.toml @@ -8,13 +8,11 @@ mem_pool_mem_limit = 512 # MB mem_pool_size = 524288 mem_pool_fee_bump_shift = 3 # 12.5% allow_create_shard = false -notify_work = [] force_sealing = true reseal_on_txs = "all" reseal_min_period = 4000 reseal_max_period = 120000 no_reseal_timer = false -work_queue_size = 20 allowed_past_gap = 30000 allowed_future_gap = 5000 @@ -53,9 +51,5 @@ max_connections = 100 disable = true path = "snapshot" -[stratum] -disable = true -port = 8008 - [email_alarm] disable = true diff --git a/foundry/foundry.yml b/foundry/foundry.yml index 0558880d58..4269a4ca33 100644 --- a/foundry/foundry.yml +++ b/foundry/foundry.yml @@ -6,7 +6,7 @@ args: - chain: short: c long: chain - help: Set the blockchain type out of solo, simple_poa, tendermint, cuckoo, blake_pow, corgi, mainnet or a path to chain scheme file. + help: Set the blockchain type out of solo, simple_poa, tendermint, corgi, mainnet or a path to chain scheme file. takes_value: true global: true - allowed-future-gap: @@ -183,14 +183,6 @@ args: long: allow-create-shard help: Make the miner allow CreateShard transactions takes_value: false - - notify-work: - long: notify-work - value_name: URLS - help: URLs to which work package notifications are pushed. - takes_value: true - multiple: true - conflicts_with: - - no-miner - force-sealing: long: force-sealing help: Force the node to author new blocks as if it were always sealing/mining. @@ -263,16 +255,6 @@ args: - no-snapshot: long: no-snapshot help: Disable snapshots - - no-stratum: - long: no-stratum - help: Do not run Stratum server for miner push notification. - - stratum-port: - long: stratum-port - value_name: PORT - help: Specify the port portion of the Stratum server. - takes_value: true - conflicts_with: - - no-stratum - whitelist-path: long: whitelist-path value_name: PATH diff --git a/foundry/rpc_apis.rs b/foundry/rpc_apis.rs index 3f4d3c016a..35c8f1e72c 100644 --- a/foundry/rpc_apis.rs +++ b/foundry/rpc_apis.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Kodebox, Inc. +// Copyright 2018-2019 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -42,7 +42,6 @@ impl ApiDependencies { ); } handler.extend_with(EngineClient::new(Arc::clone(&self.client), Arc::clone(&self.miner)).to_delegate()); - handler.extend_with(MinerClient::new(Arc::clone(&self.client), Arc::clone(&self.miner)).to_delegate()); handler.extend_with(NetClient::new(Arc::clone(&self.network_control)).to_delegate()); handler.extend_with( AccountClient::new(Arc::clone(&self.account_provider), Arc::clone(&self.client), Arc::clone(&self.miner)) diff --git a/foundry/run_node.rs b/foundry/run_node.rs index 97aa244829..2fa44e59ba 100644 --- a/foundry/run_node.rs +++ b/foundry/run_node.rs @@ -20,8 +20,8 @@ use std::sync::{Arc, Weak}; use std::time::{SystemTime, UNIX_EPOCH}; use ccore::{ - AccountProvider, AccountProviderError, BlockId, ChainNotify, Client, ClientConfig, ClientService, EngineInfo, - EngineType, Miner, MinerService, Scheme, Stratum, StratumConfig, StratumError, NUM_COLUMNS, + AccountProvider, AccountProviderError, BlockId, ChainNotify, ClientConfig, ClientService, EngineInfo, EngineType, + Miner, MinerService, Scheme, NUM_COLUMNS, }; use cdiscovery::{Config, Discovery}; use ckey::{Address, NetworkId, PlatformAddress}; @@ -104,20 +104,6 @@ fn client_start( Ok(service) } -fn stratum_start(cfg: &StratumConfig, miner: &Arc, client: Arc) -> Result<(), String> { - match Stratum::start(cfg, Arc::clone(&miner), client) { - // FIXME: Add specified condition like AddrInUse - Err(StratumError::Service(_)) => - Err(format!("STRATUM address {} is already in use, make sure that another instance of a CodeChain node is not running or change the address using the --stratum-port option.", cfg.port)), - Err(e) => Err(format!("STRATUM start error: {:?}", e)), - Ok(stratum) => { - miner.add_work_listener(Box::new(stratum)); - cinfo!(STRATUM, "Listening on {}", cfg.port); - Ok(()) - } - } -} - fn new_miner( config: &config::Config, scheme: &Scheme, @@ -127,13 +113,6 @@ fn new_miner( let miner = Miner::new(config.miner_options()?, scheme, Some(ap), db); match miner.engine_type() { - EngineType::PoW => match &config.mining.author { - Some(ref author) => { - miner.set_author((*author).into_address()).expect("set_author never fails when PoW is used") - } - None if config.mining.engine_signer.is_some() => return Err("PoW type engine needs not an engine-signer but an author for mining. Specify the author using --author option.".to_string()), - None => (), - }, EngineType::PBFT | EngineType::PoA => match &config.mining.engine_signer { Some(ref engine_signer) => match miner.set_author((*engine_signer).into_address()) { Err(AccountProviderError::NotUnlocked) => { @@ -348,10 +327,6 @@ pub fn run_node(matches: &ArgMatches<'_>) -> Result<(), String> { } }; - if (!config.stratum.disable.unwrap()) && (miner.engine_type() == EngineType::PoW) { - stratum_start(&config.stratum_config(), &miner, client.client())? - } - let _snapshot_service = { if !config.snapshot.disable.unwrap() { // FIXME: Let's make it load snapshot period dynamically to support changing the period. diff --git a/json/src/scheme/engine.rs b/json/src/scheme/engine.rs index a4849b238a..a3e6362966 100644 --- a/json/src/scheme/engine.rs +++ b/json/src/scheme/engine.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Kodebox, Inc. +// Copyright 2018-2019 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use super::{BlakePoW, Cuckoo, NullEngine, SimplePoA, Solo, Tendermint}; +use super::{NullEngine, SimplePoA, Solo, Tendermint}; /// Engine deserialization. #[derive(Debug, PartialEq, Deserialize)] @@ -25,8 +25,6 @@ pub enum Engine { Solo(Solo), SimplePoA(SimplePoA), Tendermint(Box), - Cuckoo(Box), - BlakePoW(BlakePoW), } #[cfg(test)] @@ -90,35 +88,5 @@ mod tests { Engine::Tendermint(_) => {} // Tendermint is unit tested in its own file. _ => panic!(), }; - - let s = r#"{ - "cuckoo": { - "params": { - "blockReward": "0x0d", - "minScore" : "0x020000", - "maxVertex" : "16", - "maxEdge" : "8", - "cycleLength" : "6" - } - } - }"#; - let deserialized: Engine = serde_json::from_str(s).unwrap(); - match deserialized { - Engine::Cuckoo(_) => {} // Tendermint is unit tested in its own file. - _ => panic!(), - }; - - let s = r#"{ - "blakePoW": { - "params": { - "blockReward": "0x0d" - } - } - }"#; - let deserialized: Engine = serde_json::from_str(s).unwrap(); - match deserialized { - Engine::BlakePoW(_) => {} // BlakePoW is unit tested in its own file. - _ => panic!(), - }; } } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index b82e0c8dc4..5b76587066 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Kodebox, Inc. +// Copyright 2018-2019 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -16,18 +16,16 @@ extern crate codechain_core as ccore; extern crate codechain_crypto as ccrypto; -#[macro_use] -extern crate codechain_logger as clogger; extern crate codechain_json as cjson; extern crate codechain_key as ckey; extern crate codechain_keystore as ckeystore; +extern crate codechain_logger as clogger; extern crate codechain_network as cnetwork; extern crate codechain_state as cstate; extern crate codechain_sync as csync; extern crate codechain_types as ctypes; #[macro_use] extern crate lazy_static; -#[macro_use] extern crate log; #[macro_use] extern crate serde_derive; diff --git a/rpc/src/v1/errors.rs b/rpc/src/v1/errors.rs index 2dc961786b..6692f66746 100644 --- a/rpc/src/v1/errors.rs +++ b/rpc/src/v1/errors.rs @@ -14,8 +14,6 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use std::fmt; - use ccore::AccountProviderError; use ccore::Error as CoreError; use ckey::Error as KeyError; @@ -46,8 +44,6 @@ impl From for ConversionError { } mod codes { - pub const NO_AUTHOR: i64 = -32002; - pub const NO_WORK_REQUIRED: i64 = -32004; pub const HEX_ERROR: i64 = -32007; pub const RLP_ERROR: i64 = -32009; pub const CORE_ERROR: i64 = -32010; @@ -231,22 +227,6 @@ pub fn account_provider(error: AccountProviderError) -> Error { } } -pub fn no_author() -> Error { - Error { - code: ErrorCode::ServerError(codes::NO_AUTHOR), - message: "Author not configured. Run Parity with --author to configure.".into(), - data: None, - } -} - -pub fn no_work_required() -> Error { - Error { - code: ErrorCode::ServerError(codes::NO_WORK_REQUIRED), - message: "External work is only required for Proof of Work engines.".into(), - data: None, - } -} - pub fn network_control(error: &NetworkControlError) -> Error { match error { NetworkControlError::NotConnected => Error { @@ -293,14 +273,3 @@ pub fn invalid_custom_action(err: String) -> Error { data: None, } } - -/// Internal error signifying a logic error in code. -/// Should not be used when function can just fail -/// because of invalid parameters or incomplete node state. -pub fn internal(error: &str, data: T) -> Error { - Error { - code: ErrorCode::InternalError, - message: format!("Internal error occurred: {}", error), - data: Some(Value::String(format!("{:?}", data))), - } -} diff --git a/rpc/src/v1/impls/miner.rs b/rpc/src/v1/impls/miner.rs deleted file mode 100644 index bee179060d..0000000000 --- a/rpc/src/v1/impls/miner.rs +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2018 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use std::sync::Arc; - -use ccore::block::IsBlock; -use ccore::{EngineClient, EngineInfo, MinerService, MiningBlockChainClient, TermInfo}; -use cjson::bytes::Bytes; -use ctypes::BlockHash; -use jsonrpc_core::Result; - -use super::super::errors; -use super::super::traits::Miner; -use super::super::types::Work; - -pub struct MinerClient { - client: Arc, - miner: Arc, -} - -impl MinerClient { - pub fn new(client: Arc, miner: Arc) -> Self { - Self { - client, - miner, - } - } -} - -impl Miner for MinerClient -where - C: MiningBlockChainClient + EngineClient + EngineInfo + TermInfo + 'static, - M: MinerService + 'static, -{ - fn get_work(&self) -> Result { - if !self.miner.can_produce_work_package() { - cwarn!(MINER, "Cannot give work package - engine seals internally."); - return Err(errors::no_work_required()) - } - if self.miner.authoring_params().author.is_zero() { - cwarn!(MINER, "Cannot give work package - no author is configured. Use --author to configure!"); - return Err(errors::no_author()) - } - self.miner - .map_sealing_work(&*self.client, |b| { - let pow_hash = b.hash(); - let target = self.client.score_to_target(b.block().header().score()); - - Ok(Work { - pow_hash, - target, - }) - }) - .unwrap_or_else(|| Err(errors::internal("No work found.", ""))) - } - - fn submit_work(&self, pow_hash: BlockHash, seal: Vec) -> Result { - if !self.miner.can_produce_work_package() { - cwarn!(MINER, "Cannot give work package - engine seals internally."); - return Err(errors::no_work_required()) - } - let seal = seal.iter().cloned().map(Into::into).collect(); - Ok(self.miner.submit_seal(&*self.client, pow_hash, seal).is_ok()) - } -} diff --git a/rpc/src/v1/impls/mod.rs b/rpc/src/v1/impls/mod.rs index 45e7678459..eccf961e68 100644 --- a/rpc/src/v1/impls/mod.rs +++ b/rpc/src/v1/impls/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Kodebox, Inc. +// Copyright 2018-2019 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -19,7 +19,6 @@ mod chain; mod devel; mod engine; mod mempool; -mod miner; mod net; pub use self::account::AccountClient; @@ -27,5 +26,4 @@ pub use self::chain::ChainClient; pub use self::devel::DevelClient; pub use self::engine::EngineClient; pub use self::mempool::MempoolClient; -pub use self::miner::MinerClient; pub use self::net::NetClient; diff --git a/rpc/src/v1/traits/miner.rs b/rpc/src/v1/traits/miner.rs deleted file mode 100644 index ea204c4549..0000000000 --- a/rpc/src/v1/traits/miner.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2018 Kodebox, Inc. -// This file is part of CodeChain. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as -// published by the Free Software Foundation, either version 3 of the -// License, or (at your option) any later version. -// -// This program 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 Affero General Public License for more details. -// -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . - -use cjson::bytes::Bytes; -use ctypes::BlockHash; -use jsonrpc_core::Result; - -use super::super::types::Work; - -#[rpc(server)] -pub trait Miner { - #[rpc(name = "miner_getWork")] - fn get_work(&self) -> Result; - - #[rpc(name = "miner_submitWork")] - fn submit_work(&self, pow_hash: BlockHash, seal: Vec) -> Result; -} diff --git a/rpc/src/v1/traits/mod.rs b/rpc/src/v1/traits/mod.rs index 719f186e49..bd136c0866 100644 --- a/rpc/src/v1/traits/mod.rs +++ b/rpc/src/v1/traits/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2018 Kodebox, Inc. +// Copyright 2018-2019 Kodebox, Inc. // This file is part of CodeChain. // // This program is free software: you can redistribute it and/or modify @@ -19,7 +19,6 @@ mod chain; mod devel; mod engine; mod mempool; -mod miner; mod net; pub use self::account::Account; @@ -27,5 +26,4 @@ pub use self::chain::Chain; pub use self::devel::Devel; pub use self::engine::Engine; pub use self::mempool::Mempool; -pub use self::miner::Miner; pub use self::net::Net; diff --git a/stratum/Cargo.toml b/stratum/Cargo.toml deleted file mode 100644 index 5b8ff7136c..0000000000 --- a/stratum/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -description = "CodeChain stratum lib" -name = "codechain-stratum" -version = "1.11.0" -license = "GPL-3.0" -authors = ["Parity Technologies ", "CodeChain Team "] -edition = "2018" - -[dependencies] -codechain-crypto = { git = "https://github.com/CodeChain-io/rust-codechain-crypto.git", version = "0.1" } -codechain-logger = { path = "../util/logger" } -codechain-json = { path = "../json" } -jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", tag = "v14.0.3" } -jsonrpc-derive = { git = "https://github.com/paritytech/jsonrpc.git", tag = "v14.0.3" } -jsonrpc-tcp-server = { git = "https://github.com/paritytech/jsonrpc.git", tag = "v14.0.3" } -log = "0.4.6" -parking_lot = "0.6.0" -primitives = { git = "https://github.com/CodeChain-io/rust-codechain-primitives.git", version = "0.4" } - -[dev-dependencies] -env_logger = "0.6.0" -tokio-core = "0.1.17" -tokio-io = "0.1.10" diff --git a/stratum/src/lib.rs b/stratum/src/lib.rs deleted file mode 100644 index e6b4224dcb..0000000000 --- a/stratum/src/lib.rs +++ /dev/null @@ -1,574 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Stratum protocol implementation for CodeChain clients - -extern crate codechain_crypto as ccrypto; -#[macro_use] -extern crate codechain_logger as clogger; -extern crate codechain_json as cjson; -#[macro_use] -extern crate log; -#[cfg(test)] -extern crate tokio_core; -#[cfg(test)] -extern crate tokio_io; - -use jsonrpc_core; - -mod traits; - -pub use crate::traits::{Error, JobDispatcher, PushWorkHandler, ServiceConfiguration}; - -use std::collections::{HashMap, HashSet}; -use std::net::SocketAddr; -use std::sync::Arc; - -use ccrypto::blake256; -use cjson::bytes::Bytes; -use jsonrpc_core::{to_value, Compatibility, IoDelegate, MetaIoHandler, Metadata, Params}; -use jsonrpc_tcp_server::{ - Dispatcher, MetaExtractor, PushMessageError, RequestContext, Server as JsonRpcServer, - ServerBuilder as JsonRpcServerBuilder, -}; -use parking_lot::RwLock; -use primitives::H256; - -type RpcResult = Result; - -const NOTIFY_COUNTER_INITIAL: u32 = 16; - -/// Container which owns rpc server and stratum implementation -pub struct Stratum { - /// RPC server - /// - /// It is an `Option` so it can be easily closed and released during `drop` phase - rpc_server: Option, - /// stratum protocol implementation - /// - /// It is owned by a container and rpc server - implementation: Arc, - /// Message dispatcher (tcp/ip service) - /// - /// Used to push messages to peers - tcp_dispatcher: Dispatcher, -} - -impl Stratum { - pub fn start( - addr: &SocketAddr, - dispatcher: Arc, - secret: Option, - ) -> Result { - let implementation = Arc::new(StratumImpl { - subscribers: RwLock::new(Vec::new()), - job_que: RwLock::new(HashSet::new()), - dispatcher, - workers: Arc::new(RwLock::new(HashMap::new())), - secret, - notify_counter: RwLock::new(NOTIFY_COUNTER_INITIAL), - }); - - let mut delegate = IoDelegate::::new(implementation.clone()); - delegate.add_method_with_meta("mining.subscribe", StratumImpl::subscribe); - delegate.add_method_with_meta("mining.authorize", StratumImpl::authorize); - delegate.add_method_with_meta("mining.submit", StratumImpl::submit); - let mut handler = MetaIoHandler::::with_compatibility(Compatibility::Both); - handler.extend_with(delegate); - - let server_builder = JsonRpcServerBuilder::new(handler); - let tcp_dispatcher = server_builder.dispatcher(); - let server_builder = server_builder.session_meta_extractor(PeerMetaExtractor::new(tcp_dispatcher.clone())); - let server = server_builder.start(addr)?; - - let stratum = Stratum { - rpc_server: Some(server), - implementation, - tcp_dispatcher, - }; - - Ok(stratum) - } -} - -impl PushWorkHandler for Stratum { - fn push_work_all(&self, payload: String) -> Result<(), Error> { - self.implementation.push_work_all(payload.as_str(), &self.tcp_dispatcher) - } - - fn push_work(&self, payloads: Vec) -> Result<(), Error> { - self.implementation.push_work(payloads, &self.tcp_dispatcher) - } -} - -impl Drop for Stratum { - fn drop(&mut self) { - // shut down rpc server - if let Some(server) = self.rpc_server.take() { - server.close(); - } - } -} - -struct StratumImpl { - /// Subscribed clients - subscribers: RwLock>, - /// List of workers supposed to receive job update - job_que: RwLock>, - /// Payload manager - dispatcher: Arc, - /// Authorized workers (socket - worker_id) - workers: Arc>>, - /// Secret if any - secret: Option, - /// Dispatch notify counter - notify_counter: RwLock, -} - -trait StratumRpc { - fn subscribe(&self, _params: Params, meta: SocketMetadata) -> RpcResult; - fn authorize(&self, params: Params, meta: SocketMetadata) -> RpcResult; - fn submit(&self, params: Params, meta: SocketMetadata) -> RpcResult; -} - -impl StratumRpc for StratumImpl { - /// rpc method `mining.subscribe` - fn subscribe(&self, _params: Params, meta: SocketMetadata) -> RpcResult { - use std::str::FromStr; - - self.subscribers.write().push(*meta.addr()); - self.job_que.write().insert(*meta.addr()); - ctrace!(STRATUM, "Subscription request from {:?}", meta.addr()); - - Ok(match self.dispatcher.initial() { - Some(initial) => match jsonrpc_core::Value::from_str(&initial) { - Ok(val) => Ok(val), - Err(e) => { - cwarn!(STRATUM, "Invalid payload: '{}' ({:?})", &initial, e); - to_value(&[0u8; 0]) - } - }, - None => to_value(&[0u8; 0]), - } - .expect("Empty slices are serializable")) - } - - /// rpc method `mining.authorize` - fn authorize(&self, params: Params, meta: SocketMetadata) -> RpcResult { - params - .parse::<(String, String)>() - .map(|(worker_id, secret)| { - if let Some(valid_secret) = self.secret { - let hash = blake256(secret); - if hash != valid_secret { - return to_value(&false) - } - } - ctrace!(STRATUM, "New worker #{} registered", worker_id); - self.workers.write().insert(*meta.addr(), worker_id); - to_value(true) - }) - .map(|v| v.expect("Only true/false is returned and it's always serializable")) - } - - /// rpc method `mining.submit` - fn submit(&self, params: Params, meta: SocketMetadata) -> RpcResult { - let workers = self.workers.read(); - if !workers.contains_key(&meta.addr) { - return Err(Error::UnauthorizedWorker.into()) - } - - params.parse::<(H256, Vec)>().and_then(|(pow_hash, seal)| { - let seal = seal.iter().cloned().map(Into::into).collect(); - match self.dispatcher.submit((pow_hash, seal)) { - Ok(()) => { - self.update_peers(&meta.tcp_dispatcher.expect("tcp_dispatcher is always initialized")); - Ok(jsonrpc_core::Value::Null) - } - Err(submit_err) => { - cwarn!(STRATUM, "Error while submitting share: {:?}", submit_err); - Err(submit_err.into()) - } - } - }) - } -} - -impl StratumImpl { - /// Helper method - fn update_peers(&self, tcp_dispatcher: &Dispatcher) { - if let Some(job) = self.dispatcher.job() { - if let Err(e) = self.push_work_all(job.as_str(), tcp_dispatcher) { - warn!("Failed to update some of the peers: {:?}", e); - } - } - } - - fn push_work_all(&self, payload: &str, tcp_dispatcher: &Dispatcher) -> Result<(), Error> { - let hup_peers = { - let workers = self.workers.read(); - let next_request_id = { - let mut counter = self.notify_counter.write(); - if *counter == ::std::u32::MAX { - *counter = NOTIFY_COUNTER_INITIAL; - } else { - *counter += 1 - } - *counter - }; - - let mut hup_peers = HashSet::with_capacity(0); // most of the cases won't be needed, hence avoid allocation - let workers_msg = - format!("{{ \"id\": {}, \"method\": \"mining.notify\", \"params\": {} }}", next_request_id, payload); - ctrace!(STRATUM, "pushing work for {} workers (payload: '{}')", workers.len(), &workers_msg); - for (ref addr, _) in workers.iter() { - ctrace!(STRATUM, "pusing work to {}", addr); - match tcp_dispatcher.push_message(addr, workers_msg.clone()) { - Err(PushMessageError::NoSuchPeer) => { - ctrace!(STRATUM, "Worker no longer connected: {}", &addr); - hup_peers.insert(**addr); - } - Err(e) => { - cwarn!(STRATUM, "Unexpected transport error: {:?}", e); - } - Ok(_) => {} - } - } - hup_peers - }; - - if !hup_peers.is_empty() { - let mut workers = self.workers.write(); - for hup_peer in hup_peers { - workers.remove(&hup_peer); - } - } - - Ok(()) - } - - fn push_work(&self, payloads: Vec, tcp_dispatcher: &Dispatcher) -> Result<(), Error> { - if !payloads.len() > 0 { - return Err(Error::NoWork) - } - let workers = self.workers.read(); - let addrs = workers.keys().collect::>(); - if !workers.len() > 0 { - return Err(Error::NoWorkers) - } - let mut que = payloads; - let mut addr_index = 0; - while !que.is_empty() { - let next_worker = addrs[addr_index]; - let mut next_payload = que.drain(0..1); - tcp_dispatcher.push_message( - next_worker, - next_payload.nth(0).expect("drained successfully of 0..1, so 0-th element should exist"), - )?; - addr_index += 1; - } - Ok(()) - } -} - -#[derive(Clone)] -pub struct SocketMetadata { - addr: SocketAddr, - // with the new version of jsonrpc-core, SocketMetadata - // won't have to implement default, so this field will not - // have to be an Option - tcp_dispatcher: Option, -} - -impl Default for SocketMetadata { - fn default() -> Self { - SocketMetadata { - addr: "0.0.0.0:0".parse().unwrap(), - tcp_dispatcher: None, - } - } -} - -impl SocketMetadata { - pub fn addr(&self) -> &SocketAddr { - &self.addr - } -} - -impl Metadata for SocketMetadata {} - -pub struct PeerMetaExtractor { - tcp_dispatcher: Dispatcher, -} - -impl PeerMetaExtractor { - fn new(tcp_dispatcher: Dispatcher) -> Self { - PeerMetaExtractor { - tcp_dispatcher, - } - } -} - -impl MetaExtractor for PeerMetaExtractor { - fn extract(&self, context: &RequestContext) -> SocketMetadata { - SocketMetadata { - addr: context.peer_addr, - tcp_dispatcher: Some(self.tcp_dispatcher.clone()), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::net::{SocketAddr, TcpListener}; - use std::str::FromStr; - use std::sync::Arc; - - use jsonrpc_core::futures::{future, Future}; - use primitives::{Bytes, H256}; - use tokio_core::net::TcpStream; - use tokio_core::reactor::{Core, Timeout}; - use tokio_io::io; - - pub struct VoidManager; - - impl JobDispatcher for VoidManager { - fn submit(&self, _payload: (H256, Vec)) -> Result<(), Error> { - Ok(()) - } - } - - fn dummy_request(addr: &SocketAddr, data: &str) -> Vec { - let mut core = Core::new().expect("Tokio Core should be created with no errors"); - let mut buffer = vec![0u8; 2048]; - - let mut data_vec = data.as_bytes().to_vec(); - data_vec.extend(b"\n"); - - let stream = TcpStream::connect(addr, &core.handle()) - .and_then(|stream| io::write_all(stream, &data_vec)) - .and_then(|(stream, _)| io::read(stream, &mut buffer)) - .and_then(|(_, read_buf, len)| future::ok(read_buf[0..len].to_vec())); - core.run(stream).expect("Core should run with no errors") - } - - fn get_available_test_addr(start: u32, end: u32) -> SocketAddr { - (start..end) - .map(|port| SocketAddr::from_str(&format!("127.0.0.1:{}", port)).unwrap()) - .find(|addr| TcpListener::bind(addr).is_ok()) - .unwrap() - } - - #[test] - fn start() { - let addr = get_available_test_addr(19000, 19100); - let stratum = Stratum::start(&addr, Arc::new(VoidManager), None); - assert!(stratum.is_ok()); - } - - #[test] - fn records_subscriber() { - let addr = get_available_test_addr(19100, 19200); - let stratum = Stratum::start(&addr, Arc::new(VoidManager), None).unwrap(); - let request = r#"{"jsonrpc": "2.0", "method": "mining.subscribe", "params": [], "id": 1}"#; - dummy_request(&addr, request); - assert_eq!(1, stratum.implementation.subscribers.read().len()); - } - - struct DummyManager { - initial_payload: String, - } - - impl DummyManager { - fn new() -> Arc { - Arc::new(Self::build()) - } - - fn build() -> DummyManager { - DummyManager { - initial_payload: r#"[ "dummy payload" ]"#.to_owned(), - } - } - - fn of_initial(mut self, new_initial: &str) -> DummyManager { - self.initial_payload = new_initial.to_owned(); - self - } - } - - impl JobDispatcher for DummyManager { - fn initial(&self) -> Option { - Some(self.initial_payload.clone()) - } - - fn submit(&self, _payload: (H256, Vec)) -> Result<(), Error> { - Ok(()) - } - } - - fn terminated_str(origin: &'static str) -> String { - let mut s = String::new(); - s.push_str(origin); - s.push_str("\n"); - s - } - - #[test] - fn receives_initial_paylaod() { - let addr = get_available_test_addr(19200, 19300); - let _stratum = - Stratum::start(&addr, DummyManager::new(), None).expect("There should be no error starting stratum"); - let request = r#"{"jsonrpc": "2.0", "method": "mining.subscribe", "params": [], "id": 2}"#; - - let response = String::from_utf8(dummy_request(&addr, request)).unwrap(); - - assert_eq!(terminated_str(r#"{"jsonrpc":"2.0","result":["dummy payload"],"id":2}"#), response); - } - - #[test] - fn authorize() { - let addr = get_available_test_addr(19300, 19400); - let stratum = - Stratum::start(&addr, Arc::new(DummyManager::build().of_initial(r#"["dummy authorize payload"]"#)), None) - .expect("There should be no error starting stratum"); - - let request = r#"{"jsonrpc": "2.0", "method": "mining.authorize", "params": ["miner1", ""], "id": 1}"#; - let response = String::from_utf8(dummy_request(&addr, request)).unwrap(); - - assert_eq!(terminated_str(r#"{"jsonrpc":"2.0","result":true,"id":1}"#), response); - assert_eq!(1, stratum.implementation.workers.read().len()); - } - - #[test] - fn push_work() { - let addr = get_available_test_addr(19400, 19500); - let stratum = - Stratum::start(&addr, Arc::new(DummyManager::build().of_initial(r#"["dummy authorize payload"]"#)), None) - .expect("There should be no error starting stratum"); - - let mut auth_request = - br#"{"jsonrpc": "2.0", "method": "mining.authorize", "params": ["miner1", ""], "id": 1}"#.to_vec(); - auth_request.extend(b"\n"); - - let mut core = Core::new().expect("Tokio Core should be created with no errors"); - let timeout1 = Timeout::new(::std::time::Duration::from_millis(100), &core.handle()) - .expect("There should be a timeout produced in message test"); - let timeout2 = Timeout::new(::std::time::Duration::from_millis(100), &core.handle()) - .expect("There should be a timeout produced in message test"); - let mut buffer = vec![0u8; 2048]; - let mut buffer2 = vec![0u8; 2048]; - let stream = TcpStream::connect(&addr, &core.handle()) - .and_then(|stream| io::write_all(stream, &auth_request)) - .and_then(|(stream, _)| io::read(stream, &mut buffer)) - .and_then(|(stream, ..)| { - ctrace!(STRATUM, "Received authorization confirmation"); - timeout1.join(future::ok(stream)) - }) - .and_then(|(_, stream)| { - ctrace!(STRATUM, "Pusing work to peers"); - stratum - .push_work_all(r#"{ "00040008", "100500" }"#.to_owned()) - .expect("Pushing work should produce no errors"); - timeout2.join(future::ok(stream)) - }) - .and_then(|(_, stream)| { - ctrace!(STRATUM, "Ready to read work from server"); - io::read(stream, &mut buffer2) - }) - .and_then(|(_, read_buf, len)| { - ctrace!(STRATUM, "Received work from server"); - future::ok(read_buf[0..len].to_vec()) - }); - let response = String::from_utf8(core.run(stream).expect("Core should run with no errors")) - .expect("Response should be utf-8"); - - assert_eq!( - "{ \"id\": 17, \"method\": \"mining.notify\", \"params\": { \"00040008\", \"100500\" } }\n", - response - ); - } - - #[test] - fn respond_to_submition() { - let addr = get_available_test_addr(19500, 19600); - let _stratum = - Stratum::start(&addr, Arc::new(DummyManager::build().of_initial(r#"["dummy authorize payload"]"#)), None) - .expect("There should be no error starting stratum"); - - let mut auth_request = - br#"{"jsonrpc": "2.0", "method": "mining.authorize", "params": ["miner1", ""], "id": 1}"#.to_vec(); - auth_request.extend(b"\n"); - - let mut submit_request = - br#"{"jsonrpc": "2.0", "method": "mining.submit", "params": ["0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", ["0x56642f04d519ae3262c7ba6facf1c5b11450ebaeb7955337cfbc45420d573077"]], "id": 2}"# - .to_vec(); - submit_request.extend(b"\n"); - - let mut core = Core::new().expect("Tokio Core should be created with no errors"); - let timeout1 = Timeout::new(::std::time::Duration::from_millis(100), &core.handle()) - .expect("There should be a timeout produced in message test"); - let mut buffer = vec![0u8; 2048]; - let mut buffer2 = vec![0u8; 2048]; - let stream = TcpStream::connect(&addr, &core.handle()) - .and_then(|stream| io::write_all(stream, &auth_request)) - .and_then(|(stream, _)| io::read(stream, &mut buffer)) - .and_then(|(stream, ..)| { - ctrace!(STRATUM, "Received authorization confirmation"); - timeout1.join(future::ok(stream)) - }) - .and_then(|(_, stream)| io::write_all(stream, &submit_request)) - .and_then(|(stream, _)| io::read(stream, &mut buffer2)) - .and_then(|(_, read_buf, len)| { - ctrace!(STRATUM, "Received work from server"); - future::ok(read_buf[0..len].to_vec()) - }); - - let response = String::from_utf8(core.run(stream).expect("Core should run with no errors")) - .expect("Response should be utf-8"); - assert_eq!("{\"jsonrpc\":\"2.0\",\"result\":null,\"id\":2}\n", response); - } - - #[test] - fn return_error_when_unauthorized_worker_submits() { - let addr = get_available_test_addr(19600, 19700); - let _stratum = - Stratum::start(&addr, Arc::new(DummyManager::build().of_initial(r#"["dummy authorize payload"]"#)), None) - .expect("There should be no error starting stratum"); - - let mut submit_request = - br#"{"jsonrpc": "2.0", "method": "mining.submit", "params": ["0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", ["0x56642f04d519ae3262c7ba6facf1c5b11450ebaeb7955337cfbc45420d573077"]], "id": 2}"# - .to_vec(); - submit_request.extend(b"\n"); - - let mut core = Core::new().expect("Tokio Core should be created with no errors"); - let mut buffer = vec![0u8; 2048]; - let stream = TcpStream::connect(&addr, &core.handle()) - .and_then(|stream| io::write_all(stream, &submit_request)) - .and_then(|(stream, _)| io::read(stream, &mut buffer)) - .and_then(|(_, read_buf, len)| { - ctrace!(STRATUM, "Received result from server"); - future::ok(read_buf[0..len].to_vec()) - }); - - let response = String::from_utf8(core.run(stream).expect("Core should run with no errors")) - .expect("Response should be utf-8"); - assert_eq!( - "{\"jsonrpc\":\"2.0\",\"error\":{\"code\":23,\"message\":\"Unauthorized worker\"},\"id\":2}\n", - response - ); - } -} diff --git a/stratum/src/traits.rs b/stratum/src/traits.rs deleted file mode 100644 index 12c041212e..0000000000 --- a/stratum/src/traits.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2015-2017 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std; -use std::error::Error as StdError; - -use jsonrpc_core::{Error as JsonError, ErrorCode as JsonErrorCode}; -use jsonrpc_tcp_server::PushMessageError; -use primitives::{Bytes, H256}; - -#[derive(Debug, Clone)] -pub enum Error { - InternalError, - PowHashInvalid, - PowInvalid, - UnauthorizedWorker, - NoWork, - NoWorkers, - Io(String), - Tcp(String), -} - -impl From for Error { - fn from(err: std::io::Error) -> Self { - Error::Io(err.description().to_owned()) - } -} - -impl From for Error { - fn from(err: PushMessageError) -> Self { - Error::Tcp(format!("Push message error: {:?}", err)) - } -} - -impl From for JsonError { - fn from(err: Error) -> Self { - let (code, message) = match err { - Error::PowHashInvalid => (21, "Invalid Pow hash".to_string()), - Error::PowInvalid => (22, "Invalid the nonce".to_string()), - Error::UnauthorizedWorker => (23, "Unauthorized worker".to_string()), - _ => (20, "Internal error".to_string()), - }; - - JsonError { - code: JsonErrorCode::ServerError(code), - message, - data: None, - } - } -} - -/// Interface that can provide pow/blockchain-specific responses for the clients -pub trait JobDispatcher: Send + Sync { - // json for initial client handshake - fn initial(&self) -> Option { - None - } - // json for difficulty dispatch - fn difficulty(&self) -> Option { - None - } - // json for job update given worker_id (payload manager should split job!) - fn job(&self) -> Option { - None - } - // miner job result - fn submit(&self, payload: (H256, Vec)) -> Result<(), Error>; -} - -/// Interface that can handle requests to push job for workers -pub trait PushWorkHandler: Send + Sync { - /// push the same work package for all workers (`payload`: json of pow-specific set of work specification) - fn push_work_all(&self, payload: String) -> Result<(), Error>; - - /// push the work packages worker-wise (`payload`: json of pow-specific set of work specification) - fn push_work(&self, payloads: Vec) -> Result<(), Error>; -} - -pub struct ServiceConfiguration { - pub listen_addr: String, - pub port: u16, - pub secret: Option, -} diff --git a/test/src/config/mem-pool-min-fee1.toml b/test/src/config/mem-pool-min-fee1.toml index 7211ead60e..7d22d4bdb7 100644 --- a/test/src/config/mem-pool-min-fee1.toml +++ b/test/src/config/mem-pool-min-fee1.toml @@ -13,6 +13,4 @@ min_pay_transaction_cost = 150 [snapshot] -[stratum] - [email_alarm] diff --git a/test/src/config/mem-pool-min-fee2.toml b/test/src/config/mem-pool-min-fee2.toml index f7dab7f1f3..d9bce6d64b 100644 --- a/test/src/config/mem-pool-min-fee2.toml +++ b/test/src/config/mem-pool-min-fee2.toml @@ -13,6 +13,4 @@ min_pay_transaction_cost = 200 [snapshot] -[stratum] - [email_alarm]