// Copyright 2019 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Substrate is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . //! Module helpers for offchain calls. use codec::Encode; use sr_primitives::app_crypto::{self, RuntimeAppPublic}; use sr_primitives::traits::{Extrinsic as ExtrinsicT, IdentifyAccount}; /// A trait responsible for signing a payload using given account. pub trait Signer { /// Sign any encodable payload with given account and produce a signature. /// /// Returns `Some` if signing succeeded and `None` in case the `account` couldn't be used. fn sign(public: Public, payload: &Payload) -> Option; } /// A `Signer` implementation for any `AppPublic` type. /// /// This implementation additionaly supports conversion to/from multi-signature/multi-signer /// wrappers. /// If the wrapped crypto doesn't match `AppPublic`s crypto `None` is returned. impl Signer for AppPublic where AppPublic: RuntimeAppPublic + app_crypto::AppPublic + From<::Generic>, ::Signature: app_crypto::AppSignature, Signature: From< <::Signature as app_crypto::AppSignature>::Generic >, Public: rstd::convert::TryInto<::Generic> { fn sign(public: Public, raw_payload: &Payload) -> Option { raw_payload.using_encoded(|payload| { let public = public.try_into().ok()?; AppPublic::from(public).sign(&payload) .map( <::Signature as app_crypto::AppSignature> ::Generic::from ) .map(Signature::from) }) } } /// Creates runtime-specific signed transaction. pub trait CreateTransaction { /// A `Public` key representing a particular `AccountId`. type Public: IdentifyAccount + Clone; /// A `Signature` generated by the `Signer`. type Signature; /// Attempt to create signed extrinsic data that encodes call from given account. /// /// Runtime implementation is free to construct the payload to sign and the signature /// in any way it wants. /// Returns `None` if signed extrinsic could not be created (either because signing failed /// or because of any other runtime-specific reason). fn create_transaction>( call: Extrinsic::Call, public: Self::Public, account: T::AccountId, nonce: T::Index, ) -> Option<(Extrinsic::Call, Extrinsic::SignaturePayload)>; } type PublicOf = < >::CreateTransaction as CreateTransaction< T, >::Extrinsic, > >::Public; /// A trait to sign and submit transactions in offchain calls. pub trait SubmitSignedTransaction { /// Unchecked extrinsic type. type Extrinsic: ExtrinsicT + codec::Encode; /// A runtime-specific type to produce signed data for the extrinsic. type CreateTransaction: CreateTransaction; /// A type used to sign transactions created using `CreateTransaction`. type Signer: Signer< PublicOf, >::Signature, >; /// Sign given call and submit it to the transaction pool. /// /// Returns `Ok` if the transaction was submitted correctly /// and `Err` if the key for given `id` was not found or the /// transaction was rejected from the pool. fn sign_and_submit(call: impl Into, public: PublicOf) -> Result<(), ()> { let call = call.into(); let id = public.clone().into_account(); let expected = >::account_nonce(&id); let (call, signature_data) = Self::CreateTransaction ::create_transaction::(call, public, id, expected) .ok_or(())?; let xt = Self::Extrinsic::new(call, Some(signature_data)).ok_or(())?; runtime_io::offchain::submit_transaction(xt.encode()) } } /// A trait to submit unsigned transactions in offchain calls. pub trait SubmitUnsignedTransaction { /// Unchecked extrinsic type. type Extrinsic: ExtrinsicT + codec::Encode; /// Submit given call to the transaction pool as unsigned transaction. /// /// Returns `Ok` if the transaction was submitted correctly /// and `Err` if transaction was rejected from the pool. fn submit_unsigned(call: impl Into) -> Result<(), ()> { let xt = Self::Extrinsic::new(call.into(), None).ok_or(())?; runtime_io::offchain::submit_transaction(xt.encode()) } } /// A default type used to submit transactions to the pool. pub struct TransactionSubmitter { _signer: rstd::marker::PhantomData<(S, C, E)>, } impl Default for TransactionSubmitter { fn default() -> Self { Self { _signer: Default::default(), } } } /// A blanket implementation to simplify creation of transaction signer & submitter in the runtime. impl SubmitSignedTransaction for TransactionSubmitter where T: crate::Trait, C: CreateTransaction, S: Signer<>::Public, >::Signature>, E: ExtrinsicT + codec::Encode, { type Extrinsic = E; type CreateTransaction = C; type Signer = S; } /// A blanket impl to use the same submitter for usigned transactions as well. impl SubmitUnsignedTransaction for TransactionSubmitter where T: crate::Trait, E: ExtrinsicT + codec::Encode, { type Extrinsic = E; }