AuthorityEngine: Minor cleanups. (#11408)

This commit is contained in:
Andreas Fackler 2020-01-27 14:30:42 +01:00 committed by Andronik Ordian
parent 6ab7789604
commit e69539357f
1 changed files with 107 additions and 95 deletions

View File

@ -370,7 +370,6 @@ impl EpochManager {
debug!(target: "engine", "Zooming to epoch after block {}", hash);
trace!(target: "engine", "Current validator set: {:?}", self.validators());
// epoch_transition_for can be an expensive call, but in the absence of
// forks it will only need to be called for the block directly after
// epoch transition, in which case it will be O(1) and require a single
@ -390,25 +389,27 @@ impl EpochManager {
let (signal_number, set_proof, _) = destructure_proofs(&last_transition.proof)
.expect("proof produced by this engine; therefore it is valid; qed");
trace!(target: "engine", "extracting epoch validator set for epoch ({}, {}) signalled at #{}",
last_transition.block_number, last_transition.block_hash, signal_number);
trace!(
target: "engine",
"extracting epoch validator set for epoch ({}, {}) signalled at #{}",
last_transition.block_number, last_transition.block_hash, signal_number
);
let first = signal_number == 0;
let epoch_set = validators.epoch_set(
let (list, _) = validators.epoch_set(
first,
machine,
signal_number, // use signal number so multi-set first calculation is correct.
set_proof,
)
.ok()
.map(|(list, _)| {
trace!(target: "engine", "Updating finality checker with new validator set extracted from epoch ({}, {}): {:?}",
last_transition.block_number, last_transition.block_hash, &list);
).expect("proof produced by this engine; therefore it is valid; qed");
list.into_inner()
})
.expect("proof produced by this engine; therefore it is valid; qed");
trace!(
target: "engine",
"Updating finality checker with new validator set extracted from epoch ({}, {}): {:?}",
last_transition.block_number, last_transition.block_hash, &list
);
let epoch_set = list.into_inner();
let two_thirds_majority_transition = self.finality_checker.two_thirds_majority_transition();
self.finality_checker = RollingFinality::blank(epoch_set, two_thirds_majority_transition);
}
@ -435,10 +436,22 @@ impl EpochManager {
/// A message broadcast by authorities when it's their turn to seal a block but there are no
/// transactions. Other authorities accumulate these messages and later include them in the seal as
/// proof.
///
/// An empty step message is created _instead of_ a block if there are no pending transactions.
/// It cannot itself be a parent, and `parent_hash` always points to the most recent block. E.g.:
/// * Validator A creates block `bA`.
/// * Validator B has no pending transactions, so it signs an empty step message `mB`
/// instead whose hash points to block `bA`.
/// * Validator C also has no pending transactions, so it also signs an empty step message `mC`
/// instead whose hash points to block `bA`.
/// * Validator D creates block `bD`. The parent is block `bA`, and the header includes `mB` and `mC`.
#[derive(Clone, Debug, PartialEq, Eq)]
struct EmptyStep {
/// The signature of the other two fields, by the message's author.
signature: H520,
/// This message's step number.
step: u64,
/// The hash of the most recent block.
parent_hash: H256,
}
@ -447,6 +460,7 @@ impl PartialOrd for EmptyStep {
Some(self.cmp(other))
}
}
impl Ord for EmptyStep {
fn cmp(&self, other: &Self) -> cmp::Ordering {
self.step.cmp(&other.step)
@ -463,6 +477,7 @@ impl EmptyStep {
EmptyStep { signature, step, parent_hash }
}
/// Returns `true` if the message has a valid signature by the expected proposer in the message's step.
fn verify(&self, validators: &dyn ValidatorSet) -> Result<bool, Error> {
let message = keccak(empty_step_rlp(self.step, &self.parent_hash));
let correct_proposer = step_proposer(validators, &self.parent_hash, self.step);
@ -773,7 +788,7 @@ fn verify_external(header: &Header, validators: &dyn ValidatorSet, empty_steps_t
}
fn combine_proofs(signal_number: BlockNumber, set_proof: &[u8], finality_proof: &[u8]) -> Vec<u8> {
let mut stream = ::rlp::RlpStream::new_list(3);
let mut stream = RlpStream::new_list(3);
stream.append(&signal_number).append(&set_proof).append(&finality_proof);
stream.out()
}
@ -830,30 +845,21 @@ impl AuthorityRound {
let initial_step = our_params.start_step.unwrap_or(0);
let mut durations = Vec::new();
let mut prev_step = 0u64;
let mut prev_time = 0u64;
let mut prev_dur = our_params.step_durations[&0];
durations.push(StepDurationInfo {
transition_step: prev_step,
transition_timestamp: prev_time,
step_duration: prev_dur
});
for (time, dur) in our_params.step_durations.iter().skip(1) {
let (step, time) = next_step_time_duration(
StepDurationInfo{
transition_step: prev_step,
transition_timestamp: prev_time,
step_duration: prev_dur,
}, *time)
.ok_or(BlockError::TimestampOverflow)?;
durations.push(StepDurationInfo {
transition_step: step,
transition_timestamp: time,
step_duration: *dur
});
prev_step = step;
prev_time = time;
prev_dur = *dur;
{
let mut dur_info = StepDurationInfo {
transition_step: 0u64,
transition_timestamp: 0u64,
step_duration: our_params.step_durations[&0],
};
durations.push(dur_info);
for (time, dur) in our_params.step_durations.iter().skip(1) {
let (step, time) = next_step_time_duration(dur_info, *time)
.ok_or(BlockError::TimestampOverflow)?;
dur_info.transition_step = step;
dur_info.transition_timestamp = time;
dur_info.step_duration = *dur;
durations.push(dur_info);
}
}
let step = Step {
@ -907,13 +913,7 @@ impl AuthorityRound {
(CowLike::Borrowed(&*self.validators), header.number())
} else {
let mut epoch_manager = self.epoch_manager.lock();
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
Some(client) => client,
None => {
debug!(target: "engine", "Unable to verify sig: missing client ref.");
return Err(EngineError::RequiresClient.into())
}
};
let client = self.upgrade_client_or("Unable to verify sig")?;
if !epoch_manager.zoom_to_after(&*client, &self.machine, &*self.validators, *header.parent_hash()) {
debug!(target: "engine", "Unable to zoom to epoch.");
@ -981,14 +981,19 @@ impl AuthorityRound {
}
fn broadcast_message(&self, message: Vec<u8>) {
if let Some(ref weak) = *self.client.read() {
if let Some(c) = weak.upgrade() {
c.broadcast_consensus_message(message);
}
if let Ok(c) = self.upgrade_client_or(None) {
c.broadcast_consensus_message(message);
}
}
fn report_skipped(&self, header: &Header, current_step: u64, parent_step: u64, validators: &dyn ValidatorSet, set_number: u64) {
fn report_skipped(
&self,
header: &Header,
current_step: u64,
parent_step: u64,
validators: &dyn ValidatorSet,
set_number: u64
) {
// we're building on top of the genesis block so don't report any skipped steps
if header.number() == 1 {
return;
@ -1004,8 +1009,12 @@ impl AuthorityRound {
if skipped_primary != me {
// Stop reporting once validators start repeating.
if !reported.insert(skipped_primary) { break; }
trace!(target: "engine", "Reporting benign misbehaviour (cause: skipped step) at block #{}, epoch set number {}, step proposer={:#x}. Own address: {}",
header.number(), set_number, skipped_primary, me);
trace!(
target: "engine",
"Reporting benign misbehaviour (cause: skipped step) at block #{}, \
epoch set number {}, step proposer={:#x}. Own address: {}",
header.number(), set_number, skipped_primary, me
);
self.validators.report_benign(&skipped_primary, set_number, header.number());
} else {
trace!(target: "engine", "Primary that skipped is self, not self-reporting. Own address: {}", me);
@ -1018,12 +1027,9 @@ impl AuthorityRound {
fn build_finality(&self, chain_head: &Header, ancestry: &mut dyn Iterator<Item=Header>) -> Vec<H256> {
if self.immediate_transitions { return Vec::new() }
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
Some(client) => client,
None => {
warn!(target: "engine", "Unable to apply ancestry actions: missing client ref.");
return Vec::new();
}
let client = match self.upgrade_client_or("Unable to apply ancestry actions") {
Ok(client) => client,
Err(_) => return Vec::new(),
};
let mut epoch_manager = self.epoch_manager.lock();
@ -1079,7 +1085,7 @@ impl AuthorityRound {
}
fn address(&self) -> Option<Address> {
self.signer.read().as_ref().map(|s| s.address() )
self.signer.read().as_ref().map(|s| s.address())
}
/// Make calls to the randomness contract.
@ -1095,10 +1101,7 @@ impl AuthorityRound {
None => return Ok(Vec::new()), // We are not a validator, so we shouldn't call the contracts.
};
let our_addr = signer.address();
let client = self.client.read().as_ref().and_then(|weak| weak.upgrade()).ok_or_else(|| {
debug!(target: "engine", "Unable to prepare block: missing client ref.");
EngineError::RequiresClient
})?;
let client = self.upgrade_client_or("Unable to prepare block")?;
let full_client = client.as_full_client()
.ok_or_else(|| EngineError::FailedSystemCall("Failed to upgrade to BlockchainClient.".to_string()))?;
@ -1116,6 +1119,18 @@ impl AuthorityRound {
let tx_request = TransactionRequest::call(contract_addr, data).gas_price(U256::zero()).nonce(nonce);
Ok(vec![full_client.create_transaction(tx_request)?])
}
/// Returns the reference to the client, if registered.
fn upgrade_client_or<'a, T>(&self, opt_error_msg: T) -> Result<Arc<dyn EngineClient>, EngineError>
where T: Into<Option<&'a str>>,
{
self.client.read().as_ref().and_then(|weak| weak.upgrade()).ok_or_else(|| {
if let Some(error_msg) = opt_error_msg.into() {
debug!(target: "engine", "{}: missing client ref.", error_msg);
}
EngineError::RequiresClient
})
}
}
fn unix_now() -> Duration {
@ -1174,10 +1189,8 @@ impl Engine for AuthorityRound {
fn step(&self) {
self.step.inner.increment();
self.step.can_propose.store(true, AtomicOrdering::SeqCst);
if let Some(ref weak) = *self.client.read() {
if let Some(c) = weak.upgrade() {
c.update_sealing(ForceUpdateSealing::No);
}
if let Ok(c) = self.upgrade_client_or(None) {
c.update_sealing(ForceUpdateSealing::No);
}
}
@ -1257,12 +1270,9 @@ impl Engine for AuthorityRound {
}
};
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
Some(client) => client,
None => {
warn!(target: "engine", "Not preparing block: missing client ref.");
return SealingState::NotReady;
}
let client = match self.upgrade_client_or("Not preparing block") {
Ok(client) => client,
Err(_) => return SealingState::NotReady,
};
let parent = match client.as_full_client() {
@ -1296,7 +1306,7 @@ impl Engine for AuthorityRound {
}
fn handle_message(&self, rlp: &[u8]) -> Result<(), EngineError> {
fn fmt_err<T: ::std::fmt::Debug>(x: T) -> EngineError {
fn fmt_err<T: fmt::Debug>(x: T) -> EngineError {
EngineError::MalformedMessage(format!("{:?}", x))
}
@ -1625,8 +1635,12 @@ impl Engine for AuthorityRound {
match validate_empty_steps() {
Ok(len) => len,
Err(err) => {
trace!(target: "engine", "Reporting benign misbehaviour (cause: invalid empty steps) at block #{}, epoch set number {}. Own address: {}",
header.number(), set_number, self.address().unwrap_or_default());
trace!(
target: "engine",
"Reporting benign misbehaviour (cause: invalid empty steps) \
at block #{}, epoch set number {}. Own address: {}",
header.number(), set_number, self.address().unwrap_or_default()
);
self.validators.report_benign(header.author(), set_number, header.number());
return Err(err);
},
@ -1640,7 +1654,10 @@ impl Engine for AuthorityRound {
if header.number() >= self.validate_score_transition {
let expected_difficulty = calculate_score(parent_step.into(), step.into(), empty_steps_len.into());
if header.difficulty() != &expected_difficulty {
return Err(From::from(BlockError::InvalidDifficulty(Mismatch { expected: expected_difficulty, found: header.difficulty().clone() })));
return Err(From::from(BlockError::InvalidDifficulty(Mismatch {
expected: expected_difficulty,
found: header.difficulty().clone()
})));
}
}
@ -1656,7 +1673,10 @@ impl Engine for AuthorityRound {
let res = verify_external(header, &*validators, self.empty_steps_transition);
match res {
Err(Error::Engine(EngineError::NotProposer(_))) => {
trace!(target: "engine", "Reporting benign misbehaviour (cause: block from incorrect proposer) at block #{}, epoch set number {}. Own address: {}",
trace!(
target: "engine",
"Reporting benign misbehaviour (cause: block from incorrect proposer) \
at block #{}, epoch set number {}. Own address: {}",
header.number(), set_number, self.address().unwrap_or_default());
self.validators.report_benign(header.author(), set_number, header.number());
},
@ -1692,13 +1712,7 @@ impl Engine for AuthorityRound {
if self.immediate_transitions { return None }
let epoch_transition_hash = {
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
Some(client) => client,
None => {
warn!(target: "engine", "Unable to check for epoch end: missing client ref.");
return None;
}
};
let client = self.upgrade_client_or("Unable to check for epoch end").ok()?;
let mut epoch_manager = self.epoch_manager.lock();
if !epoch_manager.zoom_to_after(&*client, &self.machine, &*self.validators, *chain_head.parent_hash()) {
@ -1710,7 +1724,7 @@ impl Engine for AuthorityRound {
let mut hash = *chain_head.parent_hash();
let mut ancestry = std::iter::repeat_with(move || {
let mut ancestry = iter::repeat_with(move || {
chain(hash).and_then(|header| {
if header.number() == 0 { return None }
hash = *header.parent_hash();
@ -1739,7 +1753,11 @@ impl Engine for AuthorityRound {
// Apply transitions that don't require finality and should be enacted immediately (e.g from chain spec)
if let Some(change) = self.validators.is_epoch_end(first, chain_head) {
info!(target: "engine", "Immediately applying validator set change signalled at block {}", chain_head.number());
info!(
target: "engine",
"Immediately applying validator set change signalled at block {}",
chain_head.number()
);
self.epoch_manager.lock().note_new_epoch();
let change = combine_proofs(chain_head.number(), &change, &[]);
return Some(change)
@ -1752,7 +1770,7 @@ impl Engine for AuthorityRound {
// to construct transition proof. author == ec_recover(sig) known
// since the blocks are in the DB.
let mut hash = chain_head.hash();
let mut finality_proof: Vec<_> = std::iter::repeat_with(move || {
let mut finality_proof: Vec<_> = iter::repeat_with(move || {
chain(hash).and_then(|header| {
hash = *header.parent_hash();
if header.number() == 0 { None }
@ -1865,13 +1883,7 @@ impl Engine for AuthorityRound {
fn gas_limit_override(&self, header: &Header) -> Option<U256> {
let (_, &address) = self.block_gas_limit_contract_transitions.range(..=header.number()).last()?;
let client = match self.client.read().as_ref().and_then(|weak| weak.upgrade()) {
Some(client) => client,
None => {
error!(target: "engine", "Unable to prepare block: missing client ref.");
return None;
}
};
let client = self.upgrade_client_or("Unable to prepare block").ok()?;
let full_client = match client.as_full_client() {
Some(full_client) => full_client,
None => {
@ -2392,7 +2404,7 @@ mod tests {
]);
}
fn assert_insufficient_proof<T: ::std::fmt::Debug>(result: Result<T, Error>, contains: &str) {
fn assert_insufficient_proof<T: std::fmt::Debug>(result: Result<T, Error>, contains: &str) {
match result {
Err(Error::Engine(EngineError::InsufficientProof(ref s))) =>{
assert!(s.contains(contains), "Expected {:?} to contain {:?}", s, contains);