referrerpolicy=no-referrer-when-downgrade

sc_mixnet/
request.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Sender-side request logic. Some things from this module are also used on the receiver side, eg
20//! [`extrinsic_delay`], but most of the receiver-side request logic lives elsewhere.
21
22use 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
54/// First byte of a submit extrinsic request, identifying it as such.
55pub const SUBMIT_EXTRINSIC: u8 = 1;
56
57const EXTRINSIC_DELAY_PERSONA: &[u8; 16] = b"submit-extrn-dly";
58
59/// Returns the artificial delay that should be inserted between receipt of a submit extrinsic
60/// request with the given message ID and import of the extrinsic into the local transaction pool.
61pub 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
68/// Request parameters and local reply channel. Stored by the
69/// [`RequestManager`](mixnet::request_manager::RequestManager).
70pub enum Request {
71	SubmitExtrinsic { extrinsic: Bytes, reply_sender: oneshot::Sender<Result<(), Error>> },
72}
73
74impl Request {
75	/// Forward an error to the user of the mixnet service.
76	fn send_err(self, err: Error) {
77		match self {
78			Request::SubmitExtrinsic { reply_sender, .. } => send_err(reply_sender, err),
79		}
80	}
81
82	/// Forward a reply to the user of the mixnet service.
83	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.as_ref()].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}