// Copyright 2015-2019 Parity Technologies (UK) Ltd. // This file is part of Parity Ethereum. // Parity Ethereum 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. // Parity Ethereum 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 Parity Ethereum. If not, see . use std::sync::Arc; use ethereum_types::U256; use jsonrpc_core::{Result, Error}; use jsonrpc_core::futures::{Future, Poll, Async, IntoFuture}; use types::transaction::SignedTransaction; use v1::helpers::{errors, nonce, FilledTransactionRequest}; use super::{Accounts, SignWith, WithToken, PostSign}; #[derive(Debug, Clone, Copy)] enum ProspectiveSignerState { TryProspectiveSign, WaitForPostSign, WaitForNonce, } pub struct ProspectiveSigner { signer: Arc, filled: FilledTransactionRequest, chain_id: Option, reserved: nonce::Reserved, password: SignWith, state: ProspectiveSignerState, prospective: Option>, ready: Option, post_sign: Option

, post_sign_future: Option<::Future> } impl ProspectiveSigner

{ pub fn new( signer: Arc, filled: FilledTransactionRequest, chain_id: Option, reserved: nonce::Reserved, password: SignWith, post_sign: P ) -> Self { let supports_prospective = signer.supports_prospective_signing(&filled.from, &password); ProspectiveSigner { signer, filled, chain_id, reserved, password, state: if supports_prospective { ProspectiveSignerState::TryProspectiveSign } else { ProspectiveSignerState::WaitForNonce }, prospective: None, ready: None, post_sign: Some(post_sign), post_sign_future: None } } fn sign(&self, nonce: &U256) -> Result> { self.signer.sign_transaction( self.filled.clone(), self.chain_id, *nonce, self.password.clone() ) } fn poll_reserved(&mut self) -> Poll { self.reserved.poll().map_err(|_| errors::internal("Nonce reservation failure", "")) } } impl Future for ProspectiveSigner

{ type Item = P::Item; type Error = Error; fn poll(&mut self) -> Poll { use self::ProspectiveSignerState::*; loop { match self.state { TryProspectiveSign => { // Try to poll reserved, it might be ready. match self.poll_reserved()? { Async::NotReady => { self.state = WaitForNonce; self.prospective = Some(self.sign(self.reserved.prospective_value())?); }, Async::Ready(nonce) => { self.state = WaitForPostSign; self.post_sign_future = Some( self.post_sign.take() .expect("post_sign is set on creation; qed") .execute(self.sign(nonce.value())?) .into_future() ); self.ready = Some(nonce); }, } }, WaitForNonce => { let nonce = try_ready!(self.poll_reserved()); let prospective = match (self.prospective.take(), nonce.matches_prospective()) { (Some(prospective), true) => prospective, _ => self.sign(nonce.value())?, }; self.ready = Some(nonce); self.state = WaitForPostSign; self.post_sign_future = Some(self.post_sign.take() .expect("post_sign is set on creation; qed") .execute(prospective) .into_future()); }, WaitForPostSign => { if let Some(fut) = self.post_sign_future.as_mut() { match fut.poll()? { Async::Ready(item) => { let nonce = self.ready .take() .expect("nonce is set before state transitions to WaitForPostSign; qed"); nonce.mark_used(); return Ok(Async::Ready(item)) }, Async::NotReady => { return Ok(Async::NotReady) } } } else { panic!("Poll after ready."); } } } } } }