Skip to content

Commit d8ce548

Browse files
committed
Improve ChainId implementation; this is API breaking change
ChainId::new allocates a new String so there’s no point in passing ownership of name argument. The constructor can accept it as a str slice without loss of functionality. This reduces allocations when creating ids since caller no longer has to have an owned string. Replace From implementations with TryFrom implementations. Conversion now fails if string is not in an epoch format. There’s still a way to construct an identifier without epoch format if it comes from tendermint::chain::Id (or by using ChainId::new with zero version; behaviour of that might change). And since there’s From implementation available, also get rid of ChainId::from_string. Optimise epoch format parsing. `from_string` used to check if argument was in epoch format and then call `chain_version` which did it again. To avoid duplicating work, introduce `split_chain_id` method which does the parsing and returns result which includes all the information callers might want. Similarly, calling `split` and collecting values into a vector is wasteful if all we need is the last token. Furthermore, regexes are quite a heavy machinery for the task of checking if string ends with a number. To address that, use `split_last` and parse the number to check if it’s valid.
1 parent db2ca48 commit d8ce548

File tree

9 files changed

+156
-105
lines changed

9 files changed

+156
-105
lines changed

Diff for: crates/ibc/src/clients/ics07_tendermint/client_state.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -637,7 +637,9 @@ impl TryFrom<RawTmClientState> for ClientState {
637637
type Error = Error;
638638

639639
fn try_from(raw: RawTmClientState) -> Result<Self, Self::Error> {
640-
let chain_id = ChainId::from_string(raw.chain_id.as_str());
640+
let chain_id = ChainId::try_from(&raw.chain_id).map_err(|_| Error::InvalidRawChainId {
641+
chain_id: raw.chain_id,
642+
})?;
641643

642644
let trust_level = {
643645
let trust_level = raw
@@ -853,15 +855,15 @@ mod tests {
853855
Test {
854856
name: "Valid long (50 chars) chain-id".to_string(),
855857
params: ClientStateParams {
856-
id: ChainId::new("a".repeat(48), 0),
858+
id: ChainId::new(&"a".repeat(48), 0),
857859
..default_params.clone()
858860
},
859861
want_pass: true,
860862
},
861863
Test {
862864
name: "Invalid too-long (51 chars) chain-id".to_string(),
863865
params: ClientStateParams {
864-
id: ChainId::new("a".repeat(49), 0),
866+
id: ChainId::new(&"a".repeat(49), 0),
865867
..default_params.clone()
866868
},
867869
want_pass: false,
@@ -964,7 +966,7 @@ mod tests {
964966
cs_result.is_ok(),
965967
"ClientState::new() failed for test {}, \nmsg{:?} with error {:?}",
966968
test.name,
967-
test.params.clone(),
969+
&test.params,
968970
cs_result.err(),
969971
);
970972
}
@@ -974,7 +976,7 @@ mod tests {
974976
fn client_state_verify_height() {
975977
// Define a "default" set of parameters to reuse throughout these tests.
976978
let default_params: ClientStateParams = ClientStateParams {
977-
id: ChainId::new("ibc".to_string(), 1),
979+
id: ChainId::new("ibc", 1),
978980
trust_level: TrustThreshold::ONE_THIRD,
979981
trusting_period: Duration::new(64000, 0),
980982
unbonding_period: Duration::new(128000, 0),
@@ -1127,7 +1129,7 @@ pub mod test_util {
11271129

11281130
pub fn new_dummy_from_header(tm_header: Header) -> ClientState {
11291131
ClientState::new(
1130-
tm_header.chain_id.clone().into(),
1132+
tm_header.chain_id.clone().try_into().unwrap(),
11311133
Default::default(),
11321134
Duration::from_secs(64000),
11331135
Duration::from_secs(128000),
@@ -1151,7 +1153,7 @@ pub mod test_util {
11511153
pub fn get_dummy_raw_tm_client_state(frozen_height: RawHeight) -> RawTmClientState {
11521154
#[allow(deprecated)]
11531155
RawTmClientState {
1154-
chain_id: ChainId::new("ibc".to_string(), 0).to_string(),
1156+
chain_id: ChainId::new("ibc", 1).to_string(),
11551157
trust_level: Some(Fraction {
11561158
numerator: 1,
11571159
denominator: 3,

Diff for: crates/ibc/src/clients/ics07_tendermint/error.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use tendermint_light_client_verifier::Verdict;
1717
/// The main error type
1818
#[derive(Debug, Display)]
1919
pub enum Error {
20-
/// chain-id is (`{chain_id}`) is too long, got: `{len}`, max allowed: `{max_len}`
20+
/// chain-id (`{chain_id}`) is too long, got: `{len}`, max allowed: `{max_len}`
2121
ChainIdTooLong {
2222
chain_id: ChainId,
2323
len: usize,
@@ -101,6 +101,8 @@ pub enum Error {
101101
MisbehaviourHeadersNotAtSameHeight,
102102
/// invalid raw client id: `{client_id}`
103103
InvalidRawClientId { client_id: String },
104+
/// chain-id (`{chain_id}`) has no epoch version
105+
InvalidRawChainId { chain_id: String },
104106
}
105107

106108
#[cfg(feature = "std")]

Diff for: crates/ibc/src/core/ics02_client/handler/update_client.rs

+13-13
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,10 @@ mod tests {
181181
let client_id = ClientId::new(tm_client_type(), 0).unwrap();
182182
let client_height = Height::new(1, 20).unwrap();
183183
let update_height = Height::new(1, 21).unwrap();
184-
let chain_id_b = ChainId::new("mockgaiaB".to_string(), 1);
184+
let chain_id_b = ChainId::new("mockgaiaB", 1);
185185

186186
let mut ctx = MockContext::new(
187-
ChainId::new("mockgaiaA".to_string(), 1),
187+
ChainId::new("mockgaiaA", 1),
188188
HostType::Mock,
189189
5,
190190
Height::new(1, 1).unwrap(),
@@ -227,10 +227,10 @@ mod tests {
227227
let client_id = ClientId::new(tm_client_type(), 0).unwrap();
228228
let client_height = Height::new(1, 20).unwrap();
229229
let update_height = Height::new(1, 21).unwrap();
230-
let chain_id_b = ChainId::new("mockgaiaB".to_string(), 1);
230+
let chain_id_b = ChainId::new("mockgaiaB", 1);
231231

232232
let mut ctx = MockContext::new(
233-
ChainId::new("mockgaiaA".to_string(), 1),
233+
ChainId::new("mockgaiaA", 1),
234234
HostType::Mock,
235235
5,
236236
Height::new(1, 1).unwrap(),
@@ -274,8 +274,8 @@ mod tests {
274274
let client_id = ClientId::new(tm_client_type(), 0).unwrap();
275275
let client_height = Height::new(1, 20).unwrap();
276276

277-
let ctx_a_chain_id = ChainId::new("mockgaiaA".to_string(), 1);
278-
let ctx_b_chain_id = ChainId::new("mockgaiaB".to_string(), 1);
277+
let ctx_a_chain_id = ChainId::new("mockgaiaA", 1);
278+
let ctx_b_chain_id = ChainId::new("mockgaiaB", 1);
279279
let start_height = Height::new(1, 11).unwrap();
280280

281281
let mut ctx_a = MockContext::new(ctx_a_chain_id, HostType::Mock, 5, start_height)
@@ -329,7 +329,7 @@ mod tests {
329329
let client_state = {
330330
#[allow(deprecated)]
331331
let raw_client_state = RawTmClientState {
332-
chain_id: ChainId::from(tm_block.header().chain_id.clone()).to_string(),
332+
chain_id: tm_block.header().chain_id.to_string(),
333333
trust_level: Some(Fraction {
334334
numerator: 1,
335335
denominator: 3,
@@ -399,7 +399,7 @@ mod tests {
399399
let chain_start_height = Height::new(1, 11).unwrap();
400400

401401
let ctx = MockContext::new(
402-
ChainId::new("mockgaiaA".to_string(), 1),
402+
ChainId::new("mockgaiaA", 1),
403403
HostType::Mock,
404404
5,
405405
chain_start_height,
@@ -412,7 +412,7 @@ mod tests {
412412
);
413413

414414
let ctx_b = MockContext::new(
415-
ChainId::new("mockgaiaB".to_string(), 1),
415+
ChainId::new("mockgaiaB", 1),
416416
HostType::SyntheticTendermint,
417417
5,
418418
client_height,
@@ -538,11 +538,11 @@ mod tests {
538538
let client_id = ClientId::new(tm_client_type(), 0).unwrap();
539539
let client_height = Height::new(1, 20).unwrap();
540540
let misbehaviour_height = Height::new(1, 21).unwrap();
541-
let chain_id_b = ChainId::new("mockgaiaB".to_string(), 1);
541+
let chain_id_b = ChainId::new("mockgaiaB", 1);
542542

543543
// Create a mock context for chain-A with a synthetic tendermint light client for chain-B
544544
let mut ctx_a = MockContext::new(
545-
ChainId::new("mockgaiaA".to_string(), 1),
545+
ChainId::new("mockgaiaA", 1),
546546
HostType::Mock,
547547
5,
548548
Height::new(1, 1).unwrap(),
@@ -599,11 +599,11 @@ mod tests {
599599
let client_id = ClientId::new(tm_client_type(), 0).unwrap();
600600
let client_height = Height::new(1, 20).unwrap();
601601
let misbehaviour_height = Height::new(1, 21).unwrap();
602-
let chain_id_b = ChainId::new("mockgaiaB".to_string(), 1);
602+
let chain_id_b = ChainId::new("mockgaiaB", 1);
603603

604604
// Create a mock context for chain-A with a synthetic tendermint light client for chain-B
605605
let mut ctx_a = MockContext::new(
606-
ChainId::new("mockgaiaA".to_string(), 1),
606+
ChainId::new("mockgaiaA", 1),
607607
HostType::Mock,
608608
5,
609609
Height::new(1, 1).unwrap(),

Diff for: crates/ibc/src/core/ics03_connection/handler/conn_open_ack.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,7 @@ mod tests {
254254

255255
let ctx_default = MockContext::default();
256256
let ctx_new = MockContext::new(
257-
ChainId::new("mockgaia".to_string(), latest_height.revision_number()),
257+
ChainId::new("mockgaia", latest_height.revision_number()),
258258
HostType::Mock,
259259
max_history_size,
260260
latest_height,

Diff for: crates/ibc/src/core/ics03_connection/handler/conn_open_try.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ mod tests {
253253
};
254254

255255
let ctx_new = MockContext::new(
256-
ChainId::new("mockgaia".to_string(), 0),
256+
ChainId::new("mockgaia", 0),
257257
HostType::Mock,
258258
max_history_size,
259259
host_chain_height,

0 commit comments

Comments
 (0)