Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Backporting to beta #4211

Merged
merged 7 commits into from
Jan 19, 2017
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
48 changes: 24 additions & 24 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions dapps/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ rand = "0.3"
log = "0.3"
env_logger = "0.3"
futures = "0.1"
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" }
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" }
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git", branch="mio-old" }
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git", branch="mio-old" }
hyper = { default-features = false, git = "https://github.com/ethcore/hyper" }
unicase = "1.3"
url = "1.0"
Expand Down
6 changes: 3 additions & 3 deletions ethcore/src/client/test_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ impl TestBlockChainClient {
value: U256::from(100),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: U256::one(),
gas_price: U256::from(200_000_000_000u64),
nonce: U256::zero()
};
let signed_tx = tx.sign(keypair.secret(), None);
Expand Down Expand Up @@ -308,11 +308,11 @@ impl TestBlockChainClient {
value: U256::from(100),
data: "3331600055".from_hex().unwrap(),
gas: U256::from(100_000),
gas_price: U256::one(),
gas_price: U256::from(20_000_000_000u64),
nonce: U256::zero()
};
let signed_tx = tx.sign(keypair.secret(), None);
self.set_balance(signed_tx.sender().unwrap(), 10_000_000.into());
self.set_balance(signed_tx.sender().unwrap(), 10_000_000_000_000_000_000u64.into());
let res = self.miner.import_external_transactions(self, vec![signed_tx]);
let res = res.into_iter().next().unwrap().expect("Successful import");
assert_eq!(res, TransactionImportResult::Current);
Expand Down
32 changes: 16 additions & 16 deletions ethcore/src/miner/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ impl GasPriceCalibrator {
if Instant::now() >= self.next_calibration {
let usd_per_tx = self.options.usd_per_tx;
trace!(target: "miner", "Getting price info");
let price_info = PriceInfo::get(move |price: PriceInfo| {

PriceInfo::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;
Expand All @@ -159,11 +160,7 @@ impl GasPriceCalibrator {
set_price(U256::from(wei_per_gas as u64));
});

if price_info.is_ok() {
self.next_calibration = Instant::now() + self.options.recalibration_period;
} else {
warn!(target: "miner", "Unable to update Ether price.");
}
self.next_calibration = Instant::now() + self.options.recalibration_period;
}
}
}
Expand Down Expand Up @@ -307,16 +304,6 @@ impl Miner {
#[cfg_attr(feature="dev", allow(match_same_arms))]
/// Prepares new block for sealing including top transactions from queue.
fn prepare_block(&self, chain: &MiningBlockChainClient) -> (ClosedBlock, Option<H256>) {
{
trace!(target: "miner", "prepare_block: recalibrating...");
let txq = self.transaction_queue.clone();
self.gas_pricer.lock().recalibrate(move |price| {
trace!(target: "miner", "prepare_block: Got gas price! {}", price);
txq.lock().set_minimal_gas_price(price);
});
trace!(target: "miner", "prepare_block: done recalibration.");
}

let _timer = PerfTimer::new("prepare_block");
let chain_info = chain.chain_info();
let (transactions, mut open_block, original_work_hash) = {
Expand Down Expand Up @@ -431,6 +418,16 @@ impl Miner {
(block, original_work_hash)
}

/// Asynchronously updates minimal gas price for transaction queue
pub fn recalibrate_minimal_gas_price(&self) {
debug!(target: "miner", "minimal_gas_price: recalibrating...");
let txq = self.transaction_queue.clone();
self.gas_pricer.lock().recalibrate(move |price| {
debug!(target: "miner", "minimal_gas_price: Got gas price! {}", price);
txq.lock().set_minimal_gas_price(price);
});
}

/// Check is reseal is allowed and necessary.
fn requires_reseal(&self, best_block: BlockNumber) -> bool {
let has_local_transactions = self.transaction_queue.lock().has_local_pending_transactions();
Expand Down Expand Up @@ -1124,6 +1121,9 @@ impl MinerService for Miner {
// First update gas limit in transaction queue
self.update_gas_limit(chain);

// Update minimal gas price
self.recalibrate_minimal_gas_price();

// Then import all transactions...
{
retracted.par_iter()
Expand Down
74 changes: 49 additions & 25 deletions ethcore/src/miner/price_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,20 @@ use std::time::Duration;
use std::str::FromStr;
use std::sync::mpsc;
use hyper::client::{Handler, Request, Response, Client};
use hyper::{Next, Encoder, Decoder};
use hyper::{Url, Next, Encoder, Decoder};
use hyper::net::HttpStream;

#[derive(Debug)]
pub struct PriceInfo {
pub ethusd: f32,
}

pub struct SetPriceHandler<F: Fn(PriceInfo) + Sync + Send + 'static> {
pub struct SetPriceHandler<F> {
set_price: F,
channel: mpsc::Sender<()>,
}

impl<F: Fn(PriceInfo) + Sync + Send + 'static> Drop for SetPriceHandler<F> {
impl<F> Drop for SetPriceHandler<F> {
fn drop(&mut self) {
let _ = self.channel.send(());
}
Expand All @@ -47,37 +47,61 @@ impl<F: Fn(PriceInfo) + Sync + Send + 'static> Handler<HttpStream> for SetPriceH

fn on_response_readable(&mut self, r: &mut Decoder<HttpStream>) -> Next {
let mut body = String::new();
let _ = r.read_to_string(&mut body).ok()
.and_then(|_| Json::from_str(&body).ok())
.and_then(|json| json.find_path(&["result", "ethusd"])
.and_then(|obj| match *obj {
Json::String(ref s) => Some((self.set_price)(PriceInfo {
ethusd: FromStr::from_str(s)
.expect("Etherscan API will always return properly formatted price; qed")
})),
_ => None,
}));
let info = r.read_to_string(&mut body)
.map_err(|e| format!("Unable to read response: {:?}", e))
.and_then(|_| self.process_response(&body));

if let Err(e) = info {
warn!("Failed to auto-update latest ETH price: {:?}", e);
}
Next::end()
}
}

impl<F: Fn(PriceInfo) + Sync + Send + 'static> SetPriceHandler<F> {
fn process_response(&self, body: &str) -> Result<(), String> {
let json = Json::from_str(body).map_err(|e| format!("Invalid JSON returned: {:?}", e))?;
let obj = json.find_path(&["result", "ethusd"]).ok_or("USD price not found".to_owned())?;
let ethusd = match *obj {
Json::String(ref s) => FromStr::from_str(s).ok(),
_ => None,
}.ok_or("Unexpected price format.".to_owned())?;

(self.set_price)(PriceInfo {
ethusd: ethusd,
});
Ok(())
}
}

impl PriceInfo {
pub fn get<F: Fn(PriceInfo) + Sync + Send + 'static>(set_price: F) -> Result<(), ()> {
// TODO: Handle each error type properly
let client = Client::new().map_err(|_| ())?;
pub fn get<F: Fn(PriceInfo) + Sync + Send + 'static>(set_price: F) {
thread::spawn(move || {
let (tx, rx) = mpsc::channel();
let url = FromStr::from_str("http://api.etherscan.io/api?module=stats&action=ethprice")
.expect("string known to be a valid URL; qed");
let _ = client.request(
url,
SetPriceHandler {
set_price: set_price,
channel: tx,
}).ok().and_then(|_| rx.recv().ok());
client.close();

if let Err(e) = Self::request(url, set_price) {
warn!("Failed to auto-update latest ETH price: {:?}", e);
}
});
}

fn request<F: Fn(PriceInfo) + Send + Sync + 'static>(url: Url, set_price: F) -> Result<(), String> {
let (tx, rx) = mpsc::channel();
let client = Client::new().map_err(|e| format!("Unable to start client: {:?}", e))?;

client.request(
url,
SetPriceHandler {
set_price: set_price,
channel: tx,
},
).map_err(|_| "Request failed.".to_owned())?;

// Wait for exit
let _ = rx.recv().map_err(|e| format!("Request interrupted: {:?}", e))?;
client.close();

Ok(())
}
}
Expand All @@ -93,7 +117,7 @@ fn should_get_price_info() {
let done = Arc::new((Mutex::new(PriceInfo { ethusd: 0f32 }), Condvar::new()));
let rdone = done.clone();

PriceInfo::get(move |price| { let mut p = rdone.0.lock(); *p = price; rdone.1.notify_one(); }).unwrap();
PriceInfo::get(move |price| { let mut p = rdone.0.lock(); *p = price; rdone.1.notify_one(); });
let mut p = done.0.lock();
let t = done.1.wait_for(&mut p, Duration::from_millis(10000));
assert!(!t.timed_out());
Expand Down
20 changes: 20 additions & 0 deletions js/src/contracts/badgereg.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,26 @@ export default class BadgeReg {
});
}

fetchCertifierByName (name) {
return this
.getContract()
.then((badgeReg) => {
return badgeReg.instance.fromName.call({}, [ name ]);
})
.then(([ id, address, owner ]) => {
if (address === ZERO20) {
throw new Error(`Certifier ${name} does not exist.`);
}

return this.fetchMeta(id)
.then(({ title, icon }) => {
const data = { address, id, name, title, icon };
this.certifiers[id] = data;
return data;
});
});
}

fetchMeta (id) {
return this
.getContract()
Expand Down
2 changes: 1 addition & 1 deletion js/src/dapps/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

module.exports = [
{ name: 'basiccoin', entry: 'basiccoin.js', title: 'Basic Token Deployment' },
{ name: 'dappreg', entry: 'dappreg.js', title: 'Dapp Registry', secure: true },
{ name: 'dappreg', entry: 'dappreg.js', title: 'Dapp Registry' },
{ name: 'githubhint', entry: 'githubhint.js', title: 'GitHub Hint', secure: true },
{ name: 'localtx', entry: 'localtx.js', title: 'Local transactions Viewer', secure: true },
{ name: 'registry', entry: 'registry.js', title: 'Registry' },
Expand Down
1 change: 1 addition & 0 deletions js/src/dapps/static/console.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
// TODO: Fix linting issues

if (typeof(window.parity) == 'object')
window.api = window.parent.secureApi;
window.parity.api.subscribe('eth_blockNumber', function (error, blockNumber) {
if (error) {
console.log('error', error);
Expand Down
Loading