Limit for logs filter. (#2180)

* Limit for logs filter.

* Moving limit inside the filter object

* Fixing tests
This commit is contained in:
Tomasz Drwięga
2016-09-21 12:51:10 +02:00
committed by Gav Wood
parent 2e6684dae8
commit 8c111da70b
11 changed files with 147 additions and 47 deletions

View File

@@ -26,7 +26,7 @@ mod signing_queue;
mod network_settings;
pub use self::poll_manager::PollManager;
pub use self::poll_filter::PollFilter;
pub use self::poll_filter::{PollFilter, limit_logs};
pub use self::requests::{TransactionRequest, FilledTransactionRequest, ConfirmationRequest, ConfirmationPayload, CallRequest};
pub use self::signing_queue::{ConfirmationsQueue, ConfirmationPromise, ConfirmationResult, SigningQueue, QueueEvent};
pub use self::signer::SignerService;

View File

@@ -13,6 +13,15 @@ pub enum PollFilter {
Block(BlockNumber),
/// Hashes of all transactions which client was notified about.
PendingTransaction(Vec<H256>),
/// Number of From block number, pending logs and log filter iself.
/// Number of From block number, pending logs and log filter itself.
Logs(BlockNumber, HashSet<Log>, Filter)
}
/// Returns only last `n` logs
pub fn limit_logs(mut logs: Vec<Log>, limit: Option<usize>) -> Vec<Log> {
let len = logs.len();
match limit {
Some(limit) if len >= limit => logs.split_off(len - limit),
_ => logs,
}
}

View File

@@ -43,7 +43,7 @@ use ethcore::filter::Filter as EthcoreFilter;
use self::ethash::SeedHashCompute;
use v1::traits::Eth;
use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, CallRequest, Index, Filter, Log, Receipt, H64 as RpcH64, H256 as RpcH256, H160 as RpcH160, U256 as RpcU256};
use v1::helpers::{CallRequest as CRequest, errors};
use v1::helpers::{CallRequest as CRequest, errors, limit_logs};
use v1::helpers::dispatch::{default_gas_price, dispatch_transaction};
use v1::helpers::params::{expect_no_params, params_len, from_params_default_second, from_params_default_third};
@@ -498,14 +498,10 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
fn logs(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
let params = match params_len(&params) {
1 => from_params::<(Filter, )>(params).map(|(filter, )| (filter, None)),
_ => from_params::<(Filter, usize)>(params).map(|(filter, val)| (filter, Some(val))),
};
params.and_then(|(filter, limit)| {
from_params::<(Filter, )>(params).and_then(|(filter,)| {
let include_pending = filter.to_block == Some(BlockNumber::Pending);
let filter: EthcoreFilter = filter.into();
let mut logs = take_weak!(self.client).logs(filter.clone(), limit)
let mut logs = take_weak!(self.client).logs(filter.clone())
.into_iter()
.map(From::from)
.collect::<Vec<Log>>();
@@ -515,14 +511,7 @@ impl<C, S: ?Sized, M, EM> Eth for EthClient<C, S, M, EM> where
logs.extend(pending);
}
let len = logs.len();
match limit {
Some(limit) if len >= limit => {
logs = logs.split_off(len - limit);
},
_ => {},
}
let logs = limit_logs(logs, filter.limit);
Ok(to_value(&logs))
})
}

View File

@@ -25,8 +25,8 @@ use ethcore::client::{BlockChainClient, BlockID};
use util::Mutex;
use v1::traits::EthFilter;
use v1::types::{BlockNumber, Index, Filter, Log, H256 as RpcH256, U256 as RpcU256};
use v1::helpers::{PollFilter, PollManager};
use v1::helpers::params::expect_no_params;
use v1::helpers::{PollFilter, PollManager, limit_logs};
use v1::helpers::params::{expect_no_params, params_len};
use v1::impls::eth::pending_logs;
/// Eth filter rpc implementation.
@@ -65,8 +65,8 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
fn new_filter(&self, params: Params) -> Result<Value, Error> {
try!(self.active());
from_params::<(Filter,)>(params)
.and_then(|(filter,)| {
from_params::<(Filter, )>(params)
.and_then(|(filter, )| {
let mut polls = self.polls.lock();
let block_number = take_weak!(self.client).chain_info().best_block_number;
let id = polls.create_poll(PollFilter::Logs(block_number, Default::default(), filter));
@@ -152,7 +152,7 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
filter.to_block = BlockID::Latest;
// retrieve logs in range from_block..min(BlockID::Latest..to_block)
let mut logs = client.logs(filter.clone(), None)
let mut logs = client.logs(filter.clone())
.into_iter()
.map(From::from)
.collect::<Vec<Log>>();
@@ -174,6 +174,8 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
logs.extend(new_pending_logs);
}
let logs = limit_logs(logs, filter.limit);
// save the number of the next block as a first block from which
// we want to get logs
*block_number = current_number + 1;
@@ -194,7 +196,7 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => {
let include_pending = filter.to_block == Some(BlockNumber::Pending);
let filter: EthcoreFilter = filter.clone().into();
let mut logs = take_weak!(self.client).logs(filter.clone(), None)
let mut logs = take_weak!(self.client).logs(filter.clone())
.into_iter()
.map(From::from)
.collect::<Vec<Log>>();
@@ -203,6 +205,8 @@ impl<C, M> EthFilter for EthFilterClient<C, M> where
logs.extend(pending_logs(&*take_weak!(self.miner), &filter));
}
let logs = limit_logs(logs, filter.limit);
Ok(to_value(&logs))
},
// just empty array

View File

@@ -27,7 +27,7 @@ use ethcore::receipt::LocalizedReceipt;
use ethcore::transaction::{Transaction, Action};
use ethcore::miner::{ExternalMiner, MinerService};
use ethsync::SyncState;
use v1::{Eth, EthClient, EthClientOptions, EthSigning, EthSigningUnsafeClient};
use v1::{Eth, EthClient, EthClientOptions, EthFilter, EthFilterClient, EthSigning, EthSigningUnsafeClient};
use v1::tests::helpers::{TestSyncProvider, Config, TestMinerService};
use rustc_serialize::hex::ToHex;
use time::get_time;
@@ -76,10 +76,12 @@ impl EthTester {
let hashrates = Arc::new(Mutex::new(HashMap::new()));
let external_miner = Arc::new(ExternalMiner::new(hashrates.clone()));
let eth = EthClient::new(&client, &sync, &ap, &miner, &external_miner, options).to_delegate();
let filter = EthFilterClient::new(&client, &miner).to_delegate();
let sign = EthSigningUnsafeClient::new(&client, &ap, &miner).to_delegate();
let io = IoHandler::new();
io.add_delegate(eth);
io.add_delegate(sign);
io.add_delegate(filter);
EthTester {
client: client,
@@ -152,23 +154,88 @@ fn rpc_eth_hashrate() {
#[test]
fn rpc_eth_logs() {
let tester = EthTester::default();
tester.client.set_logs(vec![LocalizedLogEntry {
block_number: 1,
block_hash: H256::default(),
entry: LogEntry {
address: Address::default(),
topics: vec![],
data: vec![1,2,3],
},
transaction_index: 0,
transaction_hash: H256::default(),
log_index: 0,
}, LocalizedLogEntry {
block_number: 1,
block_hash: H256::default(),
entry: LogEntry {
address: Address::default(),
topics: vec![],
data: vec![1,2,3],
},
transaction_index: 0,
transaction_hash: H256::default(),
log_index: 0,
}]);
let request = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{}], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":[],"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request), Some(response.to_owned()));
let request1 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{}], "id": 1}"#;
let request2 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":1}], "id": 1}"#;
let request3 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{"limit":0}], "id": 1}"#;
let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"}],"id":1}"#;
let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"}],"id":1}"#;
let response3 = r#"{"jsonrpc":"2.0","result":[],"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request1), Some(response1.to_owned()));
assert_eq!(tester.io.handle_request_sync(request2), Some(response2.to_owned()));
assert_eq!(tester.io.handle_request_sync(request3), Some(response3.to_owned()));
}
#[test]
fn rpc_eth_logs_with_limit() {
fn rpc_logs_filter() {
let tester = EthTester::default();
// Set some logs
tester.client.set_logs(vec![LocalizedLogEntry {
block_number: 1,
block_hash: H256::default(),
entry: LogEntry {
address: Address::default(),
topics: vec![],
data: vec![1,2,3],
},
transaction_index: 0,
transaction_hash: H256::default(),
log_index: 0,
}, LocalizedLogEntry {
block_number: 1,
block_hash: H256::default(),
entry: LogEntry {
address: Address::default(),
topics: vec![],
data: vec![1,2,3],
},
transaction_index: 0,
transaction_hash: H256::default(),
log_index: 0,
}]);
let request1 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{}, 1], "id": 1}"#;
let request2 = r#"{"jsonrpc": "2.0", "method": "eth_getLogs", "params": [{}, 0], "id": 1}"#;
let response = r#"{"jsonrpc":"2.0","result":[],"id":1}"#;
// Register filters first
let request_default = r#"{"jsonrpc": "2.0", "method": "eth_newFilter", "params": [{}], "id": 1}"#;
let request_limit = r#"{"jsonrpc": "2.0", "method": "eth_newFilter", "params": [{"limit":1}], "id": 1}"#;
let response1 = r#"{"jsonrpc":"2.0","result":"0x0","id":1}"#;
let response2 = r#"{"jsonrpc":"2.0","result":"0x1","id":1}"#;
assert_eq!(tester.io.handle_request_sync(request1), Some(response.to_owned()));
assert_eq!(tester.io.handle_request_sync(request2), Some(response.to_owned()));
assert_eq!(tester.io.handle_request_sync(request_default), Some(response1.to_owned()));
assert_eq!(tester.io.handle_request_sync(request_limit), Some(response2.to_owned()));
let request_changes1 = r#"{"jsonrpc": "2.0", "method": "eth_getFilterChanges", "params": ["0x0"], "id": 1}"#;
let request_changes2 = r#"{"jsonrpc": "2.0", "method": "eth_getFilterChanges", "params": ["0x1"], "id": 1}"#;
let response1 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"},{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"}],"id":1}"#;
let response2 = r#"{"jsonrpc":"2.0","result":[{"address":"0x0000000000000000000000000000000000000000","blockHash":"0x0000000000000000000000000000000000000000000000000000000000000000","blockNumber":"0x1","data":"0x010203","logIndex":"0x0","topics":[],"transactionHash":"0x0000000000000000000000000000000000000000000000000000000000000000","transactionIndex":"0x0","type":"mined"}],"id":1}"#;
assert_eq!(tester.io.handle_request_sync(request_changes1), Some(response1.to_owned()));
assert_eq!(tester.io.handle_request_sync(request_changes2), Some(response2.to_owned()));
}
#[test]

View File

@@ -66,6 +66,8 @@ pub struct Filter {
pub address: Option<FilterAddress>,
/// Topics
pub topics: Option<Vec<Topic>>,
/// Limit
pub limit: Option<usize>,
}
impl Into<EthFilter> for Filter {
@@ -85,7 +87,8 @@ impl Into<EthFilter> for Filter {
VariadicValue::Multiple(t) => Some(t.into_iter().map(Into::into).collect())
}).filter_map(|m| m).collect()).into_iter();
vec![iter.next(), iter.next(), iter.next(), iter.next()]
}
},
limit: self.limit,
}
}
}
@@ -120,7 +123,8 @@ mod tests {
from_block: Some(BlockNumber::Earliest),
to_block: Some(BlockNumber::Latest),
address: None,
topics: None
topics: None,
limit: None,
});
}
}