Skip to content

Commit

Permalink
Add the basic for stratum style mining protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
kakao-jun-e committed Jul 24, 2018
1 parent a8724e6 commit 60c17cd
Show file tree
Hide file tree
Showing 12 changed files with 266 additions and 55 deletions.
37 changes: 19 additions & 18 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ codechain-rpc = { path = "rpc" }
codechain-sync = { path = "sync" }
codechain-types = { path = "types" }
codechain-vm = { path = "vm" }
codechain-stratum = { path = "stratum" }
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
fdlimit = "0.1"
futures = "0.1"
Expand All @@ -31,7 +32,6 @@ primitives = { path = "util/primitives" }
rpassword = "2.0.0"
serde = "1.0"
serde_derive = "1.0"
stratum = { path = "stratum" }
tokio-core = "0.1.6"
toml = "0.4"

Expand Down
12 changes: 12 additions & 0 deletions codechain/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ mod chain_type;
use std::fs;
use std::str::FromStr;

use ccore::StratumConfig;
use ckey::Address;
use clap;
use cnetwork::{NetworkConfig, SocketAddr};
Expand Down Expand Up @@ -144,6 +145,17 @@ impl<'a> Into<RpcHttpConfig> for &'a Rpc {
}
}

impl<'a> Into<StratumConfig> for &'a Stratum {
// FIXME: Add listen_addr and secret
fn into(self) -> StratumConfig {
StratumConfig {
listen_addr: "127.0.0.1".to_string(),
port: self.port,
secret: None,
}
}
}

pub fn load(config_path: &str) -> Result<Config, String> {
let toml_string = fs::read_to_string(config_path).map_err(|e| format!("Fail to read file: {:?}", e))?;
toml::from_str(toml_string.as_ref()).map_err(|e| format!("Error while parse TOML: {:?}", e))
Expand Down
26 changes: 23 additions & 3 deletions codechain/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ extern crate panic_hook;
extern crate parking_lot;
extern crate primitives;
extern crate rpassword;
#[cfg(feature = "stratum")]
extern crate stratum;
extern crate toml;

mod account_command;
Expand All @@ -60,7 +58,10 @@ use std::sync::Arc;
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use app_dirs::AppInfo;
use ccore::{AccountProvider, ClientService, EngineType, Miner, MinerOptions, MinerService, Spec};
use ccore::{
AccountProvider, Client, ClientService, EngineType, Miner, MinerOptions, MinerService, Spec, Stratum,
StratumConfig, StratumError,
};
use cdiscovery::{KademliaConfig, KademliaExtension, UnstructuredConfig, UnstructuredExtension};
use ckeystore::accounts_dir::RootDiskDirectory;
use ckeystore::KeyStore;
Expand Down Expand Up @@ -141,6 +142,20 @@ pub fn client_start(cfg: &config::Config, spec: &Spec, miner: Arc<Miner>) -> Res
Ok(service)
}

pub fn stratum_start(cfg: &StratumConfig, miner: Arc<Miner>, client: Arc<Client>) -> Result<(), String> {
info!("STRATUM Listening on {}", cfg.port);
match Stratum::start(cfg, miner.clone(), 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));
Ok(())
}
}
}

#[cfg(all(unix, target_arch = "x86_64"))]
fn main() -> Result<(), String> {
panic_hook::set();
Expand Down Expand Up @@ -349,6 +364,11 @@ fn run_node(matches: ArgMatches) -> Result<(), String> {
}
};

if !config.stratum.disable {
let stratum_config = (&config.stratum).into();
stratum_start(&stratum_config, Arc::clone(&miner), client.client())?
}

