Parameter to allow user to force the sealing mechanism (#918)

* Allow block sealing mechanism to be forced, even when not mining.

* Fix deadlock in dispatch_transaction. Fix tests.

* Horrible workaround for transaction importing.

* Reduce tracing. Cleanups.

* Remove logging.

* Remove broken code inherited from dodgy implementation.

* pre-query tx queue nonce also if any

* remove outside nonce queries

* remove queue nonces
This commit is contained in:
Gav Wood 2016-04-11 11:52:33 -07:00
parent edf4735542
commit c48374dbc6
7 changed files with 38 additions and 17 deletions

View File

@ -30,6 +30,7 @@ pub struct Miner {
transaction_queue: Mutex<TransactionQueue>, transaction_queue: Mutex<TransactionQueue>,
// for sealing... // for sealing...
force_sealing: bool,
sealing_enabled: AtomicBool, sealing_enabled: AtomicBool,
sealing_block_last_request: Mutex<u64>, sealing_block_last_request: Mutex<u64>,
sealing_work: Mutex<UsingQueue<ClosedBlock>>, sealing_work: Mutex<UsingQueue<ClosedBlock>>,
@ -42,6 +43,7 @@ impl Default for Miner {
fn default() -> Miner { fn default() -> Miner {
Miner { Miner {
transaction_queue: Mutex::new(TransactionQueue::new()), transaction_queue: Mutex::new(TransactionQueue::new()),
force_sealing: false,
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_work: Mutex::new(UsingQueue::new(5)), sealing_work: Mutex::new(UsingQueue::new(5)),
@ -54,8 +56,17 @@ impl Default for Miner {
impl Miner { impl Miner {
/// Creates new instance of miner /// Creates new instance of miner
pub fn new() -> Arc<Miner> { pub fn new(force_sealing: bool) -> Arc<Miner> {
Arc::new(Miner::default()) Arc::new(Miner {
transaction_queue: Mutex::new(TransactionQueue::new()),
force_sealing: force_sealing,
sealing_enabled: AtomicBool::new(force_sealing),
sealing_block_last_request: Mutex::new(0),
sealing_work: Mutex::new(UsingQueue::new(5)),
gas_floor_target: RwLock::new(U256::zero()),
author: RwLock::new(Address::default()),
extra_data: RwLock::new(Vec::new()),
})
} }
/// Get the author that we will seal blocks as. /// Get the author that we will seal blocks as.
@ -241,7 +252,7 @@ impl MinerService for Miner {
if self.sealing_enabled.load(atomic::Ordering::Relaxed) { if self.sealing_enabled.load(atomic::Ordering::Relaxed) {
let current_no = chain.chain_info().best_block_number; let current_no = chain.chain_info().best_block_number;
let last_request = *self.sealing_block_last_request.lock().unwrap(); let last_request = *self.sealing_block_last_request.lock().unwrap();
let should_disable_sealing = current_no > last_request && current_no - last_request > SEALING_TIMEOUT_IN_BLOCKS; let should_disable_sealing = !self.force_sealing && current_no > last_request && current_no - last_request > SEALING_TIMEOUT_IN_BLOCKS;
if should_disable_sealing { if should_disable_sealing {
trace!(target: "miner", "Miner sleeping (current {}, last {})", current_no, last_request); trace!(target: "miner", "Miner sleeping (current {}, last {})", current_no, last_request);

View File

@ -383,19 +383,19 @@ impl TransactionQueue {
} }
let vtx = try!(VerifiedTransaction::new(tx)); let vtx = try!(VerifiedTransaction::new(tx));
let account = fetch_account(&vtx.sender()); let client_account = fetch_account(&vtx.sender());
let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas; let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas;
if account.balance < cost { if client_account.balance < cost {
trace!(target: "miner", "Dropping transaction without sufficient balance: {:?} ({} < {})", trace!(target: "miner", "Dropping transaction without sufficient balance: {:?} ({} < {})",
vtx.hash(), account.balance, cost); vtx.hash(), client_account.balance, cost);
return Err(Error::Transaction(TransactionError::InsufficientBalance { return Err(Error::Transaction(TransactionError::InsufficientBalance {
cost: cost, cost: cost,
balance: account.balance balance: client_account.balance
})); }));
} }
self.import_tx(vtx, account.nonce).map_err(Error::Transaction) self.import_tx(vtx, client_account.nonce).map_err(Error::Transaction)
} }
/// Removes all transactions identified by hashes given in slice /// Removes all transactions identified by hashes given in slice
@ -1188,6 +1188,7 @@ mod test {
#[test] #[test]
fn should_replace_same_transaction_when_has_higher_fee() { fn should_replace_same_transaction_when_has_higher_fee() {
init_log();
// given // given
let mut txq = TransactionQueue::new(); let mut txq = TransactionQueue::new();
let keypair = KeyPair::create().unwrap(); let keypair = KeyPair::create().unwrap();
@ -1264,7 +1265,7 @@ mod test {
#[test] #[test]
fn should_return_none_when_transaction_from_given_address_does_not_exist() { fn should_return_none_when_transaction_from_given_address_does_not_exist() {
// given // given
let mut txq = TransactionQueue::new(); let txq = TransactionQueue::new();
// then // then
assert_eq!(txq.last_nonce(&Address::default()), None); assert_eq!(txq.last_nonce(&Address::default()), None);
@ -1277,7 +1278,7 @@ mod test {
let tx = new_tx(); let tx = new_tx();
let from = tx.sender().unwrap(); let from = tx.sender().unwrap();
let nonce = tx.nonce; let nonce = tx.nonce;
let details = |a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() }; let details = |_a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() };
// when // when
txq.add(tx, &details).unwrap(); txq.add(tx, &details).unwrap();

View File

@ -152,6 +152,8 @@ API and Console Options:
conjunction with --webapp-user. conjunction with --webapp-user.
Sealing/Mining Options: Sealing/Mining Options:
--force-sealing Force the node to author new blocks as if it were
always sealing/mining.
--usd-per-tx USD Amount of USD to be paid for a basic transaction --usd-per-tx USD Amount of USD to be paid for a basic transaction
[default: 0.005]. The minimum gas price is set [default: 0.005]. The minimum gas price is set
accordingly. accordingly.
@ -239,6 +241,7 @@ struct Args {
flag_webapp_interface: String, flag_webapp_interface: String,
flag_webapp_user: Option<String>, flag_webapp_user: Option<String>,
flag_webapp_pass: Option<String>, flag_webapp_pass: Option<String>,
flag_force_sealing: bool,
flag_author: String, flag_author: String,
flag_usd_per_tx: String, flag_usd_per_tx: String,
flag_usd_per_eth: String, flag_usd_per_eth: String,
@ -657,7 +660,7 @@ impl Configuration {
let client = service.client(); let client = service.client();
// Miner // Miner
let miner = Miner::new(); let miner = Miner::new(self.args.flag_force_sealing);
miner.set_author(self.author()); miner.set_author(self.author());
miner.set_gas_floor_target(self.gas_floor_target()); miner.set_gas_floor_target(self.gas_floor_target());
miner.set_extra_data(self.extra_data()); miner.set_extra_data(self.extra_data());

View File

@ -26,6 +26,7 @@ use ethminer::{MinerService, AccountDetails};
use jsonrpc_core::*; use jsonrpc_core::*;
use util::numbers::*; use util::numbers::*;
use util::sha3::*; use util::sha3::*;
use util::bytes::{ToPretty};
use util::rlp::{encode, UntrustedRlp, View}; use util::rlp::{encode, UntrustedRlp, View};
use ethcore::client::*; use ethcore::client::*;
use ethcore::block::IsBlock; use ethcore::block::IsBlock;
@ -191,9 +192,13 @@ impl<C, S, A, M, EM> EthClient<C, S, A, M, EM>
let import = { let import = {
let client = take_weak!(self.client); let client = take_weak!(self.client);
take_weak!(self.miner).import_transactions(vec![signed_transaction], |a: &Address| AccountDetails { let miner = take_weak!(self.miner);
nonce: client.nonce(a),
balance: client.balance(a), miner.import_transactions(vec![signed_transaction], |a: &Address| {
AccountDetails {
nonce: client.nonce(&a),
balance: client.balance(&a),
}
}) })
}; };
@ -499,6 +504,7 @@ impl<C, S, A, M, EM> Eth for EthClient<C, S, A, M, EM>
data: request.data.map_or_else(Vec::new, |d| d.to_vec()), data: request.data.map_or_else(Vec::new, |d| d.to_vec()),
}.sign(&secret) }.sign(&secret)
}; };
trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty());
self.dispatch_transaction(signed_transaction) self.dispatch_transaction(signed_transaction)
}, },
Err(_) => { to_value(&H256::zero()) } Err(_) => { to_value(&H256::zero()) }

View File

@ -1476,7 +1476,7 @@ mod tests {
} }
fn dummy_sync_with_peer(peer_latest_hash: H256) -> ChainSync { fn dummy_sync_with_peer(peer_latest_hash: H256) -> ChainSync {
let mut sync = ChainSync::new(SyncConfig::default(), Miner::new()); let mut sync = ChainSync::new(SyncConfig::default(), Miner::new(false));
sync.peers.insert(0, sync.peers.insert(0,
PeerInfo { PeerInfo {
protocol_version: 0, protocol_version: 0,

View File

@ -45,7 +45,7 @@
//! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); //! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap();
//! let dir = env::temp_dir(); //! let dir = env::temp_dir();
//! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); //! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap();
//! let miner = Miner::new(); //! let miner = Miner::new(false);
//! EthSync::register(&mut service, SyncConfig::default(), client, miner); //! EthSync::register(&mut service, SyncConfig::default(), client, miner);
//! } //! }
//! ``` //! ```

View File

@ -93,7 +93,7 @@ impl TestNet {
for _ in 0..n { for _ in 0..n {
net.peers.push(TestPeer { net.peers.push(TestPeer {
chain: TestBlockChainClient::new(), chain: TestBlockChainClient::new(),
sync: ChainSync::new(SyncConfig::default(), Miner::new()), sync: ChainSync::new(SyncConfig::default(), Miner::new(false)),
queue: VecDeque::new(), queue: VecDeque::new(),
}); });
} }