Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ futures-cpupool = "0.1"
fdlimit = "0.1"
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
jsonrpc-core = { git = "https://github.com/paritytech/jsonrpc.git", branch = "parity-1.11" }
ethcore = { path = "ethcore" }
ethcore = { path = "ethcore", features = ["work-notify", "price-info", "stratum"] }
ethcore-bytes = { path = "util/bytes" }
ethcore-io = { path = "util/io" }
ethcore-light = { path = "ethcore/light" }
Expand Down
6 changes: 4 additions & 2 deletions ethcore/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ crossbeam = "0.3"
ethash = { path = "../ethash" }
ethcore-bloom-journal = { path = "../util/bloom" }
ethcore-bytes = { path = "../util/bytes" }
fetch = { path = "../util/fetch" }
hashdb = { path = "../util/hashdb" }
memorydb = { path = "../util/memorydb" }
patricia-trie = { path = "../util/patricia_trie" }
Expand All @@ -26,7 +25,7 @@ error-chain = { version = "0.12", default-features = false }
ethcore-io = { path = "../util/io" }
ethcore-logger = { path = "../logger" }
ethcore-miner = { path = "../miner" }
ethcore-stratum = { path = "./stratum" }
ethcore-stratum = { path = "./stratum", optional = true }
ethcore-transaction = { path = "./transaction" }
ethereum-types = "0.3"
memory-cache = { path = "../util/memory_cache" }
Expand Down Expand Up @@ -99,3 +98,6 @@ test-heavy = []
benches = []
# Compile test helpers
test-helpers = ["tempdir"]
work-notify = ["ethcore-miner/work-notify"]
price-info = ["ethcore-miner/price-info"]
stratum = ["ethcore-stratum"]
1 change: 1 addition & 0 deletions ethcore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ extern crate ethcore_io as io;
extern crate ethcore_bytes as bytes;
extern crate ethcore_logger;
extern crate ethcore_miner;
#[cfg(feature = "stratum")]
extern crate ethcore_stratum;
extern crate ethcore_transaction as transaction;
extern crate ethereum_types;
Expand Down
47 changes: 37 additions & 10 deletions ethcore/src/miner/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use engines::{EthEngine, Seal};
use error::{Error, ErrorKind, ExecutionError};
use ethcore_miner::gas_pricer::GasPricer;
use ethcore_miner::pool::{self, TransactionQueue, VerifiedTransaction, QueueStatus, PrioritizationStrategy};
#[cfg(feature = "work-notify")]
use ethcore_miner::work_notify::NotifyWork;
use ethereum_types::{H256, U256, Address};
use parking_lot::{Mutex, RwLock};
Expand Down Expand Up @@ -200,6 +201,7 @@ pub struct Miner {
// NOTE [ToDr] When locking always lock in this order!
sealing: Mutex<SealingWork>,
params: RwLock<AuthoringParams>,
#[cfg(feature = "work-notify")]
listeners: RwLock<Vec<Box<NotifyWork>>>,
nonce_cache: RwLock<HashMap<Address, U256>>,
gas_pricer: Mutex<GasPricer>,
Expand All @@ -212,6 +214,7 @@ pub struct Miner {

impl Miner {
/// Push listener that will handle new jobs
#[cfg(feature = "work-notify")]
pub fn add_work_listener(&self, notifier: Box<NotifyWork>) {
self.listeners.write().push(notifier);
self.sealing.lock().enabled = true;
Expand All @@ -238,6 +241,7 @@ impl Miner {
last_request: None,
}),
params: RwLock::new(AuthoringParams::default()),
#[cfg(feature = "work-notify")]
listeners: RwLock::new(vec![]),
gas_pricer: Mutex::new(gas_pricer),
nonce_cache: RwLock::new(HashMap::with_capacity(1024)),
Expand Down Expand Up @@ -491,7 +495,14 @@ impl Miner {
/// 1. --force-sealing CLI parameter is provided
/// 2. There are listeners awaiting new work packages (e.g. remote work notifications or stratum).
fn forced_sealing(&self) -> bool {
self.options.force_sealing || !self.listeners.read().is_empty()
let listeners_empty = {
#[cfg(feature = "work-notify")]
{ self.listeners.read().is_empty() }
#[cfg(not(feature = "work-notify"))]
{ true }
};

self.options.force_sealing || !listeners_empty
}

/// Check is reseal is allowed and necessary.
Expand Down Expand Up @@ -639,9 +650,13 @@ impl Miner {
let is_new = original_work_hash.map_or(true, |h| h != block_hash);

sealing.queue.push(block);
// If push notifications are enabled we assume all work items are used.
if is_new && !self.listeners.read().is_empty() {
sealing.queue.use_last_ref();

#[cfg(feature = "work-notify")]
{
// If push notifications are enabled we assume all work items are used.
if is_new && !self.listeners.read().is_empty() {
sealing.queue.use_last_ref();
}
}

(Some((block_hash, *block_header.difficulty(), block_header.number())), is_new)
Expand All @@ -655,12 +670,23 @@ impl Miner {
);
(work, is_new)
};
if is_new {
work.map(|(pow_hash, difficulty, number)| {
for notifier in self.listeners.read().iter() {
notifier.notify(pow_hash, difficulty, number)
}
});

#[cfg(feature = "work-notify")]
{
if is_new {
work.map(|(pow_hash, difficulty, number)| {
for notifier in self.listeners.read().iter() {
notifier.notify(pow_hash, difficulty, number)
}
});
}
}

// NB: hack to use variables to avoid warning.
#[cfg(not(feature = "work-notify"))]
{
let _work = work;
let _is_new = is_new;
}
}

Expand Down Expand Up @@ -1405,6 +1431,7 @@ mod tests {
assert!(!miner.is_currently_sealing());
}

#[cfg(feature = "work-notify")]
#[test]
fn should_mine_if_fetch_work_request() {
struct DummyNotifyWork;
Expand Down
1 change: 1 addition & 0 deletions ethcore/src/miner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ mod miner;
mod service_transaction_checker;

pub mod pool_client;
#[cfg(feature = "stratum")]
pub mod stratum;

pub use self::miner::{Miner, MinerOptions, Penalization, PendingSet, AuthoringParams};
Expand Down
8 changes: 6 additions & 2 deletions ethcore/src/miner/stratum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ use client::{Client, ImportSealedBlock};
use ethereum_types::{H64, H256, clean_0x, U256};
use ethereum::ethash::Ethash;
use ethash::SeedHashCompute;
#[cfg(feature = "work-notify")]
use ethcore_miner::work_notify::NotifyWork;
#[cfg(feature = "work-notify")]
use ethcore_stratum::PushWorkHandler;
use ethcore_stratum::{
JobDispatcher, PushWorkHandler,
Stratum as StratumService, Error as StratumServiceError,
JobDispatcher, Stratum as StratumService, Error as StratumServiceError,
};
use miner::{Miner, MinerService};
use parking_lot::Mutex;
Expand Down Expand Up @@ -209,6 +211,7 @@ impl From<AddrParseError> for Error {
fn from(err: AddrParseError) -> Error { Error::Address(err) }
}

#[cfg(feature = "work-notify")]
impl NotifyWork for Stratum {
fn notify(&self, pow_hash: H256, difficulty: U256, number: u64) {
trace!(target: "stratum", "Notify work");
Expand Down Expand Up @@ -242,6 +245,7 @@ impl Stratum {
}

/// Start STRATUM job dispatcher and register it in the miner
#[cfg(feature = "work-notify")]
pub fn register(cfg: &Options, miner: Arc<Miner>, client: Weak<Client>) -> Result<(), Error> {
let stratum = Stratum::start(cfg, Arc::downgrade(&miner.clone()), client)?;
miner.add_work_listener(Box::new(stratum) as Box<NotifyWork>);
Expand Down
15 changes: 9 additions & 6 deletions miner/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ authors = ["Parity Technologies <admin@parity.io>"]

[dependencies]
# Only work_notify, consider a separate crate
ethash = { path = "../ethash" }
fetch = { path = "../util/fetch" }
hyper = "0.11"
parity-reactor = { path = "../util/reactor" }
url = "1"
ethash = { path = "../ethash", optional = true }
fetch = { path = "../util/fetch", optional = true }
hyper = { version = "0.11", optional = true }
parity-reactor = { path = "../util/reactor", optional = true }
url = { version = "1", optional = true }

# Miner
ansi_term = "0.10"
Expand All @@ -26,7 +26,7 @@ keccak-hash = { path = "../util/hash" }
linked-hash-map = "0.5"
log = "0.3"
parking_lot = "0.6"
price-info = { path = "../price-info" }
price-info = { path = "../price-info", optional = true }
rlp = { path = "../util/rlp" }
trace-time = { path = "../util/trace-time" }
transaction-pool = { path = "../transaction-pool" }
Expand All @@ -35,3 +35,6 @@ transaction-pool = { path = "../transaction-pool" }
env_logger = "0.4"
ethkey = { path = "../ethkey" }
rustc-hex = "1.0"

[features]
work-notify = ["ethash", "fetch", "hyper", "parity-reactor", "url"]
73 changes: 73 additions & 0 deletions miner/src/gas_price_calibrator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2015-2018 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 <http://www.gnu.org/licenses/>.

//! Auto-updates minimal gas price requirement from a price-info source.

use std::time::{Instant, Duration};

use ansi_term::Colour;
use ethereum_types::U256;
use futures_cpupool::CpuPool;
use price_info::{Client as PriceInfoClient, PriceInfo};
use price_info::fetch::Client as FetchClient;

/// Options for the dynamic gas price recalibrator.
#[derive(Debug, PartialEq)]
pub struct GasPriceCalibratorOptions {
/// Base transaction price to match against.
pub usd_per_tx: f32,
/// How frequently we should recalibrate.
pub recalibration_period: Duration,
}

/// The gas price validator variant for a `GasPricer`.
#[derive(Debug, PartialEq)]
pub struct GasPriceCalibrator {
options: GasPriceCalibratorOptions,
next_calibration: Instant,
price_info: PriceInfoClient,
}

impl GasPriceCalibrator {
/// Create a new gas price calibrator.
pub fn new(options: GasPriceCalibratorOptions, fetch: FetchClient, p: CpuPool) -> GasPriceCalibrator {
GasPriceCalibrator {
options: options,
next_calibration: Instant::now(),
price_info: PriceInfoClient::new(fetch, p),
}
}

pub(crate) fn recalibrate<F: FnOnce(U256) + Sync + Send + 'static>(&mut self, set_price: F) {
trace!(target: "miner", "Recalibrating {:?} versus {:?}", Instant::now(), self.next_calibration);
if Instant::now() >= self.next_calibration {
let usd_per_tx = self.options.usd_per_tx;
trace!(target: "miner", "Getting price info");

self.price_info.get(move |price: PriceInfo| {
trace!(target: "miner", "Price info arrived: {:?}", price);
let usd_per_eth = price.ethusd;
let wei_per_usd: f32 = 1.0e18 / usd_per_eth;
let gas_per_tx: f32 = 21000.0;
let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx;
info!(target: "miner", "Updated conversion rate to Ξ1 = {} ({} wei/gas)", Colour::White.bold().paint(format!("US${:.2}", usd_per_eth)), Colour::Yellow.bold().paint(format!("{}", wei_per_gas)));
set_price(U256::from(wei_per_gas as u64));
});

self.next_calibration = Instant::now() + self.options.recalibration_period;
}
}
}
58 changes: 7 additions & 51 deletions miner/src/gas_pricer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,70 +16,25 @@

//! Auto-updates minimal gas price requirement.

use std::time::{Instant, Duration};

use ansi_term::Colour;
use ethereum_types::U256;
use futures_cpupool::CpuPool;
use price_info::{Client as PriceInfoClient, PriceInfo};
use price_info::fetch::Client as FetchClient;

/// Options for the dynamic gas price recalibrator.
#[derive(Debug, PartialEq)]
pub struct GasPriceCalibratorOptions {
/// Base transaction price to match against.
pub usd_per_tx: f32,
/// How frequently we should recalibrate.
pub recalibration_period: Duration,
}

/// The gas price validator variant for a `GasPricer`.
#[derive(Debug, PartialEq)]
pub struct GasPriceCalibrator {
options: GasPriceCalibratorOptions,
next_calibration: Instant,
price_info: PriceInfoClient,
}

impl GasPriceCalibrator {
fn recalibrate<F: FnOnce(U256) + Sync + Send + 'static>(&mut self, set_price: F) {
trace!(target: "miner", "Recalibrating {:?} versus {:?}", Instant::now(), self.next_calibration);
if Instant::now() >= self.next_calibration {
let usd_per_tx = self.options.usd_per_tx;
trace!(target: "miner", "Getting price info");

self.price_info.get(move |price: PriceInfo| {
trace!(target: "miner", "Price info arrived: {:?}", price);
let usd_per_eth = price.ethusd;
let wei_per_usd: f32 = 1.0e18 / usd_per_eth;
let gas_per_tx: f32 = 21000.0;
let wei_per_gas: f32 = wei_per_usd * usd_per_tx / gas_per_tx;
info!(target: "miner", "Updated conversion rate to Ξ1 = {} ({} wei/gas)", Colour::White.bold().paint(format!("US${:.2}", usd_per_eth)), Colour::Yellow.bold().paint(format!("{}", wei_per_gas)));
set_price(U256::from(wei_per_gas as u64));
});

self.next_calibration = Instant::now() + self.options.recalibration_period;
}
}
}
#[cfg(feature = "price-info")]
use gas_price_calibrator::GasPriceCalibrator;

/// Struct to look after updating the acceptable gas price of a miner.
#[derive(Debug, PartialEq)]
pub enum GasPricer {
/// A fixed gas price in terms of Wei - always the argument given.
Fixed(U256),
/// Gas price is calibrated according to a fixed amount of USD.
#[cfg(feature = "price-info")]
Calibrated(GasPriceCalibrator),
}

impl GasPricer {
/// Create a new Calibrated `GasPricer`.
pub fn new_calibrated(options: GasPriceCalibratorOptions, fetch: FetchClient, p: CpuPool) -> GasPricer {
GasPricer::Calibrated(GasPriceCalibrator {
options: options,
next_calibration: Instant::now(),
price_info: PriceInfoClient::new(fetch, p),
})
#[cfg(feature = "price-info")]
pub fn new_calibrated(calibrator: GasPriceCalibrator) -> GasPricer {
GasPricer::Calibrated(calibrator)
}

/// Create a new Fixed `GasPricer`.
Expand All @@ -91,6 +46,7 @@ impl GasPricer {
pub fn recalibrate<F: FnOnce(U256) + Sync + Send + 'static>(&mut self, set_price: F) {
match *self {
GasPricer::Fixed(ref max) => set_price(max.clone()),
#[cfg(feature = "price-info")]
GasPricer::Calibrated(ref mut cal) => cal.recalibrate(set_price),
}
}
Expand Down
4 changes: 4 additions & 0 deletions miner/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ extern crate heapsize;
extern crate keccak_hash as hash;
extern crate linked_hash_map;
extern crate parking_lot;
#[cfg(feature = "price-info")]
extern crate price_info;
extern crate rlp;
extern crate transaction_pool as txpool;
Expand All @@ -47,6 +48,9 @@ extern crate ethkey;
extern crate env_logger;

pub mod external;
#[cfg(feature = "price-info")]
pub mod gas_price_calibrator;
pub mod gas_pricer;
pub mod pool;
#[cfg(feature = "work-notify")]
pub mod work_notify;
Loading