Page MenuHomePhabricator

[chronik] better use the merkle tree cache
ClosedPublic

Authored by PiRK on Sep 23 2024, 13:07.

Details

Reviewers
Fabien
Group Reviewers
Restricted Project
Commits
rABC76bdc41caf1f: [chronik] better use the merkle tree cache
Summary

The current logic is wrong, we only use the cache when computing a merkle root for a block height lower than the previous highest one, i.e if the cache contains all or more intermediate hashes than we need.

With this change, we now use the cache even if it provides only part of the intermediate hashes.

Test Plan

ninja all check-all

Diff Detail

Repository
rABC Bitcoin ABC
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

PiRK requested review of this revision.Sep 23 2024, 13:07

Benchmark:

diff --git a/chronik/chronik-indexer/src/query/blocks.rs b/chronik/chronik-indexer/src/query/blocks.rs
index 01e658e2fd..f130f2e7f3 100644
--- a/chronik/chronik-indexer/src/query/blocks.rs
+++ b/chronik/chronik-indexer/src/query/blocks.rs
@@ -33,6 +33,7 @@ use crate::{
         OutputsSpent, TxTokenData,
     },
 };
+use std::time::{Duration, Instant};

 const MAX_BLOCKS_PAGE_SIZE: usize = 500;

@@ -368,6 +369,7 @@ impl<'a> QueryBlocks<'a> {
     ) -> Result<(Vec<u8>, Vec<Vec<u8>>)> {
         let mut root = Vec::<u8>::new();
         let mut branch = Vec::<Vec<u8>>::new();
+        let mut start = Instant::now();
         if checkpoint_height > 0 {
             Self::check_checkpoint_height(block_height, checkpoint_height)?;
             let bridge = &self.node.bridge;
@@ -376,9 +378,16 @@ impl<'a> QueryBlocks<'a> {
                 .iter()
                 .map(|raw_hash| Sha256d::from_le_bytes(raw_hash.data))
                 .collect();
+            let duration = start.elapsed();
+            println!("Time elapsed fetching headers is: {:?}", duration);
+            start = Instant::now();
             let mut block_merkle_tree = self.block_merkle_tree.lock().await;
             let (root_hash, branch_hashes) = block_merkle_tree
                 .merkle_root_and_branch(&hashes, block_height as usize);
+
+            let duration = start.elapsed();
+            println!("Time elapsed computing merkle tree is: {:?}", duration);
+
             root = root_hash.to_le_bytes().to_vec();
             branch = branch_
$ python
Python 3.12.3 (main, Sep 11 2024, 14:17:37) [GCC 13.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from chronik import client
>>> cl = client.ChronikClient("127.0.0.1", 8331)
>>> pb = cl.block_header(863480, 863480)
>>> pb = cl.block_header(863482, 863482)
>>> pb = cl.block_header(863484, 863484)
>>> pb = cl.block_header(863486, 863486)
>>> pb = cl.block_header(863488, 863488)

Before:

Time elapsed fetching headers is: 92.83265ms
Time elapsed computing merkle tree is: 144.761108ms

Time elapsed fetching headers is: 86.521631ms
Time elapsed computing merkle tree is: 96.598198ms

Time elapsed fetching headers is: 86.687492ms
Time elapsed computing merkle tree is: 120.510652ms

Time elapsed fetching headers is: 86.431005ms
Time elapsed computing merkle tree is: 97.853639ms

Time elapsed fetching headers is: 86.039362ms
Time elapsed computing merkle tree is: 144.968584ms

After

Time elapsed fetching headers is: 96.03466ms
Time elapsed computing merkle tree is: 144.438252ms

Time elapsed fetching headers is: 87.074127ms
Time elapsed computing merkle tree is: 54.741982ms

Time elapsed fetching headers is: 87.528585ms
Time elapsed computing merkle tree is: 49.760862ms

Time elapsed fetching headers is: 87.293025ms
Time elapsed computing merkle tree is: 55.79699ms

Time elapsed fetching headers is: 86.483147ms
Time elapsed computing merkle tree is: 48.828292ms

I found this issue while working on an optimization to not load all the blockhashes when we only need the last few ones.

This revision is now accepted and ready to land.Sep 23 2024, 14:34
This revision was automatically updated to reflect the committed changes.