-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Light client logs should include 'from_block' when querying logs #9331
Conversation
prior to this fix the pubsub process did send a query for each new block header (and for each subs : there is something to optimize here) by setting from and to of the filter at this block number; but there was a bug in the code that fetch logs : it was non inclusive for its start bound, meaning that with start bound = end bound we never query any block (and attached logs).
It looks like @cheme signed our Contributor License Agreement. 👍 Many thanks, Parity Technologies CLA Bot |
rpc/src/v1/helpers/light_fetch.rs
Outdated
.take_while(|ref hdr| BlockId::Hash(hdr.hash()) != filter.from_block) | ||
.take_while(|ref hdr|{ | ||
BlockId::Hash(hdr.hash()) != filter.from_block | ||
&& BlockId::Number(hdr.number()) != filter.from_block |
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.
this is a bug. this take_while will never return false
therefore this iterator will never end
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.
take_while(a).take_while(b)
is equivalent to take_while(a && b)
, right?
Should we check for the BlockId::Latest
case as well?
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.
Seems correct to me (also when testing). I can still switch back to using two take_while
(does not make a lot of difference as it combines correctly).
rpc/src/v1/helpers/light_fetch.rs
Outdated
BlockId::Hash(hdr.hash()) != filter.from_block | ||
&& BlockId::Number(hdr.number()) != filter.from_block | ||
}) | ||
.chain(::std::iter::once(self.client.block_header(filter.from_block).expect("checked before"))) | ||
.filter(|ref hdr| { | ||
let hdr_bloom = hdr.log_bloom(); | ||
bit_combos.iter().find(|&bloom| hdr_bloom & *bloom == *bloom).is_some() |
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.
not related to this pr, but it's more optimal to use contains_bloom
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.
Yes, this kind of logic should definitely use dedicated function.
rpc/src/v1/helpers/light_fetch.rs
Outdated
BlockId::Hash(hdr.hash()) != filter.from_block | ||
&& BlockId::Number(hdr.number()) != filter.from_block | ||
}) | ||
.chain(::std::iter::once(self.client.block_header(filter.from_block).expect("checked before"))) |
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.
I think, you can just write
.chain(self.client.block_header(filter.from_block).ok())
Option
implements iterator
Use of bloom existing function to check if a bloom contains another.
rpc/src/v1/helpers/light_fetch.rs
Outdated
.take_while(|ref hdr| BlockId::Hash(hdr.hash()) != filter.from_block) | ||
.take_while(|ref hdr|{ | ||
BlockId::Hash(hdr.hash()) != filter.from_block | ||
&& BlockId::Number(hdr.number()) != filter.from_block |
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.
take_while(a).take_while(b)
is equivalent to take_while(a && b)
, right?
Should we check for the BlockId::Latest
case as well?
rpc/src/v1/helpers/light_fetch.rs
Outdated
BlockId::Hash(hdr.hash()) != filter.from_block | ||
&& BlockId::Number(hdr.number()) != filter.from_block | ||
}) | ||
.chain(Some(self.client.block_header(filter.from_block).expect("checked before"))) |
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.
block_header
can return None
and I don't see where do we check it's not None
, could you point me to that line?
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 was tested in the case of a block hash (in block_number
) and I added a condition before to make sure the number case would be in range to, it is certainly not explicit enough.
I did a little change to test it explicitly in my last commit (plus remove the need to have two condition in takewhile).
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.
LGTM
|
||
match block_number(filter.to_block) { | ||
Some(to) if to < from_block_number || from_block_number > best_number | ||
=> return Either::A(future::ok(Vec::new())), |
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.
Minor nit but I would put the =>
in the previous line, I don't know what's our style on this though.
Fixes #8560 .
When using a websocket on logs, there was no entry displayed. The issue was that we called light client get logs method for each block (with a range of one block in the filter), but the method did not include the first block to query (with a range of one block it did include nothing).
This PR fixes this by making LightClient
log
works correctly (by including the start block of the filter).For the websocket usecase it also increases OnDemand query a lot, so this other PR may be helpfull : #9318 (during my testing without #9318 the lightclient became a bit irresponsive after a while). There is also probably room for optimization in function 'notify_log', yet it should not directly impact network query (if OnDemand cache works as intended of course).
I did try to change as less as possible code, but from a personal point of view I would rather use :
than
So if the reviewers prefer the more imperative version please tell me.