Skip to content

Commit

Permalink
Squashed backport of openethereum#10920. (#199)
Browse files Browse the repository at this point in the history
Original commit messages:

RPC method parity_clearEngineSigner

Add RPC method parity_clearEngineSigner
Fixes #113

corrected the return type of clear_author

review comment responses and a rebase fix

removed a spurrious warning

moved clear_signer functionality to set_signer

Merge clear_author into MinerService::set_author.

Add trace logs to Clique::set_signer.

Clique: Don't lock signer multiple times.
  • Loading branch information
afck authored and varasev committed Oct 23, 2019
1 parent 6b9e8bc commit 6bc6f15
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 99 deletions.
79 changes: 32 additions & 47 deletions ethcore/src/engines/authority_round/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1809,12 +1809,8 @@ impl Engine<EthereumMachine> for AuthorityRound {
self.validators.register_client(client);
}

fn set_signer(&self, signer: Box<dyn EngineSigner>) {
*self.signer.write() = Some(signer);
}

fn clear_signer(&self) {
*self.signer.write() = Default::default();
fn set_signer(&self, signer: Option<Box<dyn EngineSigner>>) {
*self.signer.write() = signer;
}

fn sign(&self, hash: H256) -> Result<Signature, Error> {
Expand Down Expand Up @@ -1964,36 +1960,21 @@ mod tests {
fn generates_seal_and_does_not_double_propose() {
let tap = Arc::new(AccountProvider::transient_provider());
let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap();
let addr2 = tap.insert_account(keccak("2").into(), &"2".into()).unwrap();

let spec = Spec::new_test_round();
let engine = &*spec.engine;
let genesis_header = spec.genesis_header();
let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
let b1 = b1.close_and_lock().unwrap();
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
let b2 = b2.close_and_lock().unwrap();

engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
if let Seal::Regular(seal) = engine.generate_seal(&b1, &genesis_header) {
assert!(b1.clone().try_seal(engine, seal).is_ok());
// Second proposal is forbidden.
assert!(engine.generate_seal(&b1, &genesis_header) == Seal::None);
}

engine.set_signer(Box::new((tap, addr2, "2".into())));
if let Seal::Regular(seal) = engine.generate_seal(&b2, &genesis_header) {
// FIXME: This branch is unreachable because the call to `generate_seal` above always
// returns `Seal::None`. Meanwhile it looks as if the intention of the test writer was
// to receive a `Seal::Regular` here. This can be achieved similarly to how it's done in
// `generates_seal_iff_sealer_is_set()`, by stepping the engine and issuing a block in
// the new step signed by `keccak("0")`.
assert!(b2.clone().try_seal(engine, seal).is_ok());
// Second proposal is forbidden.
assert!(engine.generate_seal(&b2, &genesis_header) == Seal::None);
} else {
panic!("block 1 not sealed");
}
}

Expand All @@ -2013,7 +1994,7 @@ mod tests {
// Not a signer. A seal cannot be generated.
assert!(engine.generate_seal(&b1, &genesis_header) == Seal::None);
// Become a signer.
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
if let Seal::Regular(seal) = engine.generate_seal(&b1, &genesis_header) {
assert!(b1.clone().try_seal(engine, seal).is_ok());
// Second proposal is forbidden.
Expand All @@ -2022,7 +2003,7 @@ mod tests {
panic!("block 1 not sealed");
}
// Stop being a signer.
engine.clear_signer();
engine.set_signer(None);
// Make a step first and then create a new block in that new step.
engine.step();
let addr2 = tap.insert_account(keccak("0").into(), &"0".into()).unwrap();
Expand All @@ -2038,7 +2019,7 @@ mod tests {
// Not a signer. A seal cannot be generated.
assert!(engine.generate_seal(&b2, &header2) == Seal::None);
// Become a signer once more.
engine.set_signer(Box::new((tap, addr2, "0".into())));
engine.set_signer(Some(Box::new((tap, addr2, "0".into()))));
if let Seal::Regular(seal) = engine.generate_seal(&b2, &header2) {
assert!(b2.clone().try_seal(engine, seal).is_ok());
// Second proposal is forbidden.
Expand Down Expand Up @@ -2067,13 +2048,13 @@ mod tests {
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
let b2 = b2.close_and_lock().unwrap();

engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
match engine.generate_seal(&b1, &genesis_header) {
Seal::None | Seal::Proposal(_) => panic!("wrong seal"),
Seal::Regular(_) => {
engine.step();

engine.set_signer(Box::new((tap.clone(), addr2, "0".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into()))));
match engine.generate_seal(&b2, &genesis_header) {
Seal::Regular(_) | Seal::Proposal(_) => panic!("sealed despite wrong difficulty"),
Seal::None => {}
Expand Down Expand Up @@ -2181,7 +2162,11 @@ mod tests {
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 0);

aura.set_signer(Box::new((Arc::new(AccountProvider::transient_provider()), Default::default(), "".into())));
aura.set_signer(Some(Box::new((
Arc::new(AccountProvider::transient_provider()),
Default::default(),
"".into()
))));

// Do not report on steps skipped between genesis and first block.
header.set_number(1);
Expand Down Expand Up @@ -2331,7 +2316,7 @@ mod tests {
client.add_notify(notify.clone());
engine.register_client(Arc::downgrade(&client) as _);

engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));

let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
let b1 = b1.close_and_lock().unwrap();
Expand Down Expand Up @@ -2375,7 +2360,7 @@ mod tests {
let b1 = b1.close_and_lock().unwrap();

// since the block is empty it isn't sealed and we generate empty steps
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
engine.step();

Expand All @@ -2392,9 +2377,9 @@ mod tests {
let b2 = b2.close_and_lock().unwrap();

// we will now seal a block with 1tx and include the accumulated empty step message
engine.set_signer(Box::new((tap.clone(), addr2, "0".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into()))));
if let Seal::Regular(seal) = engine.generate_seal(&b2, &genesis_header) {
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
let empty_step2 = sealed_empty_step(engine, 2, &genesis_header.hash());
let empty_steps = ::rlp::encode_list(&vec![empty_step2]);

Expand Down Expand Up @@ -2428,14 +2413,14 @@ mod tests {
let b1 = b1.close_and_lock().unwrap();

// since the block is empty it isn't sealed and we generate empty steps
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
engine.step();

// step 3
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
let b2 = b2.close_and_lock().unwrap();
engine.set_signer(Box::new((tap.clone(), addr2, "0".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into()))));
assert_eq!(engine.generate_seal(&b2, &genesis_header), Seal::None);
engine.step();

Expand All @@ -2444,10 +2429,10 @@ mod tests {
let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false, None).unwrap();
let b3 = b3.close_and_lock().unwrap();

engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
if let Seal::Regular(seal) = engine.generate_seal(&b3, &genesis_header) {
let empty_step2 = sealed_empty_step(engine, 2, &genesis_header.hash());
engine.set_signer(Box::new((tap.clone(), addr2, "0".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into()))));
let empty_step3 = sealed_empty_step(engine, 3, &genesis_header.hash());

let empty_steps = ::rlp::encode_list(&vec![empty_step2, empty_step3]);
Expand Down Expand Up @@ -2478,7 +2463,7 @@ mod tests {
let b1 = b1.close_and_lock().unwrap();

// since the block is empty it isn't sealed and we generate empty steps
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
engine.step();

Expand Down Expand Up @@ -2532,7 +2517,7 @@ mod tests {
);

// empty step with valid signature from incorrect proposer for step
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
let empty_steps = vec![sealed_empty_step(engine, 1, &parent_header.hash())];
set_empty_steps_seal(&mut header, 2, &signature, &empty_steps);

Expand All @@ -2542,9 +2527,9 @@ mod tests {
);

// valid empty steps
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
let empty_step2 = sealed_empty_step(engine, 2, &parent_header.hash());
engine.set_signer(Box::new((tap.clone(), addr2, "0".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into()))));
let empty_step3 = sealed_empty_step(engine, 3, &parent_header.hash());

let empty_steps = vec![empty_step2, empty_step3];
Expand Down Expand Up @@ -2589,7 +2574,7 @@ mod tests {
let b1 = b1.close_and_lock().unwrap();

// since the block is empty it isn't sealed and we generate empty steps
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
engine.step();

Expand Down Expand Up @@ -2627,7 +2612,7 @@ mod tests {
let engine = &*spec.engine;

let addr1 = accounts[0];
engine.set_signer(Box::new((tap.clone(), addr1, "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));

let mut header: Header = Header::default();
let empty_step = empty_step(engine, 1, &header.parent_hash());
Expand Down Expand Up @@ -2708,7 +2693,7 @@ mod tests {
header.set_author(accounts[0]);

// when
engine.set_signer(Box::new((tap.clone(), accounts[1], "0".into())));
engine.set_signer(Some(Box::new((tap.clone(), accounts[1], "0".into()))));
let empty_steps = vec![
sealed_empty_step(&*engine, 1, &parent.hash()),
sealed_empty_step(&*engine, 1, &parent.hash()),
Expand Down Expand Up @@ -2745,9 +2730,9 @@ mod tests {
header.set_author(accounts[0]);

// when
engine.set_signer(Box::new((tap.clone(), accounts[1], "0".into())));
engine.set_signer(Some(Box::new((tap.clone(), accounts[1], "0".into()))));
let es1 = sealed_empty_step(&*engine, 1, &parent.hash());
engine.set_signer(Box::new((tap.clone(), accounts[0], "1".into())));
engine.set_signer(Some(Box::new((tap.clone(), accounts[0], "1".into()))));
let es2 = sealed_empty_step(&*engine, 2, &parent.hash());

let mut empty_steps = vec![es2, es1];
Expand Down
14 changes: 5 additions & 9 deletions ethcore/src/engines/basic_authority.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,12 +193,8 @@ impl Engine<EthereumMachine> for BasicAuthority {
self.validators.register_client(client);
}

fn set_signer(&self, signer: Box<EngineSigner>) {
*self.signer.write() = Some(signer);
}

fn clear_signer(&self) {
*self.signer.write() = Default::default();
fn set_signer(&self, signer: Option<Box<dyn EngineSigner>>) {
*self.signer.write() = signer;
}

fn sign(&self, hash: H256) -> Result<Signature, Error> {
Expand Down Expand Up @@ -268,7 +264,7 @@ mod tests {

let spec = new_test_authority();
let engine = &*spec.engine;
engine.set_signer(Box::new((Arc::new(tap), addr, "".into())));
engine.set_signer(Some(Box::new((Arc::new(tap), addr, "".into()))));
let genesis_header = spec.genesis_header();
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
Expand All @@ -286,9 +282,9 @@ mod tests {

let engine = new_test_authority().engine;
assert_eq!(SealingState::NotReady, engine.sealing_state());
engine.set_signer(Box::new((Arc::new(tap), authority, "".into())));
engine.set_signer(Some(Box::new((Arc::new(tap), authority, "".into()))));
assert_eq!(SealingState::Ready, engine.sealing_state());
engine.clear_signer();
engine.set_signer(None);
assert_eq!(SealingState::NotReady, engine.sealing_state());
}
}
11 changes: 8 additions & 3 deletions ethcore/src/engines/clique/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,9 +720,14 @@ impl Engine<EthereumMachine> for Clique {
}
}

fn set_signer(&self, signer: Box<EngineSigner>) {
trace!(target: "engine", "set_signer: {}", signer.address());
*self.signer.write() = Some(signer);
fn set_signer(&self, signer: Option<Box<dyn EngineSigner>>) {
let mut current_signer = self.signer.write();
if let Some(signer) = signer.as_ref() {
trace!(target: "engine", "set_signer: {:?}", signer.address());
} else if let Some(signer) = &*current_signer {
trace!(target: "engine", "set_signer: cleared; previous signer: {:?})", signer.address());
}
*current_signer = signer;
}

fn register_client(&self, client: Weak<EngineClient>) {
Expand Down
5 changes: 1 addition & 4 deletions ethcore/src/engines/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -441,10 +441,7 @@ pub trait Engine<M: Machine>: Sync + Send {
fn handle_message(&self, _message: &[u8]) -> Result<(), EngineError> { Err(EngineError::UnexpectedMessage) }

/// Register a component which signs consensus messages.
fn set_signer(&self, _signer: Box<EngineSigner>) {}

/// Unregisters the engine signer address to stop signing consensus messages.
fn clear_signer(&self) {}
fn set_signer(&self, _signer: Option<Box<EngineSigner>>) {}

/// Sign using the EngineSigner, to be used for consensus tx signing.
fn sign(&self, _hash: H256) -> Result<Signature, M::Error> { unimplemented!() }
Expand Down
55 changes: 32 additions & 23 deletions ethcore/src/miner/miner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -881,30 +881,39 @@ impl miner::MinerService for Miner {
self.params.write().extra_data = extra_data;
}

fn set_author(&self, author: Author) {
self.params.write().author = author.address();

if let Author::Sealer(signer) = author {
if self.engine.sealing_state() != SealingState::External {
// Enable sealing
self.sealing.lock().enabled = true;
// --------------------------------------------------------------------------
// | NOTE Code below may require author and sealing locks |
// | (some `Engine`s call `EngineClient.update_sealing()`) |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self.engine.set_signer(signer);
} else {
warn!("Setting an EngineSigner while Engine does not require one.");
fn set_author<T: Into<Option<Author>>>(&self, author: T) {
let author_opt = author.into();
self.params.write().author = author_opt.as_ref().map(Author::address).unwrap_or_default();

match author_opt {
Some(Author::Sealer(signer)) => {
if self.engine.sealing_state() != SealingState::External {
// Enable sealing
self.sealing.lock().enabled = true;
// --------------------------------------------------------------------------
// | NOTE Code below may require author and sealing locks |
// | (some `Engine`s call `EngineClient.update_sealing()`) |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self.engine.set_signer(Some(signer));
} else {
warn!("Setting an EngineSigner while Engine does not require one.");
}
}
Some(Author::External(_address)) => (),
None => {
// Clear the author.
if self.engine.sealing_state() != SealingState::External {
// Disable sealing.
self.sealing.lock().enabled = false;
// --------------------------------------------------------------------------
// | NOTE Code below may require author and sealing locks |
// | (some `Engine`s call `EngineClient.update_sealing()`) |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self.engine.set_signer(None);
}
}
}
}

fn clear_author(&self) {
self.params.write().author = Default::default();
if self.engine.sealing_state() != SealingState::External {
self.sealing.lock().enabled = false;
self.engine.clear_signer();
}
}

Expand Down
5 changes: 1 addition & 4 deletions ethcore/src/miner/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,10 +131,7 @@ pub trait MinerService : Send + Sync {
/// Set info necessary to sign consensus messages and block authoring.
///
/// On chains where sealing is done externally (e.g. PoW) we provide only reward beneficiary.
fn set_author(&self, author: Author);

/// Clears the engine signer and stops signing.
fn clear_author(&self);
fn set_author<T: Into<Option<Author>>>(&self, author: T);

// Transaction Pool

Expand Down
2 changes: 1 addition & 1 deletion rpc/src/v1/impls/parity_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
}

fn clear_engine_signer(&self) -> Result<bool> {
self.miner.clear_author();
self.miner.set_author(None);
Ok(true)
}

Expand Down
Loading

0 comments on commit 6bc6f15

Please sign in to comment.