Skip to content

Commit

Permalink
Configure state machines with independent challenge periods (#293)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wizdave97 authored Aug 14, 2024
1 parent aab7a08 commit 49f8a18
Show file tree
Hide file tree
Showing 36 changed files with 498 additions and 181 deletions.
2 changes: 1 addition & 1 deletion modules/hyperclient/src/any_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ impl Client for AnyClient {

async fn query_challenge_period(
&self,
id: ismp::consensus::ConsensusStateId,
id: ismp::consensus::StateMachineId,
) -> Result<std::time::Duration, anyhow::Error> {
match self {
AnyClient::Evm(inner) => inner.query_challenge_period(id).await,
Expand Down
10 changes: 4 additions & 6 deletions modules/hyperclient/src/internals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,9 +150,8 @@ pub async fn encode_request_message_and_wait_for_challenge_period(
let calldata =
encode_request_call_data(hyperbridge, dest_client, post, commitment, height).await?;
let proof_height = StateMachineHeight { id: hyperbridge.state_machine, height };
let challenge_period = dest_client
.query_challenge_period(hyperbridge.state_machine_id().consensus_state_id)
.await?;
let challenge_period =
dest_client.query_challenge_period(hyperbridge.state_machine_id()).await?;
let update_time = dest_client.query_state_machine_update_time(proof_height).await?;
wait_for_challenge_period(dest_client, update_time, challenge_period).await?;

Expand All @@ -167,9 +166,8 @@ pub async fn encode_response_message_and_wait_for_challenge_period(
) -> Result<Vec<u8>, anyhow::Error> {
let calldata = encode_response_call_data(hyperbridge, dest_client, response, height).await?;
let proof_height = StateMachineHeight { id: hyperbridge.state_machine, height };
let challenge_period = dest_client
.query_challenge_period(hyperbridge.state_machine_id().consensus_state_id)
.await?;
let challenge_period =
dest_client.query_challenge_period(hyperbridge.state_machine_id()).await?;
let update_time = dest_client.query_state_machine_update_time(proof_height).await?;
wait_for_challenge_period(dest_client, update_time, challenge_period).await?;

Expand Down
8 changes: 2 additions & 6 deletions modules/hyperclient/src/internals/post_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -745,9 +745,7 @@ pub async fn timeout_post_request_stream(
timeout_proof: Proof { height, proof },
});
let challenge_period = hyperbridge_client
.query_challenge_period(
dest_client.state_machine_id().consensus_state_id,
)
.query_challenge_period(dest_client.state_machine_id())
.await?;
let update_time =
hyperbridge_client.query_state_machine_update_time(height).await?;
Expand Down Expand Up @@ -851,9 +849,7 @@ pub async fn timeout_post_request_stream(
timeout_proof: Proof { height, proof },
});
let challenge_period = source_client
.query_challenge_period(
hyperbridge_client.state_machine_id().consensus_state_id,
)
.query_challenge_period(hyperbridge_client.state_machine_id())
.await?;
let update_time =
source_client.query_state_machine_update_time(height).await?;
Expand Down
2 changes: 1 addition & 1 deletion modules/hyperclient/src/providers/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,7 @@ impl Client for EvmClient {
Ok(Duration::from_secs(value.low_u64()))
}

async fn query_challenge_period(&self, _id: ConsensusStateId) -> Result<Duration, Error> {
async fn query_challenge_period(&self, _id: StateMachineId) -> Result<Duration, Error> {
let contract = EvmHost::new(self.host_address, self.client.clone());
let value = contract.challenge_period().call().await?;
Ok(Duration::from_secs(value.low_u64()))
Expand Down
5 changes: 2 additions & 3 deletions modules/hyperclient/src/providers/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::types::{BoxStream, EventMetadata};
use core::time::Duration;
use ethers::{prelude::H256, types::H160};
use ismp::{
consensus::{ConsensusStateId, StateCommitment, StateMachineHeight, StateMachineId},
consensus::{StateCommitment, StateMachineHeight, StateMachineId},
events::{Event, StateMachineUpdated},
host::StateMachine,
messaging::Message,
Expand Down Expand Up @@ -163,8 +163,7 @@ pub trait Client: Clone + Send + Sync + 'static {
) -> Result<Duration, anyhow::Error>;

/// Query the challenge period for client
async fn query_challenge_period(&self, id: ConsensusStateId)
-> Result<Duration, anyhow::Error>;
async fn query_challenge_period(&self, id: StateMachineId) -> Result<Duration, anyhow::Error>;
}

pub async fn wait_for_challenge_period<C: Client>(
Expand Down
4 changes: 2 additions & 2 deletions modules/hyperclient/src/providers/substrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use futures::{stream, StreamExt};
use hashbrown::HashMap;
use hex_literal::hex;
use ismp::{
consensus::{ConsensusStateId, StateCommitment, StateMachineHeight, StateMachineId},
consensus::{StateCommitment, StateMachineHeight, StateMachineId},
events::{Event, StateMachineUpdated},
host::StateMachine,
messaging::{hash_request, hash_response, Message},
Expand Down Expand Up @@ -543,7 +543,7 @@ impl<C: subxt::Config + Clone> Client for SubstrateClient<C> {
Ok(Duration::from_secs(value))
}

async fn query_challenge_period(&self, id: ConsensusStateId) -> Result<Duration, Error> {
async fn query_challenge_period(&self, id: StateMachineId) -> Result<Duration, Error> {
let params = rpc_params![id];
let response: u64 = self.client.rpc().request("ismp_queryChallengePeriod", params).await?;

Expand Down
25 changes: 23 additions & 2 deletions modules/ismp/clients/parachain/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ pub mod pallet {
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;
use ismp::{
host::IsmpHost,
consensus::StateMachineId,
host::{IsmpHost, StateMachine},
messaging::{ConsensusMessage, Message},
};
use migration::StorageV0;
Expand Down Expand Up @@ -126,8 +127,18 @@ pub mod pallet {
#[pallet::weight(<T as frame_system::Config>::DbWeight::get().writes(para_ids.len() as u64))]
pub fn add_parachain(origin: OriginFor<T>, para_ids: Vec<ParachainData>) -> DispatchResult {
T::AdminOrigin::ensure_origin(origin)?;
let host = <T::IsmpHost>::default();
for para in &para_ids {
let state_id = match host.host_state_machine() {
StateMachine::Kusama(_) => StateMachine::Kusama(para.id),
StateMachine::Polkadot(_) => StateMachine::Polkadot(para.id),
_ => continue,
};
Parachains::<T>::insert(para.id, para.slot_duration);
let _ = host.store_challenge_period(
StateMachineId { state_id, consensus_state_id: PARACHAIN_CONSENSUS_ID },
0,
);
}

Self::deposit_event(Event::ParachainsAdded { para_ids });
Expand Down Expand Up @@ -212,10 +223,20 @@ pub mod pallet {
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
Pallet::<T>::initialize();
let host = <T::IsmpHost>::default();

// insert the parachain ids
for para in &self.parachains {
Parachains::<T>::insert(para.id, para.slot_duration);
let state_id = match host.host_state_machine() {
StateMachine::Kusama(_) => StateMachine::Kusama(para.id),
StateMachine::Polkadot(_) => StateMachine::Polkadot(para.id),
_ => continue,
};
let _ = host.store_challenge_period(
StateMachineId { state_id, consensus_state_id: PARACHAIN_CONSENSUS_ID },
0,
);
}
}
}
Expand All @@ -242,7 +263,7 @@ impl<T: Config> Pallet<T> {
// insert empty bytes
consensus_state: vec![],
unbonding_period: u64::MAX,
challenge_period: 0,
challenge_periods: Default::default(),
consensus_state_id: PARACHAIN_CONSENSUS_ID,
consensus_client_id: PARACHAIN_CONSENSUS_ID,
state_machine_commitments: vec![],
Expand Down
8 changes: 4 additions & 4 deletions modules/ismp/core/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
//! ISMP error definitions
use crate::{
consensus::{ConsensusClientId, ConsensusStateId, StateMachineHeight},
consensus::{ConsensusClientId, ConsensusStateId, StateMachineHeight, StateMachineId},
events::Meta,
};
use alloc::{string::String, vec::Vec};
Expand All @@ -37,7 +37,7 @@ pub enum Error {
/// new consensus updates in the mean time.
ChallengePeriodNotElapsed {
/// The consensus client identifier
consensus_state_id: ConsensusStateId,
state_machine_id: StateMachineId,
/// The last time the consensus client was updated
update_time: Duration,
/// The current time
Expand Down Expand Up @@ -122,8 +122,8 @@ pub enum Error {

/// Challenge period has not been configured for this consensus state
ChallengePeriodNotConfigured {
/// Consensus state Id
consensus_state_id: ConsensusStateId,
/// State Machine Id
state_machine: StateMachineId,
},
/// Consensus state id already exists
DuplicateConsensusStateId {
Expand Down
10 changes: 4 additions & 6 deletions modules/ismp/core/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,9 @@ where
H: IsmpHost,
{
let update_time = host.state_machine_update_time(*proof_height)?;
let delay_period = host.challenge_period(proof_height.id.consensus_state_id).ok_or(
Error::ChallengePeriodNotConfigured {
consensus_state_id: proof_height.id.consensus_state_id,
},
)?;
let delay_period = host
.challenge_period(proof_height.id)
.ok_or(Error::ChallengePeriodNotConfigured { state_machine: proof_height.id })?;
let current_timestamp = host.timestamp();
Ok(delay_period.as_secs() == 0 || current_timestamp.saturating_sub(update_time) > delay_period)
}
Expand Down Expand Up @@ -109,7 +107,7 @@ where
// Ensure delay period has elapsed
if !verify_delay_passed(host, &proof_height)? {
return Err(Error::ChallengePeriodNotElapsed {
consensus_state_id: proof_height.id.consensus_state_id,
state_machine_id: proof_height.id,
current_time: host.timestamp(),
update_time: host.state_machine_update_time(proof_height)?,
});
Expand Down
7 changes: 6 additions & 1 deletion modules/ismp/core/src/handlers/consensus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,14 @@ where
// Store the initial state for the consensus client
host.store_consensus_state(message.consensus_state_id, message.consensus_state)?;
host.store_unbonding_period(message.consensus_state_id, message.unbonding_period)?;
host.store_challenge_period(message.consensus_state_id, message.challenge_period)?;
host.store_consensus_state_id(message.consensus_state_id, message.consensus_client_id)?;

// Store all challenge periods
for (state_id, challenge_period) in message.challenge_periods {
let id = StateMachineId { state_id, consensus_state_id: message.consensus_state_id };
host.store_challenge_period(id, challenge_period)?;
}

// Store all intermediate state machine commitments
for (id, state_commitment) in message.state_machine_commitments {
let height = StateMachineHeight { id, height: state_commitment.height };
Expand Down
4 changes: 2 additions & 2 deletions modules/ismp/core/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,12 @@ pub trait IsmpHost: Keccak256 {
fn consensus_clients(&self) -> Vec<Box<dyn ConsensusClient>>;

/// Should return the configured delay period for a consensus state
fn challenge_period(&self, consensus_state_id: ConsensusStateId) -> Option<Duration>;
fn challenge_period(&self, state_machine: StateMachineId) -> Option<Duration>;

/// Set the challenge period in seconds for a consensus state.
fn store_challenge_period(
&self,
consensus_state_id: ConsensusStateId,
state_machine: StateMachineId,
period: u64,
) -> Result<(), Error>;

Expand Down
7 changes: 5 additions & 2 deletions modules/ismp/core/src/messaging.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@
// Messages are processed in batches, all messages in a batch should
// originate from the same chain

use alloc::collections::BTreeMap;

use crate::{
consensus::{
ConsensusClientId, ConsensusStateId, StateCommitment, StateMachineHeight, StateMachineId,
},
error::Error,
host::StateMachine,
router::{GetResponse, PostRequest, PostResponse, Request, RequestResponse, Response},
};
use alloc::{string::ToString, vec::Vec};
Expand Down Expand Up @@ -95,8 +98,8 @@ pub struct CreateConsensusState {
pub consensus_state_id: ConsensusStateId,
/// Unbonding period for this consensus state.
pub unbonding_period: u64,
/// Challenge period for this consensus state
pub challenge_period: u64,
/// Challenge period for the supported state machines
pub challenge_periods: BTreeMap<StateMachine, u64>,
/// State machine commitments
pub state_machine_commitments: Vec<(StateMachineId, StateCommitmentHeight)>,
}
Expand Down
6 changes: 3 additions & 3 deletions modules/ismp/pallets/pallet/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ pub enum HandlingError {
update_time: u64,
current_time: u64,
delay_period: Option<u64>,
consensus_client_id: Option<ConsensusClientId>,
consensus_client_id: Option<StateMachineId>,
},
ConsensusStateNotFound {
id: ConsensusClientId,
Expand Down Expand Up @@ -172,14 +172,14 @@ impl From<ismp::error::Error> for HandlingError {
fn from(value: ismp::error::Error) -> Self {
match value {
IsmpError::ChallengePeriodNotElapsed {
consensus_state_id,
state_machine_id,
current_time,
update_time,
} => HandlingError::ChallengePeriodNotElapsed {
update_time: update_time.as_secs(),
current_time: current_time.as_secs(),
delay_period: None,
consensus_client_id: Some(consensus_state_id),
consensus_client_id: Some(state_machine_id),
},
IsmpError::ConsensusStateNotFound { consensus_state_id } =>
HandlingError::ConsensusStateNotFound { id: consensus_state_id },
Expand Down
8 changes: 4 additions & 4 deletions modules/ismp/pallets/pallet/src/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,16 +271,16 @@ impl<T: Config> IsmpHost for Pallet<T> {
<T as Config>::ConsensusClients::consensus_clients()
}

fn challenge_period(&self, id: ConsensusStateId) -> Option<Duration> {
ChallengePeriod::<T>::get(&id).map(Duration::from_secs)
fn challenge_period(&self, state_machine: StateMachineId) -> Option<Duration> {
ChallengePeriod::<T>::get(&state_machine).map(Duration::from_secs)
}

fn store_challenge_period(
&self,
consensus_state_id: ConsensusStateId,
state_machine: StateMachineId,
period: u64,
) -> Result<(), Error> {
ChallengePeriod::<T>::insert(consensus_state_id, period);
ChallengePeriod::<T>::insert(state_machine, period);
Ok(())
}

Expand Down
10 changes: 6 additions & 4 deletions modules/ismp/pallets/pallet/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,11 +344,11 @@ pub mod pallet {
pub type UnbondingPeriod<T: Config> =
StorageMap<_, Blake2_128Concat, ConsensusStateId, u64, OptionQuery>;

/// A mapping of consensus state identifiers to their challenge periods
/// A mapping of state machine Ids to their challenge periods
#[pallet::storage]
#[pallet::getter(fn challenge_period)]
pub type ChallengePeriod<T: Config> =
StorageMap<_, Blake2_128Concat, ConsensusStateId, u64, OptionQuery>;
StorageMap<_, Blake2_128Concat, StateMachineId, u64, OptionQuery>;

/// Holds a map of consensus clients frozen due to byzantine
/// behaviour
Expand Down Expand Up @@ -512,8 +512,10 @@ pub mod pallet {
.map_err(|_| Error::<T>::UnbondingPeriodUpdateFailed)?;
}

if let Some(challenge_period) = message.challenge_period {
host.store_challenge_period(message.consensus_state_id, challenge_period)
for (state_id, period) in message.challenge_periods {
let id =
StateMachineId { state_id, consensus_state_id: message.consensus_state_id };
host.store_challenge_period(id, period)
.map_err(|_| Error::<T>::UnbondingPeriodUpdateFailed)?;
}

Expand Down
11 changes: 8 additions & 3 deletions modules/ismp/pallets/pallet/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@

//! Pallet utilities
use alloc::collections::BTreeMap;

use codec::{Decode, Encode};
use frame_support::PalletId;
use ismp::consensus::{ConsensusClient, ConsensusStateId};
use ismp::{
consensus::{ConsensusClient, ConsensusStateId},
host::StateMachine,
};
use sp_core::{
crypto::{AccountId32, ByteArray},
H160, H256,
Expand All @@ -31,8 +36,8 @@ pub struct UpdateConsensusState {
pub consensus_state_id: ConsensusStateId,
/// Unbonding duration
pub unbonding_period: Option<u64>,
/// Challenge period duration
pub challenge_period: Option<u64>,
/// Challenge period duration for different state machines
pub challenge_periods: BTreeMap<StateMachine, u64>,
}

/// Holds a commitment to either a request or response
Expand Down
Loading

0 comments on commit 49f8a18

Please sign in to comment.