// Copyright 2019-2020 Parity Technologies (UK) Ltd. // This file is part of substrate-subxt. // // subxt 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. // // subxt 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-subxt. If not, see . //! A library to **sub**mit e**xt**rinsics to a //! [substrate](https://github.com/paritytech/substrate) node via RPC. use crate::{ extra::SignedExtra, frame::system::System, Encoded, }; use codec::Encode; use sp_core::Pair; use sp_runtime::{ generic::{ SignedPayload, UncheckedExtrinsic, }, traits::{ IdentifyAccount, Verify, }, }; use std::{ future::Future, marker::PhantomData, pin::Pin, }; /// Extrinsic signer. pub trait Signer> { /// Returns the account id. fn account_id(&self) -> &T::AccountId; /// Optionally returns a nonce. fn nonce(&self) -> Option; /// Takes an unsigned extrinsic and returns a signed extrinsic. /// /// Some signers may fail, for instance because the hardware on which the keys are located has /// refused the operation. fn sign( &self, extrinsic: SignedPayload, ) -> Pin< Box< dyn Future< Output = Result< UncheckedExtrinsic, String, >, > + Send + Sync, >, >; } /// Extrinsic signer using a private key. pub struct PairSigner, P: Pair> { _marker: PhantomData<(S, E)>, account_id: T::AccountId, nonce: Option, signer: P, } impl PairSigner where T: System, S: Encode + Verify + From, S::Signer: From + IdentifyAccount, E: SignedExtra, P: Pair, { /// Creates a new `Signer` from a `Pair`. pub fn new(signer: P) -> Self { let account_id = S::Signer::from(signer.public()).into_account(); Self { _marker: PhantomData, account_id, nonce: None, signer, } } /// Sets the nonce to a new value. pub fn set_nonce(&mut self, nonce: T::Index) { self.nonce = Some(nonce); } /// Increment the nonce pub fn increment_nonce(&mut self) { self.nonce = self.nonce.map(|nonce| nonce + 1.into()); } } impl Signer for PairSigner where T: System + 'static, T::AccountId: Into + 'static, S: Encode + 'static + Send + Sync, E: SignedExtra + 'static, P: Pair + 'static, P::Signature: Into + 'static, { fn account_id(&self) -> &T::AccountId { &self.account_id } fn nonce(&self) -> Option { self.nonce } fn sign( &self, extrinsic: SignedPayload, ) -> Pin< Box< dyn Future< Output = Result< UncheckedExtrinsic, String, >, > + Send + Sync, >, > { let signature = extrinsic.using_encoded(|payload| self.signer.sign(payload)); let (call, extra, _) = extrinsic.deconstruct(); Box::pin(futures::future::ok(UncheckedExtrinsic::new_signed( call, self.account_id.clone().into(), signature.into(), extra, ))) } } impl Signer for Box + Send + Sync> where T: System, S: Encode, E: SignedExtra, { fn account_id(&self) -> &T::AccountId { (**self).account_id() } fn nonce(&self) -> Option { (**self).nonce() } fn sign( &self, extrinsic: SignedPayload, ) -> Pin< Box< dyn Future< Output = Result< UncheckedExtrinsic, String, >, > + Send + Sync, >, > { (**self).sign(extrinsic) } }