Skip to content

Serve typed blocks from recent block cache to avoid repeated deserialization#6400

Open
incrypto32 wants to merge 2 commits intomasterfrom
krishna/typed-block-cache
Open

Serve typed blocks from recent block cache to avoid repeated deserialization#6400
incrypto32 wants to merge 2 commits intomasterfrom
krishna/typed-block-cache

Conversation

@incrypto32
Copy link
Member

No description provided.

…h crate

Move EthereumJsonBlock and JSON patching utilities from chain/ethereum to
graph/src/components/ethereum/ so they can be used by the store layer
without circular dependencies. This prepares for typed block caching where
CachedBlock::from_json() needs access to these utilities.
@incrypto32 incrypto32 marked this pull request as draft February 27, 2026 12:03
@incrypto32 incrypto32 force-pushed the krishna/typed-block-cache branch 2 times, most recently from 1f360ae to fd65e1a Compare February 27, 2026 12:42
@incrypto32 incrypto32 force-pushed the krishna/typed-block-cache branch from fd65e1a to 4ba28d6 Compare February 27, 2026 14:03
@incrypto32 incrypto32 marked this pull request as ready for review February 27, 2026 14:05
@incrypto32 incrypto32 requested a review from lutter February 27, 2026 14:05
Copy link
Collaborator

@lutter lutter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I left a few comments for additional improvements - I am totally fine merging this as-is to see how much this helps, but I think we should also do some of the suggestions as follow-on work. In particular, we should be able to get rid of deep clones of blocks; we also have a pretty big number of different block structs all over the code base; it would be nice to simplify and reduce that though that might be pretty hairy.

BlockStream, BlockStreamBuilder, BlockStreamError, BlockStreamMapper, FirehoseCursor,
TriggersAdapterWrapper,
};
use graph::components::ethereum::EthereumJsonBlock;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very minor: since this is in a module called ethereum, it's probably enough to call this JsonBlock


pub fn into_light_block(self) -> LightEthereumBlock {
match self {
CachedBlock::Full(block) => block.block.as_ref().clone(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you change this to

pub fn into_light_block(self) -> Arc<LightEthereumBlock> {
        match self {
            CachedBlock::Full(block) => block.block,
            CachedBlock::Light(block) => Arc::new(block),
        }
}

you can avoid a deep clone of the block

.ok()
})
.map(Arc::new)
.map(|cached| Arc::new(cached.into_light_block()))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This then becomes .map(CachedBlock::into_light_block)


/// Typed cached block for Ethereum. Stores the deserialized block so that
/// repeated reads from the in-memory cache avoid `serde_json::from_value()`.
#[derive(Clone, Debug)]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to get rid of Clone for this and all other block structs; that's probably a bigger puzzle and requires using Arc judiciously in various data structures, i.e., something for another PR; but conceptually, blocks are readonly and it should therefore be possible to Arc them.


/// Returns blocks as raw JSON. Used by callers that need the original
/// JSON representation (e.g., GraphQL block queries, CLI tools).
async fn blocks_as_json(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should try and get rid of this one, but that's also for another PR

Ok(ptr)
}

fn cache_block_to_block_ptr_ext(block: &CacheBlock) -> Result<ExtendedBlockPtr, Error> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be a method on CacheBlock

let block = JsonBlock::new(block.ptr(), parent_hash, block.data().ok());
self.recent_blocks_cache.insert_block(block);
let json_block = JsonBlock::new(block.ptr(), parent_hash, block.data().ok());
self.recent_blocks_cache.insert_json_block(json_block);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

upsert_block is only used in 2 places (apart from tests) It should be possible to tighten the type of block to a concrete type here so we don't have to go through JSON. It's kinda low priority since this code path is only used on the block ingestor, which isn't that performance critical.

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

Successfully merging this pull request may close these issues.

2 participants