Skip to content

Commit

Permalink
Create tree cache schema
Browse files Browse the repository at this point in the history
  • Loading branch information
popzxc committed Mar 28, 2022
1 parent 4508a4c commit 048223b
Show file tree
Hide file tree
Showing 8 changed files with 259 additions and 227 deletions.
147 changes: 2 additions & 145 deletions core/lib/storage/src/chain/block/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use zksync_types::{
};
// Local imports
use self::records::{
AccountTreeCache, BlockTransactionItem, StorageBlock, StorageBlockDetails,
StorageBlockMetadata, StoragePendingBlock, StorageRootHash, TransactionItem,
BlockTransactionItem, StorageBlock, StorageBlockDetails, StorageBlockMetadata,
StoragePendingBlock, StorageRootHash, TransactionItem,
};
use crate::{
chain::operations::{
Expand Down Expand Up @@ -1182,109 +1182,6 @@ impl<'a, 'c> BlockSchema<'a, 'c> {
Ok(())
}

/// Stores account tree cache for a block.
/// Expects `tree_cache` to be a valid encoded JSON.
pub async fn store_account_tree_cache(
&mut self,
block: BlockNumber,
tree_cache: String,
) -> QueryResult<()> {
let start = Instant::now();
if *block == 0 {
return Ok(());
}

sqlx::query!(
"
INSERT INTO account_tree_cache (block, tree_cache)
VALUES ($1, $2)
ON CONFLICT (block)
DO NOTHING
",
*block as i64,
tree_cache,
)
.execute(self.0.conn())
.await?;

metrics::histogram!("sql.chain.block.store_account_tree_cache", start.elapsed());
Ok(())
}

/// Gets the number of the latest block that has a stored cache.
/// Returns `None` if there are no caches in the database.
pub async fn get_last_block_with_account_tree_cache(
&mut self,
) -> QueryResult<Option<BlockNumber>> {
let start = Instant::now();

let last_block_with_cache = sqlx::query!("SELECT MAX(block) FROM account_tree_cache")
.fetch_one(self.0.conn())
.await?
.max;

metrics::histogram!(
"sql.chain.block.get_last_block_with_account_tree_cache",
start.elapsed()
);
Ok(last_block_with_cache.map(|block| BlockNumber(block as u32)))
}

/// Gets the latest stored account tree cache.
/// Returns `None` if there are no caches in the database.
/// Returns the block number and associated cache otherwise.
pub async fn get_account_tree_cache(
&mut self,
) -> QueryResult<Option<(BlockNumber, serde_json::Value)>> {
let start = Instant::now();
let account_tree_cache = sqlx::query_as!(
AccountTreeCache,
"
SELECT * FROM account_tree_cache
ORDER BY block DESC
LIMIT 1
",
)
.fetch_optional(self.0.conn())
.await?;

metrics::histogram!("sql.chain.block.get_account_tree_cache", start.elapsed());
Ok(account_tree_cache.map(|w| {
(
BlockNumber(w.block as u32),
serde_json::from_str(&w.tree_cache)
.expect("Failed to deserialize Account Tree Cache"),
)
}))
}

/// Gets stored account tree cache for a certain block.
/// Returns `None` if there is no cache for requested block.
pub async fn get_account_tree_cache_block(
&mut self,
block: BlockNumber,
) -> QueryResult<Option<serde_json::Value>> {
let start = Instant::now();
let account_tree_cache = sqlx::query_as!(
AccountTreeCache,
"
SELECT * FROM account_tree_cache
WHERE block = $1
",
*block as i64
)
.fetch_optional(self.0.conn())
.await?;

metrics::histogram!(
"sql.chain.block.get_account_tree_cache_block",
start.elapsed()
);
Ok(account_tree_cache.map(|w| {
serde_json::from_str(&w.tree_cache).expect("Failed to deserialize Account Tree Cache")
}))
}

pub async fn save_genesis_block(&mut self, root_hash: Fr) -> QueryResult<()> {
let mut transaction = self.0.start_transaction().await?;

Expand Down Expand Up @@ -1579,46 +1476,6 @@ impl<'a, 'c> BlockSchema<'a, 'c> {
Ok(())
}

// Removes account tree cache for blocks with number greater than `last_block`
pub async fn remove_new_account_tree_cache(
&mut self,
last_block: BlockNumber,
) -> QueryResult<()> {
let start = Instant::now();
sqlx::query!(
"DELETE FROM account_tree_cache WHERE block > $1",
*last_block as i64
)
.execute(self.0.conn())
.await?;

metrics::histogram!(
"sql.chain.block.remove_new_account_tree_cache",
start.elapsed()
);
Ok(())
}

// Removes account tree cache for blocks with number less than `last_block`
pub async fn remove_old_account_tree_cache(
&mut self,
last_block: BlockNumber,
) -> QueryResult<()> {
let start = Instant::now();
sqlx::query!(
"DELETE FROM account_tree_cache WHERE block < $1",
*last_block as i64
)
.execute(self.0.conn())
.await?;

metrics::histogram!(
"sql.chain.block.remove_old_account_tree_cache",
start.elapsed()
);
Ok(())
}

pub async fn store_factories_for_block_withdraw_nfts(
&mut self,
from_block: BlockNumber,
Expand Down
6 changes: 0 additions & 6 deletions core/lib/storage/src/chain/block/records.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,12 +103,6 @@ pub(crate) struct TransactionItem {
pub batch_id: Option<i64>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccountTreeCache {
pub block: i64,
pub tree_cache: String,
}

impl StorageBlockDetails {
/// Checks if block is finalized, meaning that
/// both Verify operation is performed for it, and this
Expand Down
1 change: 1 addition & 0 deletions core/lib/storage/src/chain/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod operations;
pub mod operations_ext;
pub mod state;
pub mod stats;
pub mod tree_cache;

use super::StorageProcessor;

Expand Down
159 changes: 159 additions & 0 deletions core/lib/storage/src/chain/tree_cache/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
// Built-in deps
use std::time::Instant;
// External imports
// Workspace imports
use zksync_types::BlockNumber;
// Local imports
use self::records::AccountTreeCache;
use crate::{QueryResult, StorageProcessor};

pub mod records;

/// Tree cache schema contains methods to store/load Merkle tree cache.
#[derive(Debug)]
pub struct TreeCacheSchema<'a, 'c>(pub &'a mut StorageProcessor<'c>);

impl<'a, 'c> TreeCacheSchema<'a, 'c> {
/// Stores account tree cache for a block.
/// Expects `tree_cache` to be a valid encoded JSON.
pub async fn store_account_tree_cache(
&mut self,
block: BlockNumber,
tree_cache: String,
) -> QueryResult<()> {
let start = Instant::now();
if *block == 0 {
return Ok(());
}

sqlx::query!(
"
INSERT INTO account_tree_cache (block, tree_cache)
VALUES ($1, $2)
ON CONFLICT (block)
DO NOTHING
",
*block as i64,
tree_cache,
)
.execute(self.0.conn())
.await?;

metrics::histogram!("sql.chain.block.store_account_tree_cache", start.elapsed());
Ok(())
}

/// Gets the number of the latest block that has a stored cache.
/// Returns `None` if there are no caches in the database.
pub async fn get_last_block_with_account_tree_cache(
&mut self,
) -> QueryResult<Option<BlockNumber>> {
let start = Instant::now();

let last_block_with_cache = sqlx::query!("SELECT MAX(block) FROM account_tree_cache")
.fetch_one(self.0.conn())
.await?
.max;

metrics::histogram!(
"sql.chain.block.get_last_block_with_account_tree_cache",
start.elapsed()
);
Ok(last_block_with_cache.map(|block| BlockNumber(block as u32)))
}

/// Gets the latest stored account tree cache.
/// Returns `None` if there are no caches in the database.
/// Returns the block number and associated cache otherwise.
pub async fn get_account_tree_cache(
&mut self,
) -> QueryResult<Option<(BlockNumber, serde_json::Value)>> {
let start = Instant::now();
let account_tree_cache = sqlx::query_as!(
AccountTreeCache,
"
SELECT * FROM account_tree_cache
ORDER BY block DESC
LIMIT 1
",
)
.fetch_optional(self.0.conn())
.await?;

metrics::histogram!("sql.chain.block.get_account_tree_cache", start.elapsed());
Ok(account_tree_cache.map(|w| {
(
BlockNumber(w.block as u32),
serde_json::from_str(&w.tree_cache)
.expect("Failed to deserialize Account Tree Cache"),
)
}))
}

/// Gets stored account tree cache for a certain block.
/// Returns `None` if there is no cache for requested block.
pub async fn get_account_tree_cache_block(
&mut self,
block: BlockNumber,
) -> QueryResult<Option<serde_json::Value>> {
let start = Instant::now();
let account_tree_cache = sqlx::query_as!(
AccountTreeCache,
"
SELECT * FROM account_tree_cache
WHERE block = $1
",
*block as i64
)
.fetch_optional(self.0.conn())
.await?;

metrics::histogram!(
"sql.chain.block.get_account_tree_cache_block",
start.elapsed()
);
Ok(account_tree_cache.map(|w| {
serde_json::from_str(&w.tree_cache).expect("Failed to deserialize Account Tree Cache")
}))
}

// Removes account tree cache for blocks with number greater than `last_block`
pub async fn remove_new_account_tree_cache(
&mut self,
last_block: BlockNumber,
) -> QueryResult<()> {
let start = Instant::now();
sqlx::query!(
"DELETE FROM account_tree_cache WHERE block > $1",
*last_block as i64
)
.execute(self.0.conn())
.await?;

metrics::histogram!(
"sql.chain.block.remove_new_account_tree_cache",
start.elapsed()
);
Ok(())
}

// Removes account tree cache for blocks with number less than `last_block`
pub async fn remove_old_account_tree_cache(
&mut self,
last_block: BlockNumber,
) -> QueryResult<()> {
let start = Instant::now();
sqlx::query!(
"DELETE FROM account_tree_cache WHERE block < $1",
*last_block as i64
)
.execute(self.0.conn())
.await?;

metrics::histogram!(
"sql.chain.block.remove_old_account_tree_cache",
start.elapsed()
);
Ok(())
}
}
10 changes: 10 additions & 0 deletions core/lib/storage/src/chain/tree_cache/records.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// External imports
use serde::{Deserialize, Serialize};
// Workspace imports
// Local imports

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccountTreeCache {
pub block: i64,
pub tree_cache: String,
}
Loading

0 comments on commit 048223b

Please sign in to comment.