1
// This file is part of Substrate.
2

            
3
// Copyright (C) Parity Technologies (UK) Ltd.
4
// SPDX-License-Identifier: Apache-2.0
5

            
6
// Licensed under the Apache License, Version 2.0 (the "License");
7
// you may not use this file except in compliance with the License.
8
// You may obtain a copy of the License at
9
//
10
// 	http://www.apache.org/licenses/LICENSE-2.0
11
//
12
// Unless required by applicable law or agreed to in writing, software
13
// distributed under the License is distributed on an "AS IS" BASIS,
14
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
// See the License for the specific language governing permissions and
16
// limitations under the License.
17

            
18
//! Module helpers for off-chain calls.
19
//!
20
//! ## Overview
21
//!
22
//! This module provides transaction related helpers to:
23
//! - Submit a raw unsigned transaction
24
//! - Submit an unsigned transaction with a signed payload
25
//! - Submit a signed transaction.
26
//!
27
//! ## Usage
28
//!
29
//! Please refer to [`example-offchain-worker`](../../pallet_example_offchain_worker/index.html) for
30
//! a concrete example usage of this crate.
31
//!
32
//! ### Submit a raw unsigned transaction
33
//!
34
//! To submit a raw unsigned transaction, [`SubmitTransaction`](./struct.SubmitTransaction.html)
35
//! can be used.
36
//!
37
//! ### Signing transactions
38
//!
39
//! To be able to use signing, the following trait should be implemented:
40
//!
41
//! - [`AppCrypto`](./trait.AppCrypto.html): where an application-specific key is defined and can be
42
//!   used by this module's helpers for signing.
43
//! - [`CreateSignedTransaction`](./trait.CreateSignedTransaction.html): where the manner in which
44
//!   the transaction is constructed is defined.
45
//!
46
//! #### Submit an unsigned transaction with a signed payload
47
//!
48
//! Initially, a payload instance that implements the `SignedPayload` trait should be defined.
49
//! See [`PricePayload`](../../pallet_example_offchain_worker/struct.PricePayload.html)
50
//!
51
//! The payload type that is defined defined can then be signed and submitted onchain.
52
//!
53
//! #### Submit a signed transaction
54
//!
55
//! [`Signer`](./struct.Signer.html) can be used to sign/verify payloads
56

            
57
#![warn(missing_docs)]
58

            
59
use alloc::{boxed::Box, collections::btree_set::BTreeSet, vec::Vec};
60
use codec::Encode;
61
use sp_runtime::{
62
	app_crypto::RuntimeAppPublic,
63
	traits::{Extrinsic as ExtrinsicT, IdentifyAccount, One},
64
	RuntimeDebug,
65
};
66

            
67
/// Marker struct used to flag using all supported keys to sign a payload.
68
pub struct ForAll {}
69
/// Marker struct used to flag using any of the supported keys to sign a payload.
70
pub struct ForAny {}
71

            
72
/// Provides the ability to directly submit signed and unsigned
73
/// transaction onchain.
74
///
75
/// For submitting unsigned transactions, `submit_unsigned_transaction`
76
/// utility function can be used. However, this struct is used by `Signer`
77
/// to submit a signed transactions providing the signature along with the call.
78
pub struct SubmitTransaction<T: SendTransactionTypes<OverarchingCall>, OverarchingCall> {
79
	_phantom: core::marker::PhantomData<(T, OverarchingCall)>,
80
}
81

            
82
impl<T, LocalCall> SubmitTransaction<T, LocalCall>
83
where
84
	T: SendTransactionTypes<LocalCall>,
