ibc_testkit/testapp/ibc/clients/mock/
header.rs

1use alloc::string::ToString;
2use core::fmt::{Display, Error as FmtError, Formatter};
3
4use ibc::core::client::types::Height;
5use ibc::core::host::types::error::DecodingError;
6use ibc::core::primitives::Timestamp;
7use ibc::primitives::proto::{Any, Protobuf};
8
9use crate::testapp::ibc::clients::mock::proto::Header as RawMockHeader;
10use crate::utils::year_2023;
11
12pub const MOCK_HEADER_TYPE_URL: &str = "/ibc.mock.Header";
13
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15#[derive(Copy, Clone, Debug, PartialEq, Eq)]
16pub struct MockHeader {
17    pub height: Height,
18    pub timestamp: Timestamp,
19}
20
21impl Default for MockHeader {
22    fn default() -> Self {
23        Self {
24            height: Height::min(0),
25            timestamp: year_2023(),
26        }
27    }
28}
29
30impl Display for MockHeader {
31    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
32        write!(
33            f,
34            "MockHeader {{ height: {}, timestamp: {} }}",
35            self.height, self.timestamp
36        )
37    }
38}
39
40impl Protobuf<RawMockHeader> for MockHeader {}
41
42impl TryFrom<RawMockHeader> for MockHeader {
43    type Error = DecodingError;
44
45    fn try_from(raw: RawMockHeader) -> Result<Self, Self::Error> {
46        Ok(Self {
47            height: raw
48                .height
49                .ok_or(DecodingError::missing_raw_data("mock header height"))?
50                .try_into()?,
51            timestamp: Timestamp::from_nanoseconds(raw.timestamp),
52        })
53    }
54}
55
56impl From<MockHeader> for RawMockHeader {
57    fn from(value: MockHeader) -> Self {
58        Self {
59            height: Some(value.height.into()),
60            timestamp: value.timestamp.nanoseconds(),
61        }
62    }
63}
64
65impl MockHeader {
66    pub fn height(&self) -> Height {
67        self.height
68    }
69
70    pub fn new(height: Height) -> Self {
71        Self {
72            height,
73            timestamp: year_2023(),
74        }
75    }
76
77    pub fn with_current_timestamp(self) -> Self {
78        Self {
79            timestamp: Timestamp::now(),
80            ..self
81        }
82    }
83
84    pub fn with_timestamp(self, timestamp: Timestamp) -> Self {
85        Self { timestamp, ..self }
86    }
87}
88
89impl Protobuf<Any> for MockHeader {}
90
91impl TryFrom<Any> for MockHeader {
92    type Error = DecodingError;
93
94    fn try_from(raw: Any) -> Result<Self, Self::Error> {
95        if let MOCK_HEADER_TYPE_URL = raw.type_url.as_str() {
96            Protobuf::<RawMockHeader>::decode_vec(&raw.value).map_err(Into::into)
97        } else {
98            Err(DecodingError::MismatchedResourceName {
99                expected: MOCK_HEADER_TYPE_URL.to_string(),
100                actual: raw.type_url,
101            })
102        }
103    }
104}
105
106impl From<MockHeader> for Any {
107    fn from(header: MockHeader) -> Self {
108        Self {
109            type_url: MOCK_HEADER_TYPE_URL.to_string(),
110            value: Protobuf::<RawMockHeader>::encode_vec(header),
111        }
112    }
113}
114
115#[cfg(test)]
116mod tests {
117
118    use super::*;
119
120    #[test]
121    fn encode_any() {
122        let header = MockHeader::new(Height::new(1, 10).expect("Never fails"));
123        let bytes = <MockHeader as Protobuf<Any>>::encode_vec(header);
124
125        assert_eq!(
126            &bytes,
127            &[
128                10, 16, 47, 105, 98, 99, 46, 109, 111, 99, 107, 46, 72, 101, 97, 100, 101, 114, 18,
129                16, 10, 4, 8, 1, 16, 10, 16, 128, 128, 136, 158, 189, 200, 129, 155, 23
130            ]
131        );
132    }
133}