let _snapshot_service = {
if !config.snapshot.disable {
// FIXME: Get snapshot period from genesis block
Expand Down
1 change: 1 addition & 0 deletions core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ codechain-merkle = { path = "../util/merkle" }
codechain-network = { path = "../network" }
codechain-state = { path = "../state" }
codechain-types = { path = "../types" }
codechain-stratum = { path = "../stratum" }
cuckoo = { git = "https://github.com/CodeChain-io/rust-cuckoo.git", rev = "280cab9c" }
hashdb = { path = "../util/hashdb" }
heapsize = "0.4"
Expand Down
3 changes: 2 additions & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ 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_types as ctypes;
extern crate cuckoo;
extern crate hashdb;
Expand Down Expand Up @@ -90,7 +91,7 @@ pub use consensus::EngineType;
pub use db::COL_STATE;
pub use error::{BlockImportError, Error, ImportError};
pub use header::{Header, Seal};
pub use miner::{Miner, MinerOptions, MinerService};
pub use miner::{Miner, MinerOptions, MinerService, Stratum, StratumConfig, StratumError};
pub use parcel::{LocalizedParcel, SignedParcel, UnverifiedParcel};
pub use service::ClientService;
pub use spec::Spec;
Expand Down
5 changes: 5 additions & 0 deletions core/src/miner/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,11 @@ pub struct Miner {
}

impl Miner {
/// Push listener that will handle new jobs
pub fn add_work_listener(&self, notifier: Box<NotifyWork>) {
self.notifiers.write().push(notifier);
}

pub fn new(options: MinerOptions, spec: &Spec, accounts: Option<Arc<AccountProvider>>) -> Arc<Self> {
Arc::new(Self::new_raw(options, spec, accounts))
}
Expand Down
2 changes: 2 additions & 0 deletions core/src/miner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ mod local_parcels;
mod mem_pool;
mod miner;
mod sealing_queue;
mod stratum;
mod work_notify;

use ckey::Address;
use cstate::TopStateInfo;
use primitives::{Bytes, H256, U256};

pub use self::miner::{Miner, MinerOptions};
pub use self::stratum::{Config as StratumConfig, Error as StratumError, Stratum};
use super::account_provider::SignError;
use super::block::ClosedBlock;
use super::client::{AccountData, BlockChain, BlockProducer, ImportSealedBlock, MiningBlockChainClient};
Expand Down
140 changes: 140 additions & 0 deletions core/src/miner/stratum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// 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 <https://www.gnu.org/licenses/>.

//! Client-side stratum job dispatcher and mining notifier handler
use std::net::{AddrParseError, SocketAddr};
use std::sync::Arc;

use cstratum::{Error as StratumServiceError, JobDispatcher, PushWorkHandler, Stratum as StratumService};
use primitives::{Bytes, H256, U256};

use super::super::client::Client;
use super::super::miner::work_notify::NotifyWork;
use super::super::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<H256>,
}

/// Job dispatcher for stratum service
pub struct StratumJobDispatcher {
client: Arc<Client>,
miner: Arc<Miner>,
}

impl JobDispatcher for StratumJobDispatcher {
fn initial(&self) -> Option<String> {
// initial payload may contain additional data, not in this case
self.job()
}

fn submit(&self, payload: (H256, Vec<Bytes>)) -> 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::NoWork)
}

match self.miner.submit_seal(&*self.client, pow_hash, seal) {
Ok(_) => Ok(()),
Err(e) => {
cwarn!(STRATUM, "submit_seal error: {:?}", e);
Err(StratumServiceError::Dispatch(e.to_string()))
}
}
}
}

impl StratumJobDispatcher {
/// New stratum job dispatcher given the miner and client
fn new(miner: Arc<Miner>, client: Arc<Client>) -> 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<StratumJobDispatcher>,
service: Arc<StratumService>,
}

#[derive(Debug)]
/// Stratum error
pub enum Error {
/// IPC sockets error
Service(StratumServiceError),
/// Invalid network address
Address(AddrParseError),
}

impl From<StratumServiceError> for Error {
fn from(service_err: StratumServiceError) -> Error {
Error::Service(service_err)
}
}

impl From<AddrParseError> 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<Miner>, client: Arc<Client>) -> Result<Stratum, Error> {
use std::net::IpAddr;

let dispatcher = Arc::new(StratumJobDispatcher::new(miner, client));
let stratum_svc = StratumService::start(
&SocketAddr::new(config.listen_addr.parse::<IpAddr>()?, config.port),
dispatcher.clone(),
config.secret.clone(),
)?;

Ok(Stratum {
dispatcher,
service: stratum_svc,
})
}
}
2 changes: 1 addition & 1 deletion stratum/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
description = "CodeChain stratum lib"
name = "stratum"
name = "codechain-stratum"
version = "1.11.0"
license = "GPL-3.0"
authors = ["Parity Technologies <admin@parity.io>", "CodeChain Team <codechain@kodebox.io>"]
Expand Down
Loading

0 comments on commit 60c17cd

Please sign in to comment.