85
{
86
	/// Submit transaction onchain by providing the call and an optional signature
87
	pub fn submit_transaction(
88
		call: <T as SendTransactionTypes<LocalCall>>::OverarchingCall,
89
		signature: Option<<T::Extrinsic as ExtrinsicT>::SignaturePayload>,
90
	) -> Result<(), ()> {
91
		let xt = T::Extrinsic::new(call, signature).ok_or(())?;
92
		sp_io::offchain::submit_transaction(xt.encode())
93
	}
94

            
95
	/// A convenience method to submit an unsigned transaction onchain.
96
	pub fn submit_unsigned_transaction(
97
		call: <T as SendTransactionTypes<LocalCall>>::OverarchingCall,
98
	) -> Result<(), ()> {
99
		SubmitTransaction::<T, LocalCall>::submit_transaction(call, None)
100
	}
101
}
102

            
103
/// Provides an implementation for signing transaction payloads.
104
///
105
/// Keys used for signing are defined when instantiating the signer object.
106
/// Signing can be done using:
107
///
108
/// - All supported keys in the keystore
109
/// - Any of the supported keys in the keystore
110
/// - An intersection of in-keystore keys and the list of provided keys
111
///
112
/// The signer is then able to:
113
/// - Submit a unsigned transaction with a signed payload
114
/// - Submit a signed transaction
115
#[derive(RuntimeDebug)]
116
pub struct Signer<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>, X = ForAny> {
117
	accounts: Option<Vec<T::Public>>,
118
	_phantom: core::marker::PhantomData<(X, C)>,
119
}
120

            
121
impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>, X> Default for Signer<T, C, X> {
122
	fn default() -> Self {
123
		Self { accounts: Default::default(), _phantom: Default::default() }
124
	}
125
}
126

            
127
impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>, X> Signer<T, C, X> {
128
	/// Use all available keys for signing.
129
	pub fn all_accounts() -> Signer<T, C, ForAll> {
130
		Default::default()
131
	}
132

            
133
	/// Use any of the available keys for signing.
134
	pub fn any_account() -> Signer<T, C, ForAny> {
135
		Default::default()
136
	}
137

            
138
	/// Use provided `accounts` for signing.
139
	///
140
	/// Note that not all keys will be necessarily used. The provided
141
	/// vector of accounts will be intersected with the supported keys
142
	/// in the keystore and the resulting list will be used for signing.
143
	pub fn with_filter(mut self, accounts: Vec<T::Public>) -> Self {
144
		self.accounts = Some(accounts);
145
		self
146
	}
147

            
148
	/// Check if there are any keys that could be used for signing.
149
	pub fn can_sign(&self) -> bool {
150
		self.accounts_from_keys().count() > 0
151
	}
152

            
153
	/// Return a vector of the intersection between
154
	/// all available accounts and the provided accounts
155
	/// in `with_filter`. If no accounts are provided,
156
	/// use all accounts by default.
157
	pub fn accounts_from_keys<'a>(&'a self) -> Box<dyn Iterator<Item = Account<T>> + 'a> {
158
		let keystore_accounts = Self::keystore_accounts();
159
		match self.accounts {
160
			None => Box::new(keystore_accounts),
161
			Some(ref keys) => {
162
				let keystore_lookup: BTreeSet<<T as SigningTypes>::Public> =
163
					keystore_accounts.map(|account| account.public).collect();
164

            
165
				Box::new(
166
					keys.iter()
167
						.enumerate()
168
						.map(|(index, key)| {
169
							let account_id = key.clone().into_account();
170
							Account::new(index, account_id, key.clone())
171
						})
172
						.filter(move |account| keystore_lookup.contains(&account.public)),
173
				)
174
			},
175
		}
176
	}
177

            
178
	/// Return all available accounts in keystore.
179
	pub fn keystore_accounts() -> impl Iterator<Item = Account<T>> {
180
		C::RuntimeAppPublic::all().into_iter().enumerate().map(|(index, key)| {
181
			let generic_public = C::GenericPublic::from(key);
182
			let public: T::Public = generic_public.into();
183
			let account_id = public.clone().into_account();
184
			Account::new(index, account_id, public)
185
		})
186
	}
187
}
188

            
189
impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>> Signer<T, C, ForAll> {
190
	fn for_all<F, R>(&self, f: F) -> Vec<(Account<T>, R)>
191
	where
192
		F: Fn(&Account<T>) -> Option<R>,
193
	{
194
		let accounts = self.accounts_from_keys();
195
		accounts
196
			.into_iter()
197
			.filter_map(|account| f(&account).map(|res| (account, res)))
198
			.collect()
199
	}
200
}
201

            
202
impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>> Signer<T, C, ForAny> {
203
	fn for_any<F, R>(&self, f: F) -> Option<(Account<T>, R)>
204
	where
205
		F: Fn(&Account<T>) -> Option<R>,
206
	{
207
		let accounts = self.accounts_from_keys();
208
		for account in accounts.into_iter() {
209
			let res = f(&account);
210
			if let Some(res) = res {
211
				return Some((account, res))
212
			}
213
		}
214
		None
215
	}
216
}
217

            
218
impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>> SignMessage<T>
219
	for Signer<T, C, ForAll>
