Skip to content

Commit

Permalink
Add ChainTime associated type (paritytech#410)
Browse files Browse the repository at this point in the history
* add HeaderTimestamp associated type

* use Header Timestamp

* rename HeaderTimestamp to ChainTime

* add unit test

* deal with clippy

* Apply suggestions from code review

Commit review suggestions

Co-authored-by: Tomasz Drwięga <[email protected]>

* code review

* cargo fmt

* get rid of additional test runtime

* unit test asserts against concrete import context

Co-authored-by: Tomasz Drwięga <[email protected]>
  • Loading branch information
2 people authored and serban300 committed Apr 9, 2024
1 parent f00be3a commit 8c561e8
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 16 deletions.
14 changes: 13 additions & 1 deletion bridges/bin/rialto/runtime/src/kovan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ use bp_header_chain::BaseHeaderChain;
use frame_support::RuntimeDebug;
use hex_literal::hex;
use pallet_bridge_eth_poa::{
AuraConfiguration, PruningStrategy as BridgePruningStrategy, ValidatorsConfiguration, ValidatorsSource,
AuraConfiguration, ChainTime as TChainTime, PruningStrategy as BridgePruningStrategy, ValidatorsConfiguration,
ValidatorsSource,
};
use sp_std::prelude::*;

Expand Down Expand Up @@ -134,6 +135,17 @@ impl BridgePruningStrategy for PruningStrategy {
}
}

/// PoA Header timestamp verification against `Timestamp` pallet.
#[derive(Default, RuntimeDebug)]
pub struct ChainTime;

impl TChainTime for ChainTime {
fn is_timestamp_ahead(&self, timestamp: u64) -> bool {
let now = super::Timestamp::now();
timestamp > now
}
}

/// The Kovan Blockchain as seen by the runtime.
pub struct KovanBlockchain;

Expand Down
2 changes: 2 additions & 0 deletions bridges/bin/rialto/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ impl pallet_bridge_eth_poa::Trait<RialtoPoA> for Runtime {
type FinalityVotesCachingInterval = rialto_poa::FinalityVotesCachingInterval;
type ValidatorsConfiguration = rialto_poa::BridgeValidatorsConfiguration;
type PruningStrategy = rialto_poa::PruningStrategy;
type ChainTime = rialto_poa::ChainTime;
type OnHeadersSubmitted = ();
}

Expand All @@ -243,6 +244,7 @@ impl pallet_bridge_eth_poa::Trait<Kovan> for Runtime {
type FinalityVotesCachingInterval = kovan::FinalityVotesCachingInterval;
type ValidatorsConfiguration = kovan::BridgeValidatorsConfiguration;
type PruningStrategy = kovan::PruningStrategy;
type ChainTime = kovan::ChainTime;
type OnHeadersSubmitted = ();
}

Expand Down
14 changes: 13 additions & 1 deletion bridges/bin/rialto/runtime/src/rialto_poa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ use bp_header_chain::BaseHeaderChain;
use frame_support::RuntimeDebug;
use hex_literal::hex;
use pallet_bridge_eth_poa::{
AuraConfiguration, PruningStrategy as TPruningStrategy, ValidatorsConfiguration, ValidatorsSource,
AuraConfiguration, ChainTime as TChainTime, PruningStrategy as TPruningStrategy, ValidatorsConfiguration,
ValidatorsSource,
};
use sp_std::prelude::*;

Expand Down Expand Up @@ -109,6 +110,17 @@ impl TPruningStrategy for PruningStrategy {
}
}

/// ChainTime provider
#[derive(Default)]
pub struct ChainTime;

impl TChainTime for ChainTime {
fn is_timestamp_ahead(&self, timestamp: u64) -> bool {
let now = super::Timestamp::now();
timestamp > now
}
}

/// The Rialto PoA Blockchain as seen by the runtime.
pub struct RialtoBlockchain;

Expand Down
1 change: 1 addition & 0 deletions bridges/modules/ethereum/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ sp-std = { version = "2.0", default-features = false }

[dev-dependencies]
libsecp256k1 = { version = "0.3.4", features = ["hmac"] }
hex-literal = "0.3"

[features]
default = ["std"]
Expand Down
3 changes: 3 additions & 0 deletions bridges/modules/ethereum/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ pub enum Error {
UnsignedTooFarInTheFuture = 19,
/// Trying to finalize sibling of finalized block.
TryingToFinalizeSibling = 20,
/// Header timestamp is ahead of on-chain timestamp
HeaderTimestampIsAhead = 21,
}

