payload.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. //! Types representing binary encoding of signable payloads and signature envelopes.
  2. use {
  3. super::router::{PriceFeedId, PriceFeedProperty},
  4. crate::{
  5. router::{ChannelId, Price, Rate},
  6. time::TimestampUs,
  7. },
  8. anyhow::bail,
  9. byteorder::{ByteOrder, ReadBytesExt, WriteBytesExt, BE, LE},
  10. serde::{Deserialize, Serialize},
  11. std::{
  12. io::{Cursor, Read, Write},
  13. num::NonZeroI64,
  14. },
  15. };
  16. /// Data contained within a signable payload.
  17. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  18. pub struct PayloadData {
  19. pub timestamp_us: TimestampUs,
  20. pub channel_id: ChannelId,
  21. // TODO: smallvec?
  22. pub feeds: Vec<PayloadFeedData>,
  23. }
  24. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  25. pub struct PayloadFeedData {
  26. pub feed_id: PriceFeedId,
  27. // TODO: smallvec?
  28. pub properties: Vec<PayloadPropertyValue>,
  29. }
  30. #[derive(Debug, Clone, PartialEq, Eq, Hash)]
  31. pub enum PayloadPropertyValue {
  32. Price(Option<Price>),
  33. BestBidPrice(Option<Price>),
  34. BestAskPrice(Option<Price>),
  35. PublisherCount(u16),
  36. Exponent(i16),
  37. Confidence(Option<Price>),
  38. FundingRate(Option<Rate>),
  39. FundingTimestamp(Option<TimestampUs>),
  40. }
  41. #[derive(Debug, Clone, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
  42. pub struct AggregatedPriceFeedData {
  43. pub price: Option<Price>,
  44. pub best_bid_price: Option<Price>,
  45. pub best_ask_price: Option<Price>,
  46. pub publisher_count: u16,
  47. pub confidence: Option<Price>,
  48. pub funding_rate: Option<Rate>,
  49. pub funding_timestamp: Option<TimestampUs>,
  50. }
  51. /// First bytes of a payload's encoding
  52. /// (in LE or BE depending on the byte order used for encoding the rest of the payload)
  53. pub const PAYLOAD_FORMAT_MAGIC: u32 = 2479346549;
  54. impl PayloadData {
  55. pub fn new(
  56. timestamp_us: TimestampUs,
  57. channel_id: ChannelId,
  58. feeds: &[(PriceFeedId, i16, AggregatedPriceFeedData)],
  59. requested_properties: &[PriceFeedProperty],
  60. ) -> Self {
  61. Self {
  62. timestamp_us,
  63. channel_id,
  64. feeds: feeds
  65. .iter()
  66. .map(|(feed_id, exponent, feed)| PayloadFeedData {
  67. feed_id: *feed_id,
  68. properties: requested_properties
  69. .iter()
  70. .map(|property| match property {
  71. PriceFeedProperty::Price => PayloadPropertyValue::Price(feed.price),
  72. PriceFeedProperty::BestBidPrice => {
  73. PayloadPropertyValue::BestBidPrice(feed.best_bid_price)
  74. }
  75. PriceFeedProperty::BestAskPrice => {
  76. PayloadPropertyValue::BestAskPrice(feed.best_ask_price)
  77. }
  78. PriceFeedProperty::PublisherCount => {
  79. PayloadPropertyValue::PublisherCount(feed.publisher_count)
  80. }
  81. PriceFeedProperty::Exponent => {
  82. PayloadPropertyValue::Exponent(*exponent)
  83. }
  84. PriceFeedProperty::Confidence => {
  85. PayloadPropertyValue::Confidence(feed.confidence)
  86. }
  87. PriceFeedProperty::FundingRate => {
  88. PayloadPropertyValue::FundingRate(feed.funding_rate)
  89. }
  90. PriceFeedProperty::FundingTimestamp => {
  91. PayloadPropertyValue::FundingTimestamp(feed.funding_timestamp)
  92. }
  93. })
  94. .collect(),
  95. })
  96. .collect(),
  97. }
  98. }
  99. pub fn serialize<BO: ByteOrder>(&self, mut writer: impl Write) -> anyhow::Result<()> {
  100. writer.write_u32::<BO>(PAYLOAD_FORMAT_MAGIC)?;
  101. writer.write_u64::<BO>(self.timestamp_us.as_micros())?;
  102. writer.write_u8(self.channel_id.0)?;
  103. writer.write_u8(self.feeds.len().try_into()?)?;
  104. for feed in &self.feeds {
  105. writer.write_u32::<BO>(feed.feed_id.0)?;
  106. writer.write_u8(feed.properties.len().try_into()?)?;
  107. for property in &feed.properties {
  108. match property {
  109. PayloadPropertyValue::Price(price) => {
  110. writer.write_u8(PriceFeedProperty::Price as u8)?;
  111. write_option_price::<BO>(&mut writer, *price)?;
  112. }
  113. PayloadPropertyValue::BestBidPrice(price) => {
  114. writer.write_u8(PriceFeedProperty::BestBidPrice as u8)?;
  115. write_option_price::<BO>(&mut writer, *price)?;
  116. }
  117. PayloadPropertyValue::BestAskPrice(price) => {
  118. writer.write_u8(PriceFeedProperty::BestAskPrice as u8)?;
  119. write_option_price::<BO>(&mut writer, *price)?;
  120. }
  121. PayloadPropertyValue::PublisherCount(count) => {
  122. writer.write_u8(PriceFeedProperty::PublisherCount as u8)?;
  123. writer.write_u16::<BO>(*count)?;
  124. }
  125. PayloadPropertyValue::Exponent(exponent) => {
  126. writer.write_u8(PriceFeedProperty::Exponent as u8)?;
  127. writer.write_i16::<BO>(*exponent)?;
  128. }
  129. PayloadPropertyValue::Confidence(confidence) => {
  130. writer.write_u8(PriceFeedProperty::Confidence as u8)?;
  131. write_option_price::<BO>(&mut writer, *confidence)?;
  132. }
  133. PayloadPropertyValue::FundingRate(rate) => {
  134. writer.write_u8(PriceFeedProperty::FundingRate as u8)?;
  135. write_option_rate::<BO>(&mut writer, *rate)?;
  136. }
  137. PayloadPropertyValue::FundingTimestamp(timestamp) => {
  138. writer.write_u8(PriceFeedProperty::FundingTimestamp as u8)?;
  139. write_option_timestamp::<BO>(&mut writer, *timestamp)?;
  140. }
  141. }
  142. }
  143. }
  144. Ok(())
  145. }
  146. pub fn deserialize_slice_le(data: &[u8]) -> anyhow::Result<Self> {
  147. Self::deserialize::<LE>(Cursor::new(data))
  148. }
  149. pub fn deserialize_slice_be(data: &[u8]) -> anyhow::Result<Self> {
  150. Self::deserialize::<BE>(Cursor::new(data))
  151. }
  152. pub fn deserialize<BO: ByteOrder>(mut reader: impl Read) -> anyhow::Result<Self> {
  153. let magic = reader.read_u32::<BO>()?;
  154. if magic != PAYLOAD_FORMAT_MAGIC {
  155. bail!("magic mismatch");
  156. }
  157. let timestamp_us = TimestampUs::from_micros(reader.read_u64::<BO>()?);
  158. let channel_id = ChannelId(reader.read_u8()?);
  159. let num_feeds = reader.read_u8()?;
  160. let mut feeds = Vec::with_capacity(num_feeds.into());
  161. for _ in 0..num_feeds {
  162. let feed_id = PriceFeedId(reader.read_u32::<BO>()?);
  163. let num_properties = reader.read_u8()?;
  164. let mut feed = PayloadFeedData {
  165. feed_id,
  166. properties: Vec::with_capacity(num_properties.into()),
  167. };
  168. for _ in 0..num_properties {
  169. let property = reader.read_u8()?;
  170. let value = if property == PriceFeedProperty::Price as u8 {
  171. PayloadPropertyValue::Price(read_option_price::<BO>(&mut reader)?)
  172. } else if property == PriceFeedProperty::BestBidPrice as u8 {
  173. PayloadPropertyValue::BestBidPrice(read_option_price::<BO>(&mut reader)?)
  174. } else if property == PriceFeedProperty::BestAskPrice as u8 {
  175. PayloadPropertyValue::BestAskPrice(read_option_price::<BO>(&mut reader)?)
  176. } else if property == PriceFeedProperty::PublisherCount as u8 {
  177. PayloadPropertyValue::PublisherCount(reader.read_u16::<BO>()?)
  178. } else if property == PriceFeedProperty::Exponent as u8 {
  179. PayloadPropertyValue::Exponent(reader.read_i16::<BO>()?)
  180. } else if property == PriceFeedProperty::Confidence as u8 {
  181. PayloadPropertyValue::Confidence(read_option_price::<BO>(&mut reader)?)
  182. } else if property == PriceFeedProperty::FundingRate as u8 {
  183. PayloadPropertyValue::FundingRate(read_option_rate::<BO>(&mut reader)?)
  184. } else if property == PriceFeedProperty::FundingTimestamp as u8 {
  185. PayloadPropertyValue::FundingTimestamp(read_option_timestamp::<BO>(
  186. &mut reader,
  187. )?)
  188. } else {
  189. bail!("unknown property");
  190. };
  191. feed.properties.push(value);
  192. }
  193. feeds.push(feed);
  194. }
  195. Ok(Self {
  196. timestamp_us,
  197. channel_id,
  198. feeds,
  199. })
  200. }
  201. }
  202. fn write_option_price<BO: ByteOrder>(
  203. mut writer: impl Write,
  204. value: Option<Price>,
  205. ) -> std::io::Result<()> {
  206. writer.write_i64::<BO>(value.map_or(0, |v| v.0.get()))
  207. }
  208. fn read_option_price<BO: ByteOrder>(mut reader: impl Read) -> std::io::Result<Option<Price>> {
  209. let value = NonZeroI64::new(reader.read_i64::<BO>()?);
  210. Ok(value.map(Price))
  211. }
  212. fn write_option_rate<BO: ByteOrder>(
  213. mut writer: impl Write,
  214. value: Option<Rate>,
  215. ) -> std::io::Result<()> {
  216. match value {
  217. Some(value) => {
  218. writer.write_u8(1)?;
  219. writer.write_i64::<BO>(value.0)
  220. }
  221. None => {
  222. writer.write_u8(0)?;
  223. Ok(())
  224. }
  225. }
  226. }
  227. fn read_option_rate<BO: ByteOrder>(mut reader: impl Read) -> std::io::Result<Option<Rate>> {
  228. let present = reader.read_u8()? != 0;
  229. if present {
  230. Ok(Some(Rate(reader.read_i64::<BO>()?)))
  231. } else {
  232. Ok(None)
  233. }
  234. }
  235. fn write_option_timestamp<BO: ByteOrder>(
  236. mut writer: impl Write,
  237. value: Option<TimestampUs>,
  238. ) -> std::io::Result<()> {
  239. match value {
  240. Some(value) => {
  241. writer.write_u8(1)?;
  242. writer.write_u64::<BO>(value.as_micros())
  243. }
  244. None => {
  245. writer.write_u8(0)?;
  246. Ok(())
  247. }
  248. }
  249. }
  250. fn read_option_timestamp<BO: ByteOrder>(
  251. mut reader: impl Read,
  252. ) -> std::io::Result<Option<TimestampUs>> {
  253. let present = reader.read_u8()? != 0;
  254. if present {
  255. Ok(Some(TimestampUs::from_micros(reader.read_u64::<BO>()?)))
  256. } else {
  257. Ok(None)
  258. }
  259. }