220
{
221
	type SignatureData = Vec<(Account<T>, T::Signature)>;
222

            
223
	fn sign_message(&self, message: &[u8]) -> Self::SignatureData {
224
		self.for_all(|account| C::sign(message, account.public.clone()))
225
	}
226

            
227
	fn sign<TPayload, F>(&self, f: F) -> Self::SignatureData
228
	where
229
		F: Fn(&Account<T>) -> TPayload,
230
		TPayload: SignedPayload<T>,
231
	{
232
		self.for_all(|account| f(account).sign::<C>())
233
	}
234
}
235

            
236
impl<T: SigningTypes, C: AppCrypto<T::Public, T::Signature>> SignMessage<T>
237
	for Signer<T, C, ForAny>
238
{
239
	type SignatureData = Option<(Account<T>, T::Signature)>;
240

            
241
	fn sign_message(&self, message: &[u8]) -> Self::SignatureData {
242
		self.for_any(|account| C::sign(message, account.public.clone()))
243
	}
244

            
245
	fn sign<TPayload, F>(&self, f: F) -> Self::SignatureData
246
	where
247
		F: Fn(&Account<T>) -> TPayload,
248
		TPayload: SignedPayload<T>,
249
	{
250
		self.for_any(|account| f(account).sign::<C>())
251
	}
252
}
253

            
254
impl<
255
		T: CreateSignedTransaction<LocalCall> + SigningTypes,
256
		C: AppCrypto<T::Public, T::Signature>,
257
		LocalCall,
258
	> SendSignedTransaction<T, C, LocalCall> for Signer<T, C, ForAny>
259
{
260
	type Result = Option<(Account<T>, Result<(), ()>)>;
261

            
262
	fn send_signed_transaction(&self, f: impl Fn(&Account<T>) -> LocalCall) -> Self::Result {
263
		self.for_any(|account| {
264
			let call = f(account);
265
			self.send_single_signed_transaction(account, call)
266
		})
267
	}
268
}
269

            
270
impl<
271
		T: SigningTypes + CreateSignedTransaction<LocalCall>,
272
		C: AppCrypto<T::Public, T::Signature>,
273
		LocalCall,
274
	> SendSignedTransaction<T, C, LocalCall> for Signer<T, C, ForAll>
275
{
276
	type Result = Vec<(Account<T>, Result<(), ()>)>;
277

            
278
	fn send_signed_transaction(&self, f: impl Fn(&Account<T>) -> LocalCall) -> Self::Result {
279
		self.for_all(|account| {
280
			let call = f(account);
281
			self.send_single_signed_transaction(account, call)
282
		})
283
	}
284
}
285

            
286
impl<
287
		T: SigningTypes + SendTransactionTypes<LocalCall>,
288
		C: AppCrypto<T::Public, T::Signature>,
289
		LocalCall,
290
	> SendUnsignedTransaction<T, LocalCall> for Signer<T, C, ForAny>
291
{
292
	type Result = Option<(Account<T>, Result<(), ()>)>;
293

            
294
	fn send_unsigned_transaction<TPayload, F>(
295
		&self,
296
		f: F,
297
		f2: impl Fn(TPayload, T::Signature) -> LocalCall,
298
	) -> Self::Result
299
	where
300
		F: Fn(&Account<T>) -> TPayload,
301
		TPayload: SignedPayload<T>,
302
	{
303
		self.for_any(|account| {
304
			let payload = f(account);
305
			let signature = payload.sign::<C>()?;
306
			let call = f2(payload, signature);
307
			self.submit_unsigned_transaction(call)
308
		})
309
	}
310
}
311

            
312
impl<
313
		T: SigningTypes + SendTransactionTypes<LocalCall>,
314
		C: AppCrypto<T::Public, T::Signature>,
315
		LocalCall,
