I'm currently trying to build a listener for events on finalized blocks, and I found the handy confirm utils which I tried to use.
Consider this code:
{
.
.
.
async fn get_block_number(_log: &Log) -> web3::error::Result<Option<U64>> {
// supposed that our log is really far from the chain current block number
Ok(Some(U64::from_str("0").unwrap()))
}
wait_for_confirmations(
web3.eth(),
web3.eth_filter(),
time::Duration::from_millis(100),
15,
|| get_block_number(&log),
)
.await?;
process_log(log).await?;
}
Now, let's see how wait_for_confirmations works
{
let filter = eth_filter.create_blocks_filter().await?;
let filter_stream = filter.stream(poll_interval).skip(confirmations);
futures::pin_mut!(filter_stream);
loop {
let _ = filter_stream.next().await;
if let Some(confirmation_block_number) = check.check().await? {
let block_number = eth.block_number().await?;
if confirmation_block_number.low_u64() + confirmations as u64 <= block_number.low_u64() {
return Ok(());
}
}
}
}
Problems:
Block number from check() in this case obviously is finalized. wait_for_confirmation should not even bother to create the stream and get the latest block.
This will cause delay, especially if you use high confirmations (I used 15 on bsc, waiting for minutes for each event was rather annoying)
Supposed that check() return a block number that is close to being finalized (for example, the log currently has 13 confirmations, but it needs 15 confirmations)
The create_blocks_filter() stream should just .skip(2) instead of doing .skip(15) as it is right now. This will optimized the waiting time even more.
Solutions:
If confirmations == 0, do return Ok(()); right away.
Computed confirmations_needed by (check() + confirmations).checked_sub(eth.block_number()).unwrap_or(0). For example:
(1000 + 15) - 1000 = 15
(1000 + 15) - 1013 = 2
(1000 + 15) - 1015 = 0
(1000 + 15) - 2000 = 0 (checked_sub & unwrap_or will ensure no arithmatic error happens)
if confirmations_needed == 0, do return Ok(());
Otherwise, create the create_blocks_filter() stream with .skip(confirmations_needed)
Loop fetching the stream and doing the check as usual
I'm currently trying to build a listener for events on finalized blocks, and I found the handy
confirm
utils which I tried to use.Consider this code:
Now, let's see how
wait_for_confirmations
worksProblems:
Block number from
check()
in this case obviously is finalized.wait_for_confirmation
should not even bother to create the stream and get the latest block.This will cause delay, especially if you use high
confirmations
(I used15
on bsc, waiting for minutes for each event was rather annoying)Supposed that
check()
return a block number that is close to being finalized (for example, the log currently has 13 confirmations, but it needs 15 confirmations)The
create_blocks_filter()
stream should just.skip(2)
instead of doing.skip(15)
as it is right now. This will optimized the waiting time even more.Solutions:
confirmations == 0
, doreturn Ok(());
right away.confirmations_needed
by(check() + confirmations).checked_sub(eth.block_number()).unwrap_or(0)
. For example:confirmations_needed == 0
, doreturn Ok(());
create_blocks_filter()
stream with.skip(confirmations_needed)
My example:
https://github.com/aofdev/event-watcher-contract-examples/pull/1/commits/d31413274331dee951b5660a177c26edd78787d8