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

Remove the concept of a "zero Height" #2346

Merged
merged 46 commits into from
Jul 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
d20ac5b
From<Height> for String fix
plafer Jun 24, 2022
aae757b
Use Option<Height> instead of Height::zero for consensus_height
plafer Jun 24, 2022
00957d2
recv_packet still had Height::zero() in events
plafer Jun 24, 2022
047727f
TryFrom<RawHeight> for Height
plafer Jun 27, 2022
444f2c3
pre height parse changes
plafer Jun 27, 2022
0b19d58
Packet.timeout_height is now an Option<Height>
plafer Jun 27, 2022
bf6192d
rustdoc
plafer Jun 28, 2022
2e47253
Remove Height::with_revision_height
plafer Jun 28, 2022
56378b5
commit pre-modifying cli
plafer Jun 28, 2022
0816c29
Merge remote-tracking branch 'origin/master' into plafer/1009-height-…
plafer Jun 28, 2022
036da49
Finish Height::new() returns Result
plafer Jun 28, 2022
362dab3
remove Height::is_zero()
plafer Jun 28, 2022
d1f9e45
Remove `Height::zero()`
plafer Jun 28, 2022
52941d4
Remove Height::default()
plafer Jun 28, 2022
7507bfd
Height fields accessors
plafer Jun 28, 2022
2004958
use revision_height accessor
plafer Jun 28, 2022
c2418c1
use revision_number accessor
plafer Jun 28, 2022
97fd832
make Height fields private (WIP)
plafer Jun 28, 2022
fca5c9e
compile error fixes
plafer Jun 28, 2022
7730de8
FIXME in transfer.rs addressed
plafer Jun 28, 2022
b10a703
Use existing constants instead of hardcoded strings
plafer Jun 28, 2022
1bc18b6
changelog
plafer Jun 28, 2022
5660a99
TimeoutHeight newtype
plafer Jun 29, 2022
69234fb
Use TimeoutHeight everywhere
plafer Jun 29, 2022
e2bfa1f
Merge remote-tracking branch 'origin/master' into plafer/1009-height-…
plafer Jun 29, 2022
bb8192e
Fixes after merging with master
plafer Jun 29, 2022
78eb9f1
has_expired() fix
plafer Jun 29, 2022
1178a2e
doc url
plafer Jun 29, 2022
a1bd379
fix send_packet test
plafer Jun 30, 2022
6e2cf23
Remove timeout_height == 0 && timestamp == 0 check
plafer Jun 30, 2022
87cbfed
Remove `has_timeout()`
plafer Jun 30, 2022
95eb992
Change TimeoutHeight impl
plafer Jun 30, 2022
b3d4248
docstrings
plafer Jun 30, 2022
6ed145b
tests fix
plafer Jun 30, 2022
a2ec5aa
fix history manipulation test
plafer Jun 30, 2022
c958e62
Merge remote-tracking branch 'origin/master' into plafer/1009-height-…
plafer Jun 30, 2022
8eff6d6
transfer test: no timeout
plafer Jun 30, 2022
62cad52
msgtransfer test
plafer Jun 30, 2022
0d3d2f2
packet no timeout or timestamp test
plafer Jun 30, 2022
c1a2a86
send_packet timeout height equal destination chain height
plafer Jun 30, 2022
a8a958c
send_packet test with timeout = height - 1
plafer Jun 30, 2022
c0fafdb
test invalid timeout height
plafer Jun 30, 2022
4a9dca7
fix docstring
plafer Jun 30, 2022
6a58582
clippy
plafer Jun 30, 2022
e262c3c
Fix clippy warnings introduced in Rust 1.62
romac Jul 1, 2022
f5c3f67
Fix serialization of `TimeoutHeight` to match the format used by `Hei…
romac Jul 1, 2022
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Remove the concept of a zero Height
([#1009](https://github.com/informalsystems/ibc-rs/issues/1009))
7 changes: 7 additions & 0 deletions e2e/e2e/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ class Height:
revision_number: int


@dataclass
class TimeoutHeight:
revision_height: int
revision_number: int


@dataclass
class Duration:
nanos: int
Expand Down Expand Up @@ -39,6 +45,7 @@ class Ordering(Enum):
ClientType = NewType('ClientType', str)
BlockHeight = NewType('BlockHeight', str)


def split():
sleep(0.5)
print()
2 changes: 1 addition & 1 deletion e2e/e2e/packet.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class Packet:
destination_port: PortId
destination_channel: ChannelId
data: Hex
timeout_height: Height
timeout_height: TimeoutHeight
timeout_timestamp: Timestamp


Expand Down
34 changes: 16 additions & 18 deletions modules/src/applications/transfer/msgs/transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use ibc_proto::ibc::applications::transfer::v1::MsgTransfer as RawMsgTransfer;
use tendermint_proto::Protobuf;

use crate::applications::transfer::error::Error;
use crate::core::ics02_client::height::Height;
use crate::core::ics04_channel::timeout::TimeoutHeight;
use crate::core::ics24_host::identifier::{ChannelId, PortId};
use crate::signer::Signer;
use crate::timestamp::Timestamp;
Expand Down Expand Up @@ -37,7 +37,7 @@ pub struct MsgTransfer<C = Coin> {
pub receiver: Signer,
/// Timeout height relative to the current block height.
/// The timeout is disabled when set to None.
pub timeout_height: Option<Height>,
pub timeout_height: TimeoutHeight,
/// Timeout timestamp relative to the current block timestamp.
/// The timeout is disabled when set to 0.
pub timeout_timestamp: Timestamp,
Expand All @@ -63,13 +63,9 @@ impl TryFrom<RawMsgTransfer> for MsgTransfer {
let timeout_timestamp = Timestamp::from_nanoseconds(raw_msg.timeout_timestamp)
.map_err(|_| Error::invalid_packet_timeout_timestamp(raw_msg.timeout_timestamp))?;

let timeout_height: Option<Height> = raw_msg
.timeout_height
.map(|raw_height| raw_height.try_into())
.transpose()
.map_err(|e| {
Error::invalid_packet_timeout_height(format!("invalid timeout height {}", e))
})?;
let timeout_height: TimeoutHeight = raw_msg.timeout_height.try_into().map_err(|e| {
Error::invalid_packet_timeout_height(format!("invalid timeout height {}", e))
})?;

Ok(MsgTransfer {
source_port: raw_msg
Expand Down Expand Up @@ -97,7 +93,7 @@ impl From<MsgTransfer> for RawMsgTransfer {
token: Some(domain_msg.token),
sender: domain_msg.sender.to_string(),
receiver: domain_msg.receiver.to_string(),
timeout_height: domain_msg.timeout_height.map(|height| height.into()),
timeout_height: domain_msg.timeout_height.into(),
timeout_timestamp: domain_msg.timeout_timestamp.nanoseconds(),
}
}
Expand Down Expand Up @@ -134,17 +130,21 @@ pub mod test_util {

use super::MsgTransfer;
use crate::bigint::U256;
use crate::core::ics04_channel::timeout::TimeoutHeight;
use crate::signer::Signer;
use crate::{
applications::transfer::{BaseCoin, PrefixedCoin},
core::ics24_host::identifier::{ChannelId, PortId},
test_utils::get_dummy_bech32_account,
timestamp::Timestamp,
Height,
};

// Returns a dummy ICS20 `MsgTransfer`, for testing only!
pub fn get_dummy_msg_transfer(height: u64) -> MsgTransfer<PrefixedCoin> {
// Returns a dummy ICS20 `MsgTransfer`. If no `timeout_timestamp` is
// specified, a timestamp of 10 seconds in the future is used.
pub fn get_dummy_msg_transfer(
timeout_height: TimeoutHeight,
timeout_timestamp: Option<Timestamp>,
) -> MsgTransfer<PrefixedCoin> {
let address: Signer = get_dummy_bech32_account().as_str().parse().unwrap();
MsgTransfer {
source_port: PortId::default(),
Expand All @@ -156,11 +156,9 @@ pub mod test_util {
.into(),
sender: address.clone(),
receiver: address,
timeout_timestamp: Timestamp::now().add(Duration::from_secs(10)).unwrap(),
timeout_height: Some(Height {
revision_number: 0,
revision_height: height,
}),
timeout_timestamp: timeout_timestamp
.unwrap_or_else(|| Timestamp::now().add(Duration::from_secs(10)).unwrap()),
timeout_height,
}
}
}
3 changes: 1 addition & 2 deletions modules/src/applications/transfer/relay/send_transfer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::applications::transfer::events::TransferEvent;
use crate::applications::transfer::msgs::transfer::MsgTransfer;
use crate::applications::transfer::packet::PacketData;
use crate::applications::transfer::{is_sender_chain_source, Coin, PrefixedCoin};
use crate::core::ics02_client::height::Height;
use crate::core::ics04_channel::handler::send_packet::send_packet;
use crate::core::ics04_channel::packet::Packet;
use crate::events::ModuleEvent;
Expand Down Expand Up @@ -81,7 +80,7 @@ where
destination_port,
destination_channel,
data,
timeout_height: msg.timeout_height.unwrap_or_else(Height::zero),
timeout_height: msg.timeout_height,
timeout_timestamp: msg.timeout_timestamp,
};

Expand Down
14 changes: 7 additions & 7 deletions modules/src/clients/ics07_tendermint/client_def.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ impl ClientDef for TendermintClient {
client_state: Self::ClientState,
header: Self::Header,
) -> Result<(Self::ClientState, Self::ConsensusState), Ics02Error> {
if header.height().revision_number != client_state.chain_id.version() {
if header.height().revision_number() != client_state.chain_id.version() {
return Err(Ics02Error::tendermint_handler_error(
Error::mismatched_revisions(
client_state.chain_id.version(),
header.height().revision_number,
header.height().revision_number(),
),
));
}
Expand Down Expand Up @@ -88,11 +88,11 @@ impl ClientDef for TendermintClient {
header_time: trusted_consensus_state.timestamp,
height: header
.trusted_height
.revision_height
.revision_height()
.try_into()
.map_err(|_| {
Ics02Error::tendermint_handler_error(Error::invalid_header_height(
header.trusted_height,
header.trusted_height.revision_height(),
))
})?,
next_validators: &header.trusted_validator_set,
Expand Down Expand Up @@ -185,7 +185,7 @@ impl ClientDef for TendermintClient {
}

Ok((
client_state.with_header(header.clone()),
client_state.with_header(header.clone())?,
ConsensusState::from(header),
))
}
Expand All @@ -205,8 +205,8 @@ impl ClientDef for TendermintClient {

let path = ClientConsensusStatePath {
client_id: client_id.clone(),
epoch: consensus_height.revision_number,
height: consensus_height.revision_height,
epoch: consensus_height.revision_number(),
height: consensus_height.revision_height(),
};
let value = expected_consensus_state
.encode_vec()
Expand Down
91 changes: 40 additions & 51 deletions modules/src/clients/ics07_tendermint/client_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize};
use tendermint_light_client_verifier::options::Options;
use tendermint_proto::Protobuf;

use ibc_proto::ibc::core::client::v1::Height as RawHeight;
use ibc_proto::ibc::lightclients::tendermint::v1::ClientState as RawClientState;

use crate::clients::ics07_tendermint::error::Error;
Expand Down Expand Up @@ -77,13 +78,6 @@ impl ClientState {
)));
}

// Basic validation for the latest_height parameter.
if latest_height <= Height::zero() {
return Err(Error::validation(
"ClientState latest height must be greater than zero".to_string(),
));
}

// `TrustThreshold` is guaranteed to be in the range `[0, 1)`, but a `TrustThreshold::ZERO`
// value is invalid in this context
if trust_level == TrustThreshold::ZERO {
Expand Down Expand Up @@ -117,22 +111,18 @@ impl ClientState {
self.latest_height
}

pub fn with_header(self, h: Header) -> Self {
// TODO: Clarify which fields should update.
ClientState {
latest_height: self
.latest_height
.with_revision_height(u64::from(h.signed_header.header.height)),
pub fn with_header(self, h: Header) -> Result<Self, Error> {
Ok(ClientState {
latest_height: Height::new(
self.latest_height.revision_number(),
h.signed_header.header.height.into(),
)
.map_err(|_| Error::invalid_header_height(h.signed_header.header.height.value()))?,
..self
}
})
}

pub fn with_frozen_height(self, h: Height) -> Result<Self, Error> {
if h == Height::zero() {
return Err(Error::validation(
"ClientState frozen height must be greater than zero".to_string(),
));
}
Ok(Self {
frozen_height: Some(h),
..self
Expand Down Expand Up @@ -264,14 +254,12 @@ impl TryFrom<RawClientState> for ClientState {
.clone()
.ok_or_else(Error::missing_trusting_period)?;

let frozen_height = raw.frozen_height.and_then(|raw_height| {
let height = raw_height.into();
if height == Height::zero() {
None
} else {
Some(height)
}
});
// In `RawClientState`, a `frozen_height` of `0` means "not frozen".
// See:
// https://github.com/cosmos/ibc-go/blob/8422d0c4c35ef970539466c5bdec1cd27369bab3/modules/light-clients/07-tendermint/types/client_state.go#L74
let frozen_height = raw
.frozen_height
.and_then(|raw_height| raw_height.try_into().ok());

Ok(Self {
chain_id: ChainId::from_string(raw.chain_id.as_str()),
Expand All @@ -296,7 +284,8 @@ impl TryFrom<RawClientState> for ClientState {
latest_height: raw
.latest_height
.ok_or_else(Error::missing_latest_height)?
.into(),
.try_into()
.map_err(|_| Error::missing_latest_height())?,
frozen_height,
upgrade_path: raw.upgrade_path,
allow_update: AllowUpdate {
Expand All @@ -316,12 +305,17 @@ impl From<ClientState> for RawClientState {
trusting_period: Some(value.trusting_period.into()),
unbonding_period: Some(value.unbonding_period.into()),
max_clock_drift: Some(value.max_clock_drift.into()),
frozen_height: Some(value.frozen_height.unwrap_or_else(Height::zero).into()),
frozen_height: Some(value.frozen_height.map(|height| height.into()).unwrap_or(
RawHeight {
revision_number: 0,
revision_height: 0,
},
)),
latest_height: Some(value.latest_height.into()),
proof_specs: value.proof_specs.into(),
upgrade_path: value.upgrade_path,
allow_update_after_expiry: value.allow_update.after_expiry,
allow_update_after_misbehaviour: value.allow_update.after_misbehaviour,
upgrade_path: value.upgrade_path,
}
}
}
Expand Down Expand Up @@ -379,7 +373,7 @@ mod tests {
trusting_period: Duration::new(64000, 0),
unbonding_period: Duration::new(128000, 0),
max_clock_drift: Duration::new(3, 0),
latest_height: Height::new(0, 10),
latest_height: Height::new(0, 10).unwrap(),
proof_specs: ProofSpecs::default(),
upgrade_path: vec!["".to_string()],
allow_update: AllowUpdate {
Expand Down Expand Up @@ -433,14 +427,6 @@ mod tests {
},
want_pass: false,
},
Test {
name: "Invalid (too small) latest height".to_string(),
params: ClientStateParams {
latest_height: Height::zero(),
..default_params.clone()
},
want_pass: false,
},
Test {
name: "Invalid (empty) proof specs".to_string(),
params: ClientStateParams {
Expand Down Expand Up @@ -502,9 +488,9 @@ mod tests {
name: "Successful delay verification".to_string(),
params: Params {
current_time: (now + Duration::from_nanos(2000)).unwrap(),
current_height: Height::new(0, 5),
current_height: Height::new(0, 5).unwrap(),
processed_time: (now + Duration::from_nanos(1000)).unwrap(),
processed_height: Height::new(0, 3),
processed_height: Height::new(0, 3).unwrap(),
delay_period_time: Duration::from_nanos(500),
delay_period_blocks: 2,
},
Expand All @@ -514,9 +500,9 @@ mod tests {
name: "Delay period(time) has not elapsed".to_string(),
params: Params {
current_time: (now + Duration::from_nanos(1200)).unwrap(),
current_height: Height::new(0, 5),
current_height: Height::new(0, 5).unwrap(),
processed_time: (now + Duration::from_nanos(1000)).unwrap(),
processed_height: Height::new(0, 3),
processed_height: Height::new(0, 3).unwrap(),
delay_period_time: Duration::from_nanos(500),
delay_period_blocks: 2,
},
Expand All @@ -526,9 +512,9 @@ mod tests {
name: "Delay period(blocks) has not elapsed".to_string(),
params: Params {
current_time: (now + Duration::from_nanos(2000)).unwrap(),
current_height: Height::new(0, 5),
current_height: Height::new(0, 5).unwrap(),
processed_time: (now + Duration::from_nanos(1000)).unwrap(),
processed_height: Height::new(0, 4),
processed_height: Height::new(0, 4).unwrap(),
delay_period_time: Duration::from_nanos(500),
delay_period_blocks: 2,
},
Expand Down Expand Up @@ -566,7 +552,7 @@ mod tests {
trusting_period: Duration::new(64000, 0),
unbonding_period: Duration::new(128000, 0),
max_clock_drift: Duration::new(3, 0),
latest_height: Height::new(1, 10),
latest_height: Height::new(1, 10).unwrap(),
proof_specs: ProofSpecs::default(),
upgrade_path: vec!["".to_string()],
allow_update: AllowUpdate {
Expand All @@ -585,21 +571,23 @@ mod tests {
let tests = vec![
Test {
name: "Successful height verification".to_string(),
height: Height::new(1, 8),
height: Height::new(1, 8).unwrap(),
setup: None,
want_pass: true,
},
Test {
name: "Invalid (too large) client height".to_string(),
height: Height::new(1, 12),
height: Height::new(1, 12).unwrap(),
setup: None,
want_pass: false,
},
Test {
name: "Invalid, client is frozen below current height".to_string(),
height: Height::new(1, 6),
height: Height::new(1, 6).unwrap(),
setup: Some(Box::new(|client_state| {
client_state.with_frozen_height(Height::new(1, 5)).unwrap()
client_state
.with_frozen_height(Height::new(1, 5).unwrap())
.unwrap()
})),
want_pass: false,
},
Expand Down Expand Up @@ -660,7 +648,8 @@ pub mod test_util {
Height::new(
ChainId::chain_version(tm_header.chain_id.as_str()),
u64::from(tm_header.height),
),
)
.unwrap(),
Default::default(),
vec!["".to_string()],
AllowUpdate {
Expand Down
Loading