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
9static 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 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 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 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 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 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}