implement send_raw_transaction

This commit is contained in:
Robert Habermeier 2017-02-09 19:17:37 +01:00
parent baf0dbc6bf
commit a559dfe9a1
3 changed files with 65 additions and 17 deletions

View File

@ -55,6 +55,7 @@ pub mod remote {
mod types; mod types;
pub use self::provider::Provider; pub use self::provider::Provider;
pub use self::transaction_queue::TransactionQueue;
pub use types::les_request as request; pub use types::les_request as request;
#[macro_use] #[macro_use]

View File

@ -26,7 +26,9 @@
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use std::collections::hash_map::Entry; use std::collections::hash_map::Entry;
use ethcore::error::TransactionError;
use ethcore::transaction::{Condition, PendingTransaction, SignedTransaction}; use ethcore::transaction::{Condition, PendingTransaction, SignedTransaction};
use ethcore::transaction_import::TransactionImportResult;
use util::{Address, U256, H256, H256FastMap}; use util::{Address, U256, H256, H256FastMap};
// Knowledge of an account's current nonce. // Knowledge of an account's current nonce.
@ -103,25 +105,29 @@ pub struct TransactionQueue {
} }
impl TransactionQueue { impl TransactionQueue {
/// Insert a pending transaction to be queued. /// Import a pending transaction to be queued.
pub fn insert(&mut self, tx: PendingTransaction) { pub fn import(&mut self, tx: PendingTransaction) -> Result<TransactionImportResult, TransactionError> {
let sender = tx.sender(); let sender = tx.sender();
let hash = tx.hash(); let hash = tx.hash();
let nonce = tx.nonce; let nonce = tx.nonce;
match self.by_account.entry(sender) { let res = match self.by_account.entry(sender) {
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
entry.insert(AccountTransactions { entry.insert(AccountTransactions {
cur_nonce: CurrentNonce::Assumed(nonce), cur_nonce: CurrentNonce::Assumed(nonce),
current: vec![tx.clone()], current: vec![tx.clone()],
future: BTreeMap::new(), future: BTreeMap::new(),
}); });
TransactionImportResult::Current
} }
Entry::Occupied(mut entry) => { Entry::Occupied(mut entry) => {
let acct_txs = entry.get_mut(); let acct_txs = entry.get_mut();
if &nonce < acct_txs.cur_nonce.value() { if &nonce < acct_txs.cur_nonce.value() {
// don't accept txs from before known current nonce. // don't accept txs from before known current nonce.
if acct_txs.cur_nonce.is_known() { return } if acct_txs.cur_nonce.is_known() {
return Err(TransactionError::Old)
}
// lower our assumption until corrected later. // lower our assumption until corrected later.
acct_txs.cur_nonce = CurrentNonce::Assumed(nonce); acct_txs.cur_nonce = CurrentNonce::Assumed(nonce);
@ -133,6 +139,8 @@ impl TransactionQueue {
sender, nonce); sender, nonce);
acct_txs.current[idx] = tx.clone(); acct_txs.current[idx] = tx.clone();
TransactionImportResult::Current
} }
Err(idx) => { Err(idx) => {
let cur_len = acct_txs.current.len(); let cur_len = acct_txs.current.len();
@ -153,23 +161,30 @@ impl TransactionQueue {
let future_nonce = future.nonce; let future_nonce = future.nonce;
acct_txs.future.insert(future_nonce, future); acct_txs.future.insert(future_nonce, future);
} }
TransactionImportResult::Current
} else if idx == cur_len && acct_txs.current.last().map_or(false, |f| f.nonce + 1.into() != nonce) { } else if idx == cur_len && acct_txs.current.last().map_or(false, |f| f.nonce + 1.into() != nonce) {
trace!(target: "txqueue", "Queued future transaction for {}, nonce={}", sender, nonce); trace!(target: "txqueue", "Queued future transaction for {}, nonce={}", sender, nonce);
let future_nonce = nonce; let future_nonce = nonce;
acct_txs.future.insert(future_nonce, tx.clone()); acct_txs.future.insert(future_nonce, tx.clone());
TransactionImportResult::Future
} else { } else {
trace!(target: "txqueue", "Queued current transaction for {}, nonce={}", sender, nonce); trace!(target: "txqueue", "Queued current transaction for {}, nonce={}", sender, nonce);
// insert, then check if we've filled any gaps. // insert, then check if we've filled any gaps.
acct_txs.current.insert(idx, tx.clone()); acct_txs.current.insert(idx, tx.clone());
acct_txs.adjust_future(); acct_txs.adjust_future();
TransactionImportResult::Current
} }
} }
} }
} }
} };
self.by_hash.insert(hash, tx); self.by_hash.insert(hash, tx);
Ok(res)
} }
/// Get pending transaction by hash. /// Get pending transaction by hash.
@ -261,7 +276,7 @@ mod tests {
let mut txq = TransactionQueue::default(); let mut txq = TransactionQueue::default();
let tx = Transaction::default().fake_sign(sender); let tx = Transaction::default().fake_sign(sender);
txq.insert(tx.into()); txq.import(tx.into()).unwrap();
assert_eq!(txq.queued_senders(), vec![sender]); assert_eq!(txq.queued_senders(), vec![sender]);
@ -282,7 +297,7 @@ mod tests {
let tx = tx.fake_sign(sender); let tx = tx.fake_sign(sender);
txq.insert(tx.into()); txq.import(tx.into()).unwrap();
} }
// current: 0..5, future: 10..15 // current: 0..5, future: 10..15
@ -313,7 +328,7 @@ mod tests {
let tx = tx.fake_sign(sender); let tx = tx.fake_sign(sender);
txq.insert(tx.into()); txq.import(tx.into()).unwrap();
} }
assert_eq!(txq.ready_transactions(0, 0).len(), 5); assert_eq!(txq.ready_transactions(0, 0).len(), 5);
@ -325,7 +340,7 @@ mod tests {
let tx = tx.fake_sign(sender); let tx = tx.fake_sign(sender);
txq.insert(tx.into()); txq.import(tx.into()).unwrap();
} }
assert_eq!(txq.ready_transactions(0, 0).len(), 3); assert_eq!(txq.ready_transactions(0, 0).len(), 3);
@ -337,7 +352,7 @@ mod tests {
let tx = tx.fake_sign(sender); let tx = tx.fake_sign(sender);
txq.insert(tx.into()); txq.import(tx.into()).unwrap();
} }
assert_eq!(txq.ready_transactions(0, 0).len(), 10); assert_eq!(txq.ready_transactions(0, 0).len(), 10);
@ -354,11 +369,11 @@ mod tests {
tx.nonce = i.into(); tx.nonce = i.into();
let tx = tx.fake_sign(sender); let tx = tx.fake_sign(sender);
txq.insert(match i { txq.import(match i {
3 => PendingTransaction::new(tx, Some(Condition::Number(100))), 3 => PendingTransaction::new(tx, Some(Condition::Number(100))),
4 => PendingTransaction::new(tx, Some(Condition::Timestamp(1234))), 4 => PendingTransaction::new(tx, Some(Condition::Timestamp(1234))),
_ => tx.into(), _ => tx.into(),
}); }).unwrap();
} }
assert_eq!(txq.ready_transactions(0, 0).len(), 3); assert_eq!(txq.ready_transactions(0, 0).len(), 3);
@ -378,7 +393,7 @@ mod tests {
let tx = tx.fake_sign(sender); let tx = tx.fake_sign(sender);
txq.insert(tx.into()); txq.import(tx.into()).unwrap();
} }
txq.cull(sender, 6.into()); txq.cull(sender, 6.into());
@ -386,4 +401,21 @@ mod tests {
assert_eq!(txq.ready_transactions(0, 0).len(), 4); assert_eq!(txq.ready_transactions(0, 0).len(), 4);
assert_eq!(txq.next_nonce(&sender).unwrap(), 10.into()); assert_eq!(txq.next_nonce(&sender).unwrap(), 10.into());
} }
#[test]
fn import_old() {
let sender = Address::default();
let mut txq = TransactionQueue::default();
let mut tx_a = Transaction::default();
tx_a.nonce = 3.into();
let mut tx_b = Transaction::default();
tx_b.nonce = 2.into();
txq.import(tx_a.fake_sign(sender).into()).unwrap();
txq.cull(sender, 3.into());
assert!(txq.import(tx_b.fake_sign(sender).into()).is_err())
}
} }

