1use std::{
24 collections::{BTreeMap, VecDeque},
25 sync::Arc,
26};
27use crate::OpaquePeerId;
28use crate::offchain::{
29 self,
30 OffchainOverlayedChange,
31 storage::InMemOffchainStorage,
32 HttpError,
33 HttpRequestId as RequestId,
34 HttpRequestStatus as RequestStatus,
35 Timestamp,
36 StorageKind,
37 OpaqueNetworkState,
38 TransactionPool,
39 OffchainStorage,
40};
41
42use parking_lot::RwLock;
43
44#[derive(Debug, Default, PartialEq, Eq)]
46pub struct PendingRequest {
47 pub method: String,
49 pub uri: String,
51 pub meta: Vec<u8>,
53 pub headers: Vec<(String, String)>,
55 pub body: Vec<u8>,
57 pub sent: bool,
59 pub response: Option<Vec<u8>>,
61 pub read: usize,
63 pub response_headers: Vec<(String, String)>,
65}
66
67#[derive(Debug, Clone, Default)]
69pub struct TestPersistentOffchainDB {
70 persistent: Arc<RwLock<InMemOffchainStorage>>,
71}
72
73impl TestPersistentOffchainDB {
74 const PREFIX: &'static [u8] = b"";
75
76 pub fn new() -> Self {
78 Self {
79 persistent: Arc::new(RwLock::new(InMemOffchainStorage::default()))
80 }
81 }
82
83 pub fn apply_offchain_changes(
85 &mut self,
86 changes: impl Iterator<Item = ((Vec<u8>, Vec<u8>), OffchainOverlayedChange)>,
87 ) {
88 let mut me = self.persistent.write();
89 for ((_prefix, key), value_operation) in changes {
90 match value_operation {
91 OffchainOverlayedChange::SetValue(val) => me.set(Self::PREFIX, key.as_slice(), val.as_slice()),
92 OffchainOverlayedChange::Remove => me.remove(Self::PREFIX, key.as_slice()),
93 }
94 }
95 }
96
97 pub fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
99 OffchainStorage::get(self, Self::PREFIX, key)
100 }
101}
102
103impl OffchainStorage for TestPersistentOffchainDB {
104 fn set(&mut self, prefix: &[u8], key: &[u8], value: &[u8]) {
105 self.persistent.write().set(prefix, key, value);
106 }
107
108 fn remove(&mut self, prefix: &[u8], key: &[u8]) {
109 self.persistent.write().remove(prefix, key);
110 }
111
112 fn get(&self, prefix: &[u8], key: &[u8]) -> Option<Vec<u8>> {
113 self.persistent.read().get(prefix, key)
114 }
115
116 fn compare_and_set(
117 &mut self,
118 prefix: &[u8],
119 key: &[u8],
120 old_value: Option<&[u8]>,
121 new_value: &[u8],
122 ) -> bool {
123 self.persistent.write().compare_and_set(prefix, key, old_value, new_value)
124 }
125}
126
127
128#[derive(Debug, Default)]
132pub struct OffchainState {
133 pub requests: BTreeMap<RequestId, PendingRequest>,
135 expected_requests: VecDeque<PendingRequest>,
137 pub persistent_storage: TestPersistentOffchainDB,
139 pub local_storage: InMemOffchainStorage,
141 pub seed: [u8; 32],
143 pub timestamp: Timestamp,
145}
146
147impl OffchainState {
148 pub fn fulfill_pending_request(
150 &mut self,
151 id: u16,
152 expected: PendingRequest,
153 response: impl Into<Vec<u8>>,
154 response_headers: impl IntoIterator<Item=(String, String)>,
155 ) {
156 match self.requests.get_mut(&RequestId(id)) {
157 None => {
158 panic!("Missing pending request: {:?}.\n\nAll: {:?}", id, self.requests);
159 }
160 Some(req) => {
161 assert_eq!(
162 *req,
163 expected,
164 );
165 req.response = Some(response.into());
166 req.response_headers = response_headers.into_iter().collect();
167 }
168 }
169 }
170
171 fn fulfill_expected(&mut self, id: u16) {
172 if let Some(mut req) = self.expected_requests.pop_back() {
173 let response = req.response.take().expect("Response checked when added.");
174 let headers = std::mem::take(&mut req.response_headers);
175 self.fulfill_pending_request(id, req, response, headers);
176 }
177 }
178
179 pub fn expect_request(&mut self, expected: PendingRequest) {
187 if expected.response.is_none() {
188 panic!("Expected request needs to have a response.");
189 }
190 self.expected_requests.push_front(expected);
191 }
192}
193
194impl Drop for OffchainState {
195 fn drop(&mut self) {
196 if !self.expected_requests.is_empty() && !std::thread::panicking() {
198 panic!("Unfulfilled expected requests: {:?}", self.expected_requests);
199 }
200 }
201}
202
203#[derive(Clone, Default, Debug)]
205pub struct TestOffchainExt(pub Arc<RwLock<OffchainState>>);
206
207impl TestOffchainExt {
208 pub fn new() -> (Self, Arc<RwLock<OffchainState>>) {
210 let ext = Self::default();
211 let state = ext.0.clone();
212 (ext, state)
213 }
214
215 pub fn with_offchain_db(offchain_db: TestPersistentOffchainDB) -> (Self, Arc<RwLock<OffchainState>>) {
217 let (ext, state) = Self::new();
218 ext.0.write().persistent_storage = offchain_db;
219 (ext, state)
220 }
221}
222
223impl offchain::Externalities for TestOffchainExt {
224 fn is_validator(&self) -> bool {
225 true
226 }
227
228 fn network_state(&self) -> Result<OpaqueNetworkState, ()> {
229 Ok(OpaqueNetworkState {
230 peer_id: Default::default(),
231 external_addresses: vec![],
232 })
233 }
234
235 fn timestamp(&mut self) -> Timestamp {
236 self.0.read().timestamp
237 }
238
239 fn sleep_until(&mut self, deadline: Timestamp) {
240 self.0.write().timestamp = deadline;
241 }
242
243 fn random_seed(&mut self) -> [u8; 32] {
244 self.0.read().seed
245 }
246
247 fn local_storage_set(&mut self, kind: StorageKind, key: &[u8], value: &[u8]) {
248 let mut state = self.0.write();
249 match kind {
250 StorageKind::LOCAL => state.local_storage.set(b"", key, value),
251 StorageKind::PERSISTENT => state.persistent_storage.set(b"", key, value),
252 };
253 }
254
255 fn local_storage_clear(&mut self, kind: StorageKind, key: &[u8]) {
256 let mut state = self.0.write();
257 match kind {
258 StorageKind::LOCAL => state.local_storage.remove(b"", key),
259 StorageKind::PERSISTENT => state.persistent_storage.remove(b"", key),
260 };
261 }
262
263 fn local_storage_compare_and_set(
264 &mut self,
265 kind: StorageKind,
266 key: &[u8],
267 old_value: Option<&[u8]>,
268 new_value: &[u8]
269 ) -> bool {
270 let mut state = self.0.write();
271 match kind {
272 StorageKind::LOCAL => state.local_storage.compare_and_set(b"", key, old_value, new_value),
273 StorageKind::PERSISTENT => state.persistent_storage.compare_and_set(b"", key, old_value, new_value),
274 }
275 }
276
277 fn local_storage_get(&mut self, kind: StorageKind, key: &[u8]) -> Option<Vec<u8>> {
278 let state = self.0.read();
279 match kind {
280 StorageKind::LOCAL => state.local_storage.get(TestPersistentOffchainDB::PREFIX, key),
281 StorageKind::PERSISTENT => state.persistent_storage.get(key),
282 }
283 }
284
285 fn http_request_start(&mut self, method: &str, uri: &str, meta: &[u8]) -> Result<RequestId, ()> {
286 let mut state = self.0.write();
287 let id = RequestId(state.requests.len() as u16);
288 state.requests.insert(id.clone(), PendingRequest {
289 method: method.into(),
290 uri: uri.into(),
291 meta: meta.into(),
292 ..Default::default()
293 });
294 Ok(id)
295 }
296
297 fn http_request_add_header(
298 &mut self,
299 request_id: RequestId,
300 name: &str,
301 value: &str,
302 ) -> Result<(), ()> {
303 let mut state = self.0.write();
304 if let Some(req) = state.requests.get_mut(&request_id) {
305 req.headers.push((name.into(), value.into()));
306 Ok(())
307 } else {
308 Err(())
309 }
310 }
311
312 fn http_request_write_body(
313 &mut self,
314 request_id: RequestId,
315 chunk: &[u8],
316 _deadline: Option<Timestamp>
317 ) -> Result<(), HttpError> {
318 let mut state = self.0.write();
319
320 let sent = {
321 let req = state.requests.get_mut(&request_id).ok_or(HttpError::IoError)?;
322 req.body.extend(chunk);
323 if chunk.is_empty() {
324 req.sent = true;
325 }
326 req.sent
327 };
328
329 if sent {
330 state.fulfill_expected(request_id.0);
331 }
332
333 Ok(())
334 }
335
336 fn http_response_wait(
337 &mut self,
338 ids: &[RequestId],
339 _deadline: Option<Timestamp>,
340 ) -> Vec<RequestStatus> {
341 let state = self.0.read();
342
343 ids.iter().map(|id| match state.requests.get(id) {
344 Some(req) if req.response.is_none() =>
345 panic!("No `response` provided for request with id: {:?}", id),
346 None => RequestStatus::Invalid,
347 _ => RequestStatus::Finished(200),
348 }).collect()
349 }
350
351 fn http_response_headers(&mut self, request_id: RequestId) -> Vec<(Vec<u8>, Vec<u8>)> {
352 let state = self.0.read();
353 if let Some(req) = state.requests.get(&request_id) {
354 req.response_headers
355 .clone()
356 .into_iter()
357 .map(|(k, v)| (k.into_bytes(), v.into_bytes()))
358 .collect()
359 } else {
360 Default::default()
361 }
362 }
363
364 fn http_response_read_body(
365 &mut self,
366 request_id: RequestId,
367 buffer: &mut [u8],
368 _deadline: Option<Timestamp>
369 ) -> Result<usize, HttpError> {
370 let mut state = self.0.write();
371 if let Some(req) = state.requests.get_mut(&request_id) {
372 let response = req.response
373 .as_mut()
374 .unwrap_or_else(|| panic!("No response provided for request: {:?}", request_id));
375
376 if req.read >= response.len() {
377 state.requests.remove(&request_id);
379 Ok(0)
380 } else {
381 let read = std::cmp::min(buffer.len(), response[req.read..].len());
382 buffer[0..read].copy_from_slice(&response[req.read..read]);
383 req.read += read;
384 Ok(read)
385 }
386 } else {
387 Err(HttpError::IoError)
388 }
389 }
390
391 fn set_authorized_nodes(&mut self, _nodes: Vec<OpaquePeerId>, _authorized_only: bool) {
392 unimplemented!()
393 }
394}
395
396#[derive(Default)]
398pub struct PoolState {
399 pub transactions: Vec<Vec<u8>>,
401}
402
403#[derive(Default)]
413pub struct TestTransactionPoolExt(Arc<RwLock<PoolState>>);
414
415impl TestTransactionPoolExt {
416 pub fn new() -> (Self, Arc<RwLock<PoolState>>) {
418 let ext = Self::default();
419 let state = ext.0.clone();
420 (ext, state)
421 }
422}
423
424impl TransactionPool for TestTransactionPoolExt {
425 fn submit_transaction(&mut self, extrinsic: Vec<u8>) -> Result<(), ()> {
426 self.0.write().transactions.push(extrinsic);
427 Ok(())
428 }
429}