Non-functioning draft of code.

This commit is contained in:
Gav Wood 2016-03-22 13:05:18 +01:00
parent 6701aff2a2
commit a134f939e9
4 changed files with 134 additions and 37 deletions

View File

@ -75,7 +75,7 @@ impl Decodable for Block {
} }
/// Internal type for a block's common elements. /// Internal type for a block's common elements.
#[derive(Debug)] #[derive(Clone)]
pub struct ExecutedBlock { pub struct ExecutedBlock {
base: Block, base: Block,
@ -168,9 +168,11 @@ pub struct OpenBlock<'x> {
/// and collected the uncles. /// and collected the uncles.
/// ///
/// There is no function available to push a transaction. /// There is no function available to push a transaction.
#[derive(Clone)]
pub struct ClosedBlock { pub struct ClosedBlock {
block: ExecutedBlock, block: ExecutedBlock,
uncle_bytes: Bytes, uncle_bytes: Bytes,
last_hashes: LastHashes,
} }
/// A block that has a valid seal. /// A block that has a valid seal.
@ -290,6 +292,7 @@ impl<'x> OpenBlock<'x> {
ClosedBlock { ClosedBlock {
block: s.block, block: s.block,
uncle_bytes: uncle_bytes, uncle_bytes: uncle_bytes,
last_hashes: s.last_hashes,
} }
} }
} }
@ -332,6 +335,15 @@ impl ClosedBlock {
/// Drop this object and return the underlieing database. /// Drop this object and return the underlieing database.
pub fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 } pub fn drain(self) -> Box<JournalDB> { self.block.state.drop().1 }
/// Given an engine reference, reopen the `ClosedBlock` into an `OpenBlock`.
pub fn reopen(self, engine: &Engine) -> OpenBlock {
OpenBlock {
block: self.block,
engine: engine,
last_hashes: self.last_hashes,
}
}
} }
impl SealedBlock { impl SealedBlock {

View File

@ -339,6 +339,18 @@ impl fmt::Debug for State {
} }
} }
impl Clone for State {
fn clone(&self) -> State {
State {
db: self.db.spawn(),
root: self.root.clone(),
cache: RefCell::new(self.cache.borrow().clone()),
snapshots: RefCell::new(self.snapshots.borrow().clone()),
account_start_nonce: self.account_start_nonce.clone(),
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -28,6 +28,72 @@ use ethcore::error::{Error};
use ethcore::transaction::SignedTransaction; use ethcore::transaction::SignedTransaction;
use super::{MinerService, MinerStatus, TransactionQueue, AccountDetails}; use super::{MinerService, MinerStatus, TransactionQueue, AccountDetails};
struct SealingWork {
/// Not yet being sealed by a miner, but if one asks for work, we'd prefer they do this.
would_seal: Option<ClosedBlock>,
/// Currently being sealed by miners.
being_sealed: Vec<ClosedBlock>,
}
impl SealingWork {
// inspect the work that would be given.
fn pending_ref(&self) -> Option<&ClosedBlock> {
self.would_seal.as_ref().or(self.being_sealed.last().as_ref())
}
// return the a reference to forst block that returns true to `f`.
fn find_if<F>(&self, f: F) -> Option<&ClosedBlock> where F: Fn(&ClosedBlock) -> bool {
if would_seal.as_ref().map(&f).unwrap_or(false) {
would_seal.as_ref()
} else {
being_sealed.iter().find_if(f)
}
}
// used for getting the work to be done.
fn use_pending_ref(&mut self) -> Option<&ClosedBlock> {
if let Some(x) = self.would_seal.take() {
self.being_sealed.push(x);
if self.being_sealed.len() > MAX_SEALING_BLOCKS_CACHE {
self.being_sealed.erase(0);
}
}
self.being_sealed.last().as_ref()
}
// set new work to be done.
fn set_pending(&mut self, b: ClosedBlock) {
self.would_seal = Some(b);
}
// get the pending block if `f(pending)`. if there is no pending block or it doesn't pass `f`, None.
// will not destroy a block if a reference to it has previously been returned by `use_pending_ref`.
fn pending_if<F>(&self, f: F) -> Option<ClosedBlock> where F: Fn(&ClosedBlock) -> bool {
// a bit clumsy - TODO: think about a nicer way of expressing this.
if let Some(x) = self.would_seal.take() {
if f(&x) {
Some(x)
} else {
self.would_seal = x;
None
}
} else {
being_sealed.last().as_ref().filter(&b).map(|b| b.clone())
/* being_sealed.last().as_ref().and_then(|b| if f(b) {
Some(b.clone())
} else {
None
})*/
}
}
// clears everything.
fn reset(&mut self) {
self.would_seal = None;
self.being_sealed.clear();
}
}
/// Keeps track of transactions using priority queue and holds currently mined block. /// Keeps track of transactions using priority queue and holds currently mined block.
pub struct Miner { pub struct Miner {
transaction_queue: Mutex<TransactionQueue>, transaction_queue: Mutex<TransactionQueue>,
@ -35,20 +101,33 @@ pub struct Miner {
// for sealing... // for sealing...
sealing_enabled: AtomicBool, sealing_enabled: AtomicBool,
sealing_block_last_request: Mutex<u64>, sealing_block_last_request: Mutex<u64>,
sealing_block: Mutex<Option<ClosedBlock>>, sealing_work: Mutex<SealingWork>,
gas_floor_target: RwLock<U256>, gas_floor_target: RwLock<U256>,
author: RwLock<Address>, author: RwLock<Address>,
extra_data: RwLock<Bytes>, extra_data: RwLock<Bytes>,
} }
/*
let sealing_work = self.sealing_work.lock();
// TODO: check to see if last ClosedBlock in would_seals is same.
// if so, duplicate, re-open and push any new transactions.
// if at least one was pushed successfully, close and enqueue new ClosedBlock;
// and remove first ClosedBlock from the queue..
*/
impl Default for Miner { impl Default for Miner {
fn default() -> Miner { fn default() -> Miner {
Miner { Miner {
transaction_queue: Mutex::new(TransactionQueue::new()), transaction_queue: Mutex::new(TransactionQueue::new()),
sealing_enabled: AtomicBool::new(false), sealing_enabled: AtomicBool::new(false),
sealing_block_last_request: Mutex::new(0), sealing_block_last_request: Mutex::new(0),
sealing_block: Mutex::new(None), sealing_work: Mutex::new(SealingWork{
would_seal: None,
being_sealed: vec![],
}),
gas_floor_target: RwLock::new(U256::zero()), gas_floor_target: RwLock::new(U256::zero()),
author: RwLock::new(Address::default()), author: RwLock::new(Address::default()),
extra_data: RwLock::new(Vec::new()), extra_data: RwLock::new(Vec::new()),
@ -107,7 +186,7 @@ impl Miner {
transactions, transactions,
); );
*self.sealing_block.lock().unwrap() = b.map(|(block, invalid_transactions)| { if let Some((block, invalid_transactions)) = b {
let mut queue = self.transaction_queue.lock().unwrap(); let mut queue = self.transaction_queue.lock().unwrap();
queue.remove_all( queue.remove_all(
&invalid_transactions.into_iter().collect::<Vec<H256>>(), &invalid_transactions.into_iter().collect::<Vec<H256>>(),
@ -116,8 +195,8 @@ impl Miner {
balance: chain.balance(a), balance: chain.balance(a),
} }
); );
block self.sealing_work.lock().unwrap().set_pending(block);
}); }
} }
fn update_gas_limit(&self, chain: &BlockChainClient) { fn update_gas_limit(&self, chain: &BlockChainClient) {
@ -138,11 +217,11 @@ impl MinerService for Miner {
fn status(&self) -> MinerStatus { fn status(&self) -> MinerStatus {
let status = self.transaction_queue.lock().unwrap().status(); let status = self.transaction_queue.lock().unwrap().status();
let block = self.sealing_block.lock().unwrap(); let sealing_work = self.sealing_work.lock().unwrap();
MinerStatus { MinerStatus {
transactions_in_pending_queue: status.pending, transactions_in_pending_queue: status.pending,
transactions_in_future_queue: status.future, transactions_in_future_queue: status.future,
transactions_in_pending_block: block.as_ref().map_or(0, |b| b.transactions().len()), transactions_in_pending_block: block.pending_ref().map_or(0, |b| b.transactions().len()),
} }
} }
@ -167,40 +246,36 @@ impl MinerService for Miner {
if should_disable_sealing { if should_disable_sealing {
self.sealing_enabled.store(false, atomic::Ordering::Relaxed); self.sealing_enabled.store(false, atomic::Ordering::Relaxed);
*self.sealing_block.lock().unwrap() = None; *self.sealing_work.lock().unwrap().reset();
} else if self.sealing_enabled.load(atomic::Ordering::Relaxed) { } else if self.sealing_enabled.load(atomic::Ordering::Relaxed) {
self.prepare_sealing(chain); self.prepare_sealing(chain);
} }
} }
fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex<Option<ClosedBlock>> { fn map_sealing_work<F, T>(&self, chain: &BlockChainClient, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T {
if self.sealing_block.lock().unwrap().is_none() { let have_work = self.sealing_work.lock().unwrap().pending_ref().is_none();
if !have_work {
self.sealing_enabled.store(true, atomic::Ordering::Relaxed); self.sealing_enabled.store(true, atomic::Ordering::Relaxed);
self.prepare_sealing(chain); self.prepare_sealing(chain);
} }
*self.sealing_block_last_request.lock().unwrap() = chain.chain_info().best_block_number; *self.sealing_block_last_request.lock().unwrap() = chain.chain_info().best_block_number;
&self.sealing_block self.sealing_work.lock().unwrap().use_pending().map(f)
} }
fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec<Bytes>) -> Result<(), Error> { fn submit_seal(&self, chain: &BlockChainClient, pow_hash: H256, seal: Vec<Bytes>) -> Result<(), Error> {
let mut maybe_b = self.sealing_block.lock().unwrap(); if let Some(b) = self.sealing_work().lock().unwrap().take_if(|b| &b.hash() == &pow_hash) {
match *maybe_b { match chain.try_seal(b.unwrap(), seal) {
Some(ref b) if b.hash() == pow_hash => {} Err(old) => {
_ => { return Err(Error::PowHashInvalid); } Err(Error::PowInvalid)
} }
Ok(sealed) => {
let b = maybe_b.take(); // TODO: commit DB from `sealed.drain` and make a VerifiedBlock to skip running the transactions twice.
match chain.try_seal(b.unwrap(), seal) { try!(chain.import_block(sealed.rlp_bytes()));
Err(old) => { Ok(())
*maybe_b = Some(old); }
Err(Error::PowInvalid)
}
Ok(sealed) => {
// TODO: commit DB from `sealed.drain` and make a VerifiedBlock to skip running the transactions twice.
try!(chain.import_block(sealed.rlp_bytes()));
Ok(())
} }
} else {
Err(Error::PowHashInvalid)
} }
} }
@ -281,7 +356,7 @@ mod tests {
let miner = Miner::default(); let miner = Miner::default();
// when // when
let res = miner.sealing_block(&client); let res = miner.would_seal(&client);
// then // then
assert!(res.lock().unwrap().is_some(), "Expected closed block"); assert!(res.lock().unwrap().is_some(), "Expected closed block");
@ -292,7 +367,7 @@ mod tests {
// given // given
let client = TestBlockChainClient::default(); let client = TestBlockChainClient::default();
let miner = Miner::default(); let miner = Miner::default();
let res = miner.sealing_block(&client); let res = miner.would_seal(&client);
// TODO [ToDr] Uncomment after fixing TestBlockChainClient // TODO [ToDr] Uncomment after fixing TestBlockChainClient
// assert!(res.lock().unwrap().is_some(), "Expected closed block"); // assert!(res.lock().unwrap().is_some(), "Expected closed block");

View File

@ -334,7 +334,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
match params { match params {
Params::None => { Params::None => {
let client = take_weak!(self.client); let client = take_weak!(self.client);
// check if we're still syncing and return empty strings int that case // check if we're still syncing and return empty strings in that case
{ {
let sync = take_weak!(self.sync); let sync = take_weak!(self.sync);
if sync.status().state != SyncState::Idle && client.queue_info().is_empty() { if sync.status().state != SyncState::Idle && client.queue_info().is_empty() {
@ -343,17 +343,15 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
} }
let miner = take_weak!(self.miner); let miner = take_weak!(self.miner);
let client = take_weak!(self.client); miner.map_sealing_work(client.deref(), |b| match b {
let u = miner.sealing_block(client.deref()).lock().unwrap(); Some(b) => {
match *u {
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_hash = Ethash::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())
} })
}, },
_ => Err(Error::invalid_params()) _ => Err(Error::invalid_params())
} }