316
	> SendUnsignedTransaction<T, LocalCall> for Signer<T, C, ForAll>
317
{
318
	type Result = Vec<(Account<T>, Result<(), ()>)>;
319

            
320
	fn send_unsigned_transaction<TPayload, F>(
321
		&self,
322
		f: F,
323
		f2: impl Fn(TPayload, T::Signature) -> LocalCall,
324
	) -> Self::Result
325
	where
326
		F: Fn(&Account<T>) -> TPayload,
327
		TPayload: SignedPayload<T>,
328
	{
329
		self.for_all(|account| {
330
			let payload = f(account);
331
			let signature = payload.sign::<C>()?;
332
			let call = f2(payload, signature);
333
			self.submit_unsigned_transaction(call)
334
		})
335
	}
336
}
337

            
338
/// Details of an account for which a private key is contained in the keystore.
339
#[derive(RuntimeDebug, PartialEq)]
340
pub struct Account<T: SigningTypes> {
341
	/// Index on the provided list of accounts or list of all accounts.
342
	pub index: usize,
343
	/// Runtime-specific `AccountId`.
344
	pub id: T::AccountId,
345
	/// A runtime-specific `Public` key for that key pair.
346
	pub public: T::Public,
347
}
348

            
349
impl<T: SigningTypes> Account<T> {
350
	/// Create a new Account instance
351
	pub fn new(index: usize, id: T::AccountId, public: T::Public) -> Self {
352
		Self { index, id, public }
353
	}
354
}
355

            
356
impl<T: SigningTypes> Clone for Account<T>
357
where
358
	T::AccountId: Clone,
359
	T::Public: Clone,
