Skip to content

Commit 368c4f4

Browse files
committed
feat: turn ClientConsensusStatePath::haight into Height
Replace ClientConsensusStatePath’s epoch and height fields with a single height field whose type is Height. This stores the exact same information but allows infallible way to get Height out of the path. Arguably it also makes more sense conceptually since the epoch and height are really just a single Height field. Even in formatted paths those two are a single component so it makes sense to have them as a single field. Issue: #603
1 parent bf77378 commit 368c4f4

File tree

3 files changed

+79
-23
lines changed

3 files changed

+79
-23
lines changed

crates/ibc-testkit/src/testapp/ibc/core/client_ctx.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -235,11 +235,9 @@ impl ClientExecutionContext for MockContext {
235235
client_state: Default::default(),
236236
});
237237

238-
let height = Height::new(consensus_state_path.epoch, consensus_state_path.height)
239-
.expect("Never fails");
240238
client_record
241239
.consensus_states
242-
.insert(height, consensus_state);
240+
.insert(consensus_state_path.height, consensus_state);
243241

244242
Ok(())
245243
}
@@ -258,10 +256,9 @@ impl ClientExecutionContext for MockContext {
258256
client_state: Default::default(),
259257
});
260258

261-
let height = Height::new(consensus_state_path.epoch, consensus_state_path.height)
262-
.expect("Never fails");
263-
264-
client_record.consensus_states.remove(&height);
259+
client_record
260+
.consensus_states
261+
.remove(&consensus_state_path.height);
265262

266263
Ok(())
267264
}

crates/ibc-testkit/src/testapp/ibc/core/core_ctx.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,18 +70,18 @@ impl ValidationContext for MockContext {
7070
client_cons_state_path: &ClientConsensusStatePath,
7171
) -> Result<AnyConsensusState, ContextError> {
7272
let client_id = &client_cons_state_path.client_id;
73-
let height = Height::new(client_cons_state_path.epoch, client_cons_state_path.height)?;
73+
let height = &client_cons_state_path.height;
7474
match self.ibc_store.lock().clients.get(client_id) {
75-
Some(client_record) => match client_record.consensus_states.get(&height) {
75+
Some(client_record) => match client_record.consensus_states.get(height) {
7676
Some(consensus_state) => Ok(consensus_state.clone()),
7777
None => Err(ClientError::ConsensusStateNotFound {
7878
client_id: client_id.clone(),
79-
height,
79+
height: height.clone(),
8080
}),
8181
},
8282
None => Err(ClientError::ConsensusStateNotFound {
8383
client_id: client_id.clone(),
84-
height,
84+
height: height.clone(),
8585
}),
8686
}
8787
.map_err(ContextError::ClientError)

crates/ibc/src/core/ics24_host/path.rs

Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,22 +74,84 @@ impl ClientStatePath {
7474
feature = "borsh",
7575
derive(borsh::BorshSerialize, borsh::BorshDeserialize)
7676
)]
77-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7877
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Display)]
79-
#[display(fmt = "clients/{client_id}/consensusStates/{epoch}-{height}")]
78+
#[display(
79+
fmt = "clients/{}/consensusStates/{}-{}",
80+
client_id,
81+
"height.revision_number()",
82+
"height.revision_height()"
83+
)]
8084
pub struct ClientConsensusStatePath {
8185
pub client_id: ClientId,
82-
pub epoch: u64,
83-
pub height: u64,
86+
pub height: Height,
8487
}
8588

8689
impl ClientConsensusStatePath {
8790
pub fn new(client_id: &ClientId, height: &Height) -> ClientConsensusStatePath {
8891
ClientConsensusStatePath {
8992
client_id: client_id.clone(),
90-
epoch: height.revision_number(),
91-
height: height.revision_height(),
93+
height: height.clone(),
94+
}
95+
}
96+
97+
pub fn revision_number(&self) -> u64 {
98+
self.height.revision_number()
99+
}
100+
101+
pub fn revision_height(&self) -> u64 {
102+
self.height.revision_height()
103+
}
104+
}
105+
106+
#[cfg(feature = "serde")]
107+
impl serde::Serialize for ClientConsensusStatePath {
108+
/// Serialises the path as a struct with three elements.
109+
///
110+
/// Rather than serialising the path as a nested type with `height` being an
111+
/// embedded structure, serialises it as a structure with three fields:
112+
///
113+
/// ```ignore
114+
/// struct ClientConsensusStatePath {
115+
/// client_id: ClientId,
116+
/// epoch: u64, // equal height.revision_number()
117+
/// height: u64, // equal height.revision_height()
118+
/// }
119+
/// ```
120+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
121+
where
122+
S: serde::Serializer,
123+
{
124+
use serde::ser::SerializeStruct;
125+
126+
let mut serializer = serializer.serialize_struct("ClientConsensusStatePath", 3)?;
127+
serializer.serialize_field("client_id", &self.client_id)?;
128+
serializer.serialize_field("epoch", &self.revision_number())?;
129+
serializer.serialize_field("height", &self.revision_height())?;
130+
serializer.end()
131+
}
132+
}
133+
134+
#[cfg(feature = "serde")]
135+
impl<'de> serde::Deserialize<'de> for ClientConsensusStatePath {
136+
/// Deserialises the path from a struct with three elements.
137+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
138+
where
139+
D: serde::Deserializer<'de>,
140+
{
141+
use serde::de::Error;
142+
143+
#[derive(serde::Deserialize)]
144+
struct ClientConsensusStatePath {
145+
client_id: ClientId,
146+
epoch: u64,
147+
height: u64,
92148
}
149+
150+
let path = ClientConsensusStatePath::deserialize(deserializer)?;
151+
let client_id = path.client_id;
152+
Height::new(path.epoch, path.height)
153+
.map(|height| Self { client_id, height })
154+
.map_err(|_| D::Error::custom("height cannot be zero"))
93155
}
94156
}
95157

@@ -480,8 +542,7 @@ fn parse_client_paths(components: &[&str]) -> Option<Path> {
480542
Some(
481543
ClientConsensusStatePath {
482544
client_id,
483-
epoch,
484-
height,
545+
height: Height::new(epoch, height).ok()?,
485546
}
486547
.into(),
487548
)
@@ -862,8 +923,7 @@ mod tests {
862923
parse_client_paths(&components),
863924
Some(Path::ClientConsensusState(ClientConsensusStatePath {
864925
client_id: ClientId::default(),
865-
epoch: 15,
866-
height: 31,
926+
height: Height::new(15, 31).unwrap(),
867927
}))
868928
);
869929
}
@@ -890,8 +950,7 @@ mod tests {
890950
path.unwrap(),
891951
Path::ClientConsensusState(ClientConsensusStatePath {
892952
client_id: ClientId::default(),
893-
epoch: 15,
894-
height: 31,
953+
height: Height::new(15, 31).unwrap(),
895954
})
896955
);
897956
}

0 commit comments

Comments
 (0)