Merge pull request #211 from ethcore/sync_serve_transactions
Serve transactions requests
This commit is contained in:
commit
d273048d08
|
@ -333,6 +333,10 @@ impl Storage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_by_hash(&self, h: &H256) -> Option<&Transaction> {
|
||||||
|
self.by_hash.get(h).map(|e| &e.transaction)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn read_with_strategy(&self, strategy: OrderingStrategy) -> Option<H256> {
|
pub fn read_with_strategy(&self, strategy: OrderingStrategy) -> Option<H256> {
|
||||||
match strategy {
|
match strategy {
|
||||||
OrderingStrategy::ByTimestamp => self.references.ordered.by_storage_index.iter().map(|entry| entry.hash.clone()).nth(0),
|
OrderingStrategy::ByTimestamp => self.references.ordered.by_storage_index.iter().map(|entry| entry.hash.clone()).nth(0),
|
||||||
|
@ -575,6 +579,11 @@ impl MemoryPool {
|
||||||
self.storage.remove_by_hash(h).map(|entry| entry.transaction)
|
self.storage.remove_by_hash(h).map(|entry| entry.transaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads single transaction by its hash.
|
||||||
|
pub fn read_by_hash(&self, h: &H256) -> Option<&Transaction> {
|
||||||
|
self.storage.read_by_hash(h)
|
||||||
|
}
|
||||||
|
|
||||||
/// Reads hash of the 'top' transaction from the `MemoryPool` using selected strategy.
|
/// Reads hash of the 'top' transaction from the `MemoryPool` using selected strategy.
|
||||||
/// Ancestors are always returned before descendant transactions.
|
/// Ancestors are always returned before descendant transactions.
|
||||||
pub fn read_with_strategy(&mut self, strategy: OrderingStrategy) -> Option<H256> {
|
pub fn read_with_strategy(&mut self, strategy: OrderingStrategy) -> Option<H256> {
|
||||||
|
|
|
@ -610,6 +610,12 @@ impl Chain {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get transaction by hash (if it's in memory pool or verifying)
|
||||||
|
pub fn transaction_by_hash(&self, hash: &H256) -> Option<Transaction> {
|
||||||
|
self.verifying_transactions.get(hash).cloned()
|
||||||
|
.or_else(|| self.memory_pool.read_by_hash(hash).cloned())
|
||||||
|
}
|
||||||
|
|
||||||
/// Insert transaction to memory pool
|
/// Insert transaction to memory pool
|
||||||
pub fn insert_verified_transaction(&mut self, transaction: Transaction) {
|
pub fn insert_verified_transaction(&mut self, transaction: Transaction) {
|
||||||
self.memory_pool.insert_verified(transaction);
|
self.memory_pool.insert_verified(transaction);
|
||||||
|
|
|
@ -189,6 +189,15 @@ impl SynchronizationServer {
|
||||||
None => unknown_items.push(item),
|
None => unknown_items.push(item),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
InventoryType::MessageTx => {
|
||||||
|
match chain.transaction_by_hash(&item.hash) {
|
||||||
|
Some(transaction) => {
|
||||||
|
let task = IndexedServerTask::new(ServerTask::ReturnTransaction(transaction), ServerTaskIndex::None);
|
||||||
|
new_tasks.push(task);
|
||||||
|
},
|
||||||
|
None => unknown_items.push(item),
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => (), // TODO: process other inventory types
|
_ => (), // TODO: process other inventory types
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -758,4 +767,61 @@ pub mod tests {
|
||||||
let tasks = DummyTaskExecutor::wait_tasks(executor);
|
let tasks = DummyTaskExecutor::wait_tasks(executor);
|
||||||
assert_eq!(tasks, vec![]);
|
assert_eq!(tasks, vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn server_getdata_responds_notfound_when_transaction_is_inaccessible() {
|
||||||
|
let (_, executor, server) = create_synchronization_server();
|
||||||
|
// when asking for unknown transaction or transaction that is already in the storage
|
||||||
|
let inventory = vec![
|
||||||
|
InventoryVector {
|
||||||
|
inv_type: InventoryType::MessageTx,
|
||||||
|
hash: H256::default(),
|
||||||
|
},
|
||||||
|
InventoryVector {
|
||||||
|
inv_type: InventoryType::MessageTx,
|
||||||
|
hash: test_data::genesis().transactions[0].hash(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
server.serve_getdata(0, FilteredInventory::with_unfiltered(inventory.clone())).map(|t| server.add_task(0, t));
|
||||||
|
// => respond with notfound
|
||||||
|
let tasks = DummyTaskExecutor::wait_tasks(executor);
|
||||||
|
assert_eq!(tasks, vec![Task::SendNotFound(0, inventory, ServerTaskIndex::None)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn server_getdata_responds_transaction_when_transaction_is_in_memory() {
|
||||||
|
let (chain, executor, server) = create_synchronization_server();
|
||||||
|
let tx_verifying: Transaction = test_data::TransactionBuilder::with_output(10).into();
|
||||||
|
let tx_verifying_hash = tx_verifying.hash();
|
||||||
|
let tx_verified: Transaction = test_data::TransactionBuilder::with_output(20).into();
|
||||||
|
let tx_verified_hash = tx_verified.hash();
|
||||||
|
// given in-memory transaction
|
||||||
|
{
|
||||||
|
let mut chain = chain.write();
|
||||||
|
chain.verify_transaction(tx_verifying_hash.clone(), tx_verifying.clone());
|
||||||
|
chain.insert_verified_transaction(tx_verified.clone());
|
||||||
|
}
|
||||||
|
// when asking for known in-memory transaction
|
||||||
|
let inventory = vec![
|
||||||
|
InventoryVector {
|
||||||
|
inv_type: InventoryType::MessageTx,
|
||||||
|
hash: tx_verifying_hash,
|
||||||
|
},
|
||||||
|
InventoryVector {
|
||||||
|
inv_type: InventoryType::MessageTx,
|
||||||
|
hash: tx_verified_hash,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
server.serve_getdata(0, FilteredInventory::with_unfiltered(inventory)).map(|t| server.add_task(0, t));
|
||||||
|
// => respond with transaction
|
||||||
|
let mut tasks = DummyTaskExecutor::wait_tasks(executor.clone());
|
||||||
|
// 2 tasks => can be situation when single task is ready
|
||||||
|
if tasks.len() != 2 {
|
||||||
|
tasks.extend(DummyTaskExecutor::wait_tasks_for(executor, 100));
|
||||||
|
}
|
||||||
|
assert_eq!(tasks, vec![
|
||||||
|
Task::SendTransaction(0, tx_verifying),
|
||||||
|
Task::SendTransaction(0, tx_verified),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue