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.
|
/// 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 {
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
@ -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");
|
||||||
|
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user