360
{
361
	fn clone(&self) -> Self {
362
		Self { index: self.index, id: self.id.clone(), public: self.public.clone() }
363
	}
364
}
365

            
366
/// A type binding runtime-level `Public/Signature` pair with crypto wrapped by `RuntimeAppPublic`.
367
///
368
/// Implementations of this trait should specify the app-specific public/signature types.
369
/// This is merely a wrapper around an existing `RuntimeAppPublic` type, but with
370
/// extra non-application-specific crypto type that is being wrapped (e.g. `sr25519`, `ed25519`).
371
/// This is needed to later on convert into runtime-specific `Public` key, which might support
372
/// multiple different crypto.
373
/// The point of this trait is to be able to easily convert between `RuntimeAppPublic`, the wrapped
374
/// (generic = non application-specific) crypto types and the `Public` type required by the runtime.
375
///
376
/// Example (pseudo-)implementation:
377
/// ```ignore
378
/// // im-online specific crypto
379
/// type RuntimeAppPublic = ImOnline(sr25519::Public);
380
///
381
/// // wrapped "raw" crypto
382
/// type GenericPublic = sr25519::Public;
383
/// type GenericSignature = sr25519::Signature;
384
///
385
/// // runtime-specific public key
386
/// type Public = MultiSigner: From<sr25519::Public>;
387
/// type Signature = MultiSignature: From<sr25519::Signature>;
388
/// ```
389
// TODO [#5662] Potentially use `IsWrappedBy` types, or find some other way to make it easy to
390
// obtain unwrapped crypto (and wrap it back).
391
pub trait AppCrypto<Public, Signature> {
392
	/// A application-specific crypto.
393
	type RuntimeAppPublic: RuntimeAppPublic;
394

            
395
	/// A raw crypto public key wrapped by `RuntimeAppPublic`.
396
	type GenericPublic: From<Self::RuntimeAppPublic>
397
		+ Into<Self::RuntimeAppPublic>
398
		+ TryFrom<Public>
399
		+ Into<Public>;
400

            
401
	/// A matching raw crypto `Signature` type.
402
	type GenericSignature: From<<Self::RuntimeAppPublic as RuntimeAppPublic>::Signature>
403
		+ Into<<Self::RuntimeAppPublic as RuntimeAppPublic>::Signature>
404
		+ TryFrom<Signature>
405
		+ Into<Signature>;
406

            
407
	/// Sign payload with the private key to maps to the provided public key.
408
	fn sign(payload: &[u8], public: Public) -> Option<Signature> {
409
		let p: Self::GenericPublic = public.try_into().ok()?;
410
		let x = Into::<Self::RuntimeAppPublic>::into(p);
411
		x.sign(&payload)
412
			.map(|x| {
413
				let sig: Self::GenericSignature = x.into();
414
				sig
415
			})
416
			.map(Into::into)
417
	}
418

            
419
	/// Verify signature against the provided public key.
420
	fn verify(payload: &[u8], public: Public, signature: Signature) -> bool {
421
		let p: Self::GenericPublic = match public.try_into() {
422
			Ok(a) => a,
423
			_ => return false,
424
		};
425
		let x = Into::<Self::RuntimeAppPublic>::into(p);
426
		let signature: Self::GenericSignature = match signature.try_into() {
427
			Ok(a) => a,
428
			_ => return false,
429
		};
430
		let signature =
431
			Into::<<Self::RuntimeAppPublic as RuntimeAppPublic>::Signature>::into(signature);
432

            
433
		x.verify(&payload, &signature)
434
	}
435
}
436

            
437
/// A wrapper around the types which are used for signing.
438
///
439
/// This trait adds extra bounds to `Public` and `Signature` types of the runtime
440
/// that are necessary to use these types for signing.
441
// TODO [#5663] Could this be just `T::Signature as traits::Verify>::Signer`?
442
// Seems that this may cause issues with bounds resolution.
443
pub trait SigningTypes: crate::Config {
444
	/// A public key that is capable of identifying `AccountId`s.
445
	///
446
	/// Usually that's either a raw crypto public key (e.g. `sr25519::Public`) or
447
	/// an aggregate type for multiple crypto public keys, like `MultiSigner`.
448
	type Public: Clone
449
		+ PartialEq
450
		+ IdentifyAccount<AccountId = Self::AccountId>
451
		+ core::fmt::Debug
452
		+ codec::Codec
453
		+ Ord
454
		+ scale_info::TypeInfo;
455

            
456
	/// A matching `Signature` type.
457
	type Signature: Clone + PartialEq + core::fmt::Debug + codec::Codec + scale_info::TypeInfo;
458
}
459

            
460
/// A definition of types required to submit transactions from within the runtime.
461
pub trait SendTransactionTypes<LocalCall> {
462
	/// The extrinsic type expected by the runtime.
463
	type Extrinsic: ExtrinsicT<Call = Self::OverarchingCall> + codec::Encode;
464
	/// The runtime's call type.
465
	///
466
	/// This has additional bound to be able to be created from pallet-local `Call` types.
467
	type OverarchingCall: From<LocalCall> + codec::Encode;
468
}
469

            
470
/// Create signed transaction.
471
///
472
/// This trait is meant to be implemented by the runtime and is responsible for constructing
473
/// a payload to be signed and contained within the extrinsic.
474
/// This will most likely include creation of `SignedExtra` (a set of `SignedExtensions`).
475
/// Note that the result can be altered by inspecting the `Call` (for instance adjusting
476
/// fees, or mortality depending on the `pallet` being called).
477
pub trait CreateSignedTransaction<LocalCall>:
478
	SendTransactionTypes<LocalCall> + SigningTypes
479
{
480
	/// Attempt to create signed extrinsic data that encodes call from given account.
481
	///
482
	/// Runtime implementation is free to construct the payload to sign and the signature
483
	/// in any way it wants.
484
	/// Returns `None` if signed extrinsic could not be created (either because signing failed
485
	/// or because of any other runtime-specific reason).
486
	fn create_transaction<C: AppCrypto<Self::Public, Self::Signature>>(
487
		call: Self::OverarchingCall,
488
		public: Self::Public,
489
		account: Self::AccountId,
490
		nonce: Self::Nonce,
491
	) -> Option<(Self::OverarchingCall, <Self::Extrinsic as ExtrinsicT>::SignaturePayload)>;
492
}
493

            
494
/// A message signer.
495
pub trait SignMessage<T: SigningTypes> {
496
	/// A signature data.
497
	///
498
	/// May contain account used for signing and the `Signature` itself.
499
	type SignatureData;
500

            
501
	/// Sign a message.
502
	///
503
	/// Implementation of this method should return
504
	/// a result containing the signature.
505
	fn sign_message(&self, message: &[u8]) -> Self::SignatureData;
506

            
507
	/// Construct and sign given payload.
508
	///
509
	/// This method expects `f` to return a `SignedPayload`
510
	/// object which is then used for signing.
511
	fn sign<TPayload, F>(&self, f: F) -> Self::SignatureData
512
	where
513
		F: Fn(&Account<T>) -> TPayload,
514
		TPayload: SignedPayload<T>;
515
}
516

            
517
/// Submit a signed transaction to the transaction pool.
518
pub trait SendSignedTransaction<
519
	T: SigningTypes + CreateSignedTransaction<LocalCall>,
