1use super::{config::SubstrateConfig, error::Error};
23use blake2::{
24 digest::{consts::U16, Mac},
25 Blake2bMac,
26};
27use codec::{Decode, DecodeAll};
28use futures::channel::oneshot;
29use log::debug;
30use mixnet::core::{Delay, MessageId, PostErr, Scattered};
31use sp_core::Bytes;
32use std::time::Duration;
33
34const LOG_TARGET: &str = "mixnet";
35
36fn send_err<T>(reply_sender: oneshot::Sender<Result<T, Error>>, err: Error) {
37 if let Err(Err(err)) = reply_sender.send(Err(err)) {
38 debug!(target: LOG_TARGET, "Failed to inform requester of error: {err}");
39 }
40}
41
42fn send_reply<T: Decode>(reply_sender: oneshot::Sender<Result<T, Error>>, mut data: &[u8]) {
43 let res = match Result::decode_all(&mut data) {
44 Ok(res) => res.map_err(Error::Remote),
45 Err(_) => Err(Error::BadReply),
46 };
47 match reply_sender.send(res) {
48 Ok(_) => (),
49 Err(Ok(_)) => debug!(target: LOG_TARGET, "Failed to send reply to requester"),
50 Err(Err(err)) => debug!(target: LOG_TARGET, "Failed to inform requester of error: {err}"),
51 }
52}
53
54pub const SUBMIT_EXTRINSIC: u8 = 1;
56
57const EXTRINSIC_DELAY_PERSONA: &[u8; 16] = b"submit-extrn-dly";
58
59pub fn extrinsic_delay(message_id: &MessageId, config: &SubstrateConfig) -> Duration {
62 let h = Blake2bMac::<U16>::new_with_salt_and_personal(message_id, b"", EXTRINSIC_DELAY_PERSONA)
63 .expect("Key, salt, and persona sizes are fixed and small enough");
64 let delay = Delay::exp(h.finalize().into_bytes().as_ref());
65 delay.to_duration(config.mean_extrinsic_delay)
66}
67
68pub enum Request {
71 SubmitExtrinsic { extrinsic: Bytes, reply_sender: oneshot::Sender<Result<(), Error>> },
72}
73
74impl Request {
75 fn send_err(self, err: Error) {
77 match self {
78 Request::SubmitExtrinsic { reply_sender, .. } => send_err(reply_sender, err),
79 }
80 }
81
82 pub fn send_reply(self, data: &[u8]) {
84 match self {
85 Request::SubmitExtrinsic { reply_sender, .. } => send_reply(reply_sender, data),
86 }
87 }
88}
89
90impl mixnet::request_manager::Request for Request {
91 type Context = SubstrateConfig;
92
93 fn with_data<T>(&self, f: impl FnOnce(Scattered<u8>) -> T, _context: &Self::Context) -> T {
94 match self {
95 Request::SubmitExtrinsic { extrinsic, .. } =>
96 f([&[SUBMIT_EXTRINSIC][..], extrinsic.0.as_slice()].as_slice().into()),
97 }
98 }
99
100 fn num_surbs(&self, context: &Self::Context) -> usize {
101 match self {
102 Request::SubmitExtrinsic { .. } => context.surb_factor,
103 }
104 }
105
106 fn handling_delay(&self, message_id: &MessageId, context: &Self::Context) -> Duration {
107 match self {
108 Request::SubmitExtrinsic { .. } => extrinsic_delay(message_id, context),
109 }
110 }
111
112 fn handle_post_err(self, err: PostErr, _context: &Self::Context) {
113 self.send_err(err.into());
114 }
115
116 fn handle_retry_limit_reached(self, _context: &Self::Context) {
117 self.send_err(Error::NoReply);
118 }
119}