use crate::{
consensus::{ConsensusClientId, StateMachineClient, StateMachineHeight},
error::Error,
events::Event,
host::IsmpHost,
messaging::Message,
};
use crate::{consensus::ConsensusStateId, module::DispatchResult};
use alloc::{boxed::Box, vec::Vec};
pub use consensus::create_client;
use sp_weights::Weight;
mod consensus;
mod request;
mod response;
mod timeout;
pub struct ConsensusClientCreatedResult {
pub consensus_client_id: ConsensusClientId,
pub consensus_state_id: ConsensusStateId,
}
#[derive(Debug)]
pub enum MessageResult {
ConsensusMessage(Vec<Event>),
FrozenClient(ConsensusStateId),
Request {
events: Vec<DispatchResult>,
weight: Weight,
},
Response {
events: Vec<DispatchResult>,
weight: Weight,
},
Timeout {
events: Vec<DispatchResult>,
weight: Weight,
},
}
impl MessageResult {
pub fn weight(&self) -> Weight {
match self {
MessageResult::Request { weight, .. } => *weight,
MessageResult::Response { weight, .. } => *weight,
MessageResult::Timeout { weight, .. } => *weight,
MessageResult::ConsensusMessage(_) | MessageResult::FrozenClient(_) => Weight::zero(),
}
}
}
pub fn handle_incoming_message<H>(
host: &H,
message: Message,
) -> Result<MessageResult, anyhow::Error>
where
H: IsmpHost,
{
match message {
Message::Consensus(consensus_message) => consensus::update_client(host, consensus_message),
Message::FraudProof(fraud_proof) => consensus::freeze_client(host, fraud_proof),
Message::Request(req) => request::handle(host, req),
Message::Response(resp) => response::handle(host, resp),
Message::Timeout(timeout) => timeout::handle(host, timeout),
}
}
pub fn verify_delay_passed<H>(host: &H, proof_height: &StateMachineHeight) -> Result<bool, Error>
where
H: IsmpHost,
{
let update_time = host.state_machine_update_time(*proof_height)?;
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)
}
pub fn validate_state_machine<H>(
host: &H,
proof_height: StateMachineHeight,
) -> Result<Box<dyn StateMachineClient>, Error>
where
H: IsmpHost,
{
let consensus_client_id = host.consensus_client_id(proof_height.id.consensus_state_id).ok_or(
Error::ConsensusStateIdNotRecognized {
consensus_state_id: proof_height.id.consensus_state_id,
},
)?;
let consensus_client = host.consensus_client(consensus_client_id)?;
host.is_consensus_client_frozen(proof_height.id.consensus_state_id)?;
if !verify_delay_passed(host, &proof_height)? {
return Err(Error::ChallengePeriodNotElapsed {
state_machine_id: proof_height.id,
current_time: host.timestamp(),
update_time: host.state_machine_update_time(proof_height)?,
});
}
consensus_client.state_machine(proof_height.id.state_id)
}