520
	C: AppCrypto<T::Public, T::Signature>,
521
	LocalCall,
522
>
523
{
524
	/// A submission result.
525
	///
526
	/// This should contain an indication of success and the account that was used for signing.
527
	type Result;
528

            
529
	/// Submit a signed transaction to the local pool.
530
	///
531
	/// Given `f` closure will be called for every requested account and expects a `Call` object
532
	/// to be returned.
533
	/// The call is then wrapped into a transaction (see `#CreateSignedTransaction`), signed and
534
	/// submitted to the pool.
535
	fn send_signed_transaction(&self, f: impl Fn(&Account<T>) -> LocalCall) -> Self::Result;
536

            
537
	/// Wraps the call into transaction, signs using given account and submits to the pool.
538
	fn send_single_signed_transaction(
539
		&self,
540
		account: &Account<T>,
541
		call: LocalCall,
542
	) -> Option<Result<(), ()>> {
543
		let mut account_data = crate::Account::<T>::get(&account.id);
544
		log::debug!(
545
			target: "runtime::offchain",
546
			"Creating signed transaction from account: {:?} (nonce: {:?})",
547
			account.id,
548
			account_data.nonce,
549
		);
550
		let (call, signature) = T::create_transaction::<C>(
551
			call.into(),
552
			account.public.clone(),
553
			account.id.clone(),
554
			account_data.nonce,
555
		)?;
556
		let res = SubmitTransaction::<T, LocalCall>::submit_transaction(call, Some(signature));
557

            
558
		if res.is_ok() {
559
			// increment the nonce. This is fine, since the code should always
560
			// be running in off-chain context, so we NEVER persists data.
561
			account_data.nonce += One::one();
562
			crate::Account::<T>::insert(&account.id, account_data);
563
		}
564

            
565
		Some(res)
566
	}
567
}
568

            
569
/// Submit an unsigned transaction onchain with a signed payload
570
pub trait SendUnsignedTransaction<T: SigningTypes + SendTransactionTypes<LocalCall>, LocalCall> {
571
	/// A submission result.
572
	///
573
	/// Should contain the submission result and the account(s) that signed the payload.
574
	type Result;
575

            
576
	/// Send an unsigned transaction with a signed payload.
577
	///
578
	/// This method takes `f` and `f2` where:
579
	/// - `f` is called for every account and is expected to return a `SignedPayload` object.
580
	/// - `f2` is then called with the `SignedPayload` returned by `f` and the signature and is
581
	/// expected to return a `Call` object to be embedded into transaction.
582
	fn send_unsigned_transaction<TPayload, F>(
583
		&self,
584
		f: F,
585
		f2: impl Fn(TPayload, T::Signature) -> LocalCall,
586
	) -> Self::Result
587
	where
588
		F: Fn(&Account<T>) -> TPayload,
589
		TPayload: SignedPayload<T>;
590

            
591
	/// Submits an unsigned call to the transaction pool.
592
	fn submit_unsigned_transaction(&self, call: LocalCall) -> Option<Result<(), ()>> {
593
		Some(SubmitTransaction::<T, LocalCall>::submit_unsigned_transaction(call.into()))
594
	}
595
}
596

            
597
/// Utility trait to be implemented on payloads that can be signed.
598
pub trait SignedPayload<T: SigningTypes>: Encode {
599
	/// Return a public key that is expected to have a matching key in the keystore,
600
	/// which should be used to sign the payload.
601
	fn public(&self) -> T::Public;
602

            
603
	/// Sign the payload using the implementor's provided public key.
604
	///
605
	/// Returns `Some(signature)` if public key is supported.
606
	fn sign<C: AppCrypto<T::Public, T::Signature>>(&self) -> Option<T::Signature> {
607
		self.using_encoded(|payload| C::sign(payload, self.public()))
608
	}
609

            
610
	/// Verify signature against payload.
611
	///
612
	/// Returns a bool indicating whether the signature is valid or not.
613
	fn verify<C: AppCrypto<T::Public, T::Signature>>(&self, signature: T::Signature) -> bool {
614
		self.using_encoded(|payload| C::verify(payload, self.public(), signature))
615
	}
616
}
617

            
618
#[cfg(test)]
619
mod tests {
620
	use super::*;
621
	use crate::mock::{RuntimeCall, Test as TestRuntime, CALL};
622
	use codec::Decode;
623
	use sp_core::offchain::{testing, TransactionPoolExt};
624
	use sp_runtime::testing::{TestSignature, TestXt, UintAuthorityId};
625

            
626
	impl SigningTypes for TestRuntime {
627
		type Public = UintAuthorityId;
628
		type Signature = TestSignature;
629
	}
630

            
631
	type Extrinsic = TestXt<RuntimeCall, ()>;
632

            
633
	impl SendTransactionTypes<RuntimeCall> for TestRuntime {
634
		type Extrinsic = Extrinsic;
635
		type OverarchingCall = RuntimeCall;
636
	}
637

            
638
	#[derive(codec::Encode, codec::Decode)]
639
	struct SimplePayload {
640
		pub public: UintAuthorityId,
641
		pub data: Vec<u8>,
642
	}
643

            
644
	impl SignedPayload<TestRuntime> for SimplePayload {
645
		fn public(&self) -> UintAuthorityId {
646
			self.public.clone()
647
		}
648
	}
649

            
650
	struct DummyAppCrypto;
651
	// Bind together the `SigningTypes` with app-crypto and the wrapper types.
652
	// here the implementation is pretty dummy, because we use the same type for
653
	// both application-specific crypto and the runtime crypto, but in real-life
654
	// runtimes it's going to use different types everywhere.
655
	impl AppCrypto<UintAuthorityId, TestSignature> for DummyAppCrypto {
656
		type RuntimeAppPublic = UintAuthorityId;
657
		type GenericPublic = UintAuthorityId;
658
		type GenericSignature = TestSignature;
659
	}
660

            
661
	fn assert_account(next: Option<(Account<TestRuntime>, Result<(), ()>)>, index: usize, id: u64) {
662
		assert_eq!(next, Some((Account { index, id, public: id.into() }, Ok(()))));
663
	}
664

            
665
	#[test]
666
	fn should_send_unsigned_with_signed_payload_with_all_accounts() {
667
		let (pool, pool_state) = testing::TestTransactionPoolExt::new();
668

            
669
		let mut t = sp_io::TestExternalities::default();
670
		t.register_extension(TransactionPoolExt::new(pool));
671

            
672
		// given
673
		UintAuthorityId::set_all_keys(vec![0xf0, 0xf1, 0xf2]);
674

            
675
		t.execute_with(|| {
676
			// when
677
			let result = Signer::<TestRuntime, DummyAppCrypto>::all_accounts()
678
				.send_unsigned_transaction(
679
					|account| SimplePayload { data: vec![1, 2, 3], public: account.public.clone() },
680
					|_payload, _signature| CALL.clone(),
681
				);
682

            
683
			// then
684
			let mut res = result.into_iter();
685
			assert_account(res.next(), 0, 0xf0);
686
			assert_account(res.next(), 1, 0xf1);
687
			assert_account(res.next(), 2, 0xf2);
688
			assert_eq!(res.next(), None);
689

            
690
			// check the transaction pool content:
691
			let tx1 = pool_state.write().transactions.pop().unwrap();
692
			let _tx2 = pool_state.write().transactions.pop().unwrap();
693
			let _tx3 = pool_state.write().transactions.pop().unwrap();
694
			assert!(pool_state.read().transactions.is_empty());
695
			let tx1 = Extrinsic::decode(&mut &*tx1).unwrap();
696
			assert_eq!(tx1.signature, None);
697
		});
698
	}
699

            
700
	#[test]
701
	fn should_send_unsigned_with_signed_payload_with_any_account() {
702
		let (pool, pool_state) = testing::TestTransactionPoolExt::new();
703

            
704
		let mut t = sp_io::TestExternalities::default();
705
		t.register_extension(TransactionPoolExt::new(pool));
706

            
707
		// given
708
		UintAuthorityId::set_all_keys(vec![0xf0, 0xf1, 0xf2]);
709

            
710
		t.execute_with(|| {
711
			// when
712
			let result = Signer::<TestRuntime, DummyAppCrypto>::any_account()
713
				.send_unsigned_transaction(
714
					|account| SimplePayload { data: vec![1, 2, 3], public: account.public.clone() },
715
					|_payload, _signature| CALL.clone(),
716
				);
717

            
718
			// then
719
			let mut res = result.into_iter();
720
			assert_account(res.next(), 0, 0xf0);
721
			assert_eq!(res.next(), None);
722

            
723
			// check the transaction pool content:
724
			let tx1 = pool_state.write().transactions.pop().unwrap();
725
			assert!(pool_state.read().transactions.is_empty());
726
			let tx1 = Extrinsic::decode(&mut &*tx1).unwrap();
727
			assert_eq!(tx1.signature, None);
728
		});
729
	}
730

            
731
	#[test]
732
	fn should_send_unsigned_with_signed_payload_with_all_account_and_filter() {
733
		let (pool, pool_state) = testing::TestTransactionPoolExt::new();
734

            
735
		let mut t = sp_io::TestExternalities::default();
736
		t.register_extension(TransactionPoolExt::new(pool));
737

            
738
		// given
739
		UintAuthorityId::set_all_keys(vec![0xf0, 0xf1, 0xf2]);
740

            
741
		t.execute_with(|| {
742
			// when
743
			let result = Signer::<TestRuntime, DummyAppCrypto>::all_accounts()
744
				.with_filter(vec![0xf2.into(), 0xf1.into()])
745
				.send_unsigned_transaction(
746
					|account| SimplePayload { data: vec![1, 2, 3], public: account.public.clone() },
747
					|_payload, _signature| CALL.clone(),
748
				);
749

            
750
			// then
751
			let mut res = result.into_iter();
752
			assert_account(res.next(), 0, 0xf2);
753
			assert_account(res.next(), 1, 0xf1);
754
			assert_eq!(res.next(), None);
755

            
756
			// check the transaction pool content:
757
			let tx1 = pool_state.write().transactions.pop().unwrap();
758
			let _tx2 = pool_state.write().transactions.pop().unwrap();
759
			assert!(pool_state.read().transactions.is_empty());
760
			let tx1 = Extrinsic::decode(&mut &*tx1).unwrap();
761
			assert_eq!(tx1.signature, None);
762
		});
763
	}
764

            
765
	#[test]
766
	fn should_send_unsigned_with_signed_payload_with_any_account_and_filter() {
767
		let (pool, pool_state) = testing::TestTransactionPoolExt::new();
768

            
769
		let mut t = sp_io::TestExternalities::default();
770
		t.register_extension(TransactionPoolExt::new(pool));
771

            
772
		// given
773
		UintAuthorityId::set_all_keys(vec![0xf0, 0xf1, 0xf2]);
774

            
775
		t.execute_with(|| {
776
			// when
777
			let result = Signer::<TestRuntime, DummyAppCrypto>::any_account()
778
				.with_filter(vec![0xf2.into(), 0xf1.into()])
779
				.send_unsigned_transaction(
780
					|account| SimplePayload { data: vec![1, 2, 3], public: account.public.clone() },
781
					|_payload, _signature| CALL.clone(),
782
				);
783

            
784
			// then
785
			let mut res = result.into_iter();
786
			assert_account(res.next(), 0, 0xf2);
787
			assert_eq!(res.next(), None);
788

            
789
			// check the transaction pool content:
790
			let tx1 = pool_state.write().transactions.pop().unwrap();
791
			assert!(pool_state.read().transactions.is_empty());
792
			let tx1 = Extrinsic::decode(&mut &*tx1).unwrap();
793
			assert_eq!(tx1.signature, None);
794
		});
795
	}
796
}