ilp_packet/
packet.rs

1use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
2use chrono::{DateTime, Utc, TimeZone};
3use errors::ParseError;
4use oer::{ReadOerExt, WriteOerExt};
5use std::io::prelude::*;
6use std::io::Cursor;
7use std::str;
8
9// Note this format includes a dot before the milliseconds so we need to remove that before using the output
10static INTERLEDGER_TIMESTAMP_FORMAT: &'static str = "%Y%m%d%H%M%S%3f";
11
12#[derive(Debug, PartialEq)]
13#[repr(u8)]
14enum PacketType {
15    IlpPrepare = 12,
16    IlpFulfill = 13,
17    IlpReject = 14,
18    Unknown,
19}
20impl From<u8> for PacketType {
21    fn from(type_int: u8) -> Self {
22        match type_int {
23            12 => PacketType::IlpPrepare,
24            13 => PacketType::IlpFulfill,
25            14 => PacketType::IlpReject,
26            _ => PacketType::Unknown,
27        }
28    }
29}
30
31fn serialize_envelope(packet_type: PacketType, contents: &[u8]) -> Result<Vec<u8>, ParseError> {
32    // TODO do this mutably so we don't need to copy the data
33    let mut packet = Vec::new();
34    packet.write_u8(packet_type as u8)?;
35    packet.write_var_octet_string(contents)?;
36    Ok(packet)
37}
38
39fn deserialize_envelope(bytes: &[u8]) -> Result<(PacketType, Vec<u8>), ParseError> {
40    let mut reader = Cursor::new(bytes);
41    let packet_type = PacketType::from(reader.read_u8()?);
42    Ok((packet_type, reader.read_var_octet_string()?))
43}
44
45pub trait Serializable<T> {
46    fn from_bytes(bytes: &[u8]) -> Result<T, ParseError>;
47
48    fn to_bytes(&self) -> Result<Vec<u8>, ParseError>;
49}
50
51pub enum IlpPacket {
52    IlpPrepare,
53    IlpFulfill,
54    IlpReject,
55}
56
57#[derive(Debug, PartialEq, Clone)]
58pub struct IlpPrepare {
59    pub amount: u64,
60    pub expires_at: DateTime<Utc>,
61    // TODO make this just a pointer
62    pub execution_condition: [u8; 32],
63    pub destination: String,
64    pub data: Vec<u8>,
65}
66
67impl Serializable<IlpPrepare> for IlpPrepare {
68    fn from_bytes(bytes: &[u8]) -> Result<IlpPrepare, ParseError> {
69        let (packet_type, contents) = deserialize_envelope(bytes)?;
70        if packet_type != PacketType::IlpPrepare {
71            return Err(ParseError::WrongType(
72                "attempted to deserialize other packet type as IlpPrepare",
73            ));
74        }
75
76        let mut reader = Cursor::new(contents);
77        let amount = reader.read_u64::<BigEndian>()?;
78        let mut expires_at_buf = [0; 17];
79        reader.read(&mut expires_at_buf)?;
80        let expires_at_str = String::from_utf8(expires_at_buf.to_vec())?;
81        let expires_at = Utc.datetime_from_str(&expires_at_str, INTERLEDGER_TIMESTAMP_FORMAT)?.with_timezone(&Utc);
82        let mut execution_condition = [0; 32];
83        reader.read(&mut execution_condition)?;
84        let destination_bytes = reader.read_var_octet_string()?;
85        // TODO make sure address is only ASCII characters
86        let destination = String::from_utf8(destination_bytes.to_vec())
87            .map_err(|_| ParseError::InvalidPacket("destination is not utf8"))?;
88        let data = reader.read_var_octet_string()?.to_vec();
89        Ok(IlpPrepare {
90            amount,
91            expires_at,
92            execution_condition,
93            destination,
94            data,
95        })
96    }
97
98    fn to_bytes(&self) -> Result<Vec<u8>, ParseError> {
99        let mut bytes: Vec<u8> = Vec::new();
100        bytes.write_u64::<BigEndian>(self.amount)?;
101        bytes.write(
102            self.expires_at
103                .format(INTERLEDGER_TIMESTAMP_FORMAT)
104                .to_string()
105                .as_bytes()
106        )?;
107        bytes.write(&self.execution_condition)?;
108        bytes.write_var_octet_string(&self.destination.to_string().into_bytes())?;
109        bytes.write_var_octet_string(&self.data)?;
110        serialize_envelope(PacketType::IlpPrepare, &bytes)
111    }
112}
113
114#[derive(Debug, PartialEq, Clone)]
115pub struct IlpFulfill {
116    pub fulfillment: [u8; 32],
117    pub data: Vec<u8>,
118}
119
120impl Serializable<IlpFulfill> for IlpFulfill {
121    fn from_bytes(bytes: &[u8]) -> Result<IlpFulfill, ParseError> {
122        let (packet_type, contents) = deserialize_envelope(bytes)?;
123        if packet_type != PacketType::IlpFulfill {
124            return Err(ParseError::WrongType(
125                "attempted to deserialize other packet type as IlpFulfill",
126            ));
127        }
128
129        let mut reader = Cursor::new(contents);
130        let mut fulfillment = [0; 32];
131        reader.read(&mut fulfillment)?;
132        let data = reader.read_var_octet_string()?.to_vec();
133        Ok(IlpFulfill { fulfillment, data })
134    }
135
136    fn to_bytes(&self) -> Result<Vec<u8>, ParseError> {
137        let mut bytes: Vec<u8> = Vec::new();
138        bytes.write(&self.fulfillment)?;
139        bytes.write_var_octet_string(&self.data)?;
140        serialize_envelope(PacketType::IlpFulfill, &bytes)
141    }
142}
143
144#[derive(Debug, PartialEq, Clone)]
145pub struct IlpReject {
146    pub code: String,
147    pub message: String,
148    pub triggered_by: String,
149    pub data: Vec<u8>,
150}
151
152impl Serializable<IlpReject> for IlpReject {
153    fn from_bytes(bytes: &[u8]) -> Result<IlpReject, ParseError> {
154        let (packet_type, contents) = deserialize_envelope(bytes)?;
155        if packet_type != PacketType::IlpReject {
156            return Err(ParseError::WrongType(
157                "attempted to deserialize other packet type as IlpReject",
158            ));
159        }
160
161        let mut reader = Cursor::new(contents);
162        let mut code_bytes = [0; 3];
163        reader.read(&mut code_bytes)?;
164        // TODO: make sure code is valid
165        let code = String::from_utf8(code_bytes.to_vec())
166            .map_err(|_| ParseError::InvalidPacket("code is not utf8"))?;
167        let triggered_by_bytes = reader.read_var_octet_string()?;
168        let triggered_by = String::from_utf8(triggered_by_bytes.to_vec())
169            .map_err(|_| ParseError::InvalidPacket("triggered_by is not utf8"))?;
170        let message_bytes = reader.read_var_octet_string()?;
171        let message = String::from_utf8(message_bytes.to_vec())
172            .map_err(|_| ParseError::InvalidPacket("message is not utf8"))?;
173        let data = reader.read_var_octet_string()?.to_vec();
174
175        Ok(IlpReject {
176            code,
177            message,
178            triggered_by,
179            data,
180        })
181    }
182
183    fn to_bytes(&self) -> Result<Vec<u8>, ParseError> {
184        let mut bytes: Vec<u8> = Vec::new();
185        let mut code = [0; 3];
186        self.code.as_bytes().read(&mut code)?;
187        bytes.write(&code)?;
188        bytes.write_var_octet_string(&self.triggered_by.as_bytes())?;
189        bytes.write_var_octet_string(&self.message.as_bytes())?;
190        bytes.write_var_octet_string(&self.data)?;
191        serialize_envelope(PacketType::IlpReject, &bytes)
192    }
193}
194
195#[cfg(test)]
196mod tests {
197    use super::*;
198    use hex;
199
200    lazy_static! {
201        static ref DATA: Vec<u8> = hex::decode("6c99f6a969473028ef46e09b471581c915b6d5496329c1e3a1c2748d7422a7bdcc798e286cabe3197cccfc213e930b8dba57c7abdf2d1f3b2511689de4f0eff441f53da0feffd23249a355b26c3bd0256d5122e7ccdf159fd6cb083dd73cb29397967871becd04890492119c5e3e6b024be35de26466f60c16d90a21054fb13800120cfb85b0df76e50aacd68526fd043026d3d02010c671987a1f6501b5085f0d7d5897624be5862f98c01df65792970181a87d0f3c586a0ca6bd89dc372c45eef5b38a6307b16f1d7d31e8d92e5982c9dd2986eaad581f212d43da9c5cb7b948fc18914be90219709d0c26d3b5f4ad879d8494bb3aebfe612ec54041e4a380f0").unwrap();
202    }
203
204    #[cfg(test)]
205    mod ilp_prepare {
206        use super::*;
207
208        lazy_static! {
209            static ref EXPIRES_AT: DateTime<Utc> = DateTime::parse_from_rfc3339("2018-06-07T20:48:42.483Z").unwrap().with_timezone(&Utc);
210            static ref EXECUTION_CONDITION: [u8; 32] = {
211                let mut buf = [0; 32];
212                buf.copy_from_slice(&hex::decode("117b434f1a54e9044f4f54923b2cff9e4a6d420ae281d5025d7bb040c4b4c04a").unwrap()[..32]);
213                buf
214            };
215
216            static ref PREPARE_1: IlpPrepare = IlpPrepare {
217                amount: 107,
218                destination: "example.alice".to_string(),
219                expires_at: *EXPIRES_AT,
220                execution_condition: *EXECUTION_CONDITION,
221                data: DATA.to_vec(),
222            };
223            // TODO find a better way of loading test fixtures
224            static ref PREPARE_1_SERIALIZED: Vec<u8> = hex::decode("0c82014b000000000000006b3230313830363037323034383432343833117b434f1a54e9044f4f54923b2cff9e4a6d420ae281d5025d7bb040c4b4c04a0d6578616d706c652e616c6963658201016c99f6a969473028ef46e09b471581c915b6d5496329c1e3a1c2748d7422a7bdcc798e286cabe3197cccfc213e930b8dba57c7abdf2d1f3b2511689de4f0eff441f53da0feffd23249a355b26c3bd0256d5122e7ccdf159fd6cb083dd73cb29397967871becd04890492119c5e3e6b024be35de26466f60c16d90a21054fb13800120cfb85b0df76e50aacd68526fd043026d3d02010c671987a1f6501b5085f0d7d5897624be5862f98c01df65792970181a87d0f3c586a0ca6bd89dc372c45eef5b38a6307b16f1d7d31e8d92e5982c9dd2986eaad581f212d43da9c5cb7b948fc18914be90219709d0c26d3b5f4ad879d8494bb3aebfe612ec54041e4a380f0").unwrap();
225        }
226
227        #[test]
228        fn from_bytes() {
229            assert_eq!(
230                IlpPrepare::from_bytes(&PREPARE_1_SERIALIZED).unwrap(),
231                *PREPARE_1
232            );
233        }
234
235        #[test]
236        fn to_bytes() {
237            assert_eq!(PREPARE_1.to_bytes().unwrap(), *PREPARE_1_SERIALIZED);
238        }
239    }
240
241    #[cfg(test)]
242    mod ilp_fulfill {
243        use super::*;
244
245        lazy_static! {
246            static ref FULFILLMENT: [u8; 32] = {
247                let mut buf = [0; 32];
248                buf.copy_from_slice(&hex::decode("117b434f1a54e9044f4f54923b2cff9e4a6d420ae281d5025d7bb040c4b4c04a").unwrap()[..32]);
249                buf
250            };
251
252            static ref FULFILL_1: IlpFulfill = IlpFulfill {
253                fulfillment: *FULFILLMENT,
254                data: DATA.to_vec(),
255            };
256            static ref FULFILL_1_SERIALIZED: Vec<u8> = hex::decode("0d820124117b434f1a54e9044f4f54923b2cff9e4a6d420ae281d5025d7bb040c4b4c04a8201016c99f6a969473028ef46e09b471581c915b6d5496329c1e3a1c2748d7422a7bdcc798e286cabe3197cccfc213e930b8dba57c7abdf2d1f3b2511689de4f0eff441f53da0feffd23249a355b26c3bd0256d5122e7ccdf159fd6cb083dd73cb29397967871becd04890492119c5e3e6b024be35de26466f60c16d90a21054fb13800120cfb85b0df76e50aacd68526fd043026d3d02010c671987a1f6501b5085f0d7d5897624be5862f98c01df65792970181a87d0f3c586a0ca6bd89dc372c45eef5b38a6307b16f1d7d31e8d92e5982c9dd2986eaad581f212d43da9c5cb7b948fc18914be90219709d0c26d3b5f4ad879d8494bb3aebfe612ec54041e4a380f0").unwrap();
257        }
258
259        #[test]
260        fn from_bytes() {
261            assert_eq!(
262                IlpFulfill::from_bytes(&FULFILL_1_SERIALIZED).unwrap(),
263                *FULFILL_1
264            );
265        }
266
267        #[test]
268        fn to_bytes() {
269            assert_eq!(FULFILL_1.to_bytes().unwrap(), *FULFILL_1_SERIALIZED);
270        }
271    }
272
273    #[cfg(test)]
274    mod ilp_reject {
275        use super::*;
276
277        lazy_static! {
278            static ref REJECT_1: IlpReject = IlpReject {
279                code: "F99".to_string(),
280                triggered_by: "example.connector".to_string(),
281                message: "Some error".to_string(),
282                data: DATA.to_vec()
283            };
284
285            static ref REJECT_1_SERIALIZED: Vec<u8> = hex::decode("0e820124463939116578616d706c652e636f6e6e6563746f720a536f6d65206572726f728201016c99f6a969473028ef46e09b471581c915b6d5496329c1e3a1c2748d7422a7bdcc798e286cabe3197cccfc213e930b8dba57c7abdf2d1f3b2511689de4f0eff441f53da0feffd23249a355b26c3bd0256d5122e7ccdf159fd6cb083dd73cb29397967871becd04890492119c5e3e6b024be35de26466f60c16d90a21054fb13800120cfb85b0df76e50aacd68526fd043026d3d02010c671987a1f6501b5085f0d7d5897624be5862f98c01df65792970181a87d0f3c586a0ca6bd89dc372c45eef5b38a6307b16f1d7d31e8d92e5982c9dd2986eaad581f212d43da9c5cb7b948fc18914be90219709d0c26d3b5f4ad879d8494bb3aebfe612ec54041e4a380f0").unwrap();
286        }
287
288        #[test]
289        fn from_bytes() {
290            assert_eq!(
291                IlpReject::from_bytes(&REJECT_1_SERIALIZED).unwrap(),
292                *REJECT_1
293            );
294        }
295
296        #[test]
297        fn to_bytes() {
298            assert_eq!(REJECT_1.to_bytes().unwrap(), *REJECT_1_SERIALIZED);
299        }
300    }
301}