Non-functioning draft of code.
This commit is contained in:
parent
6701aff2a2
commit
a134f939e9
@ -75,7 +75,7 @@ impl Decodable for Block {
|
||||
}
|
||||
|
||||
/// Internal type for a block's common elements.
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone)]
|
||||
pub struct ExecutedBlock {
|
||||
base: Block,
|
||||
|
||||
@ -168,9 +168,11 @@ pub struct OpenBlock<'x> {
|
||||
/// and collected the uncles.
|
||||
///
|
||||
/// There is no function available to push a transaction.
|
||||
#[derive(Clone)]
|
||||
pub struct ClosedBlock {
|
||||
block: ExecutedBlock,
|
||||
uncle_bytes: Bytes,
|
||||
last_hashes: LastHashes,
|
||||
}
|
||||
|
||||
/// A block that has a valid seal.
|
||||
@ -290,6 +292,7 @@ impl<'x> OpenBlock<'x> {
|
||||
ClosedBlock {
|
||||
block: s.block,
|
||||
uncle_bytes: uncle_bytes,
|
||||
last_hashes: s.last_hashes,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -332,6 +335,15 @@ impl ClosedBlock {
|
||||
|
||||
/// Drop this object and return the underlieing database.
|
||||
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 {
|
||||
|
@ -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)]
|
||||
mod tests {
|
||||
|
||||
|
@ -28,6 +28,72 @@ use ethcore::error::{Error};
|
||||
use ethcore::transaction::SignedTransaction;
|
||||
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.
|
||||
pub struct Miner {
|
||||
transaction_queue: Mutex<TransactionQueue>,
|
||||
@ -35,20 +101,33 @@ pub struct Miner {
|
||||
// for sealing...
|
||||
sealing_enabled: AtomicBool,
|
||||
sealing_block_last_request: Mutex<u64>,
|
||||
sealing_block: Mutex<Option<ClosedBlock>>,
|
||||
sealing_work: Mutex<SealingWork>,
|
||||
gas_floor_target: RwLock<U256>,
|
||||
author: RwLock<Address>,
|
||||
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 {
|
||||
fn default() -> Miner {
|
||||
Miner {
|
||||
transaction_queue: Mutex::new(TransactionQueue::new()),
|
||||
sealing_enabled: AtomicBool::new(false),
|
||||
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()),
|
||||
author: RwLock::new(Address::default()),
|
||||
extra_data: RwLock::new(Vec::new()),
|
||||
@ -107,7 +186,7 @@ impl Miner {
|
||||
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();
|
||||
queue.remove_all(
|
||||
&invalid_transactions.into_iter().collect::<Vec<H256>>(),
|
||||
@ -116,8 +195,8 @@ impl Miner {
|
||||
balance: chain.balance(a),
|
||||
}
|
||||
);
|
||||
block
|
||||
});
|
||||
self.sealing_work.lock().unwrap().set_pending(block);
|
||||
}
|
||||
}
|
||||
|
||||
fn update_gas_limit(&self, chain: &BlockChainClient) {
|
||||
@ -138,11 +217,11 @@ impl MinerService for Miner {
|
||||
|
||||
fn status(&self) -> MinerStatus {
|
||||
let status = self.transaction_queue.lock().unwrap().status();
|
||||
let block = self.sealing_block.lock().unwrap();
|
||||
let sealing_work = self.sealing_work.lock().unwrap();
|
||||
MinerStatus {
|
||||
transactions_in_pending_queue: status.pending,
|
||||
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 {
|
||||
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) {
|
||||
self.prepare_sealing(chain);
|
||||
}
|
||||
}
|
||||
|
||||
fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex<Option<ClosedBlock>> {
|
||||
if self.sealing_block.lock().unwrap().is_none() {
|
||||
fn map_sealing_work<F, T>(&self, chain: &BlockChainClient, f: F) -> Option<T> where F: FnOnce(&ClosedBlock) -> T {
|
||||
let have_work = self.sealing_work.lock().unwrap().pending_ref().is_none();
|
||||
if !have_work {
|
||||
self.sealing_enabled.store(true, atomic::Ordering::Relaxed);
|
||||
|
||||
self.prepare_sealing(chain);
|
||||
}
|
||||
*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> {
|
||||
let mut maybe_b = self.sealing_block.lock().unwrap();
|
||||
match *maybe_b {
|
||||
Some(ref b) if b.hash() == pow_hash => {}
|
||||
_ => { return Err(Error::PowHashInvalid); }
|
||||
}
|
||||
|
||||
let b = maybe_b.take();
|
||||
match chain.try_seal(b.unwrap(), seal) {
|
||||
Err(old) => {
|
||||
*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(())
|
||||
if let Some(b) = self.sealing_work().lock().unwrap().take_if(|b| &b.hash() == &pow_hash) {
|
||||
match chain.try_seal(b.unwrap(), seal) {
|
||||
Err(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();
|
||||
|
||||
// when
|
||||
let res = miner.sealing_block(&client);
|
||||
let res = miner.would_seal(&client);
|
||||
|
||||
// then
|
||||
assert!(res.lock().unwrap().is_some(), "Expected closed block");
|
||||
@ -292,7 +367,7 @@ mod tests {
|
||||
// given
|
||||
let client = TestBlockChainClient::default();
|
||||
let miner = Miner::default();
|
||||
let res = miner.sealing_block(&client);
|
||||
let res = miner.would_seal(&client);
|
||||
// TODO [ToDr] Uncomment after fixing TestBlockChainClient
|
||||
// assert!(res.lock().unwrap().is_some(), "Expected closed block");
|
||||
|
||||
|
@ -334,7 +334,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
|
||||
match params {
|
||||
Params::None => {
|
||||
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);
|
||||
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 client = take_weak!(self.client);
|
||||
let u = miner.sealing_block(client.deref()).lock().unwrap();
|
||||
match *u {
|
||||
Some(ref b) => {
|
||||
miner.map_sealing_work(client.deref(), |b| match b {
|
||||
Some(b) => {
|
||||
let pow_hash = b.hash();
|
||||
let target = Ethash::difficulty_to_boundary(b.block().header().difficulty());
|
||||
let seed_hash = Ethash::get_seedhash(b.block().header().number());
|
||||
to_value(&(pow_hash, seed_hash, target))
|
||||
}
|
||||
_ => Err(Error::internal_error())
|
||||
}
|
||||
})
|
||||
},
|
||||
_ => Err(Error::invalid_params())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user