diff --git a/enclave-modules/ecall-handler/src/light_client/aggregate_messages.rs b/enclave-modules/ecall-handler/src/light_client/aggregate_messages.rs index d15e1a63..6e7b4c41 100644 --- a/enclave-modules/ecall-handler/src/light_client/aggregate_messages.rs +++ b/enclave-modules/ecall-handler/src/light_client/aggregate_messages.rs @@ -4,7 +4,7 @@ use context::Context; use crypto::{EnclavePublicKey, Signer, Verifier}; use ecall_commands::{AggregateMessagesInput, AggregateMessagesResponse, LightClientResponse}; use light_client::{ - commitments::{self, prove_commitment, Message, UpdateClientMessage}, + commitments::{self, prove_commitment, ProxyMessage, UpdateStateProxyMessage}, HostContext, LightClientResolver, }; use store::KVStore; @@ -32,18 +32,18 @@ pub fn aggregate_messages( let messages = input .messages .into_iter() - .map(|c| Message::from_bytes(&c)?.try_into()) + .map(|m| ProxyMessage::from_bytes(&m)?.try_into()) .collect::, _>>()? .into_iter() .zip(input.signatures.iter()) - .map(|(c, s)| -> Result<_, Error> { - verify_commitment(&pk, &c, s)?; - c.context.validate(ctx.host_timestamp())?; - Ok(c) + .map(|(m, s)| -> Result<_, Error> { + verify_message(&pk, &m, s)?; + m.context.validate(ctx.host_timestamp())?; + Ok(m) }) .collect::, _>>()?; - let message = Message::from(commitments::aggregate_messages(messages)?); + let message = ProxyMessage::from(commitments::aggregate_messages(messages)?); let proof = prove_commitment(ek, input.signer, message)?; Ok(LightClientResponse::AggregateMessages( @@ -51,12 +51,12 @@ pub fn aggregate_messages( )) } -fn verify_commitment( +fn verify_message( verifier: &EnclavePublicKey, - commitment: &UpdateClientMessage, + message: &UpdateStateProxyMessage, signature: &[u8], ) -> Result<(), Error> { - let message_bytes = Message::UpdateClient(commitment.clone()).to_bytes(); + let message_bytes = ProxyMessage::UpdateState(message.clone()).to_bytes(); verifier .verify(&message_bytes, signature) .map_err(Error::crypto)?; diff --git a/enclave-modules/ecall-handler/src/light_client/update_client.rs b/enclave-modules/ecall-handler/src/light_client/update_client.rs index 6ec8bbd6..bf1190c4 100644 --- a/enclave-modules/ecall-handler/src/light_client/update_client.rs +++ b/enclave-modules/ecall-handler/src/light_client/update_client.rs @@ -4,7 +4,7 @@ use crate::prelude::*; use context::Context; use crypto::Signer; use ecall_commands::{LightClientResponse, UpdateClientInput, UpdateClientResponse}; -use light_client::commitments::{prove_commitment, CommitmentProof, EmittedState, Message}; +use light_client::commitments::{prove_commitment, CommitmentProof, EmittedState, ProxyMessage}; use light_client::{ClientKeeper, LightClientResolver, UpdateClientResult}; use store::KVStore; @@ -18,7 +18,7 @@ pub fn update_client( let ek = ctx.get_enclave_key(); match lc.update_client(ctx, input.client_id.clone(), input.any_header.into())? { UpdateClientResult::UpdateClient(mut data) => { - let message: Message = { + let message: ProxyMessage = { if input.include_state && data.message.emitted_states.is_empty() { data.message.emitted_states = vec![EmittedState(data.height, data.new_any_client_state.clone())]; diff --git a/modules/commitments/src/lib.rs b/modules/commitments/src/lib.rs index 16acf8a1..b86e5350 100644 --- a/modules/commitments/src/lib.rs +++ b/modules/commitments/src/lib.rs @@ -23,8 +23,8 @@ pub use context::{TrustingPeriodContext, ValidationContext}; pub use encoder::EthABIEncoder; pub use errors::Error; pub use message::{ - aggregate_messages, CommitmentPrefix, EmittedState, Message, MisbehaviourMessage, PrevState, - UpdateClientMessage, VerifyMembershipMessage, + aggregate_messages, CommitmentPrefix, EmittedState, MisbehaviourProxyMessage, PrevState, + ProxyMessage, UpdateStateProxyMessage, VerifyMembershipProxyMessage, }; pub use proof::CommitmentProof; pub use prover::prove_commitment; diff --git a/modules/commitments/src/message.rs b/modules/commitments/src/message.rs index 07e71f8b..3c2c602b 100644 --- a/modules/commitments/src/message.rs +++ b/modules/commitments/src/message.rs @@ -1,6 +1,6 @@ -pub use self::misbehaviour::{MisbehaviourMessage, PrevState}; -pub use self::update_client::{aggregate_messages, EmittedState, UpdateClientMessage}; -pub use self::verify_membership::{CommitmentPrefix, VerifyMembershipMessage}; +pub use self::misbehaviour::{MisbehaviourProxyMessage, PrevState}; +pub use self::update_client::{aggregate_messages, EmittedState, UpdateStateProxyMessage}; +pub use self::verify_membership::{CommitmentPrefix, VerifyMembershipProxyMessage}; use crate::encoder::EthABIEncoder; use crate::prelude::*; use crate::Error; @@ -14,18 +14,18 @@ mod verify_membership; pub const MESSAGE_SCHEMA_VERSION: u16 = 1; pub const MESSAGE_HEADER_SIZE: usize = 32; -pub const MESSAGE_TYPE_UPDATE_CLIENT: u16 = 1; +pub const MESSAGE_TYPE_UPDATE_STATE: u16 = 1; pub const MESSAGE_TYPE_STATE: u16 = 2; pub const MESSAGE_TYPE_MISBEHAVIOUR: u16 = 3; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub enum Message { - UpdateClient(UpdateClientMessage), - VerifyMembership(VerifyMembershipMessage), - Misbehaviour(MisbehaviourMessage), +pub enum ProxyMessage { + UpdateState(UpdateStateProxyMessage), + VerifyMembership(VerifyMembershipProxyMessage), + Misbehaviour(MisbehaviourProxyMessage), } -impl Message { +impl ProxyMessage { pub fn to_bytes(self) -> Vec { self.ethabi_encode() } @@ -47,49 +47,49 @@ impl Message { pub fn message_type(&self) -> u16 { match self { - Message::UpdateClient(_) => MESSAGE_TYPE_UPDATE_CLIENT, - Message::VerifyMembership(_) => MESSAGE_TYPE_STATE, - Message::Misbehaviour(_) => MESSAGE_TYPE_MISBEHAVIOUR, + Self::UpdateState(_) => MESSAGE_TYPE_UPDATE_STATE, + Self::VerifyMembership(_) => MESSAGE_TYPE_STATE, + Self::Misbehaviour(_) => MESSAGE_TYPE_MISBEHAVIOUR, } } pub fn validate(&self) -> Result<(), Error> { match self { - Message::UpdateClient(c) => c.validate(), - Message::VerifyMembership(c) => c.validate(), - Message::Misbehaviour(c) => c.validate(), + Self::UpdateState(c) => c.validate(), + Self::VerifyMembership(c) => c.validate(), + Self::Misbehaviour(c) => c.validate(), } } } -impl Display for Message { +impl Display for ProxyMessage { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - Message::UpdateClient(c) => write!(f, "{}", c), - Message::VerifyMembership(c) => write!(f, "{}", c), - Message::Misbehaviour(c) => write!(f, "{}", c), + Self::UpdateState(c) => write!(f, "{}", c), + Self::VerifyMembership(c) => write!(f, "{}", c), + Self::Misbehaviour(c) => write!(f, "{}", c), } } } -impl TryFrom for UpdateClientMessage { +impl TryFrom for UpdateStateProxyMessage { type Error = Error; - fn try_from(value: Message) -> Result { + fn try_from(value: ProxyMessage) -> Result { match value { - Message::UpdateClient(m) => Ok(m), + ProxyMessage::UpdateState(m) => Ok(m), _ => Err(Error::unexpected_message_type( - MESSAGE_TYPE_UPDATE_CLIENT, + MESSAGE_TYPE_UPDATE_STATE, value.message_type(), )), } } } -impl TryFrom for VerifyMembershipMessage { +impl TryFrom for VerifyMembershipProxyMessage { type Error = Error; - fn try_from(value: Message) -> Result { + fn try_from(value: ProxyMessage) -> Result { match value { - Message::VerifyMembership(m) => Ok(m), + ProxyMessage::VerifyMembership(m) => Ok(m), _ => Err(Error::unexpected_message_type( MESSAGE_TYPE_STATE, value.message_type(), @@ -98,11 +98,11 @@ impl TryFrom for VerifyMembershipMessage { } } -impl TryFrom for MisbehaviourMessage { +impl TryFrom for MisbehaviourProxyMessage { type Error = Error; - fn try_from(value: Message) -> Result { + fn try_from(value: ProxyMessage) -> Result { match value { - Message::Misbehaviour(m) => Ok(m), + ProxyMessage::Misbehaviour(m) => Ok(m), _ => Err(Error::unexpected_message_type( MESSAGE_TYPE_MISBEHAVIOUR, value.message_type(), @@ -111,21 +111,21 @@ impl TryFrom for MisbehaviourMessage { } } -impl From for Message { - fn from(value: UpdateClientMessage) -> Self { - Message::UpdateClient(value) +impl From for ProxyMessage { + fn from(value: UpdateStateProxyMessage) -> Self { + ProxyMessage::UpdateState(value) } } -impl From for Message { - fn from(value: VerifyMembershipMessage) -> Self { - Message::VerifyMembership(value) +impl From for ProxyMessage { + fn from(value: VerifyMembershipProxyMessage) -> Self { + ProxyMessage::VerifyMembership(value) } } -impl From for Message { - fn from(value: MisbehaviourMessage) -> Self { - Message::Misbehaviour(value) +impl From for ProxyMessage { + fn from(value: MisbehaviourProxyMessage) -> Self { + ProxyMessage::Misbehaviour(value) } } @@ -136,14 +136,14 @@ sol! { } } -impl EthABIEncoder for Message { +impl EthABIEncoder for ProxyMessage { fn ethabi_encode(self) -> Vec { EthABIHeaderedMessage { header: self.header().into(), message: match self { - Message::UpdateClient(c) => c.ethabi_encode(), - Message::VerifyMembership(c) => c.ethabi_encode(), - Message::Misbehaviour(c) => c.ethabi_encode(), + Self::UpdateState(c) => c.ethabi_encode(), + Self::VerifyMembership(c) => c.ethabi_encode(), + Self::Misbehaviour(c) => c.ethabi_encode(), }, } .abi_encode() @@ -177,8 +177,13 @@ impl EthABIEncoder for Message { } let message = eth_abi_message.message; match message_type { - MESSAGE_TYPE_UPDATE_CLIENT => Ok(UpdateClientMessage::ethabi_decode(&message)?.into()), - MESSAGE_TYPE_STATE => Ok(VerifyMembershipMessage::ethabi_decode(&message)?.into()), + MESSAGE_TYPE_UPDATE_STATE => { + Ok(UpdateStateProxyMessage::ethabi_decode(&message)?.into()) + } + MESSAGE_TYPE_STATE => Ok(VerifyMembershipProxyMessage::ethabi_decode(&message)?.into()), + MESSAGE_TYPE_MISBEHAVIOUR => { + Ok(MisbehaviourProxyMessage::ethabi_decode(&message)?.into()) + } _ => Err(Error::invalid_abi(format!( "invalid message type: {}", message_type @@ -203,16 +208,16 @@ mod tests { } fn test_update_client_message( - c1: UpdateClientMessage, + c1: UpdateStateProxyMessage, proof_signer: Address, proof_signature: Vec, ) { let v = c1.clone().ethabi_encode(); - let c2 = UpdateClientMessage::ethabi_decode(&v).unwrap(); + let c2 = UpdateStateProxyMessage::ethabi_decode(&v).unwrap(); assert_eq!(c1, c2); let p1 = CommitmentProof { - message: Message::from(c1).to_bytes(), + message: ProxyMessage::from(c1).to_bytes(), signer: proof_signer, signature: proof_signature.to_vec(), }; @@ -234,7 +239,7 @@ mod tests { proof_signer in any::<[u8; 20]>(), proof_signature in any::<[u8; 65]>() ) { - let c1 = UpdateClientMessage { + let c1 = UpdateStateProxyMessage { prev_height, prev_state_id, post_height, @@ -263,7 +268,7 @@ mod tests { untrusted_header_timestamp in ..=MAX_UNIX_TIMESTAMP_NANOS, trusted_state_timestamp in ..=MAX_UNIX_TIMESTAMP_NANOS ) { - let c1 = UpdateClientMessage { + let c1 = UpdateStateProxyMessage { prev_height, prev_state_id, post_height, @@ -292,7 +297,7 @@ mod tests { proof_signer in any::<[u8; 20]>(), proof_signature in any::<[u8; 65]>() ) { - let c1 = VerifyMembershipMessage { + let c1 = VerifyMembershipProxyMessage { prefix, path, value, @@ -300,11 +305,11 @@ mod tests { state_id, }; let v = c1.clone().ethabi_encode(); - let c2 = VerifyMembershipMessage::ethabi_decode(&v).unwrap(); + let c2 = VerifyMembershipProxyMessage::ethabi_decode(&v).unwrap(); assert_eq!(c1, c2); let p1 = CommitmentProof { - message: Message::from(c1).to_bytes(), + message: ProxyMessage::from(c1).to_bytes(), signer: Address(proof_signer), signature: proof_signature.to_vec(), }; diff --git a/modules/commitments/src/message/misbehaviour.rs b/modules/commitments/src/message/misbehaviour.rs index 0ea98644..96c648b4 100644 --- a/modules/commitments/src/message/misbehaviour.rs +++ b/modules/commitments/src/message/misbehaviour.rs @@ -6,7 +6,7 @@ use prost::Message; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct MisbehaviourMessage { +pub struct MisbehaviourProxyMessage { pub prev_states: Vec, pub context: ValidationContext, pub client_message: Any, @@ -18,7 +18,7 @@ pub struct PrevState { pub state_id: StateID, } -impl MisbehaviourMessage { +impl MisbehaviourProxyMessage { pub fn validate(&self) -> Result<(), Error> { if self.prev_states.is_empty() { return Err(Error::empty_prev_states()); @@ -27,7 +27,7 @@ impl MisbehaviourMessage { } } -impl Display for MisbehaviourMessage { +impl Display for MisbehaviourProxyMessage { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, @@ -43,15 +43,15 @@ sol! { bytes32 state_id; } - struct EthABIMisbehaviourMessage { + struct EthABIMisbehaviourProxyMessage { EthABIPrevState[] prev_states; bytes context; bytes client_message; } } -impl From for EthABIMisbehaviourMessage { - fn from(msg: MisbehaviourMessage) -> Self { +impl From for EthABIMisbehaviourProxyMessage { + fn from(msg: MisbehaviourProxyMessage) -> Self { Self { prev_states: msg .prev_states @@ -67,10 +67,10 @@ impl From for EthABIMisbehaviourMessage { } } -impl TryFrom for MisbehaviourMessage { +impl TryFrom for MisbehaviourProxyMessage { type Error = Error; - fn try_from(msg: EthABIMisbehaviourMessage) -> Result { + fn try_from(msg: EthABIMisbehaviourProxyMessage) -> Result { Ok(Self { prev_states: msg .prev_states @@ -87,12 +87,12 @@ impl TryFrom for MisbehaviourMessage { } } -impl EthABIEncoder for MisbehaviourMessage { +impl EthABIEncoder for MisbehaviourProxyMessage { fn ethabi_encode(self) -> Vec { - Into::::into(self).abi_encode() + Into::::into(self).abi_encode() } fn ethabi_decode(bz: &[u8]) -> Result { - EthABIMisbehaviourMessage::abi_decode(bz, true)?.try_into() + EthABIMisbehaviourProxyMessage::abi_decode(bz, true)?.try_into() } } diff --git a/modules/commitments/src/message/update_client.rs b/modules/commitments/src/message/update_client.rs index aa9f433c..6495405a 100644 --- a/modules/commitments/src/message/update_client.rs +++ b/modules/commitments/src/message/update_client.rs @@ -9,7 +9,7 @@ use prost::Message; use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct UpdateClientMessage { +pub struct UpdateStateProxyMessage { pub prev_height: Option, pub prev_state_id: Option, pub post_height: Height, @@ -33,7 +33,7 @@ impl Display for EmittedState { } } -impl UpdateClientMessage { +impl UpdateStateProxyMessage { pub fn validate(&self) -> Result<(), Error> { if self.prev_height.is_none() != self.prev_state_id.is_none() { return Err(Error::invalid_prev_state_and_height()); @@ -68,7 +68,7 @@ impl UpdateClientMessage { } } -impl Display for UpdateClientMessage { +impl Display for UpdateStateProxyMessage { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, @@ -86,8 +86,8 @@ impl Display for UpdateClientMessage { /// Aggregate a list of messages into a single message pub fn aggregate_messages( - messages: Vec, -) -> Result { + messages: Vec, +) -> Result { if messages.is_empty() { return Err(Error::message_aggregation_failed( "cannot aggregate empty messages".to_string(), @@ -102,7 +102,7 @@ pub fn aggregate_messages( } sol! { - struct EthABIUpdateClientMessage { + struct EthABIUpdateStateProxyMessage { EthABIHeight prev_height; bytes32 prev_state_id; EthABIHeight post_height; @@ -113,8 +113,8 @@ sol! { } } -impl From for EthABIUpdateClientMessage { - fn from(msg: UpdateClientMessage) -> Self { +impl From for EthABIUpdateStateProxyMessage { + fn from(msg: UpdateStateProxyMessage) -> Self { Self { prev_height: msg.prev_height.into(), prev_state_id: B256::from_slice( @@ -133,9 +133,9 @@ impl From for EthABIUpdateClientMessage { } } -impl TryFrom for UpdateClientMessage { +impl TryFrom for UpdateStateProxyMessage { type Error = Error; - fn try_from(msg: EthABIUpdateClientMessage) -> Result { + fn try_from(msg: EthABIUpdateStateProxyMessage) -> Result { Ok(Self { prev_height: msg.prev_height.into(), prev_state_id: (!msg.prev_state_id.is_zero()) @@ -153,13 +153,13 @@ impl TryFrom for UpdateClientMessage { } } -impl EthABIEncoder for UpdateClientMessage { +impl EthABIEncoder for UpdateStateProxyMessage { fn ethabi_encode(self) -> Vec { - Into::::into(self).abi_encode() + Into::::into(self).abi_encode() } fn ethabi_decode(bz: &[u8]) -> Result { - EthABIUpdateClientMessage::abi_decode(bz, true)?.try_into() + EthABIUpdateStateProxyMessage::abi_decode(bz, true)?.try_into() } } @@ -172,7 +172,7 @@ mod tests { #[test] fn test_update_client_message_aggregation() { { - let msg0 = UpdateClientMessage { + let msg0 = UpdateStateProxyMessage { prev_height: Some(Height::new(1, 1)), prev_state_id: Some(StateID::from([1u8; 32])), post_height: Height::new(2, 2), @@ -181,7 +181,7 @@ mod tests { context: ValidationContext::default(), emitted_states: vec![], }; - let msg1 = UpdateClientMessage { + let msg1 = UpdateStateProxyMessage { prev_height: Some(Height::new(2, 2)), prev_state_id: Some(StateID::from([2u8; 32])), post_height: Height::new(3, 3), @@ -190,7 +190,7 @@ mod tests { context: ValidationContext::default(), emitted_states: vec![], }; - let expected = UpdateClientMessage { + let expected = UpdateStateProxyMessage { prev_height: Some(Height::new(1, 1)), prev_state_id: Some(StateID::from([1u8; 32])), post_height: Height::new(3, 3), @@ -202,7 +202,7 @@ mod tests { assert_eq!(aggregate_messages(vec![msg0, msg1]).unwrap(), expected); } { - let msg0 = UpdateClientMessage { + let msg0 = UpdateStateProxyMessage { prev_height: Some(Height::new(1, 1)), prev_state_id: Some(StateID::from([1u8; 32])), post_height: Height::new(2, 2), @@ -214,7 +214,7 @@ mod tests { Any::new("/foo".to_string(), vec![1u8; 32]), )], }; - let msg1 = UpdateClientMessage { + let msg1 = UpdateStateProxyMessage { prev_height: Some(Height::new(2, 2)), prev_state_id: Some(StateID::from([2u8; 32])), post_height: Height::new(3, 3), @@ -226,7 +226,7 @@ mod tests { Any::new("/bar".to_string(), vec![2u8; 32]), )], }; - let expected = UpdateClientMessage { + let expected = UpdateStateProxyMessage { prev_height: Some(Height::new(1, 1)), prev_state_id: Some(StateID::from([1u8; 32])), post_height: Height::new(3, 3), @@ -248,7 +248,7 @@ mod tests { } { // trusting period aggregation - let msg0 = UpdateClientMessage { + let msg0 = UpdateStateProxyMessage { prev_height: Some(Height::new(1, 1)), prev_state_id: Some(StateID::from([1u8; 32])), post_height: Height::new(2, 2), @@ -263,7 +263,7 @@ mod tests { .into(), emitted_states: vec![], }; - let msg1 = UpdateClientMessage { + let msg1 = UpdateStateProxyMessage { prev_height: Some(Height::new(2, 2)), prev_state_id: Some(StateID::from([2u8; 32])), post_height: Height::new(3, 3), @@ -278,7 +278,7 @@ mod tests { .into(), emitted_states: vec![], }; - let expected = UpdateClientMessage { + let expected = UpdateStateProxyMessage { prev_height: Some(Height::new(1, 1)), prev_state_id: Some(StateID::from([1u8; 32])), post_height: Height::new(3, 3), @@ -297,7 +297,7 @@ mod tests { } { // invalid prev_state_id - let msg0 = UpdateClientMessage { + let msg0 = UpdateStateProxyMessage { prev_height: Some(Height::new(1, 1)), prev_state_id: Some(StateID::from([1u8; 32])), post_height: Height::new(2, 2), @@ -306,7 +306,7 @@ mod tests { context: ValidationContext::default(), emitted_states: vec![], }; - let msg1 = UpdateClientMessage { + let msg1 = UpdateStateProxyMessage { prev_height: Some(Height::new(2, 2)), prev_state_id: Some(StateID::from([3u8; 32])), post_height: Height::new(3, 3), @@ -319,7 +319,7 @@ mod tests { } { // invalid prev_height - let msg0 = UpdateClientMessage { + let msg0 = UpdateStateProxyMessage { prev_height: Some(Height::new(1, 1)), prev_state_id: Some(StateID::from([1u8; 32])), post_height: Height::new(2, 2), @@ -328,7 +328,7 @@ mod tests { context: ValidationContext::default(), emitted_states: vec![], }; - let msg1 = UpdateClientMessage { + let msg1 = UpdateStateProxyMessage { prev_height: Some(Height::new(3, 3)), prev_state_id: Some(StateID::from([2u8; 32])), post_height: Height::new(3, 3), @@ -345,7 +345,7 @@ mod tests { } { // single message - let msg0 = UpdateClientMessage { + let msg0 = UpdateStateProxyMessage { prev_height: Some(Height::new(1, 1)), prev_state_id: Some(StateID::from([1u8; 32])), post_height: Height::new(2, 2), @@ -358,7 +358,7 @@ mod tests { } { // three messages - let msg0 = UpdateClientMessage { + let msg0 = UpdateStateProxyMessage { prev_height: Some(Height::new(1, 1)), prev_state_id: Some(StateID::from([1u8; 32])), post_height: Height::new(2, 2), @@ -367,7 +367,7 @@ mod tests { context: ValidationContext::default(), emitted_states: vec![], }; - let msg1 = UpdateClientMessage { + let msg1 = UpdateStateProxyMessage { prev_height: Some(Height::new(2, 2)), prev_state_id: Some(StateID::from([2u8; 32])), post_height: Height::new(3, 3), @@ -376,7 +376,7 @@ mod tests { context: ValidationContext::default(), emitted_states: vec![], }; - let msg2 = UpdateClientMessage { + let msg2 = UpdateStateProxyMessage { prev_height: Some(Height::new(3, 3)), prev_state_id: Some(StateID::from([3u8; 32])), post_height: Height::new(4, 4), @@ -385,7 +385,7 @@ mod tests { context: ValidationContext::default(), emitted_states: vec![], }; - let expected = UpdateClientMessage { + let expected = UpdateStateProxyMessage { prev_height: Some(Height::new(1, 1)), prev_state_id: Some(StateID::from([1u8; 32])), post_height: Height::new(4, 4), diff --git a/modules/commitments/src/message/verify_membership.rs b/modules/commitments/src/message/verify_membership.rs index 856eb54c..da8ca8c4 100644 --- a/modules/commitments/src/message/verify_membership.rs +++ b/modules/commitments/src/message/verify_membership.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; pub type CommitmentPrefix = Vec; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub struct VerifyMembershipMessage { +pub struct VerifyMembershipProxyMessage { pub prefix: CommitmentPrefix, pub path: String, pub value: Option<[u8; 32]>, @@ -17,7 +17,7 @@ pub struct VerifyMembershipMessage { pub state_id: StateID, } -impl Display for VerifyMembershipMessage { +impl Display for VerifyMembershipProxyMessage { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!( f, @@ -32,7 +32,7 @@ impl Display for VerifyMembershipMessage { } sol! { - struct EthABIVerifyMembershipMessage { + struct EthABIVerifyMembershipProxyMessage { bytes prefix; bytes path; bytes32 value; @@ -41,8 +41,8 @@ sol! { } } -impl From for EthABIVerifyMembershipMessage { - fn from(msg: VerifyMembershipMessage) -> Self { +impl From for EthABIVerifyMembershipProxyMessage { + fn from(msg: VerifyMembershipProxyMessage) -> Self { Self { prefix: msg.prefix, path: msg.path.into_bytes(), @@ -53,9 +53,9 @@ impl From for EthABIVerifyMembershipMessage { } } -impl TryFrom for VerifyMembershipMessage { +impl TryFrom for VerifyMembershipProxyMessage { type Error = Error; - fn try_from(msg: EthABIVerifyMembershipMessage) -> Result { + fn try_from(msg: EthABIVerifyMembershipProxyMessage) -> Result { Ok(Self { prefix: msg.prefix, path: String::from_utf8(msg.path)?, @@ -66,7 +66,7 @@ impl TryFrom for VerifyMembershipMessage { } } -impl VerifyMembershipMessage { +impl VerifyMembershipProxyMessage { pub fn new( prefix: CommitmentPrefix, path: String, @@ -97,12 +97,12 @@ impl VerifyMembershipMessage { } } -impl EthABIEncoder for VerifyMembershipMessage { +impl EthABIEncoder for VerifyMembershipProxyMessage { fn ethabi_encode(self) -> Vec { - Into::::into(self).abi_encode() + Into::::into(self).abi_encode() } fn ethabi_decode(bz: &[u8]) -> Result { - EthABIVerifyMembershipMessage::abi_decode(bz, true)?.try_into() + EthABIVerifyMembershipProxyMessage::abi_decode(bz, true)?.try_into() } } diff --git a/modules/commitments/src/proof.rs b/modules/commitments/src/proof.rs index 371c1330..9363840a 100644 --- a/modules/commitments/src/proof.rs +++ b/modules/commitments/src/proof.rs @@ -1,4 +1,4 @@ -use crate::{encoder::EthABIEncoder, prelude::*, Error, Message}; +use crate::{encoder::EthABIEncoder, prelude::*, Error, ProxyMessage}; use alloy_sol_types::{private::Address as SolAddress, sol, SolValue}; use crypto::Address; use serde::{Deserialize, Serialize}; @@ -31,8 +31,8 @@ impl CommitmentProof { !self.signature.is_empty() } - pub fn message(&self) -> Result { - Message::from_bytes(&self.message) + pub fn message(&self) -> Result { + ProxyMessage::from_bytes(&self.message) } } diff --git a/modules/commitments/src/prover.rs b/modules/commitments/src/prover.rs index 08010901..cb44bbb1 100644 --- a/modules/commitments/src/prover.rs +++ b/modules/commitments/src/prover.rs @@ -1,12 +1,12 @@ use crate::errors::Error; -use crate::{prelude::*, CommitmentProof, Message}; +use crate::{prelude::*, CommitmentProof, ProxyMessage}; use crypto::{Address, Signer}; /// Calculate the commitment of a message and sign it pub fn prove_commitment( signer: &dyn Signer, signer_address: Address, - message: Message, + message: ProxyMessage, ) -> Result { message.validate()?; let message_bytes = message.to_bytes(); diff --git a/modules/lcp-client/src/client_def.rs b/modules/lcp-client/src/client_def.rs index 519734b7..a36104fd 100644 --- a/modules/lcp-client/src/client_def.rs +++ b/modules/lcp-client/src/client_def.rs @@ -1,13 +1,12 @@ use crate::client_state::ClientState; use crate::consensus_state::ConsensusState; use crate::errors::Error; -use crate::message::{ - ClientMessage, ELCMessageReader, RegisterEnclaveKeyMessage, UpdateClientMessage, -}; +use crate::message::{ClientMessage, RegisterEnclaveKeyMessage}; use attestation_report::EndorsedAttestationVerificationReport; use crypto::{verify_signature_address, Address, Keccak256}; use light_client::commitments::{ - CommitmentPrefix, CommitmentProof, EthABIEncoder, VerifyMembershipMessage, + CommitmentPrefix, CommitmentProof, EthABIEncoder, MisbehaviourProxyMessage, ProxyMessage, + UpdateStateProxyMessage, VerifyMembershipProxyMessage, }; use light_client::types::{ClientId, Height, Time}; use light_client::{ClientKeeper, ClientReader, HostClientKeeper, HostClientReader}; @@ -48,7 +47,7 @@ impl LCPClient { } // verify_client_message verifies a client message - pub fn update_state( + pub fn update_client( &self, ctx: &mut dyn HostClientKeeper, client_id: ClientId, @@ -56,57 +55,81 @@ impl LCPClient { ) -> Result<(), Error> { let client_state = ctx.client_state(&client_id)?.try_into()?; match message { - ClientMessage::UpdateClient(header) => { - self.update_client(ctx, client_id, client_state, header) - } - ClientMessage::RegisterEnclaveKey(header) => { - self.register_enclave_key(ctx, client_id, client_state, header) + ClientMessage::UpdateClient(msg) => match msg.proxy_message { + ProxyMessage::UpdateState(pmsg) => self.update_state( + ctx, + client_id, + client_state, + pmsg, + msg.signer, + msg.signature, + ), + ProxyMessage::Misbehaviour(pmsg) => self.submit_misbehaviour( + ctx, + client_id, + client_state, + pmsg, + msg.signer, + msg.signature, + ), + _ => Err(Error::unexpected_header_type(format!("{:?}", msg))), + }, + ClientMessage::RegisterEnclaveKey(msg) => { + self.register_enclave_key(ctx, client_id, client_state, msg) } } } - fn update_client( + fn update_state( &self, ctx: &mut dyn HostClientKeeper, client_id: ClientId, client_state: ClientState, - message: UpdateClientMessage, + message: UpdateStateProxyMessage, + signer: Address, + signature: Vec, ) -> Result<(), Error> { + message.validate()?; // TODO return an error instead of assertion + assert!(!client_state.frozen); + if client_state.latest_height.is_zero() { // if the client state's latest height is zero, the commitment's new_state must be non-nil - assert!(!message.elc_message.emitted_states.is_empty()); + assert!(!message.emitted_states.is_empty()); } else { // if the client state's latest height is non-zero, the commitment's prev_* must be non-nil - assert!(message.prev_height().is_some() && message.prev_state_id().is_some()); + assert!(message.prev_height.is_some() && message.prev_state_id.is_some()); // check if the previous consensus state exists in the store let prev_consensus_state: ConsensusState = ctx - .consensus_state(&client_id, &message.prev_height().unwrap())? + .consensus_state(&client_id, &message.prev_height.unwrap())? .try_into()?; - assert!(prev_consensus_state.state_id == message.prev_state_id().unwrap()); + assert!(prev_consensus_state.state_id == message.prev_state_id.unwrap()); } // check if the specified signer exists in the client state - assert!(self.contains_enclave_key(ctx, &client_id, message.signer())); + assert!(self.contains_enclave_key(ctx, &client_id, signer)); // check if the `header.signer` matches the commitment prover - let signer = - verify_signature_address(&message.elc_message_bytes(), &message.signature).unwrap(); - assert!(message.signer() == signer); + let signer2 = verify_signature_address( + ProxyMessage::from(message.clone()).to_bytes().as_slice(), + &signature, + ) + .unwrap(); + assert!(signer == signer2); // check if proxy's validation context matches our's context - message.context().validate(ctx.host_timestamp())?; + message.context.validate(ctx.host_timestamp())?; // create a new state let new_client_state = client_state.with_header(&message); let new_consensus_state = ConsensusState { - state_id: message.state_id(), - timestamp: message.timestamp(), + state_id: message.post_state_id, + timestamp: message.timestamp, }; ctx.store_any_client_state(client_id.clone(), new_client_state.into())?; - ctx.store_any_consensus_state(client_id, message.height(), new_consensus_state.into())?; + ctx.store_any_consensus_state(client_id, message.post_height, new_consensus_state.into())?; Ok(()) } @@ -131,6 +154,45 @@ impl LCPClient { Ok(()) } + fn submit_misbehaviour( + &self, + ctx: &mut dyn HostClientKeeper, + client_id: ClientId, + client_state: ClientState, + message: MisbehaviourProxyMessage, + signer: Address, + signature: Vec, + ) -> Result<(), Error> { + message.validate()?; + + assert!(!client_state.frozen); + + for state in message.prev_states.iter() { + // check if the previous consensus state exists in the store + let prev_consensus_state: ConsensusState = + ctx.consensus_state(&client_id, &state.height)?.try_into()?; + assert!(prev_consensus_state.state_id == state.state_id); + } + + // check if the specified signer exists in the client state + assert!(self.contains_enclave_key(ctx, &client_id, signer)); + + // check if proxy's validation context matches our's context + message.context.validate(ctx.host_timestamp())?; + + // check if the `header.signer` matches the commitment prover + let signer2 = verify_signature_address( + ProxyMessage::from(message).to_bytes().as_slice(), + &signature, + )?; + assert!(signer == signer2); + + let new_client_state = client_state.with_frozen(); + ctx.store_any_client_state(client_id, new_client_state.into())?; + + Ok(()) + } + /// verify_membership is a generic proof verification method which verifies a proof of the existence of a value at a given path at the specified height. pub fn verify_membership( &self, @@ -146,7 +208,7 @@ impl LCPClient { // convert `proof` to CommitmentProof let commitment_proof = CommitmentProof::ethabi_decode(proof.as_slice()).unwrap(); - let msg: VerifyMembershipMessage = commitment_proof.message()?.try_into()?; + let msg: VerifyMembershipProxyMessage = commitment_proof.message()?.try_into()?; // check if `.prefix` matches the counterparty connection's prefix assert!(msg.prefix == prefix); @@ -260,6 +322,7 @@ fn enclave_key_path(client_id: &ClientId, key: Address) -> Vec { #[cfg(test)] mod tests { use super::*; + use crate::message::UpdateClientMessage; use alloc::rc::Rc; use alloc::sync::Arc; use attestation_report::AttestationVerificationReport; @@ -271,6 +334,7 @@ mod tests { use ibc::{ mock::{ client_state::MockClientState, consensus_state::MockConsensusState, header::MockHeader, + misbehaviour::Misbehaviour as MockMisbehaviour, }, Height as ICS02Height, }; @@ -297,9 +361,10 @@ mod tests { let lcp_client_id = { let expired_at = (Time::now() + Duration::from_secs(60)).unwrap(); let initial_client_state = ClientState { - latest_height: Height::zero(), mr_enclave: [0u8; 32].to_vec(), key_expiration: Duration::from_secs(60 * 60 * 24 * 7), + frozen: false, + latest_height: Height::zero(), }; let initial_consensus_state = ConsensusState { state_id: Default::default(), @@ -328,7 +393,7 @@ mod tests { let header = ClientMessage::RegisterEnclaveKey(RegisterEnclaveKeyMessage( generate_dummy_eavr(&ek.get_pubkey()), )); - let res = lcp_client.update_state(&mut ctx, lcp_client_id.clone(), header); + let res = lcp_client.update_client(&mut ctx, lcp_client_id.clone(), header); assert!(res.is_ok(), "res={:?}", res); } @@ -366,7 +431,7 @@ mod tests { let proof1 = { let header = MockHeader::new(ICS02Height::new(0, 2).unwrap()); - let mut ctx = Context::new(registry.clone(), lcp_store, &ek); + let mut ctx = Context::new(registry.clone(), lcp_store.clone(), &ek); ctx.set_timestamp(Time::now()); let res = mock_client.update_client( &ctx, @@ -396,7 +461,7 @@ mod tests { ctx.store_any_client_state(upstream_client_id.clone(), client_state) .unwrap(); - ctx.store_any_consensus_state(upstream_client_id, height, consensus_state) + ctx.store_any_consensus_state(upstream_client_id.clone(), height, consensus_state) .unwrap(); res.unwrap() }; @@ -404,14 +469,58 @@ mod tests { // 5. on the downstream side, updates LCP Light Client's state with the message from the ELC { let header = ClientMessage::UpdateClient(UpdateClientMessage { - elc_message: proof1.message().unwrap().try_into().unwrap(), + proxy_message: proof1.message().unwrap(), signer: proof1.signer, signature: proof1.signature, }); - let mut ctx = Context::new(registry.clone(), ibc_store, &ek); + let mut ctx = Context::new(registry.clone(), ibc_store.clone(), &ek); + ctx.set_timestamp((Time::now() + Duration::from_secs(60)).unwrap()); + + let res = lcp_client.update_client(&mut ctx, lcp_client_id.clone(), header); + assert!(res.is_ok(), "res={:?}", res); + } + + // 6. on the upstream side, updates the Light Client state with a misbehaviour + let misbehaviour_proof = { + let mut ctx = Context::new(registry.clone(), lcp_store, &ek); + ctx.set_timestamp(Time::now()); + + let mock_misbehaviour = MockMisbehaviour { + client_id: upstream_client_id.clone().into(), + header1: MockHeader::new(ICS02Height::new(0, 3).unwrap()), + header2: MockHeader::new(ICS02Height::new(0, 3).unwrap()), + }; + let res = mock_client + .update_client( + &ctx, + upstream_client_id, + mock_lc::Misbehaviour::from(mock_misbehaviour).into(), + ) + .unwrap(); + let data = match res { + UpdateClientResult::SubmitMisbehaviour(data) => data, + _ => unreachable!(), + }; + let res = prove_commitment( + ctx.get_enclave_key(), + ctx.get_enclave_key().pubkey().unwrap().as_address(), + data.message.into(), + ); + assert!(res.is_ok(), "res={:?}", res); + res.unwrap() + }; + + // 7. on the downstream side, updates LCP Light Client's state with the message from the ELC + { + let header = ClientMessage::UpdateClient(UpdateClientMessage { + proxy_message: misbehaviour_proof.message().unwrap(), + signer: misbehaviour_proof.signer, + signature: misbehaviour_proof.signature, + }); + let mut ctx = Context::new(registry, ibc_store, &ek); ctx.set_timestamp((Time::now() + Duration::from_secs(60)).unwrap()); - let res = lcp_client.update_state(&mut ctx, lcp_client_id, header); + let res = lcp_client.update_client(&mut ctx, lcp_client_id, header); assert!(res.is_ok(), "res={:?}", res); } } diff --git a/modules/lcp-client/src/client_state.rs b/modules/lcp-client/src/client_state.rs index fc777b62..13b39755 100644 --- a/modules/lcp-client/src/client_state.rs +++ b/modules/lcp-client/src/client_state.rs @@ -1,7 +1,7 @@ -use crate::message::ELCMessageReader; +use crate::errors::Error; use crate::prelude::*; -use crate::{errors::Error, message::UpdateClientMessage}; use core::time::Duration; +use light_client::commitments::UpdateStateProxyMessage; use light_client::types::proto::{ ibc::{ core::client::v1::Height as ProtoHeight, @@ -17,29 +17,36 @@ pub const LCP_CLIENT_STATE_TYPE_URL: &str = "/ibc.lightclients.lcp.v1.ClientStat #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct ClientState { - pub latest_height: Height, pub mr_enclave: Vec, pub key_expiration: Duration, + pub latest_height: Height, + pub frozen: bool, } impl ClientState { - pub fn with_header(mut self, header: &UpdateClientMessage) -> Self { - if self.latest_height < header.height() { - self.latest_height = header.height(); + pub fn with_header(mut self, header: &UpdateStateProxyMessage) -> Self { + if self.latest_height < header.post_height { + self.latest_height = header.post_height; } self } + + pub fn with_frozen(mut self) -> Self { + self.frozen = true; + self + } } impl From for RawClientState { fn from(value: ClientState) -> Self { RawClientState { + mrenclave: value.mr_enclave, + key_expiration: value.key_expiration.as_secs(), + frozen: value.frozen, latest_height: Some(ProtoHeight { revision_number: value.latest_height.revision_number(), revision_height: value.latest_height.revision_height(), }), - mrenclave: value.mr_enclave, - key_expiration: value.key_expiration.as_secs(), allowed_quote_statuses: Default::default(), allowed_advisory_ids: Default::default(), } @@ -52,9 +59,10 @@ impl TryFrom for ClientState { fn try_from(raw: RawClientState) -> Result { let height = raw.latest_height.unwrap(); Ok(ClientState { - latest_height: Height::new(height.revision_number, height.revision_height), mr_enclave: raw.mrenclave, key_expiration: Duration::from_secs(raw.key_expiration), + frozen: raw.frozen, + latest_height: Height::new(height.revision_number, height.revision_height), }) } } diff --git a/modules/lcp-client/src/message.rs b/modules/lcp-client/src/message.rs index 7a036912..45cb7936 100644 --- a/modules/lcp-client/src/message.rs +++ b/modules/lcp-client/src/message.rs @@ -2,16 +2,12 @@ use crate::errors::Error; use crate::prelude::*; use attestation_report::EndorsedAttestationVerificationReport; use crypto::Address; -use light_client::commitments::{ - Message as ELCMessage, StateID, UpdateClientMessage as ELCUpdateClientMessage, - ValidationContext, -}; +use light_client::commitments::ProxyMessage; use light_client::types::proto::ibc::lightclients::lcp::v1::{ RegisterEnclaveKeyMessage as RawRegisterEnclaveKeyMessage, UpdateClientMessage as RawUpdateClientMessage, }; -use light_client::types::proto::protobuf::Protobuf; -use light_client::types::{Any, Height, Time}; +use light_client::types::{proto::protobuf::Protobuf, Any}; use serde::{Deserialize, Serialize}; pub const LCP_REGISTER_ENCLAVE_KEY_MESSAGE_TYPE_URL: &str = @@ -90,7 +86,7 @@ impl From for RawRegisterEnclaveKeyMessage { pub struct UpdateClientMessage { pub signer: Address, pub signature: Vec, - pub elc_message: ELCUpdateClientMessage, + pub proxy_message: ProxyMessage, } impl Protobuf for UpdateClientMessage {} @@ -101,7 +97,7 @@ impl TryFrom for UpdateClientMessage { Ok(UpdateClientMessage { signer: Address::try_from(value.signer.as_slice())?, signature: value.signature, - elc_message: ELCMessage::from_bytes(&value.elc_message)?.try_into()?, + proxy_message: ProxyMessage::from_bytes(&value.proxy_message)?, }) } } @@ -109,69 +105,9 @@ impl TryFrom for UpdateClientMessage { impl From for RawUpdateClientMessage { fn from(value: UpdateClientMessage) -> Self { RawUpdateClientMessage { - elc_message: Into::::into(value.elc_message).to_bytes(), + proxy_message: Into::::into(value.proxy_message).to_bytes(), signer: value.signer.into(), signature: value.signature, } } } - -impl ELCMessageReader for UpdateClientMessage { - fn signer(&self) -> Address { - self.signer - } - - fn elc_message(&self) -> &ELCUpdateClientMessage { - &self.elc_message - } -} - -pub trait ELCMessageReader { - fn signer(&self) -> Address; - - fn elc_message(&self) -> &ELCUpdateClientMessage; - - fn elc_message_bytes(&self) -> Vec { - ELCMessage::from(self.elc_message().clone()).to_bytes() - } - - fn height(&self) -> Height { - self.elc_message().post_height - } - - fn prev_height(&self) -> Option { - self.elc_message().prev_height - } - - fn prev_state_id(&self) -> Option { - self.elc_message().prev_state_id - } - - fn state_id(&self) -> StateID { - self.elc_message().post_state_id - } - - fn timestamp(&self) -> Time { - self.elc_message().timestamp - } - - fn context(&self) -> &ValidationContext { - &self.elc_message().context - } -} - -impl ClientMessage { - pub fn get_height(&self) -> Option { - match self { - ClientMessage::UpdateClient(h) => Some(h.height()), - _ => None, - } - } - - pub fn get_timestamp(&self) -> Option