implement send_raw_transaction
This commit is contained in:
parent
baf0dbc6bf
commit
a559dfe9a1
@ -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]
|
||||||
|
@ -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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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> {
|
||||||
|
Loading…
Reference in New Issue
Block a user