-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Add pagination for trace_filter rpc method #6312
Conversation
ethcore/src/client/client.rs
Outdated
@@ -1641,7 +1641,7 @@ impl BlockChainClient for Client { | |||
self.chain.read().logs(blocks, |entry| filter.matches(entry), filter.limit) | |||
} | |||
|
|||
fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>> { | |||
fn filter_traces(&self, filter: TraceFilter, after: Option<&TraceId>, count: Option<u64>) -> Option<Vec<LocalizedTrace>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not making it part of TraceFilter
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually there were 3 options how to add this here:
- Modify TraceFIlter
- Add optional parameters to filter_traces
- Instead add new method like filter_traces_with_pagination
I've discussed it with @arkpar and we chosen the second one. But frankly all of them pretty similar. There is no decisive advantage for any of them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using separate parameters breaks backward compatibility, we already support limit
parameter for eth_getLogs
filter object and that would be inline with that.
Would be good if those parameters could be omitted (using Trailing
), but we don't suport two optional parameters.
IMHO would be better to make it part of TraceFilter
object.
ethcore/src/client/traits.rs
Outdated
@@ -195,7 +195,7 @@ pub trait BlockChainClient : Sync + Send { | |||
fn replay(&self, t: TransactionId, analytics: CallAnalytics) -> Result<Executed, CallError>; | |||
|
|||
/// Returns traces matching given filter. | |||
fn filter_traces(&self, filter: TraceFilter) -> Option<Vec<LocalizedTrace>>; | |||
fn filter_traces(&self, filter: TraceFilter, after: Option<&TraceId>, count: Option<u64>) -> Option<Vec<LocalizedTrace>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
usize
will be enough for count
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree
ethcore/src/client/client.rs
Outdated
|
||
let mut traces_iter = traces.into_iter(); | ||
if let Some(after) = after { | ||
if let TransactionId::Location(BlockId::Hash(block_hash), transaction_number) = after.transaction { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it quietly ignores after
argument if it is Some(TransactionId::Hash(_))
? I can see that in RPC only TransactionId::Location
is used, but it is not good to have public method in separate (not RPC crate) which accepts two options and quietly works for single option only.
ethcore/src/client/client.rs
Outdated
let mut traces_iter = traces.into_iter(); | ||
if let Some(after) = after { | ||
if let TransactionId::Location(BlockId::Hash(block_hash), transaction_number) = after.transaction { | ||
match traces_iter.find(|ref trace| trace.block_hash == block_hash |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ref is not needed in ref trace
here
ethcore/src/client/client.rs
Outdated
} | ||
} | ||
if let Some(count) = count { | ||
traces_iter = traces_iter.take(count as usize).collect::<Vec<_>>().into_iter(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
count
is already usize
, so count as usize
is not needed here
ethcore/src/client/client.rs
Outdated
} | ||
} | ||
} | ||
if let Some(count) = count { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could avoid extra allocation here like that:
Some(match count {
Some(count) => traces_iter.take(count as usize).collect(),
None => traces_iter.collect(),
})
ethcore/src/client/client.rs
Outdated
TransactionId::Hash(transaction_hash) => { | ||
match traces_iter.find(|trace| trace.transaction_hash == transaction_hash) { | ||
Some(_) => {}, | ||
None => return None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's more idiomatic to write:
if traces_iter.find(|trace| trace.transaction_hash == transaction_hash).is_none() {
return None;
}
rpc/src/v1/impls/light/trace.rs
Outdated
@@ -31,7 +31,7 @@ pub struct TracesClient; | |||
impl Traces for TracesClient { | |||
type Metadata = Metadata; | |||
|
|||
fn filter(&self, _filter: TraceFilter) -> Result<Option<Vec<LocalizedTrace>>, Error> { | |||
fn filter(&self, _filter: TraceFilter, _offset: Option<TraceIndex>, _count: Option<usize>) -> Result<Option<Vec<LocalizedTrace>>, Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wouldn't offset being usize
be faster and easier to use (and to implement)?
With offset being TraceIndex
you can't fetch traces in parallel and/or from multiple clients. I imagine this might be a common practice for exchanges.
// thread 0,
ethereum_client_0.filter(filter_options, 0, 1000);
// thread 1,
ethereum_client_1.filter(filter_options, 1000, 2000);
// thread 2,
ethereum_client_2.filter(filter_options, 2000, 3000);
ethcore/src/client/client.rs
Outdated
Some(traces) | ||
let traces = self.tracedb.read().filter(&db_filter); | ||
if traces.is_empty() { | ||
return None; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not Some(vec![])
- I think None
was used to indicate invalid block range.
@grbIzl still waiting for this (fairly minor) change... |
Please keep your wiki up2date ... |
This work is done in terms of Trace & Fat DB module improvement suggestions #4858 issue.
trace_filter method was extended with two optional parameters offset and count in order to paginate through output traces.
For offset the new type was created TraceIndex in order to identify the trace. Inside the client it's converted into TraceId
New tests were not created as we have only trivial implementation for these methods in test_client.