View File

@ -25,16 +25,18 @@ use jsonrpc_core::Error;
use jsonrpc_macros::Trailing; use jsonrpc_macros::Trailing;
use light::client::Client as LightClient; use light::client::Client as LightClient;
use light::cht; use light::{cht, TransactionQueue};
use light::on_demand::{request, OnDemand}; use light::on_demand::{request, OnDemand};
use ethcore::account_provider::{AccountProvider, DappId}; use ethcore::account_provider::{AccountProvider, DappId};
use ethcore::basic_account::BasicAccount; use ethcore::basic_account::BasicAccount;
use ethcore::encoded; use ethcore::encoded;
use ethcore::ids::BlockId; use ethcore::ids::BlockId;
use ethcore::transaction::SignedTransaction;
use ethsync::LightSync; use ethsync::LightSync;
use rlp::{UntrustedRlp, View};
use util::sha3::{SHA3_NULL_RLP, SHA3_EMPTY_LIST_RLP}; use util::sha3::{SHA3_NULL_RLP, SHA3_EMPTY_LIST_RLP};
use util::U256; use util::{RwLock, U256};
use futures::{future, Future, BoxFuture}; use futures::{future, Future, BoxFuture};
use futures::sync::oneshot; use futures::sync::oneshot;
@ -56,6 +58,7 @@ pub struct EthClient {
sync: Arc<LightSync>, sync: Arc<LightSync>,
client: Arc<LightClient>, client: Arc<LightClient>,
on_demand: Arc<OnDemand>, on_demand: Arc<OnDemand>,
transaction_queue: Arc<RwLock<TransactionQueue>>,
accounts: Arc<AccountProvider>, accounts: Arc<AccountProvider>,
} }
@ -76,12 +79,14 @@ impl EthClient {
sync: Arc<LightSync>, sync: Arc<LightSync>,
client: Arc<LightClient>, client: Arc<LightClient>,
on_demand: Arc<OnDemand>, on_demand: Arc<OnDemand>,
transaction_queue: Arc<RwLock<TransactionQueue>>,
accounts: Arc<AccountProvider>, accounts: Arc<AccountProvider>,
) -> Self { ) -> Self {
EthClient { EthClient {
sync: sync, sync: sync,
client: client, client: client,
on_demand: on_demand, on_demand: on_demand,
transaction_queue: transaction_queue,
accounts: accounts, accounts: accounts,
} }
} }
@ -300,11 +305,21 @@ impl Eth for EthClient {
} }
fn send_raw_transaction(&self, raw: Bytes) -> Result<RpcH256, Error> { fn send_raw_transaction(&self, raw: Bytes) -> Result<RpcH256, Error> {
Err(errors::unimplemented(None)) UntrustedRlp::new(&raw.into_vec()).as_val()
.map_err(errors::from_rlp_error)
.and_then(|tx| SignedTransaction::new(tx).map_err(errors::from_transaction_error))
.and_then(|signed| {
let hash = signed.hash();
self.transaction_queue.write().import(signed.into())
.map(|_| hash)
.map_err(Into::into)
.map_err(errors::from_transaction_error)
})
.map(Into::into)
} }
fn submit_transaction(&self, raw: Bytes) -> Result<RpcH256, Error> { fn submit_transaction(&self, raw: Bytes) -> Result<RpcH256, Error> {
Err(errors::unimplemented(None)) self.send_raw_transaction(raw)
} }
fn call(&self, req: CallRequest, num: Trailing<BlockNumber>) -> Result<Bytes, Error> { fn call(&self, req: CallRequest, num: Trailing<BlockNumber>) -> Result<Bytes, Error> {