Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

confirm::wait_for_confirmations wait too long unnecessarily #640

Open
catflyflyfly opened this issue May 28, 2022 · 0 comments
Open

confirm::wait_for_confirmations wait too long unnecessarily #640

catflyflyfly opened this issue May 28, 2022 · 0 comments

Comments

@catflyflyfly
Copy link

catflyflyfly commented May 28, 2022

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:

  1. 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)

  2. 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:

  1. If confirmations == 0, do return Ok(()); right away.
  2. 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)
  3. if confirmations_needed == 0, do return Ok(());
  4. Otherwise, create the create_blocks_filter() stream with .skip(confirmations_needed)
  5. Loop fetching the stream and doing the check as usual

My example:

aofdev/event-watcher-contract-examples@d314132

@catflyflyfly catflyflyfly changed the title confirm::wait_for_confirmations wait too long unnecessarily confirm::wait_for_confirmations wait too long unnecessarily May 28, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant