Local transactions RPC
This commit is contained in:
parent
66e327dfcb
commit
2cd2b10327
@ -21,6 +21,9 @@ use transaction::SignedTransaction;
|
|||||||
use error::TransactionError;
|
use error::TransactionError;
|
||||||
use util::{U256, H256};
|
use util::{U256, H256};
|
||||||
|
|
||||||
|
/// Status of local transaction.
|
||||||
|
/// Can indicate that the transaction is currently part of the queue (`Pending/Future`)
|
||||||
|
/// or gives a reason why the transaction was removed.
|
||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
/// The transaction is currently in the transaction queue.
|
/// The transaction is currently in the transaction queue.
|
||||||
|
@ -23,6 +23,7 @@ use account_provider::AccountProvider;
|
|||||||
use views::{BlockView, HeaderView};
|
use views::{BlockView, HeaderView};
|
||||||
use state::{State, CleanupMode};
|
use state::{State, CleanupMode};
|
||||||
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics};
|
use client::{MiningBlockChainClient, Executive, Executed, EnvInfo, TransactOptions, BlockID, CallAnalytics};
|
||||||
|
use client::TransactionImportResult;
|
||||||
use executive::contract_address;
|
use executive::contract_address;
|
||||||
use block::{ClosedBlock, SealedBlock, IsBlock, Block};
|
use block::{ClosedBlock, SealedBlock, IsBlock, Block};
|
||||||
use error::*;
|
use error::*;
|
||||||
@ -33,10 +34,11 @@ use engines::Engine;
|
|||||||
use miner::{MinerService, MinerStatus, TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin};
|
use miner::{MinerService, MinerStatus, TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin};
|
||||||
use miner::banning_queue::{BanningTransactionQueue, Threshold};
|
use miner::banning_queue::{BanningTransactionQueue, Threshold};
|
||||||
use miner::work_notify::WorkPoster;
|
use miner::work_notify::WorkPoster;
|
||||||
use client::TransactionImportResult;
|
|
||||||
use miner::price_info::PriceInfo;
|
use miner::price_info::PriceInfo;
|
||||||
|
use miner::local_transactions::{Status as LocalTransactionStatus};
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
|
|
||||||
|
|
||||||
/// Different possible definitions for pending transaction set.
|
/// Different possible definitions for pending transaction set.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum PendingSet {
|
pub enum PendingSet {
|
||||||
@ -845,6 +847,14 @@ impl MinerService for Miner {
|
|||||||
queue.top_transactions()
|
queue.top_transactions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
|
||||||
|
let queue = self.transaction_queue.lock();
|
||||||
|
queue.local_transactions()
|
||||||
|
.iter()
|
||||||
|
.map(|(hash, status)| (*hash, status.clone()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction> {
|
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction> {
|
||||||
let queue = self.transaction_queue.lock();
|
let queue = self.transaction_queue.lock();
|
||||||
match self.options.pending_set {
|
match self.options.pending_set {
|
||||||
|
@ -52,6 +52,7 @@ mod work_notify;
|
|||||||
pub use self::external::{ExternalMiner, ExternalMinerService};
|
pub use self::external::{ExternalMiner, ExternalMinerService};
|
||||||
pub use self::miner::{Miner, MinerOptions, Banning, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit};
|
pub use self::miner::{Miner, MinerOptions, Banning, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit};
|
||||||
pub use self::transaction_queue::{TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin};
|
pub use self::transaction_queue::{TransactionQueue, PrioritizationStrategy, AccountDetails, TransactionOrigin};
|
||||||
|
pub use self::local_transactions::{Status as LocalTransactionStatus};
|
||||||
pub use client::TransactionImportResult;
|
pub use client::TransactionImportResult;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
@ -146,6 +147,9 @@ pub trait MinerService : Send + Sync {
|
|||||||
/// Get a list of all pending transactions.
|
/// Get a list of all pending transactions.
|
||||||
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction>;
|
fn pending_transactions(&self, best_block: BlockNumber) -> Vec<SignedTransaction>;
|
||||||
|
|
||||||
|
/// Get a list of local transactions with statuses.
|
||||||
|
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus>;
|
||||||
|
|
||||||
/// Get a list of all pending receipts.
|
/// Get a list of all pending receipts.
|
||||||
fn pending_receipts(&self, best_block: BlockNumber) -> BTreeMap<H256, Receipt>;
|
fn pending_receipts(&self, best_block: BlockNumber) -> BTreeMap<H256, Receipt>;
|
||||||
|
|
||||||
|
@ -86,12 +86,13 @@ use std::ops::Deref;
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::cmp;
|
use std::cmp;
|
||||||
use std::collections::{HashSet, HashMap, BTreeSet, BTreeMap};
|
use std::collections::{HashSet, HashMap, BTreeSet, BTreeMap};
|
||||||
|
use linked_hash_map::LinkedHashMap;
|
||||||
use util::{Address, H256, Uint, U256};
|
use util::{Address, H256, Uint, U256};
|
||||||
use util::table::Table;
|
use util::table::Table;
|
||||||
use transaction::*;
|
use transaction::*;
|
||||||
use error::{Error, TransactionError};
|
use error::{Error, TransactionError};
|
||||||
use client::TransactionImportResult;
|
use client::TransactionImportResult;
|
||||||
use miner::local_transactions::LocalTransactionsList;
|
use miner::local_transactions::{LocalTransactionsList, Status as LocalTransactionStatus};
|
||||||
|
|
||||||
/// Transaction origin
|
/// Transaction origin
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
@ -901,6 +902,11 @@ impl TransactionQueue {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns local transactions (some of them might not be part of the queue anymore).
|
||||||
|
pub fn local_transactions(&self) -> &LinkedHashMap<H256, LocalTransactionStatus> {
|
||||||
|
self.local_transactions.all_transactions()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn future_transactions(&self) -> Vec<SignedTransaction> {
|
fn future_transactions(&self) -> Vec<SignedTransaction> {
|
||||||
self.future.by_priority
|
self.future.by_priority
|
||||||
|
@ -22,7 +22,7 @@ macro_rules! rpc_unimplemented {
|
|||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use rlp::DecoderError;
|
use rlp::DecoderError;
|
||||||
use ethcore::error::{Error as EthcoreError, CallError};
|
use ethcore::error::{Error as EthcoreError, CallError, TransactionError};
|
||||||
use ethcore::account_provider::{Error as AccountError};
|
use ethcore::account_provider::{Error as AccountError};
|
||||||
use fetch::FetchError;
|
use fetch::FetchError;
|
||||||
use jsonrpc_core::{Error, ErrorCode, Value};
|
use jsonrpc_core::{Error, ErrorCode, Value};
|
||||||
@ -227,40 +227,44 @@ pub fn from_password_error(error: AccountError) -> Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_transaction_error(error: EthcoreError) -> Error {
|
pub fn transaction_message(error: TransactionError) -> String {
|
||||||
use ethcore::error::TransactionError::*;
|
use ethcore::error::TransactionError::*;
|
||||||
|
|
||||||
|
match error {
|
||||||
|
AlreadyImported => "Transaction with the same hash was already imported.".into(),
|
||||||
|
Old => "Transaction nonce is too low. Try incrementing the nonce.".into(),
|
||||||
|
TooCheapToReplace => {
|
||||||
|
"Transaction gas price is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce.".into()
|
||||||
|
},
|
||||||
|
LimitReached => {
|
||||||
|
"There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into()
|
||||||
|
},
|
||||||
|
InsufficientGas { minimal, got } => {
|
||||||
|
format!("Transaction gas is too low. There is not enough gas to cover minimal cost of the transaction (minimal: {}, got: {}). Try increasing supplied gas.", minimal, got)
|
||||||
|
},
|
||||||
|
InsufficientGasPrice { minimal, got } => {
|
||||||
|
format!("Transaction gas price is too low. It does not satisfy your node's minimal gas price (minimal: {}, got: {}). Try increasing the gas price.", minimal, got)
|
||||||
|
},
|
||||||
|
InsufficientBalance { balance, cost } => {
|
||||||
|
format!("Insufficient funds. Account you try to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance)
|
||||||
|
},
|
||||||
|
GasLimitExceeded { limit, got } => {
|
||||||
|
format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got)
|
||||||
|
},
|
||||||
|
InvalidNetworkId => "Invalid network id.".into(),
|
||||||
|
InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(),
|
||||||
|
SenderBanned => "Sender is banned in local queue.".into(),
|
||||||
|
RecipientBanned => "Recipient is banned in local queue.".into(),
|
||||||
|
CodeBanned => "Code is banned in local queue.".into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_transaction_error(error: EthcoreError) -> Error {
|
||||||
|
|
||||||
if let EthcoreError::Transaction(e) = error {
|
if let EthcoreError::Transaction(e) = error {
|
||||||
let msg = match e {
|
|
||||||
AlreadyImported => "Transaction with the same hash was already imported.".into(),
|
|
||||||
Old => "Transaction nonce is too low. Try incrementing the nonce.".into(),
|
|
||||||
TooCheapToReplace => {
|
|
||||||
"Transaction gas price is too low. There is another transaction with same nonce in the queue. Try increasing the gas price or incrementing the nonce.".into()
|
|
||||||
},
|
|
||||||
LimitReached => {
|
|
||||||
"There are too many transactions in the queue. Your transaction was dropped due to limit. Try increasing the fee.".into()
|
|
||||||
},
|
|
||||||
InsufficientGas { minimal, got } => {
|
|
||||||
format!("Transaction gas is too low. There is not enough gas to cover minimal cost of the transaction (minimal: {}, got: {}). Try increasing supplied gas.", minimal, got)
|
|
||||||
},
|
|
||||||
InsufficientGasPrice { minimal, got } => {
|
|
||||||
format!("Transaction gas price is too low. It does not satisfy your node's minimal gas price (minimal: {}, got: {}). Try increasing the gas price.", minimal, got)
|
|
||||||
},
|
|
||||||
InsufficientBalance { balance, cost } => {
|
|
||||||
format!("Insufficient funds. Account you try to send transaction from does not have enough funds. Required {} and got: {}.", cost, balance)
|
|
||||||
},
|
|
||||||
GasLimitExceeded { limit, got } => {
|
|
||||||
format!("Transaction cost exceeds current gas limit. Limit: {}, got: {}. Try decreasing supplied gas.", limit, got)
|
|
||||||
},
|
|
||||||
InvalidGasLimit(_) => "Supplied gas is beyond limit.".into(),
|
|
||||||
SenderBanned => "Sender is banned in local queue.".into(),
|
|
||||||
RecipientBanned => "Recipient is banned in local queue.".into(),
|
|
||||||
CodeBanned => "Code is banned in local queue.".into(),
|
|
||||||
e => format!("{}", e).into(),
|
|
||||||
};
|
|
||||||
Error {
|
Error {
|
||||||
code: ErrorCode::ServerError(codes::TRANSACTION_ERROR),
|
code: ErrorCode::ServerError(codes::TRANSACTION_ERROR),
|
||||||
message: msg,
|
message: transaction_message(e),
|
||||||
data: None,
|
data: None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -34,7 +34,11 @@ use ethcore::account_provider::AccountProvider;
|
|||||||
|
|
||||||
use jsonrpc_core::Error;
|
use jsonrpc_core::Error;
|
||||||
use v1::traits::Parity;
|
use v1::traits::Parity;
|
||||||
use v1::types::{Bytes, U256, H160, H256, H512, Peers, Transaction, RpcSettings, Histogram, TransactionStats};
|
use v1::types::{
|
||||||
|
Bytes, U256, H160, H256, H512,
|
||||||
|
Peers, Transaction, RpcSettings, Histogram,
|
||||||
|
TransactionStats, LocalTransactionStatus,
|
||||||
|
};
|
||||||
use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings};
|
use v1::helpers::{errors, SigningQueue, SignerService, NetworkSettings};
|
||||||
use v1::helpers::dispatch::DEFAULT_MAC;
|
use v1::helpers::dispatch::DEFAULT_MAC;
|
||||||
|
|
||||||
@ -269,6 +273,17 @@ impl<C, M, S: ?Sized> Parity for ParityClient<C, M, S> where
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn local_transactions(&self) -> Result<BTreeMap<H256, LocalTransactionStatus>, Error> {
|
||||||
|
try!(self.active());
|
||||||
|
|
||||||
|
let transactions = take_weak!(self.miner).local_transactions();
|
||||||
|
Ok(transactions
|
||||||
|
.into_iter()
|
||||||
|
.map(|(hash, status)| (hash.into(), status.into()))
|
||||||
|
.collect()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn signer_port(&self) -> Result<u16, Error> {
|
fn signer_port(&self) -> Result<u16, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ use ethcore::block::{ClosedBlock, IsBlock};
|
|||||||
use ethcore::header::BlockNumber;
|
use ethcore::header::BlockNumber;
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::SignedTransaction;
|
||||||
use ethcore::receipt::{Receipt, RichReceipt};
|
use ethcore::receipt::{Receipt, RichReceipt};
|
||||||
use ethcore::miner::{MinerService, MinerStatus, TransactionImportResult};
|
use ethcore::miner::{MinerService, MinerStatus, TransactionImportResult, LocalTransactionStatus};
|
||||||
|
|
||||||
/// Test miner service.
|
/// Test miner service.
|
||||||
pub struct TestMinerService {
|
pub struct TestMinerService {
|
||||||
@ -34,6 +34,8 @@ pub struct TestMinerService {
|
|||||||
pub latest_closed_block: Mutex<Option<ClosedBlock>>,
|
pub latest_closed_block: Mutex<Option<ClosedBlock>>,
|
||||||
/// Pre-existed pending transactions
|
/// Pre-existed pending transactions
|
||||||
pub pending_transactions: Mutex<HashMap<H256, SignedTransaction>>,
|
pub pending_transactions: Mutex<HashMap<H256, SignedTransaction>>,
|
||||||
|
/// Pre-existed local transactions
|
||||||
|
pub local_transactions: Mutex<BTreeMap<H256, LocalTransactionStatus>>,
|
||||||
/// Pre-existed pending receipts
|
/// Pre-existed pending receipts
|
||||||
pub pending_receipts: Mutex<BTreeMap<H256, Receipt>>,
|
pub pending_receipts: Mutex<BTreeMap<H256, Receipt>>,
|
||||||
/// Last nonces.
|
/// Last nonces.
|
||||||
@ -53,6 +55,7 @@ impl Default for TestMinerService {
|
|||||||
imported_transactions: Mutex::new(Vec::new()),
|
imported_transactions: Mutex::new(Vec::new()),
|
||||||
latest_closed_block: Mutex::new(None),
|
latest_closed_block: Mutex::new(None),
|
||||||
pending_transactions: Mutex::new(HashMap::new()),
|
pending_transactions: Mutex::new(HashMap::new()),
|
||||||
|
local_transactions: Mutex::new(BTreeMap::new()),
|
||||||
pending_receipts: Mutex::new(BTreeMap::new()),
|
pending_receipts: Mutex::new(BTreeMap::new()),
|
||||||
last_nonces: RwLock::new(HashMap::new()),
|
last_nonces: RwLock::new(HashMap::new()),
|
||||||
min_gas_price: RwLock::new(U256::from(20_000_000)),
|
min_gas_price: RwLock::new(U256::from(20_000_000)),
|
||||||
@ -195,6 +198,10 @@ impl MinerService for TestMinerService {
|
|||||||
self.pending_transactions.lock().values().cloned().collect()
|
self.pending_transactions.lock().values().cloned().collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn local_transactions(&self) -> BTreeMap<H256, LocalTransactionStatus> {
|
||||||
|
self.local_transactions.lock().iter().map(|(hash, stats)| (*hash, stats.clone())).collect()
|
||||||
|
}
|
||||||
|
|
||||||
fn pending_transactions(&self, _best_block: BlockNumber) -> Vec<SignedTransaction> {
|
fn pending_transactions(&self, _best_block: BlockNumber) -> Vec<SignedTransaction> {
|
||||||
self.pending_transactions.lock().values().cloned().collect()
|
self.pending_transactions.lock().values().cloned().collect()
|
||||||
}
|
}
|
||||||
|
@ -18,8 +18,9 @@ use std::sync::Arc;
|
|||||||
use util::log::RotatingLogger;
|
use util::log::RotatingLogger;
|
||||||
use util::Address;
|
use util::Address;
|
||||||
use ethsync::ManageNetwork;
|
use ethsync::ManageNetwork;
|
||||||
use ethcore::client::{TestBlockChainClient};
|
|
||||||
use ethcore::account_provider::AccountProvider;
|
use ethcore::account_provider::AccountProvider;
|
||||||
|
use ethcore::client::{TestBlockChainClient};
|
||||||
|
use ethcore::miner::LocalTransactionStatus;
|
||||||
use ethstore::ethkey::{Generator, Random};
|
use ethstore::ethkey::{Generator, Random};
|
||||||
|
|
||||||
use jsonrpc_core::IoHandler;
|
use jsonrpc_core::IoHandler;
|
||||||
@ -367,3 +368,16 @@ fn rpc_parity_transactions_stats() {
|
|||||||
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
|
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rpc_parity_local_transactions() {
|
||||||
|
let deps = Dependencies::new();
|
||||||
|
let io = deps.default_client();
|
||||||
|
deps.miner.local_transactions.lock().insert(10.into(), LocalTransactionStatus::Pending);
|
||||||
|
deps.miner.local_transactions.lock().insert(15.into(), LocalTransactionStatus::Future);
|
||||||
|
|
||||||
|
let request = r#"{"jsonrpc": "2.0", "method": "parity_localTransactions", "params":[], "id": 1}"#;
|
||||||
|
let response = r#"{"jsonrpc":"2.0","result":{"0x000000000000000000000000000000000000000000000000000000000000000a":{"status":"pending"},"0x000000000000000000000000000000000000000000000000000000000000000f":{"status":"future"}},"id":1}"#;
|
||||||
|
|
||||||
|
assert_eq!(io.handle_request_sync(request), Some(response.to_owned()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,11 @@ use jsonrpc_core::Error;
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use v1::helpers::auto_args::Wrap;
|
use v1::helpers::auto_args::Wrap;
|
||||||
use v1::types::{H160, H256, H512, U256, Bytes, Peers, Transaction, RpcSettings, Histogram, TransactionStats};
|
use v1::types::{
|
||||||
|
H160, H256, H512, U256, Bytes,
|
||||||
|
Peers, Transaction, RpcSettings, Histogram,
|
||||||
|
TransactionStats, LocalTransactionStatus,
|
||||||
|
};
|
||||||
|
|
||||||
build_rpc_trait! {
|
build_rpc_trait! {
|
||||||
/// Parity-specific rpc interface.
|
/// Parity-specific rpc interface.
|
||||||
@ -119,6 +123,10 @@ build_rpc_trait! {
|
|||||||
#[rpc(name = "parity_pendingTransactionsStats")]
|
#[rpc(name = "parity_pendingTransactionsStats")]
|
||||||
fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>, Error>;
|
fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>, Error>;
|
||||||
|
|
||||||
|
/// Returns a list of current and past local transactions with status details.
|
||||||
|
#[rpc(name = "parity_localTransactions")]
|
||||||
|
fn local_transactions(&self) -> Result<BTreeMap<H256, LocalTransactionStatus>, Error>;
|
||||||
|
|
||||||
/// Returns current Trusted Signer port or an error if signer is disabled.
|
/// Returns current Trusted Signer port or an error if signer is disabled.
|
||||||
#[rpc(name = "parity_signerPort")]
|
#[rpc(name = "parity_signerPort")]
|
||||||
fn signer_port(&self) -> Result<u16, Error>;
|
fn signer_port(&self) -> Result<u16, Error>;
|
||||||
|
@ -44,7 +44,7 @@ pub use self::hash::{H64, H160, H256, H512, H520, H2048};
|
|||||||
pub use self::index::Index;
|
pub use self::index::Index;
|
||||||
pub use self::log::Log;
|
pub use self::log::Log;
|
||||||
pub use self::sync::{SyncStatus, SyncInfo, Peers, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo, PeerEthereumProtocolInfo, TransactionStats};
|
pub use self::sync::{SyncStatus, SyncInfo, Peers, PeerInfo, PeerNetworkInfo, PeerProtocolsInfo, PeerEthereumProtocolInfo, TransactionStats};
|
||||||
pub use self::transaction::Transaction;
|
pub use self::transaction::{Transaction, LocalTransactionStatus};
|
||||||
pub use self::transaction_request::TransactionRequest;
|
pub use self::transaction_request::TransactionRequest;
|
||||||
pub use self::receipt::Receipt;
|
pub use self::receipt::Receipt;
|
||||||
pub use self::rpc_settings::RpcSettings;
|
pub use self::rpc_settings::RpcSettings;
|
||||||
|
@ -14,8 +14,11 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
use serde::{Serialize, Serializer};
|
||||||
|
use ethcore::miner;
|
||||||
use ethcore::contract_address;
|
use ethcore::contract_address;
|
||||||
use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction};
|
use ethcore::transaction::{LocalizedTransaction, Action, SignedTransaction};
|
||||||
|
use v1::helpers::errors;
|
||||||
use v1::types::{Bytes, H160, H256, U256, H512};
|
use v1::types::{Bytes, H160, H256, U256, H512};
|
||||||
|
|
||||||
/// Transaction
|
/// Transaction
|
||||||
@ -62,6 +65,74 @@ pub struct Transaction {
|
|||||||
pub s: H256,
|
pub s: H256,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Local Transaction Status
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum LocalTransactionStatus {
|
||||||
|
/// Transaction is pending
|
||||||
|
Pending,
|
||||||
|
/// Transaction is in future part of the queue
|
||||||
|
Future,
|
||||||
|
/// Transaction is already mined.
|
||||||
|
Mined(Transaction),
|
||||||
|
/// Transaction was dropped because of limit.
|
||||||
|
Dropped(Transaction),
|
||||||
|
/// Transaction was replaced by transaction with higher gas price.
|
||||||
|
Replaced(Transaction, U256, H256),
|
||||||
|
/// Transaction never got into the queue.
|
||||||
|
Rejected(Transaction, String),
|
||||||
|
/// Transaction is invalid.
|
||||||
|
Invalid(Transaction),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Serialize for LocalTransactionStatus {
|
||||||
|
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
|
||||||
|
where S: Serializer
|
||||||
|
{
|
||||||
|
use self::LocalTransactionStatus::*;
|
||||||
|
|
||||||
|
let elems = match *self {
|
||||||
|
Pending | Future => 1,
|
||||||
|
Mined(..) | Dropped(..) | Invalid(..) => 2,
|
||||||
|
Rejected(..) => 3,
|
||||||
|
Replaced(..) => 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
let status = "status";
|
||||||
|
let transaction = "transaction";
|
||||||
|
|
||||||
|
let mut state = try!(serializer.serialize_struct("LocalTransactionStatus", elems));
|
||||||
|
match *self {
|
||||||
|
Pending => try!(serializer.serialize_struct_elt(&mut state, status, "pending")),
|
||||||
|
Future => try!(serializer.serialize_struct_elt(&mut state, status, "future")),
|
||||||
|
Mined(ref tx) => {
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, status, "mined"));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, transaction, tx));
|
||||||
|
},
|
||||||
|
Dropped(ref tx) => {
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, status, "dropped"));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, transaction, tx));
|
||||||
|
},
|
||||||
|
Invalid(ref tx) => {
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, status, "invalid"));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, transaction, tx));
|
||||||
|
},
|
||||||
|
Rejected(ref tx, ref reason) => {
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, status, "rejected"));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, transaction, tx));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "error", reason));
|
||||||
|
},
|
||||||
|
Replaced(ref tx, ref gas_price, ref hash) => {
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, status, "replaced"));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, transaction, tx));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "hash", hash));
|
||||||
|
try!(serializer.serialize_struct_elt(&mut state, "gasPrice", gas_price));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
serializer.serialize_struct_end(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
impl From<LocalizedTransaction> for Transaction {
|
impl From<LocalizedTransaction> for Transaction {
|
||||||
fn from(t: LocalizedTransaction) -> Transaction {
|
fn from(t: LocalizedTransaction) -> Transaction {
|
||||||
let signature = t.signature();
|
let signature = t.signature();
|
||||||
@ -124,9 +195,24 @@ impl From<SignedTransaction> for Transaction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<miner::LocalTransactionStatus> for LocalTransactionStatus {
|
||||||
|
fn from(s: miner::LocalTransactionStatus) -> Self {
|
||||||
|
use ethcore::miner::LocalTransactionStatus::*;
|
||||||
|
match s {
|
||||||
|
Pending => LocalTransactionStatus::Pending,
|
||||||
|
Future => LocalTransactionStatus::Future,
|
||||||
|
Mined(tx) => LocalTransactionStatus::Mined(tx.into()),
|
||||||
|
Dropped(tx) => LocalTransactionStatus::Dropped(tx.into()),
|
||||||
|
Rejected(tx, err) => LocalTransactionStatus::Rejected(tx.into(), errors::transaction_message(err)),
|
||||||
|
Replaced(tx, gas_price, hash) => LocalTransactionStatus::Replaced(tx.into(), gas_price.into(), hash.into()),
|
||||||
|
Invalid(tx) => LocalTransactionStatus::Invalid(tx.into()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::Transaction;
|
use super::{Transaction, LocalTransactionStatus};
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -135,5 +221,50 @@ mod tests {
|
|||||||
let serialized = serde_json::to_string(&t).unwrap();
|
let serialized = serde_json::to_string(&t).unwrap();
|
||||||
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"v":0,"r":"0x0000000000000000000000000000000000000000000000000000000000000000","s":"0x0000000000000000000000000000000000000000000000000000000000000000"}"#);
|
assert_eq!(serialized, r#"{"hash":"0x0000000000000000000000000000000000000000000000000000000000000000","nonce":"0x0","blockHash":null,"blockNumber":null,"transactionIndex":null,"from":"0x0000000000000000000000000000000000000000","to":null,"value":"0x0","gasPrice":"0x0","gas":"0x0","input":"0x","creates":null,"raw":"0x","publicKey":null,"v":0,"r":"0x0000000000000000000000000000000000000000000000000000000000000000","s":"0x0000000000000000000000000000000000000000000000000000000000000000"}"#);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_local_transaction_status_serialize() {
|
||||||
|
let tx_ser = serde_json::to_string(&Transaction::default()).unwrap();
|
||||||
|
let status1 = LocalTransactionStatus::Pending;
|
||||||
|
let status2 = LocalTransactionStatus::Future;
|
||||||
|
let status3 = LocalTransactionStatus::Mined(Transaction::default());
|
||||||
|
let status4 = LocalTransactionStatus::Dropped(Transaction::default());
|
||||||
|
let status5 = LocalTransactionStatus::Invalid(Transaction::default());
|
||||||
|
let status6 = LocalTransactionStatus::Rejected(Transaction::default(), "Just because".into());
|
||||||
|
let status7 = LocalTransactionStatus::Replaced(Transaction::default(), 5.into(), 10.into());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::to_string(&status1).unwrap(),
|
||||||
|
r#"{"status":"pending"}"#
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::to_string(&status2).unwrap(),
|
||||||
|
r#"{"status":"future"}"#
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::to_string(&status3).unwrap(),
|
||||||
|
r#"{"status":"mined","transaction":"#.to_owned() + &format!("{}", tx_ser) + r#"}"#
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::to_string(&status4).unwrap(),
|
||||||
|
r#"{"status":"dropped","transaction":"#.to_owned() + &format!("{}", tx_ser) + r#"}"#
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::to_string(&status5).unwrap(),
|
||||||
|
r#"{"status":"invalid","transaction":"#.to_owned() + &format!("{}", tx_ser) + r#"}"#
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::to_string(&status6).unwrap(),
|
||||||
|
r#"{"status":"rejected","transaction":"#.to_owned() +
|
||||||
|
&format!("{}", tx_ser) +
|
||||||
|
r#","error":"Just because"}"#
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
serde_json::to_string(&status7).unwrap(),
|
||||||
|
r#"{"status":"replaced","transaction":"#.to_owned() +
|
||||||
|
&format!("{}", tx_ser) +
|
||||||
|
r#","hash":"0x000000000000000000000000000000000000000000000000000000000000000a","gasPrice":"0x5"}"#
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user