sc_network_light/light_client_requests/
handler.rs1use crate::schema;
26use codec::{self, Decode, Encode};
27use futures::prelude::*;
28use log::{debug, trace};
29use prost::Message;
30use sc_client_api::{BlockBackend, ProofProvider};
31use sc_network::{
32 config::ProtocolId,
33 request_responses::{IncomingRequest, OutgoingResponse},
34 NetworkBackend, ReputationChange,
35};
36use sc_network_types::PeerId;
37use sp_core::{
38 hexdisplay::HexDisplay,
39 storage::{ChildInfo, ChildType, PrefixedStorageKey},
40};
41use sp_runtime::traits::Block;
42use std::{marker::PhantomData, sync::Arc};
43
44const LOG_TARGET: &str = "light-client-request-handler";
45
46const MAX_LIGHT_REQUEST_QUEUE: usize = 20;
49
50pub struct LightClientRequestHandler<B, Client> {
52 request_receiver: async_channel::Receiver<IncomingRequest>,
53 client: Arc<Client>,
55 _block: PhantomData<B>,
56}
57
58impl<B, Client> LightClientRequestHandler<B, Client>
59where
60 B: Block,
61 Client: BlockBackend<B> + ProofProvider<B> + Send + Sync + 'static,
62{
63 pub fn new<N: NetworkBackend<B, <B as Block>::Hash>>(
65 protocol_id: &ProtocolId,
66 fork_id: Option<&str>,
67 client: Arc<Client>,
68 ) -> (Self, N::RequestResponseProtocolConfig) {
69 let (tx, request_receiver) = async_channel::bounded(MAX_LIGHT_REQUEST_QUEUE);
70
71 let protocol_config = super::generate_protocol_config::<_, B, N>(
72 protocol_id,
73 client
74 .block_hash(0u32.into())
75 .ok()
76 .flatten()
77 .expect("Genesis block exists; qed"),
78 fork_id,
79 tx,
80 );
81
82 (Self { client, request_receiver, _block: PhantomData::default() }, protocol_config)
83 }
84
85 pub async fn run(mut self) {
87 while let Some(request) = self.request_receiver.next().await {
88 let IncomingRequest { peer, payload, pending_response } = request;
89
90 match self.handle_request(peer, payload) {
91 Ok(response_data) => {
92 let response = OutgoingResponse {
93 result: Ok(response_data),
94 reputation_changes: Vec::new(),
95 sent_feedback: None,
96 };
97
98 match pending_response.send(response) {
99 Ok(()) => trace!(
100 target: LOG_TARGET,
101 "Handled light client request from {}.",
102 peer,
103 ),
104 Err(_) => debug!(
105 target: LOG_TARGET,
106 "Failed to handle light client request from {}: {}",
107 peer,
108 HandleRequestError::SendResponse,
109 ),
110 };
111 },
112 Err(e) => {
113 debug!(
114 target: LOG_TARGET,
115 "Failed to handle light client request from {}: {}", peer, e,
116 );
117
118 let reputation_changes = match e {
119 HandleRequestError::BadRequest(_) => {
120 vec![ReputationChange::new(-(1 << 12), "bad request")]
121 },
122 _ => Vec::new(),
123 };
124
125 let response = OutgoingResponse {
126 result: Err(()),
127 reputation_changes,
128 sent_feedback: None,
129 };
130
131 if pending_response.send(response).is_err() {
132 debug!(
133 target: LOG_TARGET,
134 "Failed to handle light client request from {}: {}",
135 peer,
136 HandleRequestError::SendResponse,
137 );
138 };
139 },
140 }
141 }
142 }
143
144 fn handle_request(
145 &mut self,
146 peer: PeerId,
147 payload: Vec<u8>,
148 ) -> Result<Vec<u8>, HandleRequestError> {
149 let request = schema::v1::light::Request::decode(&payload[..])?;
150
151 let response = match &request.request {
152 Some(schema::v1::light::request::Request::RemoteCallRequest(r)) => {
153 self.on_remote_call_request(&peer, r)?
154 },
155 Some(schema::v1::light::request::Request::RemoteReadRequest(r)) => {
156 self.on_remote_read_request(&peer, r)?
157 },
158 Some(schema::v1::light::request::Request::RemoteReadChildRequest(r)) => {
159 self.on_remote_read_child_request(&peer, r)?
160 },
161 None => {
162 return Err(HandleRequestError::BadRequest("Remote request without request data."))
163 },
164 };
165
166 let mut data = Vec::new();
167 response.encode(&mut data)?;
168
169 Ok(data)
170 }
171
172 fn on_remote_call_request(
173 &mut self,
174 peer: &PeerId,
175 request: &schema::v1::light::RemoteCallRequest,
176 ) -> Result<schema::v1::light::Response, HandleRequestError> {
177 trace!("Remote call request from {} ({} at {:?}).", peer, request.method, request.block,);
178
179 let block = Decode::decode(&mut request.block.as_ref())?;
180
181 let response = match self.client.execution_proof(block, &request.method, &request.data) {
182 Ok((_, proof)) => schema::v1::light::RemoteCallResponse { proof: Some(proof.encode()) },
183 Err(e) => {
184 trace!(
185 "remote call request from {} ({} at {:?}) failed with: {}",
186 peer,
187 request.method,
188 request.block,
189 e,
190 );
191 schema::v1::light::RemoteCallResponse { proof: None }
192 },
193 };
194
195 Ok(schema::v1::light::Response {
196 response: Some(schema::v1::light::response::Response::RemoteCallResponse(response)),
197 })
198 }
199
200 fn on_remote_read_request(
201 &mut self,
202 peer: &PeerId,
203 request: &schema::v1::light::RemoteReadRequest,
204 ) -> Result<schema::v1::light::Response, HandleRequestError> {
205 if request.keys.is_empty() {
206 debug!("Invalid remote read request sent by {}.", peer);
207 return Err(HandleRequestError::BadRequest("Remote read request without keys."));
208 }
209
210 trace!(
211 "Remote read request from {} ({} at {:?}).",
212 peer,
213 fmt_keys(request.keys.first(), request.keys.last()),
214 request.block,
215 );
216
217 let block = Decode::decode(&mut request.block.as_ref())?;
218
219 let response =
220 match self.client.read_proof(block, &mut request.keys.iter().map(AsRef::as_ref)) {
221 Ok(proof) => schema::v1::light::RemoteReadResponse { proof: Some(proof.encode()) },
222 Err(error) => {
223 trace!(
224 "remote read request from {} ({} at {:?}) failed with: {}",
225 peer,
226 fmt_keys(request.keys.first(), request.keys.last()),
227 request.block,
228 error,
229 );
230 schema::v1::light::RemoteReadResponse { proof: None }
231 },
232 };
233
234 Ok(schema::v1::light::Response {
235 response: Some(schema::v1::light::response::Response::RemoteReadResponse(response)),
236 })
237 }
238
239 fn on_remote_read_child_request(
240 &mut self,
241 peer: &PeerId,
242 request: &schema::v1::light::RemoteReadChildRequest,
243 ) -> Result<schema::v1::light::Response, HandleRequestError> {
244 if request.keys.is_empty() {
245 debug!("Invalid remote child read request sent by {}.", peer);
246 return Err(HandleRequestError::BadRequest("Remove read child request without keys."));
247 }
248
249 trace!(
250 "Remote read child request from {} ({} {} at {:?}).",
251 peer,
252 HexDisplay::from(&request.storage_key),
253 fmt_keys(request.keys.first(), request.keys.last()),
254 request.block,
255 );
256
257 let block = Decode::decode(&mut request.block.as_ref())?;
258
259 let prefixed_key = PrefixedStorageKey::new_ref(&request.storage_key);
260 let child_info = match ChildType::from_prefixed_key(prefixed_key) {
261 Some((ChildType::ParentKeyId, storage_key)) => Ok(ChildInfo::new_default(storage_key)),
262 None => Err(sp_blockchain::Error::InvalidChildStorageKey),
263 };
264 let response = match child_info.and_then(|child_info| {
265 self.client.read_child_proof(
266 block,
267 &child_info,
268 &mut request.keys.iter().map(AsRef::as_ref),
269 )
270 }) {
271 Ok(proof) => schema::v1::light::RemoteReadResponse { proof: Some(proof.encode()) },
272 Err(error) => {
273 trace!(
274 "remote read child request from {} ({} {} at {:?}) failed with: {}",
275 peer,
276 HexDisplay::from(&request.storage_key),
277 fmt_keys(request.keys.first(), request.keys.last()),
278 request.block,
279 error,
280 );
281 schema::v1::light::RemoteReadResponse { proof: None }
282 },
283 };
284
285 Ok(schema::v1::light::Response {
286 response: Some(schema::v1::light::response::Response::RemoteReadResponse(response)),
287 })
288 }
289}
290
291#[derive(Debug, thiserror::Error)]
292enum HandleRequestError {
293 #[error("Failed to decode request: {0}.")]
294 DecodeProto(#[from] prost::DecodeError),
295 #[error("Failed to encode response: {0}.")]
296 EncodeProto(#[from] prost::EncodeError),
297 #[error("Failed to send response.")]
298 SendResponse,
299 #[error("bad request: {0}")]
301 BadRequest(&'static str),
302 #[error("codec error: {0}")]
304 Codec(#[from] codec::Error),
305}
306
307fn fmt_keys(first: Option<&Vec<u8>>, last: Option<&Vec<u8>>) -> String {
308 if let (Some(first), Some(last)) = (first, last) {
309 if first == last {
310 HexDisplay::from(first).to_string()
311 } else {
312 format!("{}..{}", HexDisplay::from(first), HexDisplay::from(last))
313 }
314 } else {
315 String::from("n/a")
316 }
317}