Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor commitments #94

Merged
merged 5 commits into from
Dec 14, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
rename CommitmentContext with ValidationContext
Signed-off-by: Jun Kimura <[email protected]>
bluele committed Dec 14, 2023
commit 9ce3f3c591eed5601c2827a2432d5e3613735f03
105 changes: 53 additions & 52 deletions modules/commitments/src/context.rs
Original file line number Diff line number Diff line change
@@ -4,103 +4,104 @@ use core::{fmt::Display, time::Duration};
use lcp_types::{nanos_to_duration, Time};
use serde::{Deserialize, Serialize};

pub const COMMITMENT_CONTEXT_TYPE_EMPTY: u16 = 0;
pub const COMMITMENT_CONTEXT_TYPE_WITHIN_TRUSTING_PERIOD: u16 = 1;
pub const COMMITMENT_CONTEXT_HEADER_SIZE: usize = 32;
pub const VALIDATION_CONTEXT_TYPE_EMPTY_EMPTY: u16 = 0;
pub const VALIDATION_CONTEXT_TYPE_EMPTY_WITHIN_TRUSTING_PERIOD: u16 = 1;
pub const VALIDATION_CONTEXT_HEADER_SIZE: usize = 32;

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum CommitmentContext {
pub enum ValidationContext {
Empty,
TrustingPeriod(TrustingPeriodContext),
}

impl CommitmentContext {
impl ValidationContext {
pub fn validate(&self, current_timestamp: Time) -> Result<(), Error> {
match self {
CommitmentContext::Empty => Ok(()),
CommitmentContext::TrustingPeriod(ctx) => ctx.validate(current_timestamp),
ValidationContext::Empty => Ok(()),
ValidationContext::TrustingPeriod(ctx) => ctx.validate(current_timestamp),
}
}

// MSB first
// 0-1: type
// 2-31: reserved
pub fn header(&self) -> [u8; COMMITMENT_CONTEXT_HEADER_SIZE] {
let mut header = [0u8; COMMITMENT_CONTEXT_HEADER_SIZE];
pub fn header(&self) -> [u8; VALIDATION_CONTEXT_HEADER_SIZE] {
let mut header = [0u8; VALIDATION_CONTEXT_HEADER_SIZE];

match self {
CommitmentContext::Empty => {
header[0..=1].copy_from_slice(&COMMITMENT_CONTEXT_TYPE_EMPTY.to_be_bytes());
ValidationContext::Empty => {
header[0..=1].copy_from_slice(&VALIDATION_CONTEXT_TYPE_EMPTY_EMPTY.to_be_bytes());
}
CommitmentContext::TrustingPeriod(_) => {
header[0..=1]
.copy_from_slice(&COMMITMENT_CONTEXT_TYPE_WITHIN_TRUSTING_PERIOD.to_be_bytes());
ValidationContext::TrustingPeriod(_) => {
header[0..=1].copy_from_slice(
&VALIDATION_CONTEXT_TYPE_EMPTY_WITHIN_TRUSTING_PERIOD.to_be_bytes(),
);
}
}
header
}

fn parse_context_type_from_header(header_bytes: &[u8]) -> Result<u16, Error> {
if header_bytes.len() != COMMITMENT_CONTEXT_HEADER_SIZE {
return Err(Error::invalid_commitment_context_header(format!(
"invalid commitment context header length: expected={} actual={}",
COMMITMENT_CONTEXT_HEADER_SIZE,
if header_bytes.len() != VALIDATION_CONTEXT_HEADER_SIZE {
return Err(Error::invalid_validation_context_header(format!(
"invalid validation context header length: expected={} actual={}",
VALIDATION_CONTEXT_HEADER_SIZE,
header_bytes.len()
)));
}

let mut header = [0u8; COMMITMENT_CONTEXT_HEADER_SIZE];
let mut header = [0u8; VALIDATION_CONTEXT_HEADER_SIZE];
header.copy_from_slice(header_bytes);

Ok(u16::from_be_bytes([header[0], header[1]]))
}
}

impl EthABIEncoder for CommitmentContext {
impl EthABIEncoder for ValidationContext {
fn ethabi_encode(self) -> Vec<u8> {
let header = self.header().as_ref().try_into().unwrap();
match self {
CommitmentContext::Empty => EthABICommitmentContext {
ValidationContext::Empty => EthABIValidationContext {
header,
context_bytes: vec![],
}
.encode(),
CommitmentContext::TrustingPeriod(ctx) => EthABICommitmentContext {
ValidationContext::TrustingPeriod(ctx) => EthABIValidationContext {
header,
context_bytes: ctx.ethabi_encode(),
}
.encode(),
}
}
fn ethabi_decode(bz: &[u8]) -> Result<Self, Error> {
let EthABICommitmentContext {
let EthABIValidationContext {
header,
context_bytes,
} = EthABICommitmentContext::decode(bz)?;
} = EthABIValidationContext::decode(bz)?;

match CommitmentContext::parse_context_type_from_header(&header)? {
COMMITMENT_CONTEXT_TYPE_EMPTY => {
match ValidationContext::parse_context_type_from_header(&header)? {
VALIDATION_CONTEXT_TYPE_EMPTY_EMPTY => {
assert!(context_bytes.is_empty());
Ok(CommitmentContext::Empty)
Ok(ValidationContext::Empty)
}
COMMITMENT_CONTEXT_TYPE_WITHIN_TRUSTING_PERIOD => {
VALIDATION_CONTEXT_TYPE_EMPTY_WITHIN_TRUSTING_PERIOD => {
let ctx = TrustingPeriodContext::ethabi_decode(&context_bytes)?;
Ok(CommitmentContext::TrustingPeriod(ctx))
Ok(ValidationContext::TrustingPeriod(ctx))
}
type_ => Err(Error::invalid_commitment_context_header(format!(
"unknown commitment context type: {}",
type_ => Err(Error::invalid_validation_context_header(format!(
"unknown validation context type: {}",
type_
))),
}
}
}

pub(crate) struct EthABICommitmentContext {
pub(crate) struct EthABIValidationContext {
header: ethabi::FixedBytes, // bytes32
context_bytes: ethabi::Bytes, // bytes
}

impl EthABICommitmentContext {
impl EthABIValidationContext {
fn encode(&self) -> Vec<u8> {
use ethabi::Token;
ethabi::encode(&[Token::Tuple(vec![
@@ -133,17 +134,17 @@ impl EthABICommitmentContext {
}
}

impl Default for CommitmentContext {
impl Default for ValidationContext {
fn default() -> Self {
CommitmentContext::Empty
ValidationContext::Empty
}
}

impl Display for CommitmentContext {
impl Display for ValidationContext {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
CommitmentContext::Empty => write!(f, "Empty"),
CommitmentContext::TrustingPeriod(ctx) => write!(f, "TrustingPeriod {{{}}}", ctx),
ValidationContext::Empty => write!(f, "Empty"),
ValidationContext::TrustingPeriod(ctx) => write!(f, "TrustingPeriod {{{}}}", ctx),
}
}
}
@@ -285,9 +286,9 @@ impl EthABIEncoder for TrustingPeriodContext {
}
}

impl From<TrustingPeriodContext> for CommitmentContext {
impl From<TrustingPeriodContext> for ValidationContext {
fn from(ctx: TrustingPeriodContext) -> Self {
CommitmentContext::TrustingPeriod(ctx)
ValidationContext::TrustingPeriod(ctx)
}
}

@@ -351,58 +352,58 @@ mod tests {
untrusted_header_timestamp in ..=MAX_UNIX_TIMESTAMP_NANOS,
trusted_state_timestamp in ..=MAX_UNIX_TIMESTAMP_NANOS
) {
let ctx: CommitmentContext = TrustingPeriodContext::new(
let ctx: ValidationContext = TrustingPeriodContext::new(
nanos_to_duration(trusting_period).unwrap(),
nanos_to_duration(clock_drift).unwrap(),
Time::from_unix_timestamp_nanos(untrusted_header_timestamp).unwrap(),
Time::from_unix_timestamp_nanos(trusted_state_timestamp).unwrap(),
).into();
let bz = ctx.clone().ethabi_encode();
let ctx2 = CommitmentContext::ethabi_decode(&bz).unwrap();
let ctx2 = ValidationContext::ethabi_decode(&bz).unwrap();
assert_eq!(ctx, ctx2);
}
}

#[test]
fn test_empty_context_serialization() {
let ctx = CommitmentContext::Empty;
let ctx = ValidationContext::Empty;
let bz = ctx.clone().ethabi_encode();
let ctx2 = CommitmentContext::ethabi_decode(&bz).unwrap();
let ctx2 = ValidationContext::ethabi_decode(&bz).unwrap();
assert_eq!(ctx, ctx2);
}

#[test]
fn test_trusting_period_context_serialization() {
let ctx = CommitmentContext::TrustingPeriod(TrustingPeriodContext::new(
let ctx = ValidationContext::TrustingPeriod(TrustingPeriodContext::new(
Duration::new(60 * 60 * 24, 0),
Duration::new(60 * 60, 0),
Time::now(),
Time::now(),
));
let bz = ctx.clone().ethabi_encode();
let ctx2 = CommitmentContext::ethabi_decode(&bz).unwrap();
let ctx2 = ValidationContext::ethabi_decode(&bz).unwrap();
assert_eq!(ctx, ctx2);
}

#[test]
fn test_context_header() {
let ctx = CommitmentContext::Empty;
let ctx = ValidationContext::Empty;
let header = ctx.header();
assert_eq!(
COMMITMENT_CONTEXT_TYPE_EMPTY,
CommitmentContext::parse_context_type_from_header(&header).unwrap()
VALIDATION_CONTEXT_TYPE_EMPTY_EMPTY,
ValidationContext::parse_context_type_from_header(&header).unwrap()
);

let ctx = CommitmentContext::TrustingPeriod(TrustingPeriodContext::new(
let ctx = ValidationContext::TrustingPeriod(TrustingPeriodContext::new(
Duration::new(60 * 60 * 24, 0),
Duration::new(60 * 60, 0),
Time::now(),
Time::now(),
));
let header = ctx.header();
assert_eq!(
COMMITMENT_CONTEXT_TYPE_WITHIN_TRUSTING_PERIOD,
CommitmentContext::parse_context_type_from_header(&header).unwrap()
VALIDATION_CONTEXT_TYPE_EMPTY_WITHIN_TRUSTING_PERIOD,
ValidationContext::parse_context_type_from_header(&header).unwrap()
);
}

2 changes: 1 addition & 1 deletion modules/commitments/src/errors.rs
Original file line number Diff line number Diff line change
@@ -61,7 +61,7 @@ define_error! {
format_args!("invalid commitment header: descr={}", e.descr)
},

InvalidCommitmentContextHeader
InvalidValidationContextHeader
{
descr: String
}
2 changes: 1 addition & 1 deletion modules/commitments/src/lib.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ mod prelude {
pub use core::iter::FromIterator;
}

pub use context::{CommitmentContext, TrustingPeriodContext};
pub use context::{TrustingPeriodContext, ValidationContext};
pub use encoder::EthABIEncoder;
pub use errors::Error;
pub use message::{
6 changes: 3 additions & 3 deletions modules/commitments/src/message/update_client.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::bytes_to_bytes32;
use crate::context::CommitmentContext;
use crate::context::ValidationContext;
use crate::encoder::{EthABIEmittedState, EthABIEncoder, EthABIHeight};
use crate::prelude::*;
use crate::{Error, StateID};
@@ -14,7 +14,7 @@ pub struct UpdateClientMessage {
pub post_height: Height,
pub post_state_id: StateID,
pub timestamp: Time,
pub context: CommitmentContext,
pub context: ValidationContext,
pub emitted_states: Vec<EmittedState>,
}

@@ -142,7 +142,7 @@ impl TryFrom<EthABIUpdateClientMessage> for UpdateClientMessage {
post_height: value.post_height.into(),
post_state_id: value.post_state_id.as_slice().try_into()?,
timestamp: Time::from_unix_timestamp_nanos(value.timestamp.as_u128())?,
context: CommitmentContext::ethabi_decode(value.context.as_slice())?,
context: ValidationContext::ethabi_decode(value.context.as_slice())?,
emitted_states: value
.emitted_states
.into_iter()
6 changes: 3 additions & 3 deletions modules/lcp-client/src/message.rs
Original file line number Diff line number Diff line change
@@ -3,8 +3,8 @@ use crate::prelude::*;
use attestation_report::EndorsedAttestationVerificationReport;
use crypto::Address;
use light_client::commitments::{
CommitmentContext, Message as ELCMessage, StateID,
UpdateClientMessage as ELCUpdateClientMessage,
Message as ELCMessage, StateID, UpdateClientMessage as ELCUpdateClientMessage,
ValidationContext,
};
use light_client::types::proto::ibc::lightclients::lcp::v1::{
RegisterEnclaveKeyMessage as RawRegisterEnclaveKeyMessage,
@@ -155,7 +155,7 @@ pub trait ELCMessageReader {
self.elc_message().timestamp
}

fn context(&self) -> &CommitmentContext {
fn context(&self) -> &ValidationContext {
&self.elc_message().context
}
}
6 changes: 3 additions & 3 deletions modules/mock-lc/src/client.rs
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ use ibc::core::ics02_client::header::Header as Ics02Header;
use ibc::mock::client_state::{client_type, MockClientState, MOCK_CLIENT_STATE_TYPE_URL};
use ibc::mock::consensus_state::MockConsensusState;
use light_client::commitments::{
gen_state_id_from_any, CommitmentContext, EmittedState, UpdateClientMessage,
gen_state_id_from_any, EmittedState, UpdateClientMessage, ValidationContext,
};
use light_client::types::{Any, ClientId, Height, Time};
use light_client::{
@@ -57,7 +57,7 @@ impl LightClient for MockLightClient {
post_state_id: state_id,
post_height: height,
timestamp,
context: CommitmentContext::Empty,
context: ValidationContext::Empty,
emitted_states: vec![EmittedState(height, any_client_state)],
}
.into(),
@@ -140,7 +140,7 @@ impl LightClient for MockLightClient {
post_height: height,
post_state_id,
timestamp: header_timestamp,
context: CommitmentContext::Empty,
context: ValidationContext::Empty,
emitted_states: vec![EmittedState(height, new_any_client_state)],
}
.into(),
4 changes: 2 additions & 2 deletions modules/tendermint-lc/src/client.rs
Original file line number Diff line number Diff line change
@@ -26,7 +26,7 @@ use ibc::core::ics23_commitment::merkle::{apply_prefix, MerkleProof};
use ibc::core::ics24_host::Path;
use lcp_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof;
use light_client::commitments::{
CommitmentContext, CommitmentPrefix, EmittedState, TrustingPeriodContext, UpdateClientMessage,
CommitmentPrefix, EmittedState, TrustingPeriodContext, UpdateClientMessage, ValidationContext,
VerifyMembershipMessage,
};
use light_client::types::{Any, ClientId, Height, Time};
@@ -78,7 +78,7 @@ impl LightClient for TendermintLightClient {
post_height: height,
post_state_id: state_id,
timestamp,
context: CommitmentContext::Empty,
context: ValidationContext::Empty,
emitted_states: vec![EmittedState(height, any_client_state)],
}
.into(),