2019-01-07 11:33:07 +01:00
|
|
|
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
|
|
|
|
// This file is part of Parity Ethereum.
|
2016-09-08 12:12:24 +02:00
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
2016-09-08 12:12:24 +02:00
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
2016-09-08 12:12:24 +02:00
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
2019-01-07 11:33:07 +01:00
|
|
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
2016-09-08 12:12:24 +02:00
|
|
|
|
2016-11-02 18:42:56 +01:00
|
|
|
//! A blockchain engine that supports a non-instant BFT proof-of-authority.
|
2019-08-21 14:55:51 +02:00
|
|
|
//!
|
|
|
|
//! It is recommended to use the `two_thirds_majority_transition` option, to defend against the
|
|
|
|
//! ["Attack of the Clones"](https://arxiv.org/pdf/1902.10244.pdf). Newly started networks can
|
|
|
|
//! set this option to `0`, to use a 2/3 quorum from the beginning.
|
2019-10-14 12:56:38 +02:00
|
|
|
//!
|
|
|
|
//! To support on-chain governance, the [ValidatorSet] is pluggable: Aura supports simple
|
|
|
|
//! constant lists of validators as well as smart contract-based dynamic validator sets.
|
|
|
|
//! Misbehavior is reported to the [ValidatorSet] as well, so that e.g. governance contracts
|
|
|
|
//! can penalize or ban attacker's nodes.
|
|
|
|
//!
|
|
|
|
//! * "Benign" misbehavior are faults that can happen in normal operation, like failing
|
|
|
|
//! to propose a block in your slot, which could be due to a temporary network outage, or
|
|
|
|
//! wrong timestamps (due to out-of-sync clocks).
|
|
|
|
//! * "Malicious" reports are made only if the sender misbehaved deliberately (or due to a
|
|
|
|
//! software bug), e.g. if they proposed multiple blocks with the same step number.
|
2016-09-08 12:12:24 +02:00
|
|
|
|
2018-11-21 22:30:03 +01:00
|
|
|
use std::collections::{BTreeMap, BTreeSet, HashSet};
|
|
|
|
use std::{cmp, fmt};
|
2018-07-06 11:43:58 +02:00
|
|
|
use std::iter::FromIterator;
|
|
|
|
use std::ops::Deref;
|
2016-11-14 14:35:45 +01:00
|
|
|
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
|
2017-07-29 21:56:42 +02:00
|
|
|
use std::sync::{Weak, Arc};
|
2019-06-20 09:00:50 +02:00
|
|
|
use std::time::{UNIX_EPOCH, Duration};
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2019-08-15 17:59:22 +02:00
|
|
|
use client_traits::EngineClient;
|
2019-08-22 18:25:49 +02:00
|
|
|
use engine::{Engine, ConstructedVerifier};
|
|
|
|
use block_reward::{self, BlockRewardContract, RewardKind};
|
2017-06-28 13:17:36 +02:00
|
|
|
use ethjson;
|
2019-08-13 12:33:34 +02:00
|
|
|
use machine::{
|
|
|
|
ExecutedBlock,
|
|
|
|
Machine,
|
|
|
|
};
|
2019-08-22 18:25:49 +02:00
|
|
|
use macros::map;
|
|
|
|
use keccak_hash::keccak;
|
|
|
|
use log::{info, debug, error, trace, warn};
|
2019-08-15 17:59:22 +02:00
|
|
|
use engine::signer::EngineSigner;
|
2019-10-23 13:03:46 +02:00
|
|
|
use parity_crypto::publickey::Signature;
|
2017-06-28 13:17:36 +02:00
|
|
|
use io::{IoContext, IoHandler, TimerToken, IoService};
|
|
|
|
use itertools::{self, Itertools};
|
2018-04-16 15:52:12 +02:00
|
|
|
use rlp::{encode, Decodable, DecoderError, Encodable, RlpStream, Rlp};
|
2018-01-10 13:35:18 +01:00
|
|
|
use ethereum_types::{H256, H520, Address, U128, U256};
|
2017-09-02 20:09:13 +02:00
|
|
|
use parking_lot::{Mutex, RwLock};
|
2019-06-20 09:00:50 +02:00
|
|
|
use time_utils::CheckedSystemTime;
|
2019-08-22 18:25:49 +02:00
|
|
|
use common_types::{
|
2019-07-18 12:27:08 +02:00
|
|
|
ancestry_action::AncestryAction,
|
|
|
|
BlockNumber,
|
|
|
|
header::{Header, ExtendedHeader},
|
|
|
|
engines::{
|
2019-08-15 17:59:22 +02:00
|
|
|
Headers,
|
2019-07-18 12:27:08 +02:00
|
|
|
params::CommonParams,
|
2019-08-15 17:59:22 +02:00
|
|
|
PendingTransitionStore,
|
|
|
|
Seal,
|
2019-07-18 12:27:08 +02:00
|
|
|
SealingState,
|
|
|
|
machine::{Call, AuxiliaryData},
|
|
|
|
},
|
|
|
|
errors::{BlockError, EthcoreError as Error, EngineError},
|
2019-08-22 18:25:49 +02:00
|
|
|
snapshot::Snapshotting,
|
2019-07-18 12:27:08 +02:00
|
|
|
};
|
2017-09-05 12:14:03 +02:00
|
|
|
use unexpected::{Mismatch, OutOfBounds};
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2019-08-22 18:25:49 +02:00
|
|
|
use validator_set::{ValidatorSet, SimpleList, new_validator_set};
|
|
|
|
|
2017-06-28 13:17:36 +02:00
|
|
|
mod finality;
|
|
|
|
|
2019-08-22 18:25:49 +02:00
|
|
|
use self::finality::RollingFinality;
|
|
|
|
|
2016-09-08 12:12:24 +02:00
|
|
|
/// `AuthorityRound` params.
|
|
|
|
pub struct AuthorityRoundParams {
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
/// Time to wait before next block or authority switching,
|
|
|
|
/// in seconds.
|
|
|
|
///
|
|
|
|
/// Deliberately typed as u16 as too high of a value leads
|
|
|
|
/// to slow block issuance.
|
|
|
|
pub step_duration: u16,
|
2016-12-06 19:23:15 +01:00
|
|
|
/// Starting step,
|
|
|
|
pub start_step: Option<u64>,
|
2017-01-10 12:23:59 +01:00
|
|
|
/// Valid validators.
|
2019-06-14 18:48:35 +02:00
|
|
|
pub validators: Box<dyn ValidatorSet>,
|
2017-03-28 10:46:52 +02:00
|
|
|
/// Chain score validation transition block.
|
|
|
|
pub validate_score_transition: u64,
|
2017-05-15 22:34:01 +02:00
|
|
|
/// Monotonic step validation transition block.
|
|
|
|
pub validate_step_transition: u64,
|
2017-06-28 13:17:36 +02:00
|
|
|
/// Immediate transitions.
|
|
|
|
pub immediate_transitions: bool,
|
2017-09-26 14:19:08 +02:00
|
|
|
/// Block reward in base units.
|
|
|
|
pub block_reward: U256,
|
2019-08-22 10:45:24 +02:00
|
|
|
/// Block reward contract addresses with their associated starting block numbers.
|
|
|
|
pub block_reward_contract_transitions: BTreeMap<u64, BlockRewardContract>,
|
2017-12-05 15:57:45 +01:00
|
|
|
/// Number of accepted uncles transition block.
|
|
|
|
pub maximum_uncle_count_transition: u64,
|
2017-11-10 00:56:02 +01:00
|
|
|
/// Number of accepted uncles.
|
|
|
|
pub maximum_uncle_count: usize,
|
2018-02-15 01:39:29 +01:00
|
|
|
/// Empty step messages transition block.
|
|
|
|
pub empty_steps_transition: u64,
|
2019-08-21 14:55:51 +02:00
|
|
|
/// First block for which a 2/3 quorum (instead of 1/2) is required.
|
|
|
|
pub two_thirds_majority_transition: BlockNumber,
|
2018-02-15 01:39:29 +01:00
|
|
|
/// Number of accepted empty steps.
|
|
|
|
pub maximum_empty_steps: usize,
|
2018-12-10 19:58:38 +01:00
|
|
|
/// Transition block to strict empty steps validation.
|
|
|
|
pub strict_empty_steps_transition: u64,
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
const U16_MAX: usize = ::std::u16::MAX as usize;
|
|
|
|
|
2016-09-08 12:12:24 +02:00
|
|
|
impl From<ethjson::spec::AuthorityRoundParams> for AuthorityRoundParams {
|
|
|
|
fn from(p: ethjson::spec::AuthorityRoundParams) -> Self {
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
let mut step_duration_usize: usize = p.step_duration.into();
|
|
|
|
if step_duration_usize > U16_MAX {
|
|
|
|
step_duration_usize = U16_MAX;
|
|
|
|
warn!(target: "engine", "step_duration is too high ({}), setting it to {}", step_duration_usize, U16_MAX);
|
|
|
|
}
|
2019-08-22 10:45:24 +02:00
|
|
|
let transition_block_num = p.block_reward_contract_transition.map_or(0, Into::into);
|
|
|
|
let mut br_transitions: BTreeMap<_, _> = p.block_reward_contract_transitions
|
|
|
|
.unwrap_or_default()
|
|
|
|
.into_iter()
|
|
|
|
.map(|(block_num, address)|
|
|
|
|
(block_num.into(), BlockRewardContract::new_from_address(address.into())))
|
|
|
|
.collect();
|
|
|
|
if (p.block_reward_contract_code.is_some() || p.block_reward_contract_address.is_some()) &&
|
|
|
|
br_transitions.keys().next().map_or(false, |&block_num| block_num <= transition_block_num)
|
|
|
|
{
|
|
|
|
let s = "blockRewardContractTransition";
|
|
|
|
panic!("{} should be less than any of the keys in {}s", s, s);
|
|
|
|
}
|
|
|
|
if let Some(code) = p.block_reward_contract_code {
|
|
|
|
br_transitions.insert(
|
|
|
|
transition_block_num,
|
|
|
|
BlockRewardContract::new_from_code(Arc::new(code.into()))
|
|
|
|
);
|
|
|
|
} else if let Some(address) = p.block_reward_contract_address {
|
|
|
|
br_transitions.insert(
|
|
|
|
transition_block_num,
|
|
|
|
BlockRewardContract::new_from_address(address.into())
|
|
|
|
);
|
|
|
|
}
|
2016-09-08 12:12:24 +02:00
|
|
|
AuthorityRoundParams {
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
step_duration: step_duration_usize as u16,
|
2017-05-22 08:21:34 +02:00
|
|
|
validators: new_validator_set(p.validators),
|
2016-12-06 19:23:15 +01:00
|
|
|
start_step: p.start_step.map(Into::into),
|
2017-03-28 10:46:52 +02:00
|
|
|
validate_score_transition: p.validate_score_transition.map_or(0, Into::into),
|
2017-05-15 22:34:01 +02:00
|
|
|
validate_step_transition: p.validate_step_transition.map_or(0, Into::into),
|
2017-06-28 13:17:36 +02:00
|
|
|
immediate_transitions: p.immediate_transitions.unwrap_or(false),
|
2017-09-26 14:19:08 +02:00
|
|
|
block_reward: p.block_reward.map_or_else(Default::default, Into::into),
|
2019-08-22 10:45:24 +02:00
|
|
|
block_reward_contract_transitions: br_transitions,
|
2017-12-05 15:57:45 +01:00
|
|
|
maximum_uncle_count_transition: p.maximum_uncle_count_transition.map_or(0, Into::into),
|
2017-11-10 00:56:02 +01:00
|
|
|
maximum_uncle_count: p.maximum_uncle_count.map_or(0, Into::into),
|
2018-02-15 01:39:29 +01:00
|
|
|
empty_steps_transition: p.empty_steps_transition.map_or(u64::max_value(), |n| ::std::cmp::max(n.into(), 1)),
|
|
|
|
maximum_empty_steps: p.maximum_empty_steps.map_or(0, Into::into),
|
2019-08-21 14:55:51 +02:00
|
|
|
two_thirds_majority_transition: p.two_thirds_majority_transition.map_or_else(BlockNumber::max_value, Into::into),
|
2018-12-10 19:58:38 +01:00
|
|
|
strict_empty_steps_transition: p.strict_empty_steps_transition.map_or(0, Into::into),
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-13 20:24:21 +02:00
|
|
|
// Helper for managing the step.
|
|
|
|
#[derive(Debug)]
|
|
|
|
struct Step {
|
|
|
|
calibrate: bool, // whether calibration is enabled.
|
|
|
|
inner: AtomicUsize,
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
duration: u16,
|
2017-04-13 20:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Step {
|
2018-11-21 22:30:03 +01:00
|
|
|
fn load(&self) -> u64 { self.inner.load(AtomicOrdering::SeqCst) as u64 }
|
2017-04-13 20:24:21 +02:00
|
|
|
fn duration_remaining(&self) -> Duration {
|
|
|
|
let now = unix_now();
|
2018-11-21 22:30:03 +01:00
|
|
|
let expected_seconds = self.load()
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
.checked_add(1)
|
2017-12-21 15:01:05 +01:00
|
|
|
.and_then(|ctr| ctr.checked_mul(self.duration as u64))
|
|
|
|
.map(Duration::from_secs);
|
|
|
|
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
match expected_seconds {
|
2017-12-21 15:01:05 +01:00
|
|
|
Some(step_end) if step_end > now => step_end - now,
|
|
|
|
Some(_) => Duration::from_secs(0),
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
None => {
|
|
|
|
let ctr = self.load();
|
|
|
|
error!(target: "engine", "Step counter is too high: {}, aborting", ctr);
|
|
|
|
panic!("step counter is too high: {}", ctr)
|
|
|
|
},
|
2017-04-13 20:24:21 +02:00
|
|
|
}
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
|
2017-04-13 20:24:21 +02:00
|
|
|
}
|
2017-12-21 15:01:05 +01:00
|
|
|
|
2017-04-13 20:24:21 +02:00
|
|
|
fn increment(&self) {
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
use std::usize;
|
|
|
|
// fetch_add won't panic on overflow but will rather wrap
|
|
|
|
// around, leading to zero as the step counter, which might
|
|
|
|
// lead to unexpected situations, so it's better to shut down.
|
|
|
|
if self.inner.fetch_add(1, AtomicOrdering::SeqCst) == usize::MAX {
|
|
|
|
error!(target: "engine", "Step counter is too high: {}, aborting", usize::MAX);
|
|
|
|
panic!("step counter is too high: {}", usize::MAX);
|
|
|
|
}
|
|
|
|
|
2017-04-13 20:24:21 +02:00
|
|
|
}
|
2017-12-21 15:01:05 +01:00
|
|
|
|
2017-04-13 20:24:21 +02:00
|
|
|
fn calibrate(&self) {
|
|
|
|
if self.calibrate {
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
let new_step = unix_now().as_secs() / (self.duration as u64);
|
2017-04-13 20:24:21 +02:00
|
|
|
self.inner.store(new_step as usize, AtomicOrdering::SeqCst);
|
|
|
|
}
|
|
|
|
}
|
2017-12-21 15:01:05 +01:00
|
|
|
|
2018-11-21 22:30:03 +01:00
|
|
|
fn check_future(&self, given: u64) -> Result<(), Option<OutOfBounds<u64>>> {
|
|
|
|
const REJECTED_STEP_DRIFT: u64 = 4;
|
2017-12-21 15:01:05 +01:00
|
|
|
|
2018-01-08 14:46:11 +01:00
|
|
|
// Verify if the step is correct.
|
|
|
|
if given <= self.load() {
|
2017-12-21 15:01:05 +01:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make absolutely sure that the given step is incorrect.
|
|
|
|
self.calibrate();
|
|
|
|
let current = self.load();
|
|
|
|
|
|
|
|
// reject blocks too far in the future
|
|
|
|
if given > current + REJECTED_STEP_DRIFT {
|
|
|
|
Err(None)
|
|
|
|
// wait a bit for blocks in near future
|
2018-01-08 14:46:11 +01:00
|
|
|
} else if given > current {
|
2017-12-21 15:01:05 +01:00
|
|
|
let d = self.duration as u64;
|
|
|
|
Err(Some(OutOfBounds {
|
|
|
|
min: None,
|
2018-11-21 22:30:03 +01:00
|
|
|
max: Some(d * current),
|
|
|
|
found: d * given,
|
2017-12-21 15:01:05 +01:00
|
|
|
}))
|
2017-04-13 20:24:21 +02:00
|
|
|
} else {
|
2017-12-21 15:01:05 +01:00
|
|
|
Ok(())
|
2017-04-13 20:24:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-07 12:17:11 +01:00
|
|
|
// Chain scoring: total weight is sqrt(U256::max_value())*height - step
|
2018-11-21 22:30:03 +01:00
|
|
|
fn calculate_score(parent_step: u64, current_step: u64, current_empty_steps: usize) -> U256 {
|
|
|
|
U256::from(U128::max_value()) + U256::from(parent_step) - U256::from(current_step) + U256::from(current_empty_steps)
|
2017-12-07 12:17:11 +01:00
|
|
|
}
|
|
|
|
|
2017-06-28 13:17:36 +02:00
|
|
|
struct EpochManager {
|
|
|
|
epoch_transition_hash: H256,
|
|
|
|
epoch_transition_number: BlockNumber,
|
|
|
|
finality_checker: RollingFinality,
|
|
|
|
force: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl EpochManager {
|
2019-08-21 14:55:51 +02:00
|
|
|
fn blank(two_thirds_majority_transition: BlockNumber) -> Self {
|
2017-06-28 13:17:36 +02:00
|
|
|
EpochManager {
|
2019-06-03 15:36:21 +02:00
|
|
|
epoch_transition_hash: H256::zero(),
|
2017-06-28 13:17:36 +02:00
|
|
|
epoch_transition_number: 0,
|
2019-08-21 14:55:51 +02:00
|
|
|
finality_checker: RollingFinality::blank(Vec::new(), two_thirds_majority_transition),
|
2017-06-28 13:17:36 +02:00
|
|
|
force: true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-24 10:30:31 +02:00
|
|
|
// Zooms to the epoch after the header with the given hash. Returns true if succeeded, false otherwise.
|
|
|
|
fn zoom_to_after(
|
|
|
|
&mut self,
|
2019-06-14 18:48:35 +02:00
|
|
|
client: &dyn EngineClient,
|
2019-06-26 14:16:05 +02:00
|
|
|
machine: &Machine,
|
2019-06-14 18:48:35 +02:00
|
|
|
validators: &dyn ValidatorSet,
|
2019-05-24 10:30:31 +02:00
|
|
|
hash: H256
|
|
|
|
) -> bool {
|
|
|
|
let last_was_parent = self.finality_checker.subchain_head() == Some(hash);
|
2017-06-28 13:17:36 +02:00
|
|
|
|
|
|
|
// early exit for current target == chain head, but only if the epochs are
|
|
|
|
// the same.
|
|
|
|
if last_was_parent && !self.force {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
self.force = false;
|
2019-05-24 10:30:31 +02:00
|
|
|
debug!(target: "engine", "Zooming to epoch after block {}", hash);
|
2019-06-25 13:15:00 +02:00
|
|
|
trace!(target: "engine", "Current validator set: {:?}", self.validators());
|
|
|
|
|
2017-06-28 13:17:36 +02:00
|
|
|
|
|
|
|
// 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
|
|
|
|
// DB lookup.
|
2019-05-24 10:30:31 +02:00
|
|
|
let last_transition = match client.epoch_transition_for(hash) {
|
2017-06-28 13:17:36 +02:00
|
|
|
Some(t) => t,
|
|
|
|
None => {
|
|
|
|
// this really should never happen unless the block passed
|
|
|
|
// hasn't got a parent in the database.
|
2019-07-04 18:03:22 +02:00
|
|
|
warn!(target: "engine", "No genesis transition found. Block hash {} does not have a parent in the DB", hash);
|
2017-06-28 13:17:36 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// extract other epoch set if it's not the same as the last.
|
|
|
|
if last_transition.block_hash != self.epoch_transition_hash {
|
|
|
|
let (signal_number, set_proof, _) = destructure_proofs(&last_transition.proof)
|
|
|
|
.expect("proof produced by this engine; therefore it is valid; qed");
|
|
|
|
|
2019-06-25 13:15:00 +02:00
|
|
|
trace!(target: "engine", "extracting epoch validator set for epoch ({}, {}) signalled at #{}",
|
2017-06-28 13:17:36 +02:00
|
|
|
last_transition.block_number, last_transition.block_hash, signal_number);
|
|
|
|
|
|
|
|
let first = signal_number == 0;
|
|
|
|
let epoch_set = validators.epoch_set(
|
|
|
|
first,
|
2017-09-26 14:19:08 +02:00
|
|
|
machine,
|
2017-06-28 13:17:36 +02:00
|
|
|
signal_number, // use signal number so multi-set first calculation is correct.
|
|
|
|
set_proof,
|
|
|
|
)
|
|
|
|
.ok()
|
2019-06-25 13:15:00 +02:00
|
|
|
.map(|(list, _)| {
|
|
|
|
trace!(target: "engine", "Updating finality checker with new validator set extracted from epoch ({}, {}): {:?}",
|
2019-07-18 12:27:08 +02:00
|
|
|
last_transition.block_number, last_transition.block_hash, &list);
|
2019-06-25 13:15:00 +02:00
|
|
|
|
|
|
|
list.into_inner()
|
|
|
|
})
|
2017-06-28 13:17:36 +02:00
|
|
|
.expect("proof produced by this engine; therefore it is valid; qed");
|
|
|
|
|
2019-08-21 14:55:51 +02:00
|
|
|
let two_thirds_majority_transition = self.finality_checker.two_thirds_majority_transition();
|
|
|
|
self.finality_checker = RollingFinality::blank(epoch_set, two_thirds_majority_transition);
|
2017-06-28 13:17:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
self.epoch_transition_hash = last_transition.block_hash;
|
|
|
|
self.epoch_transition_number = last_transition.block_number;
|
|
|
|
|
|
|
|
true
|
|
|
|
}
|
|
|
|
|
2019-06-10 18:58:14 +02:00
|
|
|
// Note new epoch hash. This will force the next block to re-load
|
|
|
|
// the epoch set.
|
2017-06-28 13:17:36 +02:00
|
|
|
// TODO: optimize and don't require re-loading after epoch change.
|
|
|
|
fn note_new_epoch(&mut self) {
|
|
|
|
self.force = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get validator set. Zoom to the correct epoch first.
|
|
|
|
fn validators(&self) -> &SimpleList {
|
|
|
|
self.finality_checker.validators()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
/// 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.
|
2018-11-21 22:30:03 +01:00
|
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
2018-02-15 01:39:29 +01:00
|
|
|
struct EmptyStep {
|
|
|
|
signature: H520,
|
2018-11-21 22:30:03 +01:00
|
|
|
step: u64,
|
2018-02-15 01:39:29 +01:00
|
|
|
parent_hash: H256,
|
|
|
|
}
|
|
|
|
|
2018-11-21 22:30:03 +01:00
|
|
|
impl PartialOrd for EmptyStep {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Ord for EmptyStep {
|
|
|
|
fn cmp(&self, other: &Self) -> cmp::Ordering {
|
|
|
|
self.step.cmp(&other.step)
|
|
|
|
.then_with(|| self.parent_hash.cmp(&other.parent_hash))
|
|
|
|
.then_with(|| self.signature.cmp(&other.signature))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
impl EmptyStep {
|
|
|
|
fn from_sealed(sealed_empty_step: SealedEmptyStep, parent_hash: &H256) -> EmptyStep {
|
|
|
|
let signature = sealed_empty_step.signature;
|
|
|
|
let step = sealed_empty_step.step;
|
|
|
|
let parent_hash = parent_hash.clone();
|
|
|
|
EmptyStep { signature, step, parent_hash }
|
|
|
|
}
|
|
|
|
|
2019-06-14 18:48:35 +02:00
|
|
|
fn verify(&self, validators: &dyn ValidatorSet) -> Result<bool, Error> {
|
2018-02-15 01:39:29 +01:00
|
|
|
let message = keccak(empty_step_rlp(self.step, &self.parent_hash));
|
|
|
|
let correct_proposer = step_proposer(validators, &self.parent_hash, self.step);
|
|
|
|
|
2019-10-23 13:03:46 +02:00
|
|
|
parity_crypto::publickey::verify_address(&correct_proposer, &self.signature.into(), &message)
|
2018-02-15 01:39:29 +01:00
|
|
|
.map_err(|e| e.into())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn author(&self) -> Result<Address, Error> {
|
|
|
|
let message = keccak(empty_step_rlp(self.step, &self.parent_hash));
|
2019-10-23 13:03:46 +02:00
|
|
|
let public = parity_crypto::publickey::recover(&self.signature.into(), &message)?;
|
|
|
|
Ok(parity_crypto::publickey::public_to_address(&public))
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn sealed(&self) -> SealedEmptyStep {
|
|
|
|
let signature = self.signature;
|
|
|
|
let step = self.step;
|
|
|
|
SealedEmptyStep { signature, step }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for EmptyStep {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
2018-10-15 18:05:53 +02:00
|
|
|
write!(f, "({:x}, {}, {:x})", self.signature, self.step, self.parent_hash)
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Encodable for EmptyStep {
|
|
|
|
fn rlp_append(&self, s: &mut RlpStream) {
|
|
|
|
let empty_step_rlp = empty_step_rlp(self.step, &self.parent_hash);
|
|
|
|
s.begin_list(2)
|
|
|
|
.append(&self.signature)
|
|
|
|
.append_raw(&empty_step_rlp, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Decodable for EmptyStep {
|
2018-04-16 15:52:12 +02:00
|
|
|
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
2018-02-15 01:39:29 +01:00
|
|
|
let signature = rlp.val_at(0)?;
|
|
|
|
let empty_step_rlp = rlp.at(1)?;
|
|
|
|
|
|
|
|
let step = empty_step_rlp.val_at(0)?;
|
|
|
|
let parent_hash = empty_step_rlp.val_at(1)?;
|
|
|
|
|
|
|
|
Ok(EmptyStep { signature, step, parent_hash })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn empty_step_full_rlp(signature: &H520, empty_step_rlp: &[u8]) -> Vec<u8> {
|
|
|
|
let mut s = RlpStream::new_list(2);
|
|
|
|
s.append(signature).append_raw(empty_step_rlp, 1);
|
|
|
|
s.out()
|
|
|
|
}
|
|
|
|
|
2018-11-21 22:30:03 +01:00
|
|
|
pub fn empty_step_rlp(step: u64, parent_hash: &H256) -> Vec<u8> {
|
2018-02-15 01:39:29 +01:00
|
|
|
let mut s = RlpStream::new_list(2);
|
|
|
|
s.append(&step).append(parent_hash);
|
|
|
|
s.out()
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An empty step message that is included in a seal, the only difference is that it doesn't include
|
|
|
|
/// the `parent_hash` in order to save space. The included signature is of the original empty step
|
|
|
|
/// message, which can be reconstructed by using the parent hash of the block in which this sealed
|
|
|
|
/// empty message is included.
|
|
|
|
struct SealedEmptyStep {
|
|
|
|
signature: H520,
|
2018-11-21 22:30:03 +01:00
|
|
|
step: u64,
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Encodable for SealedEmptyStep {
|
|
|
|
fn rlp_append(&self, s: &mut RlpStream) {
|
|
|
|
s.begin_list(2)
|
|
|
|
.append(&self.signature)
|
|
|
|
.append(&self.step);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Decodable for SealedEmptyStep {
|
2018-04-16 15:52:12 +02:00
|
|
|
fn decode(rlp: &Rlp) -> Result<Self, DecoderError> {
|
2018-02-15 01:39:29 +01:00
|
|
|
let signature = rlp.val_at(0)?;
|
|
|
|
let step = rlp.val_at(1)?;
|
|
|
|
|
|
|
|
Ok(SealedEmptyStep { signature, step })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-08 16:30:44 +02:00
|
|
|
struct PermissionedStep {
|
|
|
|
inner: Step,
|
|
|
|
can_propose: AtomicBool,
|
|
|
|
}
|
|
|
|
|
2017-04-13 20:24:21 +02:00
|
|
|
/// Engine using `AuthorityRound` proof-of-authority BFT consensus.
|
2016-09-08 12:12:24 +02:00
|
|
|
pub struct AuthorityRound {
|
2016-12-07 14:49:07 +01:00
|
|
|
transition_service: IoService<()>,
|
2018-06-08 16:30:44 +02:00
|
|
|
step: Arc<PermissionedStep>,
|
2019-06-14 18:48:35 +02:00
|
|
|
client: Arc<RwLock<Option<Weak<dyn EngineClient>>>>,
|
|
|
|
signer: RwLock<Option<Box<dyn EngineSigner>>>,
|
|
|
|
validators: Box<dyn ValidatorSet>,
|
2017-03-28 10:46:52 +02:00
|
|
|
validate_score_transition: u64,
|
2017-05-15 22:34:01 +02:00
|
|
|
validate_step_transition: u64,
|
2018-11-21 22:30:03 +01:00
|
|
|
empty_steps: Mutex<BTreeSet<EmptyStep>>,
|
2017-06-28 13:17:36 +02:00
|
|
|
epoch_manager: Mutex<EpochManager>,
|
|
|
|
immediate_transitions: bool,
|
2017-09-26 14:19:08 +02:00
|
|
|
block_reward: U256,
|
2019-08-22 10:45:24 +02:00
|
|
|
block_reward_contract_transitions: BTreeMap<u64, BlockRewardContract>,
|
2017-12-05 15:57:45 +01:00
|
|
|
maximum_uncle_count_transition: u64,
|
2017-11-10 00:56:02 +01:00
|
|
|
maximum_uncle_count: usize,
|
2018-02-15 01:39:29 +01:00
|
|
|
empty_steps_transition: u64,
|
2018-12-10 19:58:38 +01:00
|
|
|
strict_empty_steps_transition: u64,
|
2019-08-21 14:55:51 +02:00
|
|
|
two_thirds_majority_transition: BlockNumber,
|
2018-02-15 01:39:29 +01:00
|
|
|
maximum_empty_steps: usize,
|
2019-06-26 14:16:05 +02:00
|
|
|
machine: Machine,
|
2019-10-14 12:56:38 +02:00
|
|
|
/// History of step hashes recently received from peers.
|
|
|
|
received_step_hashes: RwLock<BTreeMap<(u64, Address), H256>>,
|
2016-10-15 14:55:10 +02:00
|
|
|
}
|
|
|
|
|
2017-04-13 20:24:21 +02:00
|
|
|
// header-chain validator.
|
2017-04-18 14:19:10 +02:00
|
|
|
struct EpochVerifier {
|
2018-06-08 16:30:44 +02:00
|
|
|
step: Arc<PermissionedStep>,
|
2017-04-13 20:24:21 +02:00
|
|
|
subchain_validators: SimpleList,
|
2018-02-15 01:39:29 +01:00
|
|
|
empty_steps_transition: u64,
|
2019-08-21 14:55:51 +02:00
|
|
|
/// First block for which a 2/3 quorum (instead of 1/2) is required.
|
|
|
|
two_thirds_majority_transition: BlockNumber,
|
2017-04-13 20:24:21 +02:00
|
|
|
}
|
|
|
|
|
2019-08-15 17:59:22 +02:00
|
|
|
impl engine::EpochVerifier for EpochVerifier {
|
2017-04-13 20:24:21 +02:00
|
|
|
fn verify_light(&self, header: &Header) -> Result<(), Error> {
|
2018-01-19 10:38:59 +01:00
|
|
|
// Validate the timestamp
|
2018-06-08 16:30:44 +02:00
|
|
|
verify_timestamp(&self.step.inner, header_step(header, self.empty_steps_transition)?)?;
|
2017-04-13 20:24:21 +02:00
|
|
|
// always check the seal since it's fast.
|
|
|
|
// nothing heavier to do.
|
2018-02-15 01:39:29 +01:00
|
|
|
verify_external(header, &self.subchain_validators, self.empty_steps_transition)
|
2017-06-28 13:17:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn check_finality_proof(&self, proof: &[u8]) -> Option<Vec<H256>> {
|
2019-08-21 14:55:51 +02:00
|
|
|
let signers = self.subchain_validators.clone().into_inner();
|
|
|
|
let mut finality_checker = RollingFinality::blank(signers, self.two_thirds_majority_transition);
|
2017-06-28 13:17:36 +02:00
|
|
|
let mut finalized = Vec::new();
|
|
|
|
|
2018-04-16 15:52:12 +02:00
|
|
|
let headers: Vec<Header> = Rlp::new(proof).as_list().ok()?;
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
{
|
|
|
|
let mut push_header = |parent_header: &Header, header: Option<&Header>| {
|
|
|
|
// ensure all headers have correct number of seal fields so we can `verify_external`
|
|
|
|
// and get `empty_steps` without panic.
|
|
|
|
if parent_header.seal().len() != header_expected_seal_fields(parent_header, self.empty_steps_transition) {
|
|
|
|
return None
|
|
|
|
}
|
|
|
|
if header.iter().any(|h| h.seal().len() != header_expected_seal_fields(h, self.empty_steps_transition)) {
|
|
|
|
return None
|
|
|
|
}
|
|
|
|
|
|
|
|
// `verify_external` checks that signature is correct and author == signer.
|
2018-02-16 16:37:12 +01:00
|
|
|
verify_external(parent_header, &self.subchain_validators, self.empty_steps_transition).ok()?;
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
let mut signers = match header {
|
2018-02-16 16:37:12 +01:00
|
|
|
Some(header) => header_empty_steps_signers(header, self.empty_steps_transition).ok()?,
|
2018-02-15 01:39:29 +01:00
|
|
|
_ => Vec::new(),
|
|
|
|
};
|
2018-10-25 17:33:41 +02:00
|
|
|
signers.push(*parent_header.author());
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2019-08-21 14:55:51 +02:00
|
|
|
let newly_finalized =
|
|
|
|
finality_checker.push_hash(parent_header.hash(), parent_header.number(), signers).ok()?;
|
2018-02-15 01:39:29 +01:00
|
|
|
finalized.extend(newly_finalized);
|
|
|
|
|
|
|
|
Some(())
|
|
|
|
};
|
|
|
|
|
|
|
|
for window in headers.windows(2) {
|
2018-02-16 16:37:12 +01:00
|
|
|
push_header(&window[0], Some(&window[1]))?;
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(last) = headers.last() {
|
2018-02-16 16:37:12 +01:00
|
|
|
push_header(last, None)?;
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
2017-06-28 13:17:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if finalized.is_empty() { None } else { Some(finalized) }
|
2017-04-13 20:24:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
fn header_seal_hash(header: &Header, empty_steps_rlp: Option<&[u8]>) -> H256 {
|
|
|
|
match empty_steps_rlp {
|
|
|
|
Some(empty_steps_rlp) => {
|
2019-06-03 15:36:21 +02:00
|
|
|
let mut message = header.bare_hash().as_bytes().to_vec();
|
2018-02-15 01:39:29 +01:00
|
|
|
message.extend_from_slice(empty_steps_rlp);
|
|
|
|
keccak(message)
|
|
|
|
},
|
|
|
|
None => {
|
|
|
|
header.bare_hash()
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn header_expected_seal_fields(header: &Header, empty_steps_transition: u64) -> usize {
|
|
|
|
if header.number() >= empty_steps_transition {
|
|
|
|
3
|
|
|
|
} else {
|
|
|
|
2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-21 22:30:03 +01:00
|
|
|
fn header_step(header: &Header, empty_steps_transition: u64) -> Result<u64, ::rlp::DecoderError> {
|
2019-03-06 15:30:35 +01:00
|
|
|
Rlp::new(&header.seal().get(0).unwrap_or_else(||
|
2019-10-14 12:56:38 +02:00
|
|
|
panic!("was either checked with verify_block_basic or is genesis; has {} fields; qed (Make sure the spec \
|
2019-03-06 15:30:35 +01:00
|
|
|
file has a correct genesis seal)", header_expected_seal_fields(header, empty_steps_transition))
|
|
|
|
))
|
|
|
|
.as_val()
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn header_signature(header: &Header, empty_steps_transition: u64) -> Result<Signature, ::rlp::DecoderError> {
|
2019-03-06 15:30:35 +01:00
|
|
|
Rlp::new(&header.seal().get(1).unwrap_or_else(||
|
|
|
|
panic!("was checked with verify_block_basic; has {} fields; qed",
|
2019-07-18 12:27:08 +02:00
|
|
|
header_expected_seal_fields(header, empty_steps_transition))
|
2019-03-06 15:30:35 +01:00
|
|
|
))
|
|
|
|
.as_val::<H520>().map(Into::into)
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// extracts the raw empty steps vec from the header seal. should only be called when there are 3 fields in the seal
|
|
|
|
// (i.e. header.number() >= self.empty_steps_transition)
|
|
|
|
fn header_empty_steps_raw(header: &Header) -> &[u8] {
|
|
|
|
header.seal().get(2).expect("was checked with verify_block_basic; has 3 fields; qed")
|
2016-11-02 18:42:56 +01:00
|
|
|
}
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
// extracts the empty steps from the header seal. should only be called when there are 3 fields in the seal
|
|
|
|
// (i.e. header.number() >= self.empty_steps_transition).
|
|
|
|
fn header_empty_steps(header: &Header) -> Result<Vec<EmptyStep>, ::rlp::DecoderError> {
|
2018-04-16 15:52:12 +02:00
|
|
|
let empty_steps = Rlp::new(header_empty_steps_raw(header)).as_list::<SealedEmptyStep>()?;
|
2018-02-15 01:39:29 +01:00
|
|
|
Ok(empty_steps.into_iter().map(|s| EmptyStep::from_sealed(s, header.parent_hash())).collect())
|
|
|
|
}
|
|
|
|
|
|
|
|
// gets the signers of empty step messages for the given header, does not include repeated signers
|
|
|
|
fn header_empty_steps_signers(header: &Header, empty_steps_transition: u64) -> Result<Vec<Address>, Error> {
|
|
|
|
if header.number() >= empty_steps_transition {
|
|
|
|
let mut signers = HashSet::new();
|
|
|
|
for empty_step in header_empty_steps(header)? {
|
|
|
|
signers.insert(empty_step.author()?);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(Vec::from_iter(signers.into_iter()))
|
|
|
|
} else {
|
|
|
|
Ok(Vec::new())
|
|
|
|
}
|
2016-11-14 16:56:19 +01:00
|
|
|
}
|
2016-11-02 18:42:56 +01:00
|
|
|
|
2019-06-14 18:48:35 +02:00
|
|
|
fn step_proposer(validators: &dyn ValidatorSet, bh: &H256, step: u64) -> Address {
|
2018-11-21 22:30:03 +01:00
|
|
|
let proposer = validators.get(bh, step as usize);
|
2019-07-04 18:03:22 +02:00
|
|
|
trace!(target: "engine", "step_proposer: Fetched proposer for step {}: {}", step, proposer);
|
2017-06-28 13:17:36 +02:00
|
|
|
proposer
|
|
|
|
}
|
|
|
|
|
2019-06-14 18:48:35 +02:00
|
|
|
fn is_step_proposer(validators: &dyn ValidatorSet, bh: &H256, step: u64, address: &Address) -> bool {
|
2017-06-28 13:17:36 +02:00
|
|
|
step_proposer(validators, bh, step) == *address
|
|
|
|
}
|
|
|
|
|
2018-11-21 22:30:03 +01:00
|
|
|
fn verify_timestamp(step: &Step, header_step: u64) -> Result<(), BlockError> {
|
2017-12-21 15:01:05 +01:00
|
|
|
match step.check_future(header_step) {
|
|
|
|
Err(None) => {
|
2018-01-19 10:38:59 +01:00
|
|
|
trace!(target: "engine", "verify_timestamp: block from the future");
|
|
|
|
Err(BlockError::InvalidSeal.into())
|
2017-12-21 15:01:05 +01:00
|
|
|
},
|
|
|
|
Err(Some(oob)) => {
|
2018-01-19 10:38:59 +01:00
|
|
|
// NOTE This error might be returned only in early stage of verification (Stage 1).
|
|
|
|
// Returning it further won't recover the sync process.
|
|
|
|
trace!(target: "engine", "verify_timestamp: block too early");
|
2019-03-19 23:17:05 +01:00
|
|
|
|
2019-06-20 09:00:50 +02:00
|
|
|
let found = CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(oob.found))
|
|
|
|
.ok_or(BlockError::TimestampOverflow)?;
|
|
|
|
let max = oob.max.and_then(|m| CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(m)));
|
|
|
|
let min = oob.min.and_then(|m| CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(m)));
|
2019-03-19 23:17:05 +01:00
|
|
|
|
|
|
|
let new_oob = OutOfBounds { min, max, found };
|
|
|
|
|
2019-05-06 15:06:20 +02:00
|
|
|
Err(BlockError::TemporarilyInvalid(new_oob.into()))
|
2017-12-21 15:01:05 +01:00
|
|
|
},
|
2018-01-19 10:38:59 +01:00
|
|
|
Ok(_) => Ok(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-14 18:48:35 +02:00
|
|
|
fn verify_external(header: &Header, validators: &dyn ValidatorSet, empty_steps_transition: u64) -> Result<(), Error> {
|
2018-02-15 01:39:29 +01:00
|
|
|
let header_step = header_step(header, empty_steps_transition)?;
|
2018-01-19 10:38:59 +01:00
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
let proposer_signature = header_signature(header, empty_steps_transition)?;
|
2018-11-21 22:30:03 +01:00
|
|
|
let correct_proposer = validators.get(header.parent_hash(), header_step as usize);
|
2018-02-15 01:39:29 +01:00
|
|
|
let is_invalid_proposer = *header.author() != correct_proposer || {
|
|
|
|
let empty_steps_rlp = if header.number() >= empty_steps_transition {
|
|
|
|
Some(header_empty_steps_raw(header))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
let header_seal_hash = header_seal_hash(header, empty_steps_rlp);
|
2019-10-23 13:03:46 +02:00
|
|
|
!parity_crypto::publickey::verify_address(&correct_proposer, &proposer_signature, &header_seal_hash)?
|
2018-02-15 01:39:29 +01:00
|
|
|
};
|
2018-01-19 10:38:59 +01:00
|
|
|
|
|
|
|
if is_invalid_proposer {
|
2019-06-10 18:58:14 +02:00
|
|
|
warn!(target: "engine", "verify_block_external: bad proposer for step: {}", header_step);
|
2018-10-25 17:33:41 +02:00
|
|
|
Err(EngineError::NotProposer(Mismatch { expected: correct_proposer, found: *header.author() }))?
|
2018-01-19 10:38:59 +01:00
|
|
|
} else {
|
|
|
|
Ok(())
|
2017-04-13 20:24:21 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-28 13:17:36 +02:00
|
|
|
fn combine_proofs(signal_number: BlockNumber, set_proof: &[u8], finality_proof: &[u8]) -> Vec<u8> {
|
|
|
|
let mut stream = ::rlp::RlpStream::new_list(3);
|
|
|
|
stream.append(&signal_number).append(&set_proof).append(&finality_proof);
|
|
|
|
stream.out()
|
|
|
|
}
|
|
|
|
|
2019-03-19 23:17:05 +01:00
|
|
|
|
2017-06-28 13:17:36 +02:00
|
|
|
fn destructure_proofs(combined: &[u8]) -> Result<(BlockNumber, &[u8], &[u8]), Error> {
|
2018-04-16 15:52:12 +02:00
|
|
|
let rlp = Rlp::new(combined);
|
2017-06-28 13:17:36 +02:00
|
|
|
Ok((
|
|
|
|
rlp.at(0)?.as_val()?,
|
|
|
|
rlp.at(1)?.data()?,
|
|
|
|
rlp.at(2)?.data()?,
|
|
|
|
))
|
|
|
|
}
|
|
|
|
|
2016-10-15 14:55:10 +02:00
|
|
|
trait AsMillis {
|
|
|
|
fn as_millis(&self) -> u64;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsMillis for Duration {
|
|
|
|
fn as_millis(&self) -> u64 {
|
2019-03-19 23:17:05 +01:00
|
|
|
self.as_secs() * 1_000 + (self.subsec_nanos() / 1_000_000) as u64
|
2016-10-15 14:55:10 +02:00
|
|
|
}
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
|
2018-07-06 11:43:58 +02:00
|
|
|
// A type for storing owned or borrowed data that has a common type.
|
|
|
|
// Useful for returning either a borrow or owned data from a function.
|
|
|
|
enum CowLike<'a, A: 'a + ?Sized, B> {
|
|
|
|
Borrowed(&'a A),
|
|
|
|
Owned(B),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, A: ?Sized, B> Deref for CowLike<'a, A, B> where B: AsRef<A> {
|
|
|
|
type Target = A;
|
|
|
|
fn deref(&self) -> &A {
|
|
|
|
match self {
|
|
|
|
CowLike::Borrowed(b) => b,
|
|
|
|
CowLike::Owned(o) => o.as_ref(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-08 12:12:24 +02:00
|
|
|
impl AuthorityRound {
|
2016-10-15 14:55:10 +02:00
|
|
|
/// Create a new instance of AuthorityRound engine.
|
2019-06-26 14:16:05 +02:00
|
|
|
pub fn new(our_params: AuthorityRoundParams, machine: Machine) -> Result<Arc<Self>, Error> {
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
if our_params.step_duration == 0 {
|
|
|
|
error!(target: "engine", "Authority Round step duration can't be zero, aborting");
|
|
|
|
panic!("authority_round: step duration can't be zero")
|
|
|
|
}
|
2016-12-15 23:36:06 +01:00
|
|
|
let should_timeout = our_params.start_step.is_none();
|
2018-11-21 22:30:03 +01:00
|
|
|
let initial_step = our_params.start_step.unwrap_or_else(|| (unix_now().as_secs() / (our_params.step_duration as u64)));
|
2016-09-08 12:12:24 +02:00
|
|
|
let engine = Arc::new(
|
|
|
|
AuthorityRound {
|
2016-12-27 12:53:56 +01:00
|
|
|
transition_service: IoService::<()>::start()?,
|
2018-06-08 16:30:44 +02:00
|
|
|
step: Arc::new(PermissionedStep {
|
|
|
|
inner: Step {
|
2018-11-21 22:30:03 +01:00
|
|
|
inner: AtomicUsize::new(initial_step as usize),
|
2018-06-08 16:30:44 +02:00
|
|
|
calibrate: our_params.start_step.is_none(),
|
|
|
|
duration: our_params.step_duration,
|
|
|
|
},
|
|
|
|
can_propose: AtomicBool::new(true),
|
2017-04-13 20:24:21 +02:00
|
|
|
}),
|
2018-06-08 16:30:44 +02:00
|
|
|
client: Arc::new(RwLock::new(None)),
|
2019-02-07 14:34:24 +01:00
|
|
|
signer: RwLock::new(None),
|
2017-05-22 08:21:34 +02:00
|
|
|
validators: our_params.validators,
|
2017-03-28 10:46:52 +02:00
|
|
|
validate_score_transition: our_params.validate_score_transition,
|
2017-05-15 22:34:01 +02:00
|
|
|
validate_step_transition: our_params.validate_step_transition,
|
2018-11-21 22:30:03 +01:00
|
|
|
empty_steps: Default::default(),
|
2019-08-21 14:55:51 +02:00
|
|
|
epoch_manager: Mutex::new(EpochManager::blank(our_params.two_thirds_majority_transition)),
|
2017-06-28 13:17:36 +02:00
|
|
|
immediate_transitions: our_params.immediate_transitions,
|
2017-09-26 14:19:08 +02:00
|
|
|
block_reward: our_params.block_reward,
|
2019-08-22 10:45:24 +02:00
|
|
|
block_reward_contract_transitions: our_params.block_reward_contract_transitions,
|
2017-12-05 15:57:45 +01:00
|
|
|
maximum_uncle_count_transition: our_params.maximum_uncle_count_transition,
|
2017-11-10 00:56:02 +01:00
|
|
|
maximum_uncle_count: our_params.maximum_uncle_count,
|
2018-02-15 01:39:29 +01:00
|
|
|
empty_steps_transition: our_params.empty_steps_transition,
|
|
|
|
maximum_empty_steps: our_params.maximum_empty_steps,
|
2019-08-21 14:55:51 +02:00
|
|
|
two_thirds_majority_transition: our_params.two_thirds_majority_transition,
|
2018-12-10 19:58:38 +01:00
|
|
|
strict_empty_steps_transition: our_params.strict_empty_steps_transition,
|
2019-06-25 13:15:00 +02:00
|
|
|
machine,
|
2019-10-14 12:56:38 +02:00
|
|
|
received_step_hashes: RwLock::new(Default::default()),
|
2016-09-08 12:12:24 +02:00
|
|
|
});
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2016-12-15 23:36:06 +01:00
|
|
|
// Do not initialize timeouts for tests.
|
|
|
|
if should_timeout {
|
2018-06-08 16:30:44 +02:00
|
|
|
let handler = TransitionHandler {
|
|
|
|
step: engine.step.clone(),
|
|
|
|
client: engine.client.clone(),
|
|
|
|
};
|
2016-12-27 12:53:56 +01:00
|
|
|
engine.transition_service.register_handler(Arc::new(handler))?;
|
2016-12-15 23:36:06 +01:00
|
|
|
}
|
2016-11-14 18:42:56 +01:00
|
|
|
Ok(engine)
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
2018-02-15 01:39:29 +01:00
|
|
|
|
2018-07-06 11:43:58 +02:00
|
|
|
// fetch correct validator set for epoch at header, taking into account
|
|
|
|
// finality of previous transitions.
|
2019-06-14 18:48:35 +02:00
|
|
|
fn epoch_set<'a>(&'a self, header: &Header) -> Result<(CowLike<dyn ValidatorSet, SimpleList>, BlockNumber), Error> {
|
2018-07-06 11:43:58 +02:00
|
|
|
Ok(if self.immediate_transitions {
|
|
|
|
(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())
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-05-24 10:30:31 +02:00
|
|
|
if !epoch_manager.zoom_to_after(&*client, &self.machine, &*self.validators, *header.parent_hash()) {
|
2018-07-06 11:43:58 +02:00
|
|
|
debug!(target: "engine", "Unable to zoom to epoch.");
|
2019-06-25 13:15:00 +02:00
|
|
|
return Err(EngineError::MissingParent(*header.parent_hash()).into())
|
2018-07-06 11:43:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
(CowLike::Owned(epoch_manager.validators().clone()), epoch_manager.epoch_transition_number)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-11-21 22:30:03 +01:00
|
|
|
fn empty_steps(&self, from_step: u64, to_step: u64, parent_hash: H256) -> Vec<EmptyStep> {
|
|
|
|
let from = EmptyStep {
|
|
|
|
step: from_step + 1,
|
|
|
|
parent_hash,
|
|
|
|
signature: Default::default(),
|
|
|
|
};
|
|
|
|
let to = EmptyStep {
|
|
|
|
step: to_step,
|
|
|
|
parent_hash: Default::default(),
|
|
|
|
signature: Default::default(),
|
|
|
|
};
|
|
|
|
|
|
|
|
if from >= to {
|
|
|
|
return vec![];
|
|
|
|
}
|
|
|
|
|
|
|
|
self.empty_steps.lock()
|
|
|
|
.range(from..to)
|
|
|
|
.filter(|e| e.parent_hash == parent_hash)
|
|
|
|
.cloned()
|
|
|
|
.collect()
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
|
2018-11-21 22:30:03 +01:00
|
|
|
fn clear_empty_steps(&self, step: u64) {
|
2018-02-15 01:39:29 +01:00
|
|
|
// clear old `empty_steps` messages
|
2018-11-21 22:30:03 +01:00
|
|
|
let mut empty_steps = self.empty_steps.lock();
|
|
|
|
*empty_steps = empty_steps.split_off(&EmptyStep {
|
|
|
|
step: step + 1,
|
|
|
|
parent_hash: Default::default(),
|
|
|
|
signature: Default::default(),
|
|
|
|
});
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn handle_empty_step_message(&self, empty_step: EmptyStep) {
|
2018-11-21 22:30:03 +01:00
|
|
|
self.empty_steps.lock().insert(empty_step);
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn generate_empty_step(&self, parent_hash: &H256) {
|
2018-06-08 16:30:44 +02:00
|
|
|
let step = self.step.inner.load();
|
2018-02-15 01:39:29 +01:00
|
|
|
let empty_step_rlp = empty_step_rlp(step, parent_hash);
|
|
|
|
|
|
|
|
if let Ok(signature) = self.sign(keccak(&empty_step_rlp)).map(Into::into) {
|
|
|
|
let message_rlp = empty_step_full_rlp(&signature, &empty_step_rlp);
|
|
|
|
|
|
|
|
let parent_hash = *parent_hash;
|
|
|
|
let empty_step = EmptyStep { signature, step, parent_hash };
|
|
|
|
|
|
|
|
trace!(target: "engine", "broadcasting empty step message: {:?}", empty_step);
|
|
|
|
self.broadcast_message(message_rlp);
|
|
|
|
self.handle_empty_step_message(empty_step);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
warn!(target: "engine", "generate_empty_step: FAIL: accounts secret key unavailable");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-07-06 11:43:58 +02:00
|
|
|
|
2019-06-14 18:48:35 +02:00
|
|
|
fn report_skipped(&self, header: &Header, current_step: u64, parent_step: u64, validators: &dyn ValidatorSet, set_number: u64) {
|
2018-07-06 11:43:58 +02:00
|
|
|
// we're building on top of the genesis block so don't report any skipped steps
|
|
|
|
if header.number() == 1 {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-06-25 13:15:00 +02:00
|
|
|
if let (true, Some(me)) = (current_step > parent_step + 1, self.address()) {
|
2018-07-06 11:43:58 +02:00
|
|
|
debug!(target: "engine", "Author {} built block with step gap. current step: {}, parent step: {}",
|
2019-07-18 12:27:08 +02:00
|
|
|
header.author(), current_step, parent_step);
|
2018-07-06 11:43:58 +02:00
|
|
|
let mut reported = HashSet::new();
|
|
|
|
for step in parent_step + 1..current_step {
|
|
|
|
let skipped_primary = step_proposer(validators, header.parent_hash(), step);
|
|
|
|
// Do not report this signer.
|
|
|
|
if skipped_primary != me {
|
|
|
|
// Stop reporting once validators start repeating.
|
|
|
|
if !reported.insert(skipped_primary) { break; }
|
2019-07-04 18:03:22 +02:00
|
|
|
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);
|
2018-07-06 11:43:58 +02:00
|
|
|
self.validators.report_benign(&skipped_primary, set_number, header.number());
|
2019-06-25 13:15:00 +02:00
|
|
|
} else {
|
|
|
|
trace!(target: "engine", "Primary that skipped is self, not self-reporting. Own address: {}", me);
|
|
|
|
}
|
|
|
|
}
|
2018-07-06 11:43:58 +02:00
|
|
|
}
|
|
|
|
}
|
2018-10-25 17:33:41 +02:00
|
|
|
|
|
|
|
// Returns the hashes of all ancestor blocks that are finalized by the given `chain_head`.
|
2019-06-14 18:48:35 +02:00
|
|
|
fn build_finality(&self, chain_head: &Header, ancestry: &mut dyn Iterator<Item=Header>) -> Vec<H256> {
|
2018-10-25 17:33:41 +02:00
|
|
|
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 mut epoch_manager = self.epoch_manager.lock();
|
2019-05-24 10:30:31 +02:00
|
|
|
if !epoch_manager.zoom_to_after(&*client, &self.machine, &*self.validators, *chain_head.parent_hash()) {
|
2018-10-25 17:33:41 +02:00
|
|
|
return Vec::new();
|
|
|
|
}
|
|
|
|
|
|
|
|
if epoch_manager.finality_checker.subchain_head() != Some(*chain_head.parent_hash()) {
|
|
|
|
// build new finality checker from unfinalized ancestry of chain head, not including chain head itself yet.
|
|
|
|
trace!(target: "finality", "Building finality up to parent of {} ({})",
|
2019-07-18 12:27:08 +02:00
|
|
|
chain_head.hash(), chain_head.parent_hash());
|
2018-10-25 17:33:41 +02:00
|
|
|
|
|
|
|
// the empty steps messages in a header signal approval of the
|
|
|
|
// parent header.
|
|
|
|
let mut parent_empty_steps_signers = match header_empty_steps_signers(&chain_head, self.empty_steps_transition) {
|
|
|
|
Ok(empty_step_signers) => empty_step_signers,
|
|
|
|
Err(_) => {
|
|
|
|
warn!(target: "finality", "Failed to get empty step signatures from block {}", chain_head.hash());
|
|
|
|
return Vec::new();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2018-11-14 13:05:49 +01:00
|
|
|
let epoch_transition_hash = epoch_manager.epoch_transition_hash;
|
2018-10-25 17:33:41 +02:00
|
|
|
let ancestry_iter = ancestry.map(|header| {
|
|
|
|
let mut signers = vec![*header.author()];
|
|
|
|
signers.extend(parent_empty_steps_signers.drain(..));
|
|
|
|
|
|
|
|
if let Ok(empty_step_signers) = header_empty_steps_signers(&header, self.empty_steps_transition) {
|
2019-08-21 14:55:51 +02:00
|
|
|
let res = (header.hash(), header.number(), signers);
|
2018-10-25 17:33:41 +02:00
|
|
|
trace!(target: "finality", "Ancestry iteration: yielding {:?}", res);
|
|
|
|
|
|
|
|
parent_empty_steps_signers = empty_step_signers;
|
|
|
|
|
|
|
|
Some(res)
|
|
|
|
|
|
|
|
} else {
|
|
|
|
warn!(target: "finality", "Failed to get empty step signatures from block {}", header.hash());
|
|
|
|
None
|
|
|
|
}
|
|
|
|
})
|
2018-11-14 13:05:49 +01:00
|
|
|
.while_some()
|
2019-08-21 14:55:51 +02:00
|
|
|
.take_while(|&(h, _, _)| h != epoch_transition_hash);
|
2018-10-25 17:33:41 +02:00
|
|
|
|
2018-11-14 13:05:49 +01:00
|
|
|
if let Err(e) = epoch_manager.finality_checker.build_ancestry_subchain(ancestry_iter) {
|
|
|
|
debug!(target: "engine", "inconsistent validator set within epoch: {:?}", e);
|
2018-10-25 17:33:41 +02:00
|
|
|
return Vec::new();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-21 14:55:51 +02:00
|
|
|
let finalized = epoch_manager.finality_checker.push_hash(
|
|
|
|
chain_head.hash(), chain_head.number(), vec![*chain_head.author()]);
|
2018-10-25 17:33:41 +02:00
|
|
|
finalized.unwrap_or_default()
|
|
|
|
}
|
2019-06-25 13:15:00 +02:00
|
|
|
|
|
|
|
fn address(&self) -> Option<Address> {
|
|
|
|
self.signer.read().as_ref().map(|s| s.address() )
|
|
|
|
}
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
|
2016-10-15 14:55:10 +02:00
|
|
|
fn unix_now() -> Duration {
|
|
|
|
UNIX_EPOCH.elapsed().expect("Valid time has to be set in your system.")
|
|
|
|
}
|
|
|
|
|
2016-09-08 12:12:24 +02:00
|
|
|
struct TransitionHandler {
|
2018-06-08 16:30:44 +02:00
|
|
|
step: Arc<PermissionedStep>,
|
2019-06-14 18:48:35 +02:00
|
|
|
client: Arc<RwLock<Option<Weak<dyn EngineClient>>>>,
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
|
2016-11-01 19:12:06 +01:00
|
|
|
const ENGINE_TIMEOUT_TOKEN: TimerToken = 23;
|
2016-09-08 12:12:24 +02:00
|
|
|
|
2016-12-07 14:49:07 +01:00
|
|
|
impl IoHandler<()> for TransitionHandler {
|
|
|
|
fn initialize(&self, io: &IoContext<()>) {
|
2018-06-14 10:58:46 +02:00
|
|
|
let remaining = AsMillis::as_millis(&self.step.inner.duration_remaining());
|
2018-06-08 16:30:44 +02:00
|
|
|
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(remaining))
|
|
|
|
.unwrap_or_else(|e| warn!(target: "engine", "Failed to start consensus step timer: {}.", e))
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
|
2016-12-07 14:49:07 +01:00
|
|
|
fn timeout(&self, io: &IoContext<()>, timer: TimerToken) {
|
2016-09-08 12:12:24 +02:00
|
|
|
if timer == ENGINE_TIMEOUT_TOKEN {
|
2018-06-08 16:30:44 +02:00
|
|
|
// NOTE we might be lagging by couple of steps in case the timeout
|
|
|
|
// has not been called fast enough.
|
|
|
|
// Make sure to advance up to the actual step.
|
2018-06-14 10:58:46 +02:00
|
|
|
while AsMillis::as_millis(&self.step.inner.duration_remaining()) == 0 {
|
2018-06-08 16:30:44 +02:00
|
|
|
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();
|
|
|
|
}
|
2018-01-08 14:46:11 +01:00
|
|
|
}
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
2018-06-08 16:30:44 +02:00
|
|
|
|
2018-06-14 10:58:46 +02:00
|
|
|
let next_run_at = AsMillis::as_millis(&self.step.inner.duration_remaining()) >> 2;
|
2018-06-08 16:30:44 +02:00
|
|
|
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, Duration::from_millis(next_run_at))
|
|
|
|
.unwrap_or_else(|e| warn!(target: "engine", "Failed to restart consensus step timer: {}.", e))
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-26 14:16:05 +02:00
|
|
|
impl Engine for AuthorityRound {
|
2016-09-08 12:12:24 +02:00
|
|
|
fn name(&self) -> &str { "AuthorityRound" }
|
2017-03-02 12:25:55 +01:00
|
|
|
|
2019-06-26 14:16:05 +02:00
|
|
|
fn machine(&self) -> &Machine { &self.machine }
|
2017-09-26 14:19:08 +02:00
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
/// Three fields - consensus step and the corresponding proposer signature, and a list of empty
|
|
|
|
/// step messages (which should be empty if no steps are skipped)
|
|
|
|
fn seal_fields(&self, header: &Header) -> usize {
|
|
|
|
header_expected_seal_fields(header, self.empty_steps_transition)
|
|
|
|
}
|
2016-09-08 12:12:24 +02:00
|
|
|
|
2016-12-06 19:23:15 +01:00
|
|
|
fn step(&self) {
|
2018-06-08 16:30:44 +02:00
|
|
|
self.step.inner.increment();
|
|
|
|
self.step.can_propose.store(true, AtomicOrdering::SeqCst);
|
2017-01-10 12:23:59 +01:00
|
|
|
if let Some(ref weak) = *self.client.read() {
|
|
|
|
if let Some(c) = weak.upgrade() {
|
|
|
|
c.update_sealing();
|
2016-12-06 19:23:15 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-08 12:12:24 +02:00
|
|
|
/// Additional engine-specific information for the user/developer concerning `header`.
|
2016-11-15 12:10:32 +01:00
|
|
|
fn extra_info(&self, header: &Header) -> BTreeMap<String, String> {
|
2018-10-15 18:05:53 +02:00
|
|
|
if header.seal().len() < header_expected_seal_fields(header, self.empty_steps_transition) {
|
|
|
|
return BTreeMap::default();
|
|
|
|
}
|
|
|
|
|
2019-03-06 15:30:35 +01:00
|
|
|
let step = header_step(header, self.empty_steps_transition).as_ref()
|
|
|
|
.map(ToString::to_string)
|
|
|
|
.unwrap_or_default();
|
|
|
|
let signature = header_signature(header, self.empty_steps_transition).as_ref()
|
|
|
|
.map(ToString::to_string)
|
|
|
|
.unwrap_or_default();
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
let mut info = map![
|
|
|
|
"step".into() => step,
|
|
|
|
"signature".into() => signature
|
|
|
|
];
|
|
|
|
|
|
|
|
if header.number() >= self.empty_steps_transition {
|
|
|
|
let empty_steps =
|
|
|
|
if let Ok(empty_steps) = header_empty_steps(header).as_ref() {
|
|
|
|
format!("[{}]",
|
2019-07-18 12:27:08 +02:00
|
|
|
empty_steps.iter().fold(
|
|
|
|
"".to_string(),
|
|
|
|
|acc, e| if acc.len() > 0 { acc + ","} else { acc } + &e.to_string()))
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
} else {
|
|
|
|
"".into()
|
|
|
|
};
|
|
|
|
|
|
|
|
info.insert("emptySteps".into(), empty_steps);
|
|
|
|
}
|
|
|
|
|
|
|
|
info
|
2016-11-15 12:10:32 +01:00
|
|
|
}
|
2016-09-08 12:12:24 +02:00
|
|
|
|
2017-12-05 15:57:45 +01:00
|
|
|
fn maximum_uncle_count(&self, block: BlockNumber) -> usize {
|
|
|
|
if block >= self.maximum_uncle_count_transition {
|
|
|
|
self.maximum_uncle_count
|
|
|
|
} else {
|
|
|
|
// fallback to default value
|
|
|
|
2
|
|
|
|
}
|
|
|
|
}
|
2017-11-10 00:56:02 +01:00
|
|
|
|
2017-09-26 14:19:08 +02:00
|
|
|
fn populate_from_parent(&self, header: &mut Header, parent: &Header) {
|
2018-02-15 01:39:29 +01:00
|
|
|
let parent_step = header_step(parent, self.empty_steps_transition).expect("Header has been verified; qed");
|
2018-06-08 16:30:44 +02:00
|
|
|
let current_step = self.step.inner.load();
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
let current_empty_steps_len = if header.number() >= self.empty_steps_transition {
|
2018-11-21 22:30:03 +01:00
|
|
|
self.empty_steps(parent_step, current_step, parent.hash()).len()
|
2018-02-15 01:39:29 +01:00
|
|
|
} else {
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
2018-11-21 22:30:03 +01:00
|
|
|
let score = calculate_score(parent_step, current_step, current_empty_steps_len);
|
2017-12-07 12:17:11 +01:00
|
|
|
header.set_difficulty(score);
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
|
2019-05-24 10:30:31 +02:00
|
|
|
fn sealing_state(&self) -> SealingState {
|
|
|
|
let our_addr = match *self.signer.read() {
|
|
|
|
Some(ref signer) => signer.address(),
|
|
|
|
None => {
|
|
|
|
warn!(target: "engine", "Not preparing block; cannot sign.");
|
|
|
|
return SealingState::NotReady;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
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 parent = match client.as_full_client() {
|
|
|
|
Some(full_client) => full_client.best_block_header(),
|
|
|
|
None => {
|
|
|
|
debug!(target: "engine", "Not preparing block: not a full client.");
|
|
|
|
return SealingState::NotReady;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
let validators = if self.immediate_transitions {
|
|
|
|
CowLike::Borrowed(&*self.validators)
|
|
|
|
} else {
|
|
|
|
let mut epoch_manager = self.epoch_manager.lock();
|
|
|
|
if !epoch_manager.zoom_to_after(&*client, &self.machine, &*self.validators, parent.hash()) {
|
|
|
|
debug!(target: "engine", "Not preparing block: Unable to zoom to epoch.");
|
|
|
|
return SealingState::NotReady;
|
|
|
|
}
|
|
|
|
CowLike::Owned(epoch_manager.validators().clone())
|
|
|
|
};
|
|
|
|
|
|
|
|
let step = self.step.inner.load();
|
|
|
|
|
|
|
|
if !is_step_proposer(&*validators, &parent.hash(), step, &our_addr) {
|
|
|
|
trace!(target: "engine", "Not preparing block: not a proposer for step {}. (Our address: {})",
|
2019-07-18 12:27:08 +02:00
|
|
|
step, our_addr);
|
2019-05-24 10:30:31 +02:00
|
|
|
return SealingState::NotReady;
|
|
|
|
}
|
|
|
|
|
|
|
|
SealingState::Ready
|
2016-09-14 17:28:15 +02:00
|
|
|
}
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
fn handle_message(&self, rlp: &[u8]) -> Result<(), EngineError> {
|
|
|
|
fn fmt_err<T: ::std::fmt::Debug>(x: T) -> EngineError {
|
|
|
|
EngineError::MalformedMessage(format!("{:?}", x))
|
|
|
|
}
|
|
|
|
|
2018-04-16 15:52:12 +02:00
|
|
|
let rlp = Rlp::new(rlp);
|
2019-05-24 10:30:31 +02:00
|
|
|
let empty_step: EmptyStep = rlp.as_val().map_err(fmt_err)?;
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
if empty_step.verify(&*self.validators).unwrap_or(false) {
|
2018-06-08 16:30:44 +02:00
|
|
|
if self.step.inner.check_future(empty_step.step).is_ok() {
|
2018-02-15 01:39:29 +01:00
|
|
|
trace!(target: "engine", "handle_message: received empty step message {:?}", empty_step);
|
|
|
|
self.handle_empty_step_message(empty_step);
|
|
|
|
} else {
|
|
|
|
trace!(target: "engine", "handle_message: empty step message from the future {:?}", empty_step);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
trace!(target: "engine", "handle_message: received invalid step message {:?}", empty_step);
|
|
|
|
};
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-09-08 12:12:24 +02:00
|
|
|
/// Attempt to seal the block internally.
|
|
|
|
///
|
2017-07-26 17:25:32 +02:00
|
|
|
/// This operation is synchronous and may (quite reasonably) not be available, in which case
|
|
|
|
/// `Seal::None` will be returned.
|
2017-12-07 12:17:11 +01:00
|
|
|
fn generate_seal(&self, block: &ExecutedBlock, parent: &Header) -> Seal {
|
2017-06-22 20:44:04 +02:00
|
|
|
// first check to avoid generating signature most of the time
|
|
|
|
// (but there's still a race to the `compare_and_swap`)
|
2018-06-08 16:30:44 +02:00
|
|
|
if !self.step.can_propose.load(AtomicOrdering::SeqCst) {
|
2018-04-13 17:34:27 +02:00
|
|
|
trace!(target: "engine", "Aborting seal generation. Can't propose.");
|
|
|
|
return Seal::None;
|
|
|
|
}
|
2017-06-22 20:44:04 +02:00
|
|
|
|
2019-03-15 13:22:47 +01:00
|
|
|
let header = &block.header;
|
2018-11-21 22:30:03 +01:00
|
|
|
let parent_step = header_step(parent, self.empty_steps_transition)
|
|
|
|
.expect("Header has been verified; qed");
|
2017-12-07 12:17:11 +01:00
|
|
|
|
2018-06-08 16:30:44 +02:00
|
|
|
let step = self.step.inner.load();
|
2017-12-15 16:29:23 +01:00
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
// filter messages from old and future steps and different parents
|
|
|
|
let empty_steps = if header.number() >= self.empty_steps_transition {
|
2019-07-04 18:03:22 +02:00
|
|
|
self.empty_steps(parent_step, step, *header.parent_hash())
|
2018-02-15 01:39:29 +01:00
|
|
|
} else {
|
|
|
|
Vec::new()
|
|
|
|
};
|
|
|
|
|
2019-07-04 18:03:22 +02:00
|
|
|
let expected_diff = calculate_score(parent_step, step, empty_steps.len());
|
2017-12-07 12:17:11 +01:00
|
|
|
|
|
|
|
if header.difficulty() != &expected_diff {
|
2018-02-15 01:39:29 +01:00
|
|
|
debug!(target: "engine", "Aborting seal generation. The step or empty_steps have changed in the meantime. {:?} != {:?}",
|
2019-07-18 12:27:08 +02:00
|
|
|
header.difficulty(), expected_diff);
|
2018-01-08 14:46:11 +01:00
|
|
|
return Seal::None;
|
|
|
|
}
|
|
|
|
|
2019-07-04 18:03:22 +02:00
|
|
|
if parent_step > step {
|
2018-01-08 14:46:11 +01:00
|
|
|
warn!(target: "engine", "Aborting seal generation for invalid step: {} > {}", parent_step, step);
|
2017-12-07 12:17:11 +01:00
|
|
|
return Seal::None;
|
2019-07-04 18:03:22 +02:00
|
|
|
} else if parent_step == step {
|
|
|
|
// this is guarded against by `can_propose` unless the block was signed
|
|
|
|
// on the same step (implies same key) and on a different node.
|
|
|
|
warn!("Attempted to seal block on the same step as parent. Is this authority sealing with more than one node?");
|
|
|
|
return Seal::None;
|
2017-12-07 12:17:11 +01:00
|
|
|
}
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2019-07-04 18:03:22 +02:00
|
|
|
let (validators, epoch_transition_number) = match self.epoch_set(header) {
|
2018-07-06 11:43:58 +02:00
|
|
|
Err(err) => {
|
|
|
|
warn!(target: "engine", "Unable to generate seal: {}", err);
|
2017-06-28 13:17:36 +02:00
|
|
|
return Seal::None;
|
2018-07-06 11:43:58 +02:00
|
|
|
},
|
|
|
|
Ok(ok) => ok,
|
2017-06-28 13:17:36 +02:00
|
|
|
};
|
|
|
|
|
2018-07-06 11:43:58 +02:00
|
|
|
if is_step_proposer(&*validators, header.parent_hash(), step, header.author()) {
|
2019-07-04 18:03:22 +02:00
|
|
|
trace!(target: "engine", "generate_seal: we are step proposer for step={}, block=#{}", step, header.number());
|
2018-02-15 01:39:29 +01:00
|
|
|
// if there are no transactions to include in the block, we don't seal and instead broadcast a signed
|
|
|
|
// `EmptyStep(step, parent_hash)` message. If we exceed the maximum amount of `empty_step` rounds we proceed
|
|
|
|
// with the seal.
|
|
|
|
if header.number() >= self.empty_steps_transition &&
|
2019-03-15 13:22:47 +01:00
|
|
|
block.transactions.is_empty() &&
|
2018-02-15 01:39:29 +01:00
|
|
|
empty_steps.len() < self.maximum_empty_steps {
|
|
|
|
|
2018-11-21 22:30:03 +01:00
|
|
|
if self.step.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) {
|
2019-07-04 18:03:22 +02:00
|
|
|
trace!(target: "engine", "generate_seal: generating empty step at step={}, block=#{}", step, header.number());
|
2018-11-21 22:30:03 +01:00
|
|
|
self.generate_empty_step(header.parent_hash());
|
|
|
|
}
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
return Seal::None;
|
|
|
|
}
|
|
|
|
|
|
|
|
let empty_steps_rlp = if header.number() >= self.empty_steps_transition {
|
|
|
|
let empty_steps: Vec<_> = empty_steps.iter().map(|e| e.sealed()).collect();
|
2018-10-09 22:07:25 +02:00
|
|
|
Some(::rlp::encode_list(&empty_steps))
|
2018-02-15 01:39:29 +01:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
if let Ok(signature) = self.sign(header_seal_hash(header, empty_steps_rlp.as_ref().map(|e| &**e))) {
|
2017-02-02 19:11:43 +01:00
|
|
|
trace!(target: "engine", "generate_seal: Issuing a block for step {}.", step);
|
2017-06-22 20:44:04 +02:00
|
|
|
|
|
|
|
// only issue the seal if we were the first to reach the compare_and_swap.
|
2018-06-08 16:30:44 +02:00
|
|
|
if self.step.can_propose.compare_and_swap(true, false, AtomicOrdering::SeqCst) {
|
2018-07-06 11:43:58 +02:00
|
|
|
// we can drop all accumulated empty step messages that are
|
|
|
|
// older than the parent step since we're including them in
|
|
|
|
// the seal
|
2018-02-15 01:39:29 +01:00
|
|
|
self.clear_empty_steps(parent_step);
|
|
|
|
|
2018-07-06 11:43:58 +02:00
|
|
|
// report any skipped primaries between the parent block and
|
2018-09-06 13:33:46 +02:00
|
|
|
// the block we're sealing, unless we have empty steps enabled
|
|
|
|
if header.number() < self.empty_steps_transition {
|
2019-07-04 18:03:22 +02:00
|
|
|
trace!(target: "engine", "generate_seal: reporting misbehaviour for step={}, block=#{}", step, header.number());
|
|
|
|
self.report_skipped(header, step, parent_step, &*validators, epoch_transition_number);
|
2018-09-06 13:33:46 +02:00
|
|
|
}
|
2018-07-06 11:43:58 +02:00
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
let mut fields = vec![
|
2018-10-09 22:07:25 +02:00
|
|
|
encode(&step),
|
2019-06-03 15:36:21 +02:00
|
|
|
encode(&(H520::from(signature).as_bytes())),
|
2018-02-15 01:39:29 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
if let Some(empty_steps_rlp) = empty_steps_rlp {
|
|
|
|
fields.push(empty_steps_rlp);
|
|
|
|
}
|
2019-07-04 18:03:22 +02:00
|
|
|
trace!(target: "engine", "generate_seal: returning Seal::Regular for step={}, block=#{}", step, header.number());
|
2018-02-15 01:39:29 +01:00
|
|
|
return Seal::Regular(fields);
|
2017-06-22 20:44:04 +02:00
|
|
|
}
|
2016-09-08 12:12:24 +02:00
|
|
|
} else {
|
2017-02-02 19:11:43 +01:00
|
|
|
warn!(target: "engine", "generate_seal: FAIL: Accounts secret key unavailable.");
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
2016-12-06 19:23:15 +01:00
|
|
|
} else {
|
2017-06-28 13:17:36 +02:00
|
|
|
trace!(target: "engine", "generate_seal: {} not a proposer for step {}.",
|
|
|
|
header.author(), step);
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
2019-07-04 18:03:22 +02:00
|
|
|
trace!(target: "engine", "generate_seal: returning Seal::None for step={}, block=#{}", step, header.number());
|
2016-12-08 12:03:34 +01:00
|
|
|
Seal::None
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
|
2017-09-26 14:19:08 +02:00
|
|
|
fn verify_local_seal(&self, _header: &Header) -> Result<(), Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2017-06-28 13:17:36 +02:00
|
|
|
fn on_new_block(
|
|
|
|
&self,
|
|
|
|
block: &mut ExecutedBlock,
|
|
|
|
epoch_begin: bool,
|
|
|
|
) -> Result<(), Error> {
|
2017-08-29 15:16:24 +02:00
|
|
|
// with immediate transitions, we don't use the epoch mechanism anyway.
|
|
|
|
// the genesis is always considered an epoch, but we ignore it intentionally.
|
|
|
|
if self.immediate_transitions || !epoch_begin { return Ok(()) }
|
2017-06-28 13:17:36 +02:00
|
|
|
|
|
|
|
// genesis is never a new block, but might as well check.
|
2019-03-15 13:22:47 +01:00
|
|
|
let header = block.header.clone();
|
2017-06-28 13:17:36 +02:00
|
|
|
let first = header.number() == 0;
|
|
|
|
|
|
|
|
let mut call = |to, data| {
|
2017-09-26 14:19:08 +02:00
|
|
|
let result = self.machine.execute_as_system(
|
2017-06-28 13:17:36 +02:00
|
|
|
block,
|
|
|
|
to,
|
|
|
|
U256::max_value(), // unbounded gas? maybe make configurable.
|
|
|
|
Some(data),
|
|
|
|
);
|
|
|
|
|
|
|
|
result.map_err(|e| format!("{}", e))
|
|
|
|
};
|
|
|
|
|
|
|
|
self.validators.on_epoch_begin(first, &header, &mut call)
|
|
|
|
}
|
|
|
|
|
2017-01-05 21:16:13 +01:00
|
|
|
/// Apply the block reward on finalisation of the block.
|
2019-07-04 13:43:20 +02:00
|
|
|
fn on_close_block(
|
|
|
|
&self,
|
|
|
|
block: &mut ExecutedBlock,
|
|
|
|
parent: &Header,
|
|
|
|
) -> Result<(), Error> {
|
2018-08-29 17:17:18 +02:00
|
|
|
let mut beneficiaries = Vec::new();
|
2019-08-21 14:55:51 +02:00
|
|
|
|
|
|
|
if block.header.number() == self.two_thirds_majority_transition {
|
|
|
|
info!(target: "engine", "Block {}: Transitioning to 2/3 quorum.", self.two_thirds_majority_transition);
|
|
|
|
}
|
|
|
|
|
2019-03-15 13:22:47 +01:00
|
|
|
if block.header.number() >= self.empty_steps_transition {
|
|
|
|
let empty_steps = if block.header.seal().is_empty() {
|
2018-02-27 18:22:56 +01:00
|
|
|
// this is a new block, calculate rewards based on the empty steps messages we have accumulated
|
2019-07-04 13:43:20 +02:00
|
|
|
let parent_step = header_step(parent, self.empty_steps_transition)?;
|
2018-06-08 16:30:44 +02:00
|
|
|
let current_step = self.step.inner.load();
|
2019-07-04 13:43:20 +02:00
|
|
|
self.empty_steps(parent_step, current_step, parent.hash())
|
2018-02-27 18:22:56 +01:00
|
|
|
} else {
|
|
|
|
// we're verifying a block, extract empty steps from the seal
|
2019-03-15 13:22:47 +01:00
|
|
|
header_empty_steps(&block.header)?
|
2018-02-27 18:22:56 +01:00
|
|
|
};
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
for empty_step in empty_steps {
|
2018-02-27 18:22:56 +01:00
|
|
|
let author = empty_step.author()?;
|
2018-08-29 17:17:18 +02:00
|
|
|
beneficiaries.push((author, RewardKind::EmptyStep));
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-15 13:22:47 +01:00
|
|
|
let author = *block.header.author();
|
2018-08-29 17:17:18 +02:00
|
|
|
beneficiaries.push((author, RewardKind::Author));
|
2018-04-20 12:32:00 +02:00
|
|
|
|
2019-08-22 10:45:24 +02:00
|
|
|
let block_reward_contract_transition = self
|
|
|
|
.block_reward_contract_transitions
|
|
|
|
.range(..=block.header.number())
|
|
|
|
.last();
|
|
|
|
let rewards: Vec<_> = if let Some((_, contract)) = block_reward_contract_transition {
|
|
|
|
let mut call = engine::default_system_or_code_call(&self.machine, block);
|
|
|
|
let rewards = contract.reward(beneficiaries, &mut call)?;
|
|
|
|
rewards.into_iter().map(|(author, amount)| (author, RewardKind::External, amount)).collect()
|
|
|
|
} else {
|
|
|
|
beneficiaries.into_iter().map(|(author, reward_kind)| (author, reward_kind, self.block_reward)).collect()
|
2018-04-20 12:32:00 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
block_reward::apply_block_rewards(&rewards, block, &self.machine)
|
2017-01-05 21:16:13 +01:00
|
|
|
}
|
|
|
|
|
2016-09-08 12:12:24 +02:00
|
|
|
/// Check the number of seal fields.
|
2017-12-07 12:17:11 +01:00
|
|
|
fn verify_block_basic(&self, header: &Header) -> Result<(), Error> {
|
2017-09-26 14:19:08 +02:00
|
|
|
if header.number() >= self.validate_score_transition && *header.difficulty() >= U256::from(U128::max_value()) {
|
2018-01-19 10:38:59 +01:00
|
|
|
return Err(From::from(BlockError::DifficultyOutOfBounds(
|
2017-03-28 10:46:52 +02:00
|
|
|
OutOfBounds { min: None, max: Some(U256::from(U128::max_value())), found: *header.difficulty() }
|
2018-01-19 10:38:59 +01:00
|
|
|
)));
|
|
|
|
}
|
|
|
|
|
2018-06-08 16:30:44 +02:00
|
|
|
match verify_timestamp(&self.step.inner, header_step(header, self.empty_steps_transition)?) {
|
2018-01-19 10:38:59 +01:00
|
|
|
Err(BlockError::InvalidSeal) => {
|
2018-07-06 11:43:58 +02:00
|
|
|
// This check runs in Phase 1 where there is no guarantee that the parent block is
|
|
|
|
// already imported, therefore the call to `epoch_set` may fail. In that case we
|
|
|
|
// won't report the misbehavior but this is not a concern because:
|
2019-06-25 13:15:00 +02:00
|
|
|
// - Authorities will have a signing key available to report and it's expected that
|
|
|
|
// they'll be up-to-date and importing, therefore the parent header will most likely
|
|
|
|
// be available
|
2018-07-06 11:43:58 +02:00
|
|
|
// - Even if you are an authority that is syncing the chain, the contract will most
|
|
|
|
// likely ignore old reports
|
|
|
|
// - This specific check is only relevant if you're importing (since it checks
|
|
|
|
// against wall clock)
|
2019-07-18 12:27:08 +02:00
|
|
|
if let Ok((_, set_number)) = self.epoch_set(header) {
|
2019-06-25 13:15:00 +02:00
|
|
|
trace!(target: "engine", "Reporting benign misbehaviour (cause: InvalidSeal) at block #{}, epoch set number {}. Own address: {}",
|
|
|
|
header.number(), set_number, self.address().unwrap_or_default());
|
2018-07-06 11:43:58 +02:00
|
|
|
self.validators.report_benign(header.author(), set_number, header.number());
|
|
|
|
}
|
|
|
|
|
2018-01-19 10:38:59 +01:00
|
|
|
Err(BlockError::InvalidSeal.into())
|
|
|
|
}
|
|
|
|
Err(e) => Err(e.into()),
|
|
|
|
Ok(()) => Ok(()),
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-13 20:24:21 +02:00
|
|
|
/// Do the step and gas limit validation.
|
2017-09-26 14:19:08 +02:00
|
|
|
fn verify_block_family(&self, header: &Header, parent: &Header) -> Result<(), Error> {
|
2018-02-15 01:39:29 +01:00
|
|
|
let step = header_step(header, self.empty_steps_transition)?;
|
|
|
|
let parent_step = header_step(parent, self.empty_steps_transition)?;
|
2018-07-06 11:43:58 +02:00
|
|
|
|
|
|
|
let (validators, set_number) = self.epoch_set(header)?;
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2017-05-22 08:21:34 +02:00
|
|
|
// Ensure header is from the step after parent.
|
2017-05-15 22:34:01 +02:00
|
|
|
if step == parent_step
|
|
|
|
|| (header.number() >= self.validate_step_transition && step <= parent_step) {
|
2019-06-25 13:15:00 +02:00
|
|
|
warn!(target: "engine", "Multiple blocks proposed for step {}.", parent_step);
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2018-01-19 10:38:59 +01:00
|
|
|
self.validators.report_malicious(header.author(), set_number, header.number(), Default::default());
|
2018-10-25 17:33:41 +02:00
|
|
|
Err(EngineError::DoubleVote(*header.author()))?;
|
2016-11-01 19:12:06 +01:00
|
|
|
}
|
2017-09-26 14:19:08 +02:00
|
|
|
|
2019-10-14 12:56:38 +02:00
|
|
|
// Report malice if the validator produced other sibling blocks in the same step.
|
|
|
|
let received_step_key = (step, *header.author());
|
|
|
|
let new_hash = header.hash();
|
|
|
|
if self.received_step_hashes.read().get(&received_step_key).map_or(false, |h| *h != new_hash) {
|
|
|
|
trace!(target: "engine", "Validator {} produced sibling blocks in the same step", header.author());
|
|
|
|
self.validators.report_malicious(header.author(), set_number, header.number(), Default::default());
|
|
|
|
} else {
|
|
|
|
self.received_step_hashes.write().insert(received_step_key, new_hash);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove hash records older than two full rounds of steps (picked as a reasonable trade-off between
|
|
|
|
// memory consumption and fault-tolerance).
|
|
|
|
let sibling_malice_detection_period = 2 * validators.count(&parent.hash()) as u64;
|
|
|
|
let oldest_step = parent_step.saturating_sub(sibling_malice_detection_period);
|
|
|
|
if oldest_step > 0 {
|
|
|
|
let mut rsh = self.received_step_hashes.write();
|
|
|
|
let new_rsh = rsh.split_off(&(oldest_step, Address::zero()));
|
|
|
|
*rsh = new_rsh;
|
|
|
|
}
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
// If empty step messages are enabled we will validate the messages in the seal, missing messages are not
|
|
|
|
// reported as there's no way to tell whether the empty step message was never sent or simply not included.
|
2018-07-19 16:41:31 +02:00
|
|
|
let empty_steps_len = if header.number() >= self.empty_steps_transition {
|
|
|
|
let validate_empty_steps = || -> Result<usize, Error> {
|
2018-12-10 19:58:38 +01:00
|
|
|
let strict_empty_steps = header.number() >= self.strict_empty_steps_transition;
|
2018-02-15 01:39:29 +01:00
|
|
|
let empty_steps = header_empty_steps(header)?;
|
2018-07-19 16:41:31 +02:00
|
|
|
let empty_steps_len = empty_steps.len();
|
2018-12-10 19:58:38 +01:00
|
|
|
let mut prev_empty_step = 0;
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
for empty_step in empty_steps {
|
|
|
|
if empty_step.step <= parent_step || empty_step.step >= step {
|
|
|
|
Err(EngineError::InsufficientProof(
|
|
|
|
format!("empty step proof for invalid step: {:?}", empty_step.step)))?;
|
|
|
|
}
|
|
|
|
|
|
|
|
if empty_step.parent_hash != *header.parent_hash() {
|
|
|
|
Err(EngineError::InsufficientProof(
|
|
|
|
format!("empty step proof for invalid parent hash: {:?}", empty_step.parent_hash)))?;
|
|
|
|
}
|
|
|
|
|
2018-07-06 11:43:58 +02:00
|
|
|
if !empty_step.verify(&*validators).unwrap_or(false) {
|
2018-02-15 01:39:29 +01:00
|
|
|
Err(EngineError::InsufficientProof(
|
|
|
|
format!("invalid empty step proof: {:?}", empty_step)))?;
|
|
|
|
}
|
2018-12-10 19:58:38 +01:00
|
|
|
|
|
|
|
if strict_empty_steps {
|
|
|
|
if empty_step.step <= prev_empty_step {
|
|
|
|
Err(EngineError::InsufficientProof(format!(
|
|
|
|
"{} empty step: {:?}",
|
|
|
|
if empty_step.step == prev_empty_step { "duplicate" } else { "unordered" },
|
|
|
|
empty_step
|
|
|
|
)))?;
|
|
|
|
}
|
|
|
|
|
|
|
|
prev_empty_step = empty_step.step;
|
|
|
|
}
|
2017-07-13 09:48:00 +02:00
|
|
|
}
|
2018-12-10 19:58:38 +01:00
|
|
|
|
2018-07-19 16:41:31 +02:00
|
|
|
Ok(empty_steps_len)
|
2018-02-15 01:39:29 +01:00
|
|
|
};
|
|
|
|
|
2018-07-19 16:41:31 +02:00
|
|
|
match validate_empty_steps() {
|
|
|
|
Ok(len) => len,
|
|
|
|
Err(err) => {
|
2019-06-25 13:15:00 +02:00
|
|
|
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());
|
2018-07-19 16:41:31 +02:00
|
|
|
self.validators.report_benign(header.author(), set_number, header.number());
|
|
|
|
return Err(err);
|
|
|
|
},
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
} else {
|
2018-07-06 11:43:58 +02:00
|
|
|
self.report_skipped(header, step, parent_step, &*validators, set_number);
|
2018-07-19 16:41:31 +02:00
|
|
|
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
|
|
|
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() })));
|
|
|
|
}
|
2017-05-22 08:21:34 +02:00
|
|
|
}
|
2016-11-01 19:12:06 +01:00
|
|
|
|
2016-09-08 12:12:24 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2017-04-13 20:24:21 +02:00
|
|
|
// Check the validators.
|
2017-09-26 14:19:08 +02:00
|
|
|
fn verify_block_external(&self, header: &Header) -> Result<(), Error> {
|
2018-07-06 11:43:58 +02:00
|
|
|
let (validators, set_number) = self.epoch_set(header)?;
|
2017-06-28 13:17:36 +02:00
|
|
|
|
|
|
|
// verify signature against fixed list, but reports should go to the
|
|
|
|
// contract itself.
|
2018-07-06 11:43:58 +02:00
|
|
|
let res = verify_external(header, &*validators, self.empty_steps_transition);
|
|
|
|
match res {
|
2019-05-06 15:06:20 +02:00
|
|
|
Err(Error::Engine(EngineError::NotProposer(_))) => {
|
2019-06-25 13:15:00 +02:00
|
|
|
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());
|
2018-07-06 11:43:58 +02:00
|
|
|
self.validators.report_benign(header.author(), set_number, header.number());
|
|
|
|
},
|
|
|
|
Ok(_) => {
|
|
|
|
// we can drop all accumulated empty step messages that are older than this header's step
|
|
|
|
let header_step = header_step(header, self.empty_steps_transition)?;
|
|
|
|
self.clear_empty_steps(header_step.into());
|
|
|
|
},
|
|
|
|
_ => {},
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
res
|
2017-04-13 20:24:21 +02:00
|
|
|
}
|
|
|
|
|
2017-06-28 13:17:36 +02:00
|
|
|
fn genesis_epoch_data(&self, header: &Header, call: &Call) -> Result<Vec<u8>, String> {
|
|
|
|
self.validators.genesis_epoch_data(header, call)
|
|
|
|
.map(|set_proof| combine_proofs(0, &set_proof, &[]))
|
2017-04-12 18:55:38 +02:00
|
|
|
}
|
|
|
|
|
2019-08-15 17:59:22 +02:00
|
|
|
fn signals_epoch_end(&self, header: &Header, aux: AuxiliaryData) -> engine::EpochChange {
|
|
|
|
if self.immediate_transitions { return engine::EpochChange::No }
|
2017-06-28 13:17:36 +02:00
|
|
|
|
|
|
|
let first = header.number() == 0;
|
2017-09-26 14:19:08 +02:00
|
|
|
self.validators.signals_epoch_end(first, header, aux)
|
2017-04-12 18:55:38 +02:00
|
|
|
}
|
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
fn is_epoch_end_light(
|
2017-06-28 13:17:36 +02:00
|
|
|
&self,
|
|
|
|
chain_head: &Header,
|
2019-08-15 17:59:22 +02:00
|
|
|
chain: &Headers<Header>,
|
|
|
|
transition_store: &PendingTransitionStore,
|
2017-06-28 13:17:36 +02:00
|
|
|
) -> Option<Vec<u8>> {
|
|
|
|
// epochs only matter if we want to support light clients.
|
|
|
|
if self.immediate_transitions { return None }
|
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
};
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
let mut epoch_manager = self.epoch_manager.lock();
|
2019-05-24 10:30:31 +02:00
|
|
|
if !epoch_manager.zoom_to_after(&*client, &self.machine, &*self.validators, *chain_head.parent_hash()) {
|
2017-06-28 13:17:36 +02:00
|
|
|
return None;
|
|
|
|
}
|
2018-10-25 17:33:41 +02:00
|
|
|
|
|
|
|
epoch_manager.epoch_transition_hash
|
2017-06-28 13:17:36 +02:00
|
|
|
};
|
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
let mut hash = *chain_head.parent_hash();
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2019-09-08 14:30:54 +02:00
|
|
|
let mut ancestry = std::iter::repeat_with(move || {
|
2018-10-25 17:33:41 +02:00
|
|
|
chain(hash).and_then(|header| {
|
|
|
|
if header.number() == 0 { return None }
|
|
|
|
hash = *header.parent_hash();
|
|
|
|
Some(header)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
.while_some()
|
|
|
|
.take_while(|header| header.hash() != epoch_transition_hash);
|
2017-07-13 09:48:00 +02:00
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
let finalized = self.build_finality(chain_head, &mut ancestry);
|
2018-02-15 01:39:29 +01:00
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
self.is_epoch_end(chain_head, &finalized, chain, transition_store)
|
|
|
|
}
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
fn is_epoch_end(
|
|
|
|
&self,
|
|
|
|
chain_head: &Header,
|
|
|
|
finalized: &[H256],
|
2019-08-15 17:59:22 +02:00
|
|
|
chain: &Headers<Header>,
|
|
|
|
transition_store: &PendingTransitionStore,
|
2018-10-25 17:33:41 +02:00
|
|
|
) -> Option<Vec<u8>> {
|
|
|
|
// epochs only matter if we want to support light clients.
|
|
|
|
if self.immediate_transitions { return None }
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
let first = chain_head.number() == 0;
|
2018-02-15 01:39:29 +01:00
|
|
|
|
2019-03-12 19:16:29 +01:00
|
|
|
// Apply transitions that don't require finality and should be enacted immediately (e.g from chain spec)
|
2018-10-25 17:33:41 +02:00
|
|
|
if let Some(change) = self.validators.is_epoch_end(first, chain_head) {
|
2019-03-12 19:16:29 +01:00
|
|
|
info!(target: "engine", "Immediately applying validator set change signalled at block {}", chain_head.number());
|
|
|
|
self.epoch_manager.lock().note_new_epoch();
|
2018-10-25 17:33:41 +02:00
|
|
|
let change = combine_proofs(chain_head.number(), &change, &[]);
|
|
|
|
return Some(change)
|
|
|
|
}
|
2018-02-15 01:39:29 +01:00
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
// check transition store for pending transitions against recently finalized blocks
|
|
|
|
for finalized_hash in finalized {
|
|
|
|
if let Some(pending) = transition_store(*finalized_hash) {
|
|
|
|
// walk the chain backwards from current head until finalized_hash
|
|
|
|
// to construct transition proof. author == ec_recover(sig) known
|
|
|
|
// since the blocks are in the DB.
|
|
|
|
let mut hash = chain_head.hash();
|
2019-09-08 14:30:54 +02:00
|
|
|
let mut finality_proof: Vec<_> = std::iter::repeat_with(move || {
|
2018-10-25 17:33:41 +02:00
|
|
|
chain(hash).and_then(|header| {
|
|
|
|
hash = *header.parent_hash();
|
2019-01-08 11:14:59 +01:00
|
|
|
if header.number() == 0 { None }
|
|
|
|
else { Some(header) }
|
2018-10-25 17:33:41 +02:00
|
|
|
})
|
|
|
|
})
|
|
|
|
.while_some()
|
|
|
|
.take_while(|h| h.hash() != *finalized_hash)
|
|
|
|
.collect();
|
2018-02-15 01:39:29 +01:00
|
|
|
|
2019-01-08 11:14:59 +01:00
|
|
|
let finalized_header = if *finalized_hash == chain_head.hash() {
|
|
|
|
// chain closure only stores ancestry, but the chain head is also unfinalized.
|
|
|
|
chain_head.clone()
|
|
|
|
} else {
|
|
|
|
chain(*finalized_hash)
|
|
|
|
.expect("header is finalized; finalized headers must exist in the chain; qed")
|
|
|
|
};
|
2017-07-13 09:48:00 +02:00
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
let signal_number = finalized_header.number();
|
|
|
|
info!(target: "engine", "Applying validator set change signalled at block {}", signal_number);
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
finality_proof.push(finalized_header);
|
|
|
|
finality_proof.reverse();
|
2017-06-28 13:17:36 +02:00
|
|
|
|
2018-10-25 17:33:41 +02:00
|
|
|
let finality_proof = ::rlp::encode_list(&finality_proof);
|
|
|
|
|
|
|
|
self.epoch_manager.lock().note_new_epoch();
|
|
|
|
|
|
|
|
// We turn off can_propose here because upon validator set change there can
|
|
|
|
// be two valid proposers for a single step: one from the old set and
|
|
|
|
// one from the new.
|
|
|
|
//
|
|
|
|
// This way, upon encountering an epoch change, the proposer from the
|
|
|
|
// new set will be forced to wait until the next step to avoid sealing a
|
|
|
|
// block that breaks the invariant that the parent's step < the block's step.
|
|
|
|
self.step.can_propose.store(false, AtomicOrdering::SeqCst);
|
|
|
|
return Some(combine_proofs(signal_number, &pending.proof, &*finality_proof));
|
2017-06-28 13:17:36 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
2019-06-26 14:16:05 +02:00
|
|
|
fn epoch_verifier<'a>(&self, _header: &Header, proof: &'a [u8]) -> ConstructedVerifier<'a> {
|
2017-06-28 13:17:36 +02:00
|
|
|
let (signal_number, set_proof, finality_proof) = match destructure_proofs(proof) {
|
|
|
|
Ok(x) => x,
|
|
|
|
Err(e) => return ConstructedVerifier::Err(e),
|
|
|
|
};
|
|
|
|
|
|
|
|
let first = signal_number == 0;
|
2017-09-26 14:19:08 +02:00
|
|
|
match self.validators.epoch_set(first, &self.machine, signal_number, set_proof) {
|
2017-06-28 13:17:36 +02:00
|
|
|
Ok((list, finalize)) => {
|
|
|
|
let verifier = Box::new(EpochVerifier {
|
|
|
|
step: self.step.clone(),
|
|
|
|
subchain_validators: list,
|
2018-02-15 01:39:29 +01:00
|
|
|
empty_steps_transition: self.empty_steps_transition,
|
2019-08-21 14:55:51 +02:00
|
|
|
two_thirds_majority_transition: self.two_thirds_majority_transition,
|
2017-06-28 13:17:36 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
match finalize {
|
|
|
|
Some(finalize) => ConstructedVerifier::Unconfirmed(verifier, finality_proof, finalize),
|
|
|
|
None => ConstructedVerifier::Trusted(verifier),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Err(e) => ConstructedVerifier::Err(e),
|
|
|
|
}
|
2017-04-13 20:24:21 +02:00
|
|
|
}
|
|
|
|
|
2019-06-14 18:48:35 +02:00
|
|
|
fn register_client(&self, client: Weak<dyn EngineClient>) {
|
2017-01-10 12:23:59 +01:00
|
|
|
*self.client.write() = Some(client.clone());
|
2017-09-05 17:54:05 +02:00
|
|
|
self.validators.register_client(client);
|
2016-11-17 19:32:12 +01:00
|
|
|
}
|
2016-12-07 10:34:06 +01:00
|
|
|
|
2019-10-09 14:42:51 +02:00
|
|
|
fn set_signer(&self, signer: Option<Box<dyn EngineSigner>>) {
|
|
|
|
*self.signer.write() = signer;
|
2016-09-27 12:12:18 +02:00
|
|
|
}
|
2017-01-24 10:03:58 +01:00
|
|
|
|
|
|
|
fn sign(&self, hash: H256) -> Result<Signature, Error> {
|
2019-02-07 14:34:24 +01:00
|
|
|
Ok(self.signer.read()
|
|
|
|
.as_ref()
|
2019-10-23 13:03:46 +02:00
|
|
|
.ok_or(parity_crypto::publickey::Error::InvalidAddress)?
|
2019-02-07 14:34:24 +01:00
|
|
|
.sign(hash)?
|
|
|
|
)
|
2017-01-24 10:03:58 +01:00
|
|
|
}
|
2017-05-17 12:41:33 +02:00
|
|
|
|
2019-08-22 18:25:49 +02:00
|
|
|
fn snapshot_mode(&self) -> Snapshotting {
|
2017-06-28 13:17:36 +02:00
|
|
|
if self.immediate_transitions {
|
2019-08-22 18:25:49 +02:00
|
|
|
Snapshotting::Unsupported
|
2017-06-28 13:17:36 +02:00
|
|
|
} else {
|
2019-08-22 18:25:49 +02:00
|
|
|
Snapshotting::PoA
|
2017-06-28 13:17:36 +02:00
|
|
|
}
|
2017-05-17 12:41:33 +02:00
|
|
|
}
|
2018-05-16 08:58:01 +02:00
|
|
|
|
2019-06-14 18:48:35 +02:00
|
|
|
fn ancestry_actions(&self, header: &Header, ancestry: &mut dyn Iterator<Item=ExtendedHeader>) -> Vec<AncestryAction> {
|
2018-10-25 17:33:41 +02:00
|
|
|
let finalized = self.build_finality(
|
2018-11-14 13:05:49 +01:00
|
|
|
header,
|
2018-10-25 17:33:41 +02:00
|
|
|
&mut ancestry.take_while(|e| !e.is_finalized).map(|e| e.header),
|
|
|
|
);
|
|
|
|
|
|
|
|
if !finalized.is_empty() {
|
|
|
|
debug!(target: "finality", "Finalizing blocks: {:?}", finalized);
|
|
|
|
}
|
|
|
|
|
|
|
|
finalized.into_iter().map(AncestryAction::MarkFinalized).collect()
|
|
|
|
}
|
2019-07-18 12:27:08 +02:00
|
|
|
|
|
|
|
fn params(&self) -> &CommonParams {
|
|
|
|
self.machine.params()
|
|
|
|
}
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2018-10-15 18:05:53 +02:00
|
|
|
use std::collections::BTreeMap;
|
2019-08-22 10:45:24 +02:00
|
|
|
use std::str::FromStr;
|
2017-07-29 21:56:42 +02:00
|
|
|
use std::sync::Arc;
|
2017-05-22 08:21:34 +02:00
|
|
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
2019-08-22 18:25:49 +02:00
|
|
|
use keccak_hash::keccak;
|
2019-02-07 14:34:24 +01:00
|
|
|
use accounts::AccountProvider;
|
2018-02-15 01:39:29 +01:00
|
|
|
use ethereum_types::{Address, H520, H256, U256};
|
2019-10-23 13:03:46 +02:00
|
|
|
use parity_crypto::publickey::Signature;
|
2019-08-22 18:25:49 +02:00
|
|
|
use common_types::{
|
2019-07-18 12:27:08 +02:00
|
|
|
header::Header,
|
2019-08-15 17:59:22 +02:00
|
|
|
engines::{Seal, params::CommonParams},
|
2019-07-18 12:27:08 +02:00
|
|
|
errors::{EthcoreError as Error, EngineError},
|
|
|
|
transaction::{Action, Transaction},
|
|
|
|
};
|
2016-09-08 12:28:59 +02:00
|
|
|
use rlp::encode;
|
2019-08-22 18:25:49 +02:00
|
|
|
use ethcore::{
|
|
|
|
block::*,
|
|
|
|
test_helpers::{
|
|
|
|
generate_dummy_client_with_spec, get_temp_state_db,
|
|
|
|
TestNotify
|
|
|
|
},
|
2018-03-12 18:05:52 +01:00
|
|
|
};
|
2019-08-15 17:59:22 +02:00
|
|
|
use engine::Engine;
|
2019-08-22 18:25:49 +02:00
|
|
|
use block_reward::BlockRewardContract;
|
2019-06-26 14:16:05 +02:00
|
|
|
use machine::Machine;
|
2019-08-23 15:32:58 +02:00
|
|
|
use spec::{self, Spec};
|
|
|
|
use validator_set::{TestSet, SimpleList};
|
2019-08-22 10:45:24 +02:00
|
|
|
use ethjson;
|
2019-08-22 18:25:49 +02:00
|
|
|
use serde_json;
|
|
|
|
|
|
|
|
use super::{AuthorityRoundParams, AuthorityRound, EmptyStep, SealedEmptyStep, calculate_score};
|
2016-09-08 12:12:24 +02:00
|
|
|
|
2019-06-25 13:15:00 +02:00
|
|
|
fn build_aura<F>(f: F) -> Arc<AuthorityRound> where
|
2018-12-10 19:58:38 +01:00
|
|
|
F: FnOnce(&mut AuthorityRoundParams),
|
|
|
|
{
|
|
|
|
let mut params = AuthorityRoundParams {
|
|
|
|
step_duration: 1,
|
|
|
|
start_step: Some(1),
|
|
|
|
validators: Box::new(TestSet::default()),
|
|
|
|
validate_score_transition: 0,
|
|
|
|
validate_step_transition: 0,
|
|
|
|
immediate_transitions: true,
|
|
|
|
maximum_uncle_count_transition: 0,
|
|
|
|
maximum_uncle_count: 0,
|
|
|
|
empty_steps_transition: u64::max_value(),
|
|
|
|
maximum_empty_steps: 0,
|
|
|
|
block_reward: Default::default(),
|
2019-08-22 10:45:24 +02:00
|
|
|
block_reward_contract_transitions: Default::default(),
|
2018-12-10 19:58:38 +01:00
|
|
|
strict_empty_steps_transition: 0,
|
2019-08-21 14:55:51 +02:00
|
|
|
two_thirds_majority_transition: 0,
|
2018-12-10 19:58:38 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
// mutate aura params
|
|
|
|
f(&mut params);
|
|
|
|
// create engine
|
2019-07-18 12:27:08 +02:00
|
|
|
let mut c_params = CommonParams::default();
|
2018-12-10 19:58:38 +01:00
|
|
|
c_params.gas_limit_bound_divisor = 5.into();
|
2019-06-26 14:16:05 +02:00
|
|
|
let machine = Machine::regular(c_params, Default::default());
|
2018-12-10 19:58:38 +01:00
|
|
|
AuthorityRound::new(params, machine).unwrap()
|
|
|
|
}
|
|
|
|
|
2016-09-08 12:12:24 +02:00
|
|
|
#[test]
|
|
|
|
fn has_valid_metadata() {
|
2019-08-07 16:52:48 +02:00
|
|
|
let engine = spec::new_test_round().engine;
|
2019-08-22 18:25:49 +02:00
|
|
|
assert_eq!(engine.name(), "AuthorityRound");
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn can_return_schedule() {
|
2019-08-07 16:52:48 +02:00
|
|
|
let engine = spec::new_test_round().engine;
|
2017-04-19 14:30:00 +02:00
|
|
|
let schedule = engine.schedule(10000000);
|
2016-09-08 12:12:24 +02:00
|
|
|
|
|
|
|
assert!(schedule.stack_limit > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn can_do_signature_verification_fail() {
|
2019-08-07 16:52:48 +02:00
|
|
|
let engine = spec::new_test_round().engine;
|
2016-09-08 12:12:24 +02:00
|
|
|
let mut header: Header = Header::default();
|
2018-10-09 22:07:25 +02:00
|
|
|
header.set_seal(vec![encode(&H520::default())]);
|
2016-09-08 12:12:24 +02:00
|
|
|
|
2017-09-26 14:19:08 +02:00
|
|
|
let verify_result = engine.verify_block_external(&header);
|
2016-09-08 12:12:24 +02:00
|
|
|
assert!(verify_result.is_err());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2016-11-14 15:15:31 +01:00
|
|
|
fn generates_seal_and_does_not_double_propose() {
|
2017-01-18 18:49:50 +01:00
|
|
|
let tap = Arc::new(AccountProvider::transient_provider());
|
2018-06-22 15:09:15 +02:00
|
|
|
let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap();
|
2019-08-07 16:52:48 +02:00
|
|
|
let spec = spec::new_test_round();
|
2016-09-08 12:12:24 +02:00
|
|
|
let engine = &*spec.engine;
|
|
|
|
let genesis_header = spec.genesis_header();
|
2017-04-06 19:26:17 +02:00
|
|
|
let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
2016-09-08 12:12:24 +02:00
|
|
|
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
2019-07-04 13:43:20 +02:00
|
|
|
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
2018-07-16 13:53:55 +02:00
|
|
|
let b1 = b1.close_and_lock().unwrap();
|
2016-11-14 20:03:02 +01:00
|
|
|
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2019-03-15 13:22:47 +01:00
|
|
|
if let Seal::Regular(seal) = engine.generate_seal(&b1, &genesis_header) {
|
2017-04-12 14:41:19 +02:00
|
|
|
assert!(b1.clone().try_seal(engine, seal).is_ok());
|
2016-11-14 20:03:02 +01:00
|
|
|
// Second proposal is forbidden.
|
2019-03-15 13:22:47 +01:00
|
|
|
assert!(engine.generate_seal(&b1, &genesis_header) == Seal::None);
|
2019-10-09 14:42:51 +02:00
|
|
|
} else {
|
|
|
|
panic!("block 1 not sealed");
|
2016-11-14 20:03:02 +01:00
|
|
|
}
|
2019-10-09 14:42:51 +02:00
|
|
|
}
|
2016-11-14 20:03:02 +01:00
|
|
|
|
2019-10-09 14:42:51 +02:00
|
|
|
#[test]
|
|
|
|
fn generates_seal_iff_sealer_is_set() {
|
|
|
|
let tap = Arc::new(AccountProvider::transient_provider());
|
|
|
|
let addr1 = tap.insert_account(keccak("1").into(), &"1".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 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)
|
|
|
|
.unwrap().close_and_lock().unwrap();
|
|
|
|
// Not a signer. A seal cannot be generated.
|
|
|
|
assert!(engine.generate_seal(&b1, &genesis_header) == Seal::None);
|
|
|
|
// Become a signer.
|
|
|
|
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);
|
|
|
|
} else {
|
|
|
|
panic!("block 1 not sealed");
|
|
|
|
}
|
|
|
|
// Stop being a 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();
|
|
|
|
let mut header2 = genesis_header.clone();
|
|
|
|
header2.set_number(2);
|
|
|
|
header2.set_author(addr2);
|
|
|
|
header2.set_parent_hash(header2.hash());
|
|
|
|
let db2 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
|
|
|
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &header2,
|
|
|
|
last_hashes, addr2, (3141562.into(), 31415620.into()),
|
|
|
|
vec![], false)
|
|
|
|
.unwrap().close_and_lock().unwrap();
|
|
|
|
// Not a signer. A seal cannot be generated.
|
|
|
|
assert!(engine.generate_seal(&b2, &header2) == Seal::None);
|
|
|
|
// Become a signer once more.
|
|
|
|
engine.set_signer(Some(Box::new((tap, addr2, "0".into()))));
|
|
|
|
if let Seal::Regular(seal) = engine.generate_seal(&b2, &header2) {
|
2017-04-12 14:41:19 +02:00
|
|
|
assert!(b2.clone().try_seal(engine, seal).is_ok());
|
2016-11-14 20:03:02 +01:00
|
|
|
// Second proposal is forbidden.
|
2019-10-09 14:42:51 +02:00
|
|
|
assert!(engine.generate_seal(&b2, &header2) == Seal::None);
|
|
|
|
} else {
|
|
|
|
panic!("block 2 not sealed");
|
2017-12-07 12:17:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn checks_difficulty_in_generate_seal() {
|
|
|
|
let tap = Arc::new(AccountProvider::transient_provider());
|
2018-06-22 15:09:15 +02:00
|
|
|
let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap();
|
|
|
|
let addr2 = tap.insert_account(keccak("0").into(), &"0".into()).unwrap();
|
2017-12-07 12:17:11 +01:00
|
|
|
|
2019-08-07 16:52:48 +02:00
|
|
|
let spec = spec::new_test_round();
|
2017-12-07 12:17:11 +01:00
|
|
|
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()]);
|
|
|
|
|
2019-07-04 13:43:20 +02:00
|
|
|
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
2018-07-16 13:53:55 +02:00
|
|
|
let b1 = b1.close_and_lock().unwrap();
|
2019-07-04 13:43:20 +02:00
|
|
|
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
2018-07-16 13:53:55 +02:00
|
|
|
let b2 = b2.close_and_lock().unwrap();
|
2017-12-07 12:17:11 +01:00
|
|
|
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2019-03-15 13:22:47 +01:00
|
|
|
match engine.generate_seal(&b1, &genesis_header) {
|
2019-07-04 18:03:22 +02:00
|
|
|
Seal::None => panic!("wrong seal"),
|
2017-12-07 12:17:11 +01:00
|
|
|
Seal::Regular(_) => {
|
|
|
|
engine.step();
|
|
|
|
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into()))));
|
2019-03-15 13:22:47 +01:00
|
|
|
match engine.generate_seal(&b2, &genesis_header) {
|
2019-07-04 18:03:22 +02:00
|
|
|
Seal::Regular(_) => panic!("sealed despite wrong difficulty"),
|
2017-12-07 12:17:11 +01:00
|
|
|
Seal::None => {}
|
|
|
|
}
|
|
|
|
}
|
2016-11-14 20:03:02 +01:00
|
|
|
}
|
2016-09-08 12:12:24 +02:00
|
|
|
}
|
2016-09-08 16:27:54 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn proposer_switching() {
|
|
|
|
let tap = AccountProvider::transient_provider();
|
2018-06-22 15:09:15 +02:00
|
|
|
let addr = tap.insert_account(keccak("0").into(), &"0".into()).unwrap();
|
2017-03-08 14:41:24 +01:00
|
|
|
let mut parent_header: Header = Header::default();
|
2018-10-09 22:07:25 +02:00
|
|
|
parent_header.set_seal(vec![encode(&0usize)]);
|
2017-07-29 21:56:42 +02:00
|
|
|
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
2017-03-08 14:41:24 +01:00
|
|
|
let mut header: Header = Header::default();
|
|
|
|
header.set_number(1);
|
2017-07-29 21:56:42 +02:00
|
|
|
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
2016-09-08 16:27:54 +02:00
|
|
|
header.set_author(addr);
|
|
|
|
|
2019-08-07 16:52:48 +02:00
|
|
|
let engine = spec::new_test_round().engine;
|
2016-09-08 16:27:54 +02:00
|
|
|
|
2017-01-10 12:23:59 +01:00
|
|
|
// Two validators.
|
2016-12-10 10:38:10 +01:00
|
|
|
// Spec starts with step 2.
|
2018-11-21 22:30:03 +01:00
|
|
|
header.set_difficulty(calculate_score(0, 2, 0));
|
2018-07-19 16:41:31 +02:00
|
|
|
let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap();
|
2018-10-09 22:07:25 +02:00
|
|
|
header.set_seal(vec![encode(&2usize), encode(&(&*signature as &[u8]))]);
|
2017-09-26 14:19:08 +02:00
|
|
|
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
|
|
|
assert!(engine.verify_block_external(&header).is_err());
|
2018-11-21 22:30:03 +01:00
|
|
|
header.set_difficulty(calculate_score(0, 1, 0));
|
2018-07-19 16:41:31 +02:00
|
|
|
let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap();
|
2018-10-09 22:07:25 +02:00
|
|
|
header.set_seal(vec![encode(&1usize), encode(&(&*signature as &[u8]))]);
|
2017-09-26 14:19:08 +02:00
|
|
|
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
|
|
|
assert!(engine.verify_block_external(&header).is_ok());
|
2016-09-08 16:27:54 +02:00
|
|
|
}
|
2016-12-10 10:38:10 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn rejects_future_block() {
|
|
|
|
let tap = AccountProvider::transient_provider();
|
2018-06-22 15:09:15 +02:00
|
|
|
let addr = tap.insert_account(keccak("0").into(), &"0".into()).unwrap();
|
2016-12-10 10:38:10 +01:00
|
|
|
|
2017-03-08 14:41:24 +01:00
|
|
|
let mut parent_header: Header = Header::default();
|
2018-10-09 22:07:25 +02:00
|
|
|
parent_header.set_seal(vec![encode(&0usize)]);
|
2017-07-29 21:56:42 +02:00
|
|
|
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
2017-03-08 14:41:24 +01:00
|
|
|
let mut header: Header = Header::default();
|
|
|
|
header.set_number(1);
|
2017-07-29 21:56:42 +02:00
|
|
|
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
2016-12-10 10:38:10 +01:00
|
|
|
header.set_author(addr);
|
|
|
|
|
2019-08-07 16:52:48 +02:00
|
|
|
let engine = spec::new_test_round().engine;
|
2016-12-10 10:38:10 +01:00
|
|
|
|
2017-01-10 12:23:59 +01:00
|
|
|
// Two validators.
|
2016-12-10 10:38:10 +01:00
|
|
|
// Spec starts with step 2.
|
2018-11-21 22:30:03 +01:00
|
|
|
header.set_difficulty(calculate_score(0, 1, 0));
|
2018-07-19 16:41:31 +02:00
|
|
|
let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap();
|
2018-10-09 22:07:25 +02:00
|
|
|
header.set_seal(vec![encode(&1usize), encode(&(&*signature as &[u8]))]);
|
2017-09-26 14:19:08 +02:00
|
|
|
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
|
|
|
assert!(engine.verify_block_external(&header).is_ok());
|
2018-10-09 22:07:25 +02:00
|
|
|
header.set_seal(vec![encode(&5usize), encode(&(&*signature as &[u8]))]);
|
2018-01-19 10:38:59 +01:00
|
|
|
assert!(engine.verify_block_basic(&header).is_err());
|
2017-04-13 20:24:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn rejects_step_backwards() {
|
2017-04-19 20:44:11 +02:00
|
|
|
let tap = AccountProvider::transient_provider();
|
2018-06-22 15:09:15 +02:00
|
|
|
let addr = tap.insert_account(keccak("0").into(), &"0".into()).unwrap();
|
2017-04-13 20:24:21 +02:00
|
|
|
|
|
|
|
let mut parent_header: Header = Header::default();
|
2018-10-09 22:07:25 +02:00
|
|
|
parent_header.set_seal(vec![encode(&4usize)]);
|
2017-07-29 21:56:42 +02:00
|
|
|
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
2017-04-13 20:24:21 +02:00
|
|
|
let mut header: Header = Header::default();
|
|
|
|
header.set_number(1);
|
2017-07-29 21:56:42 +02:00
|
|
|
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
2017-04-13 20:24:21 +02:00
|
|
|
header.set_author(addr);
|
|
|
|
|
2019-08-07 16:52:48 +02:00
|
|
|
let engine = spec::new_test_round().engine;
|
2017-04-13 20:24:21 +02:00
|
|
|
|
|
|
|
let signature = tap.sign(addr, Some("0".into()), header.bare_hash()).unwrap();
|
|
|
|
// Two validators.
|
|
|
|
// Spec starts with step 2.
|
2018-10-09 22:07:25 +02:00
|
|
|
header.set_seal(vec![encode(&5usize), encode(&(&*signature as &[u8]))]);
|
2018-11-21 22:30:03 +01:00
|
|
|
header.set_difficulty(calculate_score(4, 5, 0));
|
2017-09-26 14:19:08 +02:00
|
|
|
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
2018-10-09 22:07:25 +02:00
|
|
|
header.set_seal(vec![encode(&3usize), encode(&(&*signature as &[u8]))]);
|
2018-11-21 22:30:03 +01:00
|
|
|
header.set_difficulty(calculate_score(4, 3, 0));
|
2017-09-26 14:19:08 +02:00
|
|
|
assert!(engine.verify_block_family(&header, &parent_header).is_err());
|
2016-12-10 10:38:10 +01:00
|
|
|
}
|
2017-05-22 08:21:34 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn reports_skipped() {
|
2019-06-25 13:15:00 +02:00
|
|
|
let validator1 = Address::from_low_u64_be(1);
|
|
|
|
let validator2 = Address::from_low_u64_be(2);
|
2017-05-22 08:21:34 +02:00
|
|
|
let last_benign = Arc::new(AtomicUsize::new(0));
|
2019-06-25 13:15:00 +02:00
|
|
|
|
|
|
|
let aura = build_aura(|p| {
|
|
|
|
let validator_set = TestSet::new(
|
|
|
|
Default::default(),
|
|
|
|
last_benign.clone(),
|
|
|
|
vec![validator1, validator2],
|
|
|
|
);
|
|
|
|
p.validators = Box::new(validator_set);
|
2018-12-10 19:58:38 +01:00
|
|
|
});
|
2017-05-22 08:21:34 +02:00
|
|
|
|
|
|
|
let mut parent_header: Header = Header::default();
|
2018-10-09 22:07:25 +02:00
|
|
|
parent_header.set_seal(vec![encode(&1usize)]);
|
2017-07-29 21:56:42 +02:00
|
|
|
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
2017-05-22 08:21:34 +02:00
|
|
|
let mut header: Header = Header::default();
|
2018-11-21 22:30:03 +01:00
|
|
|
header.set_difficulty(calculate_score(1, 3, 0));
|
2017-07-29 21:56:42 +02:00
|
|
|
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
2018-10-09 22:07:25 +02:00
|
|
|
header.set_seal(vec![encode(&3usize)]);
|
2017-05-22 08:21:34 +02:00
|
|
|
|
2017-07-13 09:48:00 +02:00
|
|
|
// Do not report when signer not present.
|
2017-09-26 14:19:08 +02:00
|
|
|
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
|
2017-07-13 09:48:00 +02:00
|
|
|
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 0);
|
|
|
|
|
2019-10-09 14:42:51 +02:00
|
|
|
aura.set_signer(Some(Box::new((
|
2019-06-25 13:15:00 +02:00
|
|
|
Arc::new(AccountProvider::transient_provider()),
|
|
|
|
validator2,
|
|
|
|
"".into(),
|
2019-10-09 14:42:51 +02:00
|
|
|
))));
|
2017-07-13 09:48:00 +02:00
|
|
|
|
2018-07-06 11:43:58 +02:00
|
|
|
// Do not report on steps skipped between genesis and first block.
|
|
|
|
header.set_number(1);
|
|
|
|
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
|
|
|
|
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 0);
|
|
|
|
|
|
|
|
// Report on skipped steps otherwise.
|
|
|
|
header.set_number(2);
|
2017-09-26 14:19:08 +02:00
|
|
|
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
|
2018-07-06 11:43:58 +02:00
|
|
|
assert_eq!(last_benign.load(AtomicOrdering::SeqCst), 2);
|
2017-05-22 08:21:34 +02:00
|
|
|
}
|
2017-12-05 15:57:45 +01:00
|
|
|
|
2019-10-14 12:56:38 +02:00
|
|
|
#[test]
|
|
|
|
fn reports_multiple_blocks_per_step() {
|
|
|
|
let tap = AccountProvider::transient_provider();
|
|
|
|
let addr0 = tap.insert_account(keccak("0").into(), &"0".into()).unwrap();
|
|
|
|
let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap();
|
|
|
|
|
|
|
|
let validator_set = TestSet::from_validators(vec![addr0, addr1]);
|
|
|
|
let aura = build_aura(|p| p.validators = Box::new(validator_set.clone()));
|
|
|
|
|
|
|
|
aura.set_signer(Some(Box::new((Arc::new(tap), addr0, "0".into()))));
|
|
|
|
|
|
|
|
let mut parent_header: Header = Header::default();
|
|
|
|
parent_header.set_number(2);
|
|
|
|
parent_header.set_seal(vec![encode(&1usize)]);
|
|
|
|
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
|
|
|
let mut header: Header = Header::default();
|
|
|
|
header.set_number(3);
|
|
|
|
header.set_difficulty(calculate_score(1, 2, 0));
|
|
|
|
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
|
|
|
header.set_seal(vec![encode(&2usize)]);
|
|
|
|
header.set_author(addr1);
|
|
|
|
|
|
|
|
// First sibling block.
|
|
|
|
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
|
|
|
|
assert_eq!(validator_set.last_malicious(), 0);
|
|
|
|
|
|
|
|
// Second sibling block: should be reported.
|
|
|
|
header.set_gas_limit("222223".parse::<U256>().unwrap());
|
|
|
|
assert!(aura.verify_block_family(&header, &parent_header).is_ok());
|
|
|
|
assert_eq!(validator_set.last_malicious(), 3);
|
|
|
|
}
|
|
|
|
|
2017-12-05 15:57:45 +01:00
|
|
|
#[test]
|
|
|
|
fn test_uncles_transition() {
|
2019-06-25 13:15:00 +02:00
|
|
|
let aura = build_aura(|params| {
|
2018-12-10 19:58:38 +01:00
|
|
|
params.maximum_uncle_count_transition = 1;
|
|
|
|
});
|
2017-12-05 15:57:45 +01:00
|
|
|
|
|
|
|
assert_eq!(aura.maximum_uncle_count(0), 2);
|
|
|
|
assert_eq!(aura.maximum_uncle_count(1), 0);
|
|
|
|
assert_eq!(aura.maximum_uncle_count(100), 0);
|
|
|
|
}
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
|
2019-06-25 13:15:00 +02:00
|
|
|
#[test]
|
|
|
|
#[should_panic(expected="counter is too high")]
|
|
|
|
fn test_counter_increment_too_high() {
|
|
|
|
use super::Step;
|
|
|
|
let step = Step {
|
|
|
|
calibrate: false,
|
|
|
|
inner: AtomicUsize::new(::std::usize::MAX),
|
|
|
|
duration: 1,
|
|
|
|
};
|
|
|
|
step.increment();
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected="counter is too high")]
|
|
|
|
fn test_counter_duration_remaining_too_high() {
|
|
|
|
use super::Step;
|
|
|
|
let step = Step {
|
|
|
|
calibrate: false,
|
|
|
|
inner: AtomicUsize::new(::std::usize::MAX),
|
|
|
|
duration: 1,
|
|
|
|
};
|
|
|
|
step.duration_remaining();
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected="authority_round: step duration can't be zero")]
|
|
|
|
fn test_step_duration_zero() {
|
2019-06-25 13:15:00 +02:00
|
|
|
build_aura(|params| {
|
2018-12-10 19:58:38 +01:00
|
|
|
params.step_duration = 0;
|
|
|
|
});
|
Problem: AuRa's unsafeties around step duration (#7282)
Firstly, `Step.duration_remaining` casts it to u32, unnecesarily
limiting it to 2^32. While theoretically this is "good enough" (at 3
seconds steps it provides room for a little over 400 years), it is
still a lossy way to calculate the remaining time until the next step.
Secondly, step duration might be zero, triggering division by zero
in `Step.calibrate`
Solution: rework the code around the fact that duration is
typically in single digits and never grows, hence, it can be represented
by a much narrower range (u16) and this highlights the fact that
multiplying u64 by u16 will only result in an overflow in even further
future, at which point we should panic informatively (if anybody's
still around)
Similarly, panic when it is detected that incrementing the step
counter wrapped around on the overflow of usize.
As for the division by zero, prevent it by making zero an invalid
value for step duration. This will make AuRa log the constraint
mismatch and panic (after all, what purpose would zero step duration
serve? it makes no sense within the definition of the protocol,
as finality can only be achieved as per the specification
if messages are received within the step duration, which would violate
the speed of light and other physical laws in this case).
2017-12-21 14:59:09 +01:00
|
|
|
}
|
2018-01-19 10:38:59 +01:00
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
fn setup_empty_steps() -> (Spec, Arc<AccountProvider>, Vec<Address>) {
|
2019-08-07 16:52:48 +02:00
|
|
|
let spec = spec::new_test_round_empty_steps();
|
2018-02-15 01:39:29 +01:00
|
|
|
let tap = Arc::new(AccountProvider::transient_provider());
|
|
|
|
|
2018-06-22 15:09:15 +02:00
|
|
|
let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap();
|
|
|
|
let addr2 = tap.insert_account(keccak("0").into(), &"0".into()).unwrap();
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
let accounts = vec![addr1, addr2];
|
|
|
|
|
|
|
|
(spec, tap, accounts)
|
|
|
|
}
|
|
|
|
|
2019-06-28 10:18:18 +02:00
|
|
|
fn empty_step(engine: &dyn Engine, step: u64, parent_hash: &H256) -> EmptyStep {
|
2018-02-15 01:39:29 +01:00
|
|
|
let empty_step_rlp = super::empty_step_rlp(step, parent_hash);
|
|
|
|
let signature = engine.sign(keccak(&empty_step_rlp)).unwrap().into();
|
|
|
|
let parent_hash = parent_hash.clone();
|
|
|
|
EmptyStep { step, signature, parent_hash }
|
|
|
|
}
|
|
|
|
|
2019-06-28 10:18:18 +02:00
|
|
|
fn sealed_empty_step(engine: &dyn Engine, step: u64, parent_hash: &H256) -> SealedEmptyStep {
|
2018-02-15 01:39:29 +01:00
|
|
|
let empty_step_rlp = super::empty_step_rlp(step, parent_hash);
|
|
|
|
let signature = engine.sign(keccak(&empty_step_rlp)).unwrap().into();
|
|
|
|
SealedEmptyStep { signature, step }
|
|
|
|
}
|
|
|
|
|
2019-10-23 13:03:46 +02:00
|
|
|
fn set_empty_steps_seal(header: &mut Header, step: u64, block_signature: &Signature, empty_steps: &[SealedEmptyStep]) {
|
2018-12-10 19:58:38 +01:00
|
|
|
header.set_seal(vec![
|
|
|
|
encode(&(step as usize)),
|
|
|
|
encode(&(&**block_signature as &[u8])),
|
|
|
|
::rlp::encode_list(&empty_steps),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn assert_insufficient_proof<T: ::std::fmt::Debug>(result: Result<T, Error>, contains: &str) {
|
|
|
|
match result {
|
2019-05-06 15:06:20 +02:00
|
|
|
Err(Error::Engine(EngineError::InsufficientProof(ref s))) =>{
|
2018-12-10 19:58:38 +01:00
|
|
|
assert!(s.contains(contains), "Expected {:?} to contain {:?}", s, contains);
|
|
|
|
},
|
|
|
|
e => assert!(false, "Unexpected result: {:?}", e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
#[test]
|
|
|
|
fn broadcast_empty_step_message() {
|
|
|
|
let (spec, tap, accounts) = setup_empty_steps();
|
|
|
|
|
|
|
|
let addr1 = accounts[0];
|
|
|
|
|
|
|
|
let engine = &*spec.engine;
|
|
|
|
let genesis_header = spec.genesis_header();
|
|
|
|
let db1 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
|
|
|
|
|
|
|
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
|
|
|
|
2019-08-07 16:52:48 +02:00
|
|
|
let client = generate_dummy_client_with_spec(spec::new_test_round_empty_steps);
|
2018-02-15 01:39:29 +01:00
|
|
|
let notify = Arc::new(TestNotify::default());
|
|
|
|
client.add_notify(notify.clone());
|
|
|
|
engine.register_client(Arc::downgrade(&client) as _);
|
|
|
|
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2018-02-15 01:39:29 +01:00
|
|
|
|
2019-07-04 13:43:20 +02:00
|
|
|
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
2018-07-16 13:53:55 +02:00
|
|
|
let b1 = b1.close_and_lock().unwrap();
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
// the block is empty so we don't seal and instead broadcast an empty step message
|
2019-03-15 13:22:47 +01:00
|
|
|
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
// spec starts with step 2
|
2018-10-09 22:07:25 +02:00
|
|
|
let empty_step_rlp = encode(&empty_step(engine, 2, &genesis_header.hash()));
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
// we've received the message
|
|
|
|
assert!(notify.messages.read().contains(&empty_step_rlp));
|
2018-11-21 22:30:03 +01:00
|
|
|
let len = notify.messages.read().len();
|
|
|
|
|
|
|
|
// make sure that we don't generate empty step for the second time
|
2019-03-15 13:22:47 +01:00
|
|
|
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
2018-11-21 22:30:03 +01:00
|
|
|
assert_eq!(len, notify.messages.read().len());
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn seal_with_empty_steps() {
|
|
|
|
let (spec, tap, accounts) = setup_empty_steps();
|
|
|
|
|
|
|
|
let addr1 = accounts[0];
|
|
|
|
let addr2 = accounts[1];
|
|
|
|
|
|
|
|
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()]);
|
|
|
|
|
2019-08-07 16:52:48 +02:00
|
|
|
let client = generate_dummy_client_with_spec(spec::new_test_round_empty_steps);
|
2018-07-16 13:53:55 +02:00
|
|
|
let notify = Arc::new(TestNotify::default());
|
|
|
|
client.add_notify(notify.clone());
|
|
|
|
engine.register_client(Arc::downgrade(&client) as _);
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
// step 2
|
2019-07-04 13:43:20 +02:00
|
|
|
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
2018-07-16 13:53:55 +02:00
|
|
|
let b1 = b1.close_and_lock().unwrap();
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
// since the block is empty it isn't sealed and we generate empty steps
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2019-03-15 13:22:47 +01:00
|
|
|
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
2018-02-15 01:39:29 +01:00
|
|
|
engine.step();
|
|
|
|
|
|
|
|
// step 3
|
2019-07-04 13:43:20 +02:00
|
|
|
let mut b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
2018-02-15 01:39:29 +01:00
|
|
|
b2.push_transaction(Transaction {
|
|
|
|
action: Action::Create,
|
|
|
|
nonce: U256::from(0),
|
|
|
|
gas_price: U256::from(3000),
|
|
|
|
gas: U256::from(53_000),
|
|
|
|
value: U256::from(1),
|
|
|
|
data: vec![],
|
|
|
|
}.fake_sign(addr2), None).unwrap();
|
2018-07-16 13:53:55 +02:00
|
|
|
let b2 = b2.close_and_lock().unwrap();
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
// we will now seal a block with 1tx and include the accumulated empty step message
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into()))));
|
2019-03-15 13:22:47 +01:00
|
|
|
if let Seal::Regular(seal) = engine.generate_seal(&b2, &genesis_header) {
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2018-02-15 01:39:29 +01:00
|
|
|
let empty_step2 = sealed_empty_step(engine, 2, &genesis_header.hash());
|
|
|
|
let empty_steps = ::rlp::encode_list(&vec![empty_step2]);
|
|
|
|
|
2018-10-09 22:07:25 +02:00
|
|
|
assert_eq!(seal[0], encode(&3usize));
|
|
|
|
assert_eq!(seal[2], empty_steps);
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn seal_empty_block_with_empty_steps() {
|
|
|
|
let (spec, tap, accounts) = setup_empty_steps();
|
|
|
|
|
|
|
|
let addr1 = accounts[0];
|
|
|
|
let addr2 = accounts[1];
|
|
|
|
|
|
|
|
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 db3 = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
|
|
|
|
|
|
|
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
|
|
|
|
2019-08-07 16:52:48 +02:00
|
|
|
let client = generate_dummy_client_with_spec(spec::new_test_round_empty_steps);
|
2018-07-16 13:53:55 +02:00
|
|
|
let notify = Arc::new(TestNotify::default());
|
|
|
|
client.add_notify(notify.clone());
|
|
|
|
engine.register_client(Arc::downgrade(&client) as _);
|
|
|
|
|
2018-02-15 01:39:29 +01:00
|
|
|
// step 2
|
2019-07-04 13:43:20 +02:00
|
|
|
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
2018-07-16 13:53:55 +02:00
|
|
|
let b1 = b1.close_and_lock().unwrap();
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
// since the block is empty it isn't sealed and we generate empty steps
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2019-03-15 13:22:47 +01:00
|
|
|
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
2018-02-15 01:39:29 +01:00
|
|
|
engine.step();
|
|
|
|
|
|
|
|
// step 3
|
2019-07-04 13:43:20 +02:00
|
|
|
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr2, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
2018-07-16 13:53:55 +02:00
|
|
|
let b2 = b2.close_and_lock().unwrap();
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into()))));
|
2019-03-15 13:22:47 +01:00
|
|
|
assert_eq!(engine.generate_seal(&b2, &genesis_header), Seal::None);
|
2018-02-15 01:39:29 +01:00
|
|
|
engine.step();
|
|
|
|
|
|
|
|
// step 4
|
|
|
|
// the spec sets the maximum_empty_steps to 2 so we will now seal an empty block and include the empty step messages
|
2019-07-04 13:43:20 +02:00
|
|
|
let b3 = OpenBlock::new(engine, Default::default(), false, db3, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
2018-07-16 13:53:55 +02:00
|
|
|
let b3 = b3.close_and_lock().unwrap();
|
2018-02-15 01:39:29 +01:00
|
|
|
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2019-03-15 13:22:47 +01:00
|
|
|
if let Seal::Regular(seal) = engine.generate_seal(&b3, &genesis_header) {
|
2018-02-15 01:39:29 +01:00
|
|
|
let empty_step2 = sealed_empty_step(engine, 2, &genesis_header.hash());
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into()))));
|
2018-02-15 01:39:29 +01:00
|
|
|
let empty_step3 = sealed_empty_step(engine, 3, &genesis_header.hash());
|
|
|
|
|
|
|
|
let empty_steps = ::rlp::encode_list(&vec![empty_step2, empty_step3]);
|
|
|
|
|
2018-10-09 22:07:25 +02:00
|
|
|
assert_eq!(seal[0], encode(&4usize));
|
|
|
|
assert_eq!(seal[2], empty_steps);
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn reward_empty_steps() {
|
|
|
|
let (spec, tap, accounts) = setup_empty_steps();
|
|
|
|
|
|
|
|
let addr1 = accounts[0];
|
|
|
|
|
|
|
|
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()]);
|
|
|
|
|
2019-08-07 16:52:48 +02:00
|
|
|
let client = generate_dummy_client_with_spec(spec::new_test_round_empty_steps);
|
2018-02-15 01:39:29 +01:00
|
|
|
engine.register_client(Arc::downgrade(&client) as _);
|
|
|
|
|
|
|
|
// step 2
|
2019-07-04 13:43:20 +02:00
|
|
|
let b1 = OpenBlock::new(engine, Default::default(), false, db1, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
2018-07-16 13:53:55 +02:00
|
|
|
let b1 = b1.close_and_lock().unwrap();
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
// since the block is empty it isn't sealed and we generate empty steps
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2019-03-15 13:22:47 +01:00
|
|
|
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
2018-02-15 01:39:29 +01:00
|
|
|
engine.step();
|
|
|
|
|
|
|
|
// step 3
|
|
|
|
// the signer of the accumulated empty step message should be rewarded
|
2019-07-04 13:43:20 +02:00
|
|
|
let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes.clone(), addr1, (3141562.into(), 31415620.into()), vec![], false).unwrap();
|
2019-03-15 13:22:47 +01:00
|
|
|
let addr1_balance = b2.state.balance(&addr1).unwrap();
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
// after closing the block `addr1` should be reward twice, one for the included empty step message and another for block creation
|
2018-07-16 13:53:55 +02:00
|
|
|
let b2 = b2.close_and_lock().unwrap();
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
// the spec sets the block reward to 10
|
2019-03-15 13:22:47 +01:00
|
|
|
assert_eq!(b2.state.balance(&addr1).unwrap(), addr1_balance + (10 * 2))
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn verify_seal_empty_steps() {
|
|
|
|
let (spec, tap, accounts) = setup_empty_steps();
|
|
|
|
let addr1 = accounts[0];
|
|
|
|
let addr2 = accounts[1];
|
|
|
|
let engine = &*spec.engine;
|
|
|
|
|
|
|
|
let mut parent_header: Header = Header::default();
|
2018-10-09 22:07:25 +02:00
|
|
|
parent_header.set_seal(vec![encode(&0usize)]);
|
2018-02-15 01:39:29 +01:00
|
|
|
parent_header.set_gas_limit("222222".parse::<U256>().unwrap());
|
|
|
|
|
|
|
|
let mut header: Header = Header::default();
|
|
|
|
header.set_parent_hash(parent_header.hash());
|
|
|
|
header.set_number(1);
|
|
|
|
header.set_gas_limit("222222".parse::<U256>().unwrap());
|
|
|
|
header.set_author(addr1);
|
|
|
|
|
|
|
|
let signature = tap.sign(addr1, Some("1".into()), header.bare_hash()).unwrap();
|
|
|
|
|
|
|
|
// empty step with invalid step
|
2019-06-03 15:36:21 +02:00
|
|
|
let empty_steps = vec![SealedEmptyStep { signature: H520::zero(), step: 2 }];
|
2018-12-10 19:58:38 +01:00
|
|
|
set_empty_steps_seal(&mut header, 2, &signature, &empty_steps);
|
2018-02-15 01:39:29 +01:00
|
|
|
|
2018-12-10 19:58:38 +01:00
|
|
|
assert_insufficient_proof(
|
|
|
|
engine.verify_block_family(&header, &parent_header),
|
|
|
|
"invalid step"
|
|
|
|
);
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
// empty step with invalid signature
|
2019-06-03 15:36:21 +02:00
|
|
|
let empty_steps = vec![SealedEmptyStep { signature: H520::zero(), step: 1 }];
|
2018-12-10 19:58:38 +01:00
|
|
|
set_empty_steps_seal(&mut header, 2, &signature, &empty_steps);
|
2018-02-15 01:39:29 +01:00
|
|
|
|
2018-12-10 19:58:38 +01:00
|
|
|
assert_insufficient_proof(
|
|
|
|
engine.verify_block_family(&header, &parent_header),
|
|
|
|
"invalid empty step proof"
|
|
|
|
);
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
// empty step with valid signature from incorrect proposer for step
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2018-02-15 01:39:29 +01:00
|
|
|
let empty_steps = vec![sealed_empty_step(engine, 1, &parent_header.hash())];
|
2018-12-10 19:58:38 +01:00
|
|
|
set_empty_steps_seal(&mut header, 2, &signature, &empty_steps);
|
2018-02-15 01:39:29 +01:00
|
|
|
|
2018-12-10 19:58:38 +01:00
|
|
|
assert_insufficient_proof(
|
|
|
|
engine.verify_block_family(&header, &parent_header),
|
|
|
|
"invalid empty step proof"
|
|
|
|
);
|
2018-02-15 01:39:29 +01:00
|
|
|
|
|
|
|
// valid empty steps
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2018-02-15 01:39:29 +01:00
|
|
|
let empty_step2 = sealed_empty_step(engine, 2, &parent_header.hash());
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr2, "0".into()))));
|
2018-02-15 01:39:29 +01:00
|
|
|
let empty_step3 = sealed_empty_step(engine, 3, &parent_header.hash());
|
|
|
|
|
|
|
|
let empty_steps = vec![empty_step2, empty_step3];
|
2018-11-21 22:30:03 +01:00
|
|
|
header.set_difficulty(calculate_score(0, 4, 2));
|
2018-07-19 16:41:31 +02:00
|
|
|
let signature = tap.sign(addr1, Some("1".into()), header.bare_hash()).unwrap();
|
2018-12-10 19:58:38 +01:00
|
|
|
set_empty_steps_seal(&mut header, 4, &signature, &empty_steps);
|
2018-02-15 01:39:29 +01:00
|
|
|
|
2018-07-19 16:41:31 +02:00
|
|
|
assert!(engine.verify_block_family(&header, &parent_header).is_ok());
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|
2018-04-20 12:32:00 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn block_reward_contract() {
|
2019-08-07 16:52:48 +02:00
|
|
|
let spec = spec::new_test_round_block_reward_contract();
|
2018-04-20 12:32:00 +02:00
|
|
|
let tap = Arc::new(AccountProvider::transient_provider());
|
|
|
|
|
2018-06-22 15:09:15 +02:00
|
|
|
let addr1 = tap.insert_account(keccak("1").into(), &"1".into()).unwrap();
|
2018-04-20 12:32:00 +02:00
|
|
|
|
|
|
|
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()]);
|
|
|
|
|
2019-08-07 16:52:48 +02:00
|
|
|
let client = generate_dummy_client_with_spec(spec::new_test_round_block_reward_contract);
|
2018-04-20 12:32:00 +02:00
|
|
|
engine.register_client(Arc::downgrade(&client) as _);
|
|
|
|
|
|
|
|
// step 2
|
|
|
|
let b1 = OpenBlock::new(
|
|
|
|
engine,
|
|
|
|
Default::default(),
|
|
|
|
false,
|
|
|
|
db1,
|
|
|
|
&genesis_header,
|
|
|
|
last_hashes.clone(),
|
|
|
|
addr1,
|
|
|
|
(3141562.into(), 31415620.into()),
|
|
|
|
vec![],
|
|
|
|
false,
|
|
|
|
).unwrap();
|
2018-07-16 13:53:55 +02:00
|
|
|
let b1 = b1.close_and_lock().unwrap();
|
2018-04-20 12:32:00 +02:00
|
|
|
|
|
|
|
// since the block is empty it isn't sealed and we generate empty steps
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2019-03-15 13:22:47 +01:00
|
|
|
assert_eq!(engine.generate_seal(&b1, &genesis_header), Seal::None);
|
2018-04-20 12:32:00 +02:00
|
|
|
engine.step();
|
|
|
|
|
|
|
|
// step 3
|
|
|
|
// the signer of the accumulated empty step message should be rewarded
|
|
|
|
let b2 = OpenBlock::new(
|
|
|
|
engine,
|
|
|
|
Default::default(),
|
|
|
|
false,
|
|
|
|
db2,
|
|
|
|
&genesis_header,
|
|
|
|
last_hashes.clone(),
|
|
|
|
addr1,
|
|
|
|
(3141562.into(), 31415620.into()),
|
|
|
|
vec![],
|
|
|
|
false,
|
|
|
|
).unwrap();
|
2019-03-15 13:22:47 +01:00
|
|
|
let addr1_balance = b2.state.balance(&addr1).unwrap();
|
2018-04-20 12:32:00 +02:00
|
|
|
|
|
|
|
// after closing the block `addr1` should be reward twice, one for the included empty step
|
|
|
|
// message and another for block creation
|
2018-07-16 13:53:55 +02:00
|
|
|
let b2 = b2.close_and_lock().unwrap();
|
2018-04-20 12:32:00 +02:00
|
|
|
|
|
|
|
// the contract rewards (1000 + kind) for each benefactor/reward kind
|
|
|
|
assert_eq!(
|
2019-03-15 13:22:47 +01:00
|
|
|
b2.state.balance(&addr1).unwrap(),
|
2018-09-04 20:13:51 +02:00
|
|
|
addr1_balance + (1000 + 0) + (1000 + 2),
|
2018-04-20 12:32:00 +02:00
|
|
|
)
|
|
|
|
}
|
2018-10-15 18:05:53 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn extra_info_from_seal() {
|
|
|
|
let (spec, tap, accounts) = setup_empty_steps();
|
|
|
|
let engine = &*spec.engine;
|
|
|
|
|
|
|
|
let addr1 = accounts[0];
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), addr1, "1".into()))));
|
2018-10-15 18:05:53 +02:00
|
|
|
|
|
|
|
let mut header: Header = Header::default();
|
|
|
|
let empty_step = empty_step(engine, 1, &header.parent_hash());
|
|
|
|
let sealed_empty_step = empty_step.sealed();
|
|
|
|
|
|
|
|
header.set_number(2);
|
|
|
|
header.set_seal(vec![
|
|
|
|
encode(&2usize),
|
|
|
|
encode(&H520::default()),
|
|
|
|
::rlp::encode_list(&vec![sealed_empty_step]),
|
|
|
|
]);
|
|
|
|
|
|
|
|
let info = engine.extra_info(&header);
|
|
|
|
|
|
|
|
let mut expected = BTreeMap::default();
|
|
|
|
expected.insert("step".into(), "2".into());
|
|
|
|
expected.insert("signature".into(), Signature::from(H520::default()).to_string());
|
|
|
|
expected.insert("emptySteps".into(), format!("[{}]", empty_step));
|
|
|
|
|
|
|
|
assert_eq!(info, expected);
|
|
|
|
|
|
|
|
header.set_seal(vec![]);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
engine.extra_info(&header),
|
|
|
|
BTreeMap::default(),
|
|
|
|
);
|
|
|
|
}
|
2018-11-21 22:30:03 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_empty_steps() {
|
2019-06-25 13:15:00 +02:00
|
|
|
let engine = build_aura(|p| {
|
2018-12-10 19:58:38 +01:00
|
|
|
p.step_duration = 4;
|
|
|
|
p.empty_steps_transition = 0;
|
|
|
|
p.maximum_empty_steps = 0;
|
|
|
|
});
|
2018-11-21 22:30:03 +01:00
|
|
|
|
2019-06-03 15:36:21 +02:00
|
|
|
let parent_hash = H256::from_low_u64_be(1);
|
2018-11-21 22:30:03 +01:00
|
|
|
let signature = H520::default();
|
|
|
|
let step = |step: u64| EmptyStep {
|
|
|
|
step,
|
|
|
|
parent_hash,
|
|
|
|
signature,
|
|
|
|
};
|
|
|
|
|
|
|
|
engine.handle_empty_step_message(step(1));
|
|
|
|
engine.handle_empty_step_message(step(3));
|
|
|
|
engine.handle_empty_step_message(step(2));
|
|
|
|
engine.handle_empty_step_message(step(1));
|
|
|
|
|
|
|
|
assert_eq!(engine.empty_steps(0, 4, parent_hash), vec![step(1), step(2), step(3)]);
|
|
|
|
assert_eq!(engine.empty_steps(2, 3, parent_hash), vec![]);
|
|
|
|
assert_eq!(engine.empty_steps(2, 4, parent_hash), vec![step(3)]);
|
|
|
|
|
|
|
|
engine.clear_empty_steps(2);
|
|
|
|
|
|
|
|
assert_eq!(engine.empty_steps(0, 3, parent_hash), vec![]);
|
|
|
|
assert_eq!(engine.empty_steps(0, 4, parent_hash), vec![step(3)]);
|
|
|
|
}
|
2018-12-10 19:58:38 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_reject_duplicate_empty_steps() {
|
|
|
|
// given
|
|
|
|
let (_spec, tap, accounts) = setup_empty_steps();
|
2019-06-25 13:15:00 +02:00
|
|
|
let engine = build_aura(|p| {
|
2018-12-10 19:58:38 +01:00
|
|
|
p.validators = Box::new(SimpleList::new(accounts.clone()));
|
|
|
|
p.step_duration = 4;
|
|
|
|
p.empty_steps_transition = 0;
|
|
|
|
p.maximum_empty_steps = 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
let mut parent = Header::default();
|
|
|
|
parent.set_seal(vec![encode(&0usize)]);
|
|
|
|
|
|
|
|
let mut header = Header::default();
|
|
|
|
header.set_number(parent.number() + 1);
|
|
|
|
header.set_parent_hash(parent.hash());
|
|
|
|
header.set_author(accounts[0]);
|
|
|
|
|
|
|
|
// when
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), accounts[1], "0".into()))));
|
2018-12-10 19:58:38 +01:00
|
|
|
let empty_steps = vec![
|
|
|
|
sealed_empty_step(&*engine, 1, &parent.hash()),
|
|
|
|
sealed_empty_step(&*engine, 1, &parent.hash()),
|
|
|
|
];
|
|
|
|
let step = 2;
|
|
|
|
let signature = tap.sign(accounts[0], Some("1".into()), header.bare_hash()).unwrap();
|
|
|
|
set_empty_steps_seal(&mut header, step, &signature, &empty_steps);
|
|
|
|
header.set_difficulty(calculate_score(0, step, empty_steps.len()));
|
|
|
|
|
|
|
|
// then
|
|
|
|
assert_insufficient_proof(
|
|
|
|
engine.verify_block_family(&header, &parent),
|
|
|
|
"duplicate empty step"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_reject_empty_steps_out_of_order() {
|
|
|
|
// given
|
|
|
|
let (_spec, tap, accounts) = setup_empty_steps();
|
2019-06-25 13:15:00 +02:00
|
|
|
let engine = build_aura(|p| {
|
2018-12-10 19:58:38 +01:00
|
|
|
p.validators = Box::new(SimpleList::new(accounts.clone()));
|
|
|
|
p.step_duration = 4;
|
|
|
|
p.empty_steps_transition = 0;
|
|
|
|
p.maximum_empty_steps = 0;
|
|
|
|
});
|
|
|
|
|
|
|
|
let mut parent = Header::default();
|
|
|
|
parent.set_seal(vec![encode(&0usize)]);
|
|
|
|
|
|
|
|
let mut header = Header::default();
|
|
|
|
header.set_number(parent.number() + 1);
|
|
|
|
header.set_parent_hash(parent.hash());
|
|
|
|
header.set_author(accounts[0]);
|
|
|
|
|
|
|
|
// when
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), accounts[1], "0".into()))));
|
2018-12-10 19:58:38 +01:00
|
|
|
let es1 = sealed_empty_step(&*engine, 1, &parent.hash());
|
2019-10-09 14:42:51 +02:00
|
|
|
engine.set_signer(Some(Box::new((tap.clone(), accounts[0], "1".into()))));
|
2018-12-10 19:58:38 +01:00
|
|
|
let es2 = sealed_empty_step(&*engine, 2, &parent.hash());
|
|
|
|
|
|
|
|
let mut empty_steps = vec![es2, es1];
|
|
|
|
|
|
|
|
let step = 3;
|
|
|
|
let signature = tap.sign(accounts[1], Some("0".into()), header.bare_hash()).unwrap();
|
|
|
|
set_empty_steps_seal(&mut header, step, &signature, &empty_steps);
|
|
|
|
header.set_difficulty(calculate_score(0, step, empty_steps.len()));
|
|
|
|
|
|
|
|
// then make sure it's rejected because of the order
|
|
|
|
assert_insufficient_proof(
|
|
|
|
engine.verify_block_family(&header, &parent),
|
|
|
|
"unordered empty step"
|
|
|
|
);
|
|
|
|
|
|
|
|
// now try to fix the order
|
|
|
|
empty_steps.reverse();
|
|
|
|
set_empty_steps_seal(&mut header, step, &signature, &empty_steps);
|
|
|
|
assert_eq!(engine.verify_block_family(&header, &parent).unwrap(), ());
|
|
|
|
}
|
2019-08-22 10:45:24 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn should_collect_block_reward_transitions() {
|
|
|
|
let config = r#"{
|
|
|
|
"params": {
|
|
|
|
"stepDuration": "5",
|
|
|
|
"validators": {
|
|
|
|
"list" : ["0x1000000000000000000000000000000000000001"]
|
|
|
|
},
|
|
|
|
"blockRewardContractTransition": "0",
|
|
|
|
"blockRewardContractAddress": "0x2000000000000000000000000000000000000002",
|
|
|
|
"blockRewardContractTransitions": {
|
|
|
|
"7": "0x3000000000000000000000000000000000000003",
|
|
|
|
"42": "0x4000000000000000000000000000000000000004"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}"#;
|
|
|
|
let deserialized: ethjson::spec::AuthorityRound = serde_json::from_str(config).unwrap();
|
|
|
|
let params = AuthorityRoundParams::from(deserialized.params);
|
|
|
|
for ((block_num1, address1), (block_num2, address2)) in
|
|
|
|
params.block_reward_contract_transitions.iter().zip(
|
|
|
|
[(0u64, BlockRewardContract::new_from_address(Address::from_str("2000000000000000000000000000000000000002").unwrap())),
|
|
|
|
(7u64, BlockRewardContract::new_from_address(Address::from_str("3000000000000000000000000000000000000003").unwrap())),
|
|
|
|
(42u64, BlockRewardContract::new_from_address(Address::from_str("4000000000000000000000000000000000000004").unwrap())),
|
|
|
|
].iter())
|
|
|
|
{
|
|
|
|
assert_eq!(block_num1, block_num2);
|
|
|
|
assert_eq!(address1, address2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
#[should_panic(expected="blockRewardContractTransition should be less than any of the keys in blockRewardContractTransitions")]
|
|
|
|
fn should_reject_out_of_order_block_reward_transition() {
|
|
|
|
let config = r#"{
|
|
|
|
"params": {
|
|
|
|
"stepDuration": "5",
|
|
|
|
"validators": {
|
|
|
|
"list" : ["0x1000000000000000000000000000000000000001"]
|
|
|
|
},
|
|
|
|
"blockRewardContractTransition": "7",
|
|
|
|
"blockRewardContractAddress": "0x2000000000000000000000000000000000000002",
|
|
|
|
"blockRewardContractTransitions": {
|
|
|
|
"0": "0x3000000000000000000000000000000000000003",
|
|
|
|
"42": "0x4000000000000000000000000000000000000004"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}"#;
|
|
|
|
let deserialized: ethjson::spec::AuthorityRound = serde_json::from_str(config).unwrap();
|
|
|
|
AuthorityRoundParams::from(deserialized.params);
|
|
|
|
}
|
2018-02-15 01:39:29 +01:00
|
|
|
}
|