impl Error {
Expand All @@ -88,6 +90,7 @@ impl Error {
Error::TransactionsReceiptsMismatch => "Invalid transactions receipts provided",
Error::UnsignedTooFarInTheFuture => "The unsigned header is too far in future",
Error::TryingToFinalizeSibling => "Trying to finalize sibling of finalized block",
Error::HeaderTimestampIsAhead => "Header timestamp is ahead of on-chain timestamp",
}
}

Expand Down
24 changes: 20 additions & 4 deletions bridges/modules/ethereum/src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::error::Error;
use crate::finality::finalize_blocks;
use crate::validators::{Validators, ValidatorsConfiguration};
use crate::verification::{is_importable_header, verify_aura_header};
use crate::{AuraConfiguration, ChangeToEnact, PruningStrategy, Storage};
use crate::{AuraConfiguration, ChainTime, ChangeToEnact, PruningStrategy, Storage};
use bp_eth_poa::{AuraHeader, HeaderId, Receipt};
use sp_std::{collections::btree_map::BTreeMap, prelude::*};

Expand All @@ -31,13 +31,16 @@ use sp_std::{collections::btree_map::BTreeMap, prelude::*};
/// we have NOT imported.
/// Returns error if fatal error has occured during import. Some valid headers may be
/// imported in this case.
pub fn import_headers<S: Storage, PS: PruningStrategy>(
/// TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/415)
#[allow(clippy::too_many_arguments)]
pub fn import_headers<S: Storage, PS: PruningStrategy, CT: ChainTime>(
storage: &mut S,
pruning_strategy: &mut PS,
aura_config: &AuraConfiguration,
validators_config: &ValidatorsConfiguration,
submitter: Option<S::Submitter>,
headers: Vec<(AuraHeader, Option<Vec<Receipt>>)>,
chain_time: &CT,
finalized_headers: &mut BTreeMap<S::Submitter, u64>,
) -> Result<(u64, u64), Error> {
let mut useful = 0;
Expand All @@ -50,6 +53,7 @@ pub fn import_headers<S: Storage, PS: PruningStrategy>(
validators_config,
submitter.clone(),
header,
chain_time,
receipts,
);

Expand Down Expand Up @@ -79,20 +83,23 @@ pub type FinalizedHeaders<S> = Vec<(HeaderId, Option<<S as Storage>::Submitter>)
/// has returned true.
///
/// Returns imported block id and list of all finalized headers.
pub fn import_header<S: Storage, PS: PruningStrategy>(
/// TODO: update me (https://github.com/paritytech/parity-bridges-common/issues/415)
#[allow(clippy::too_many_arguments)]
pub fn import_header<S: Storage, PS: PruningStrategy, CT: ChainTime>(
storage: &mut S,
pruning_strategy: &mut PS,
aura_config: &AuraConfiguration,
validators_config: &ValidatorsConfiguration,
submitter: Option<S::Submitter>,
header: AuraHeader,
chain_time: &CT,
receipts: Option<Vec<Receipt>>,
) -> Result<(HeaderId, FinalizedHeaders<S>), Error> {
// first check that we are able to import this header at all
let (header_id, finalized_id) = is_importable_header(storage, &header)?;

// verify header
let import_context = verify_aura_header(storage, aura_config, submitter, &header)?;
let import_context = verify_aura_header(storage, aura_config, submitter, &header, chain_time)?;

// check if block schedules new validators
let validators = Validators::new(validators_config);
Expand Down Expand Up @@ -195,6 +202,7 @@ mod tests {
&test_validators_config(),
None,
Default::default(),
&(),
None,
),
Err(Error::AncientHeader),
Expand All @@ -215,6 +223,7 @@ mod tests {
&test_validators_config(),
None,
header.clone(),
&(),
None,
)
.map(|_| ()),
Expand All @@ -228,6 +237,7 @@ mod tests {
&test_validators_config(),
None,
header,
&(),
None,
)
.map(|_| ()),
Expand All @@ -254,6 +264,7 @@ mod tests {
&validators_config,
None,
header,
&(),
None
)
.map(|_| ()),
Expand Down Expand Up @@ -291,6 +302,7 @@ mod tests {
&validators_config,
Some(100),
header,
&(),
None,
)
.unwrap();
Expand Down Expand Up @@ -320,6 +332,7 @@ mod tests {
&validators_config,
Some(101),
header11.clone(),
&(),
Some(vec![validators_change_receipt(latest_block_id.hash)]),
)
.unwrap();
Expand All @@ -345,6 +358,7 @@ mod tests {
&validators_config,
Some(102),
header,
&(),
None,
)
.unwrap();
Expand Down Expand Up @@ -374,6 +388,7 @@ mod tests {
&validators_config,
Some(103),
header,
&(),
None,
)
.unwrap();
Expand Down Expand Up @@ -404,6 +419,7 @@ mod tests {
)),
None,
header,
&(),
None,
)
.map(|_| id)
Expand Down
24 changes: 24 additions & 0 deletions bridges/modules/ethereum/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,25 @@ pub trait PruningStrategy: Default {
fn pruning_upper_bound(&mut self, best_number: u64, best_finalized_number: u64) -> u64;
}

/// ChainTime represents the runtime on-chain time
pub trait ChainTime: Default {
/// Is a header timestamp ahead of the current on-chain time.
///
/// Check whether `timestamp` is ahead (i.e greater than) the current on-chain
/// time. If so, return `true`, `false` otherwise.
fn is_timestamp_ahead(&self, timestamp: u64) -> bool;
}

/// ChainTime implementation for the empty type.
///
/// This implementation will allow a runtime without the timestamp pallet to use
/// the empty type as its ChainTime associated type.
impl ChainTime for () {
fn is_timestamp_ahead(&self, _: u64) -> bool {
false
}
}

/// Callbacks for header submission rewards/penalties.
pub trait OnHeadersSubmitted<AccountId> {
/// Called when valid headers have been submitted.
Expand Down Expand Up @@ -366,6 +385,8 @@ pub trait Trait<I = DefaultInstance>: frame_system::Trait {
type FinalityVotesCachingInterval: Get<Option<u64>>;
/// Headers pruning strategy.
type PruningStrategy: PruningStrategy;
/// Header timestamp verification against current on-chain time.
type ChainTime: ChainTime;

/// Handler for headers submission result.
type OnHeadersSubmitted: OnHeadersSubmitted<Self::AccountId>;
Expand All @@ -385,6 +406,7 @@ decl_module! {
&T::ValidatorsConfiguration::get(),
None,
header,
&T::ChainTime::default(),
receipts,
).map_err(|e| e.msg())?;
}
Expand All @@ -406,6 +428,7 @@ decl_module! {
&T::ValidatorsConfiguration::get(),
Some(submitter.clone()),
headers_with_receipts,
&T::ChainTime::default(),
&mut finalized_headers,
);

Expand Down Expand Up @@ -531,6 +554,7 @@ impl<T: Trait<I>, I: Instance> frame_support::unsigned::ValidateUnsigned for Mod
&T::ValidatorsConfiguration::get(),
&pool_configuration(),
header,
&T::ChainTime::default(),
receipts.as_ref(),
);

Expand Down
14 changes: 13 additions & 1 deletion bridges/modules/ethereum/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub use crate::test_utils::{insert_header, validator_utils::*, validators_change
pub use bp_eth_poa::signatures::secret_to_address;

use crate::validators::{ValidatorsConfiguration, ValidatorsSource};
use crate::{AuraConfiguration, GenesisConfig, PruningStrategy, Trait};
use crate::{AuraConfiguration, ChainTime, GenesisConfig, PruningStrategy, Trait};
use bp_eth_poa::{Address, AuraHeader, H256, U256};
use frame_support::{impl_outer_origin, parameter_types, weights::Weight};
use secp256k1::SecretKey;
Expand Down Expand Up @@ -83,6 +83,7 @@ impl Trait for TestRuntime {
type ValidatorsConfiguration = TestValidatorsConfiguration;
type FinalityVotesCachingInterval = TestFinalityVotesCachingInterval;
type PruningStrategy = KeepSomeHeadersBehindBest;
type ChainTime = ConstChainTime;
type OnHeadersSubmitted = ();
}

Expand Down Expand Up @@ -168,3 +169,14 @@ impl PruningStrategy for KeepSomeHeadersBehindBest {
best_number.saturating_sub(self.0)
}
}

/// Constant chain time
#[derive(Default)]
pub struct ConstChainTime;

impl ChainTime for ConstChainTime {
fn is_timestamp_ahead(&self, timestamp: u64) -> bool {
let now = i32::max_value() as u64 / 2;
timestamp > now
}
}
Loading

0 comments on commit 8c561e8

Please sign in to comment.