Merge pull request #841 from peterjoel/ethcompute
Caching for computing seed hashes (#541)
This commit is contained in:
commit
2178f09eec
@ -20,6 +20,8 @@
|
|||||||
// TODO: fix endianess for big endian
|
// TODO: fix endianess for big endian
|
||||||
|
|
||||||
use primal::is_prime;
|
use primal::is_prime;
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::sync::Mutex;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use sha3;
|
use sha3;
|
||||||
@ -85,6 +87,7 @@ pub type H256 = [u8; 32];
|
|||||||
pub struct Light {
|
pub struct Light {
|
||||||
block_number: u64,
|
block_number: u64,
|
||||||
cache: Vec<Node>,
|
cache: Vec<Node>,
|
||||||
|
seed_compute: Mutex<SeedHashCompute>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Light cache structur
|
/// Light cache structur
|
||||||
@ -101,17 +104,17 @@ impl Light {
|
|||||||
light_compute(self, header_hash, nonce)
|
light_compute(self, header_hash, nonce)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn file_path(block_number: u64) -> PathBuf {
|
pub fn file_path(seed_hash: H256) -> PathBuf {
|
||||||
let mut home = ::std::env::home_dir().unwrap();
|
let mut home = ::std::env::home_dir().unwrap();
|
||||||
home.push(".ethash");
|
home.push(".ethash");
|
||||||
home.push("light");
|
home.push("light");
|
||||||
let seed_hash = get_seedhash(block_number);
|
|
||||||
home.push(to_hex(&seed_hash));
|
home.push(to_hex(&seed_hash));
|
||||||
home
|
home
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_file(block_number: u64) -> io::Result<Light> {
|
pub fn from_file(block_number: u64) -> io::Result<Light> {
|
||||||
let path = Light::file_path(block_number);
|
let seed_compute = SeedHashCompute::new();
|
||||||
|
let path = Light::file_path(seed_compute.get_seedhash(block_number));
|
||||||
let mut file = try!(File::open(path));
|
let mut file = try!(File::open(path));
|
||||||
|
|
||||||
let cache_size = get_cache_size(block_number);
|
let cache_size = get_cache_size(block_number);
|
||||||
@ -126,11 +129,13 @@ impl Light {
|
|||||||
Ok(Light {
|
Ok(Light {
|
||||||
cache: nodes,
|
cache: nodes,
|
||||||
block_number: block_number,
|
block_number: block_number,
|
||||||
|
seed_compute: Mutex::new(seed_compute),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_file(&self) -> io::Result<()> {
|
pub fn to_file(&self) -> io::Result<()> {
|
||||||
let path = Light::file_path(self.block_number);
|
let seed_compute = self.seed_compute.lock().unwrap();
|
||||||
|
let path = Light::file_path(seed_compute.get_seedhash(self.block_number));
|
||||||
try!(fs::create_dir_all(path.parent().unwrap()));
|
try!(fs::create_dir_all(path.parent().unwrap()));
|
||||||
let mut file = try!(File::create(path));
|
let mut file = try!(File::create(path));
|
||||||
|
|
||||||
@ -141,6 +146,49 @@ impl Light {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SeedHashCompute {
|
||||||
|
prev_epoch: Cell<u64>,
|
||||||
|
prev_seedhash: Cell<H256>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SeedHashCompute {
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn new() -> SeedHashCompute {
|
||||||
|
SeedHashCompute { prev_epoch: Cell::new(0), prev_seedhash: Cell::new([0u8; 32]) }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn reset_cache(&self) {
|
||||||
|
self.prev_epoch.set(0);
|
||||||
|
self.prev_seedhash.set([0u8; 32]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn get_seedhash(&self, block_number: u64) -> H256 {
|
||||||
|
let epoch = block_number / ETHASH_EPOCH_LENGTH;
|
||||||
|
if epoch < self.prev_epoch.get() {
|
||||||
|
// can't build on previous hash if requesting an older block
|
||||||
|
self.reset_cache();
|
||||||
|
}
|
||||||
|
if epoch > self.prev_epoch.get() {
|
||||||
|
let seed_hash = SeedHashCompute::resume_compute_seedhash(self.prev_seedhash.get(), self.prev_epoch.get(), epoch);
|
||||||
|
self.prev_seedhash.set(seed_hash);
|
||||||
|
self.prev_epoch.set(epoch);
|
||||||
|
}
|
||||||
|
self.prev_seedhash.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn resume_compute_seedhash(mut hash: H256, start_epoch: u64, end_epoch: u64) -> H256 {
|
||||||
|
for _ in start_epoch .. end_epoch {
|
||||||
|
unsafe { sha3::sha3_256(hash[..].as_mut_ptr(), 32, hash[..].as_ptr(), 32) };
|
||||||
|
}
|
||||||
|
hash
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn fnv_hash(x: u32, y: u32) -> u32 {
|
fn fnv_hash(x: u32, y: u32) -> u32 {
|
||||||
return x.wrapping_mul(FNV_PRIME) ^ y;
|
return x.wrapping_mul(FNV_PRIME) ^ y;
|
||||||
@ -171,16 +219,6 @@ fn get_data_size(block_number: u64) -> usize {
|
|||||||
sz as usize
|
sz as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
/// Given the `block_number`, determine the seed hash for Ethash.
|
|
||||||
pub fn get_seedhash(block_number: u64) -> H256 {
|
|
||||||
let epochs = block_number / ETHASH_EPOCH_LENGTH;
|
|
||||||
let mut ret: H256 = [0u8; 32];
|
|
||||||
for _ in 0..epochs {
|
|
||||||
unsafe { sha3::sha3_256(ret[..].as_mut_ptr(), 32, ret[..].as_ptr(), 32) };
|
|
||||||
}
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Difficulty quick check for POW preverification
|
/// Difficulty quick check for POW preverification
|
||||||
///
|
///
|
||||||
@ -287,7 +325,9 @@ fn calculate_dag_item(node_index: u32, light: &Light) -> Node {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn light_new(block_number: u64) -> Light {
|
fn light_new(block_number: u64) -> Light {
|
||||||
let seedhash = get_seedhash(block_number);
|
|
||||||
|
let seed_compute = SeedHashCompute::new();
|
||||||
|
let seedhash = seed_compute.get_seedhash(block_number);
|
||||||
let cache_size = get_cache_size(block_number);
|
let cache_size = get_cache_size(block_number);
|
||||||
|
|
||||||
if cache_size % NODE_BYTES != 0 {
|
if cache_size % NODE_BYTES != 0 {
|
||||||
@ -318,6 +358,7 @@ fn light_new(block_number: u64) -> Light {
|
|||||||
Light {
|
Light {
|
||||||
cache: nodes,
|
cache: nodes,
|
||||||
block_number: block_number,
|
block_number: block_number,
|
||||||
|
seed_compute: Mutex::new(seed_compute),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -382,3 +423,34 @@ fn test_light_compute() {
|
|||||||
assert_eq!(result.mix_hash[..], mix_hash[..]);
|
assert_eq!(result.mix_hash[..], mix_hash[..]);
|
||||||
assert_eq!(result.value[..], boundary[..]);
|
assert_eq!(result.value[..], boundary[..]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_seed_compute_once() {
|
||||||
|
let seed_compute = SeedHashCompute::new();
|
||||||
|
let hash = [241, 175, 44, 134, 39, 121, 245, 239, 228, 236, 43, 160, 195, 152, 46, 7, 199, 5, 253, 147, 241, 206, 98, 43, 3, 104, 17, 40, 192, 79, 106, 162];
|
||||||
|
assert_eq!(seed_compute.get_seedhash(486382), hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_seed_compute_zero() {
|
||||||
|
let seed_compute = SeedHashCompute::new();
|
||||||
|
assert_eq!(seed_compute.get_seedhash(0), [0u8; 32]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_seed_compute_after_older() {
|
||||||
|
let seed_compute = SeedHashCompute::new();
|
||||||
|
// calculating an older value first shouldn't affect the result
|
||||||
|
let _ = seed_compute.get_seedhash(50000);
|
||||||
|
let hash = [241, 175, 44, 134, 39, 121, 245, 239, 228, 236, 43, 160, 195, 152, 46, 7, 199, 5, 253, 147, 241, 206, 98, 43, 3, 104, 17, 40, 192, 79, 106, 162];
|
||||||
|
assert_eq!(seed_compute.get_seedhash(486382), hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_seed_compute_after_newer() {
|
||||||
|
let seed_compute = SeedHashCompute::new();
|
||||||
|
// calculating an newer value first shouldn't affect the result
|
||||||
|
let _ = seed_compute.get_seedhash(972764);
|
||||||
|
let hash = [241, 175, 44, 134, 39, 121, 245, 239, 228, 236, 43, 160, 195, 152, 46, 7, 199, 5, 253, 147, 241, 206, 98, 43, 3, 104, 17, 40, 192, 79, 106, 162];
|
||||||
|
assert_eq!(seed_compute.get_seedhash(486382), hash);
|
||||||
|
}
|
||||||
|
@ -24,7 +24,7 @@ mod compute;
|
|||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use compute::Light;
|
use compute::Light;
|
||||||
pub use compute::{get_seedhash, quick_get_difficulty, H256, ProofOfWork, ETHASH_EPOCH_LENGTH};
|
pub use compute::{SeedHashCompute, quick_get_difficulty, H256, ProofOfWork, ETHASH_EPOCH_LENGTH};
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
@ -249,11 +249,6 @@ impl Ethash {
|
|||||||
x!(U256::from((U512::one() << 256) / x!(difficulty)))
|
x!(U256::from((U512::one() << 256) / x!(difficulty)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given the `block_number`, determine the seed hash for Ethash.
|
|
||||||
pub fn get_seedhash(number: BlockNumber) -> H256 {
|
|
||||||
Self::from_ethash(ethash::get_seedhash(number))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_ethash(hash: H256) -> EH256 {
|
fn to_ethash(hash: H256) -> EH256 {
|
||||||
unsafe { mem::transmute(hash) }
|
unsafe { mem::transmute(hash) }
|
||||||
}
|
}
|
||||||
@ -512,4 +507,3 @@ mod tests {
|
|||||||
|
|
||||||
// TODO: difficulty test
|
// TODO: difficulty test
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! Eth rpc implementation.
|
//! Eth rpc implementation.
|
||||||
|
|
||||||
|
extern crate ethash;
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::sync::{Arc, Weak, Mutex};
|
use std::sync::{Arc, Weak, Mutex};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
@ -30,6 +33,7 @@ use ethcore::views::*;
|
|||||||
use ethcore::ethereum::Ethash;
|
use ethcore::ethereum::Ethash;
|
||||||
use ethcore::ethereum::denominations::shannon;
|
use ethcore::ethereum::denominations::shannon;
|
||||||
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
|
use ethcore::transaction::{Transaction as EthTransaction, SignedTransaction, Action};
|
||||||
|
use self::ethash::SeedHashCompute;
|
||||||
use v1::traits::{Eth, EthFilter};
|
use v1::traits::{Eth, EthFilter};
|
||||||
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, CallRequest, OptionalValue, Index, Filter, Log, Receipt};
|
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, CallRequest, OptionalValue, Index, Filter, Log, Receipt};
|
||||||
use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner};
|
use v1::helpers::{PollFilter, PollManager, ExternalMinerService, ExternalMiner};
|
||||||
@ -56,6 +60,7 @@ pub struct EthClient<C, S, A, M, EM = ExternalMiner>
|
|||||||
accounts: Weak<A>,
|
accounts: Weak<A>,
|
||||||
miner: Weak<M>,
|
miner: Weak<M>,
|
||||||
external_miner: EM,
|
external_miner: EM,
|
||||||
|
seed_compute: Mutex<SeedHashCompute>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, S, A, M> EthClient<C, S, A, M, ExternalMiner>
|
impl<C, S, A, M> EthClient<C, S, A, M, ExternalMiner>
|
||||||
@ -86,6 +91,7 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
|
|||||||
miner: Arc::downgrade(miner),
|
miner: Arc::downgrade(miner),
|
||||||
accounts: Arc::downgrade(accounts),
|
accounts: Arc::downgrade(accounts),
|
||||||
external_miner: em,
|
external_miner: em,
|
||||||
|
seed_compute: Mutex::new(SeedHashCompute::new()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -425,7 +431,8 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
|||||||
Some(ref b) => {
|
Some(ref b) => {
|
||||||
let pow_hash = b.hash();
|
let pow_hash = b.hash();
|
||||||
let target = Ethash::difficulty_to_boundary(b.block().header().difficulty());
|
let target = Ethash::difficulty_to_boundary(b.block().header().difficulty());
|
||||||
let seed_hash = Ethash::get_seedhash(b.block().header().number());
|
let seed_compute = self.seed_compute.lock().unwrap();
|
||||||
|
let seed_hash = seed_compute.get_seedhash(b.block().header().number());
|
||||||
to_value(&(pow_hash, seed_hash, target))
|
to_value(&(pow_hash, seed_hash, target))
|
||||||
}
|
}
|
||||||
_ => Err(Error::internal_error())
|
_ => Err(Error::internal_error())
|
||||||
|
Loading…
Reference in New Issue
Block a user