diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index d76c4aa85..3a69adb4c 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -99,7 +99,9 @@ impl Engine for BasicAuthority { /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). fn on_close_block(&self, _block: &mut ExecutedBlock) {} - fn seals_internally(&self) -> bool { true } + fn is_sealer(&self, author: &Address) -> Option { + Some(self.our_params.authorities.contains(author)) + } /// Attempt to seal the block internally. /// @@ -252,4 +254,14 @@ mod tests { let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap(); assert!(b.try_seal(engine, seal).is_ok()); } + + #[test] + fn seals_internally() { + let tap = AccountProvider::transient_provider(); + let authority = tap.insert_account("".sha3(), "").unwrap(); + + let engine = new_test_authority().engine; + assert!(!engine.is_sealer(&Address::default()).unwrap()); + assert!(engine.is_sealer(&authority).unwrap()); + } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index e88c1d102..26d2ed5bf 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -58,7 +58,7 @@ impl Engine for InstantSeal { Schedule::new_homestead() } - fn seals_internally(&self) -> bool { true } + fn is_sealer(&self, _author: &Address) -> Option { Some(true) } fn generate_seal(&self, _block: &ExecutedBlock, _accounts: Option<&AccountProvider>) -> Option> { Some(Vec::new()) diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index aa90bea31..ec27a2fe2 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -73,8 +73,11 @@ pub trait Engine : Sync + Send { /// Block transformation functions, after the transactions. fn on_close_block(&self, _block: &mut ExecutedBlock) {} - /// If true, generate_seal has to be implemented. - fn seals_internally(&self) -> bool { false } + /// If Some(true) this author is able to generate seals, generate_seal has to be implemented. + /// None indicates that this Engine never seals internally regardless of author (e.g. PoW). + fn is_sealer(&self, _author: &Address) -> Option { None } + /// Checks if default address is able to seal. + fn is_default_sealer(&self) -> Option { self.is_sealer(&Default::default()) } /// Attempt to seal the block internally. /// /// If `Some` is returned, then you get a valid seal. diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 152b0e994..ad963b167 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -175,6 +175,7 @@ pub struct Miner { sealing_block_last_request: Mutex, // for sealing... options: MinerOptions, + seals_internally: bool, gas_range_target: RwLock<(U256, U256)>, author: RwLock
, @@ -194,7 +195,11 @@ impl Miner { options: Default::default(), next_allowed_reseal: Mutex::new(Instant::now()), sealing_block_last_request: Mutex::new(0), - sealing_work: Mutex::new(SealingWork{queue: UsingQueue::new(20), enabled: false}), + sealing_work: Mutex::new(SealingWork{ + queue: UsingQueue::new(20), + enabled: spec.engine.is_default_sealer().unwrap_or(false) + }), + seals_internally: spec.engine.is_default_sealer().is_some(), gas_range_target: RwLock::new((U256::zero(), U256::zero())), author: RwLock::new(Address::default()), extra_data: RwLock::new(Vec::new()), @@ -213,7 +218,13 @@ impl Miner { transaction_queue: txq, next_allowed_reseal: Mutex::new(Instant::now()), sealing_block_last_request: Mutex::new(0), - sealing_work: Mutex::new(SealingWork{queue: UsingQueue::new(options.work_queue_size), enabled: options.force_sealing || !options.new_work_notify.is_empty()}), + sealing_work: Mutex::new(SealingWork{ + queue: UsingQueue::new(options.work_queue_size), + enabled: options.force_sealing + || !options.new_work_notify.is_empty() + || spec.engine.is_default_sealer().unwrap_or(false) + }), + seals_internally: spec.engine.is_default_sealer().is_some(), gas_range_target: RwLock::new((U256::zero(), U256::zero())), author: RwLock::new(Address::default()), extra_data: RwLock::new(Vec::new()), @@ -360,7 +371,7 @@ impl Miner { true } } else { - // sealing is disabled. + trace!(target: "miner", "requires_reseal: sealing is disabled"); false } } @@ -578,6 +589,10 @@ impl MinerService for Miner { } fn set_author(&self, author: Address) { + if self.seals_internally { + let mut sealing_work = self.sealing_work.lock(); + sealing_work.enabled = self.engine.is_sealer(&author).unwrap_or(false); + } *self.author.write() = author; } @@ -703,7 +718,7 @@ impl MinerService for Miner { if imported.is_ok() && self.options.reseal_on_own_tx && self.tx_reseal_allowed() { // Make sure to do it after transaction is imported and lock is droped. // We need to create pending block and enable sealing. - if self.engine.seals_internally() || !self.prepare_work_sealing(chain) { + if self.seals_internally || !self.prepare_work_sealing(chain) { // If new block has not been prepared (means we already had one) // or Engine might be able to seal internally, // we need to update sealing. @@ -821,7 +836,7 @@ impl MinerService for Miner { // -------------------------------------------------------------------------- trace!(target: "miner", "update_sealing: preparing a block"); let (block, original_work_hash) = self.prepare_block(chain); - if self.engine.seals_internally() { + if self.seals_internally { trace!(target: "miner", "update_sealing: engine indicates internal sealing"); self.seal_and_import_block_internally(chain, block); } else { @@ -1027,7 +1042,7 @@ mod tests { assert_eq!(miner.pending_transactions_hashes().len(), 1); assert_eq!(miner.pending_receipts().len(), 1); // This method will let us know if pending block was created (before calling that method) - assert_eq!(miner.prepare_work_sealing(&client), false); + assert!(!miner.prepare_work_sealing(&client)); } #[test] @@ -1046,16 +1061,26 @@ mod tests { assert_eq!(miner.pending_transactions().len(), 0); assert_eq!(miner.pending_receipts().len(), 0); // This method will let us know if pending block was created (before calling that method) - assert_eq!(miner.prepare_work_sealing(&client), true); + assert!(miner.prepare_work_sealing(&client)); + } + + #[test] + fn should_not_seal_unless_enabled() { + let miner = miner(); + let client = TestBlockChainClient::default(); + // By default resealing is not required. + assert!(!miner.requires_reseal(1u8.into())); + + miner.import_external_transactions(&client, vec![transaction()]).pop().unwrap().unwrap(); + assert!(miner.prepare_work_sealing(&client)); + // Unless asked to prepare work. + assert!(miner.requires_reseal(1u8.into())); } #[test] fn internal_seals_without_work() { let miner = Miner::with_spec(&Spec::new_test_instant()); - { - let mut sealing_work = miner.sealing_work.lock(); - sealing_work.enabled = true; - } + let c = generate_dummy_client(2); let client = c.reference().as_ref(); diff --git a/script/deploy.sh b/script/deploy.sh new file mode 100644 index 000000000..861dd6df6 --- /dev/null +++ b/script/deploy.sh @@ -0,0 +1,4 @@ +#!/bin/bash +ll +ls +la