diff --git a/node_core/src/chain_storage/block_store.rs b/node_core/src/chain_storage/block_store.rs index e05aab38..c48ed068 100644 --- a/node_core/src/chain_storage/block_store.rs +++ b/node_core/src/chain_storage/block_store.rs @@ -8,6 +8,7 @@ use common::merkle_tree_public::merkle_tree::HashStorageMerkleTree; use common::nullifier::UTXONullifier; use common::transaction::Transaction; use common::utxo_commitment::UTXOCommitment; +use log::error; use storage::sc_db_utils::{DataBlob, DataBlobChangeVariant}; use storage::RocksDBIO; @@ -87,6 +88,36 @@ impl NodeBlockStore { Ok(serde_json::from_slice( &self.dbio.get_snapshot_transaction()?, )?) + pub fn put_snapshot_at_block_id( + &self, + id: u64, + accounts_ser: Vec, + comm_ser: Vec, + txs_ser: Vec, + nullifiers_ser: Vec, + ) -> Result<()> { + //Error notification for writing into DB error + self.dbio + .put_snapshot_block_id_db(id) + .inspect_err(|err| error!("Failed to store snapshot block id with error {err:#?}"))?; + self.dbio + .put_snapshot_account_db(accounts_ser) + .inspect_err(|err| error!("Failed to store snapshot accounts with error {err:#?}"))?; + self.dbio + .put_snapshot_commitement_db(comm_ser) + .inspect_err(|err| { + error!("Failed to store snapshot commitments with error {err:#?}") + })?; + self.dbio + .put_snapshot_transaction_db(txs_ser) + .inspect_err(|err| { + error!("Failed to store snapshot transactions with error {err:#?}") + })?; + self.dbio + .put_snapshot_nullifier_db(nullifiers_ser) + .inspect_err(|err| error!("Failed to store snapshot nullifiers with error {err:#?}"))?; + + Ok(()) } } @@ -193,4 +224,52 @@ mod tests { assert_eq!(retrieved_block.block_id, block.block_id); assert_eq!(retrieved_block.hash, block.hash); } + + #[test] + fn test_get_block_not_found() { + let temp_dir = tempdir().unwrap(); + let path = temp_dir.path(); + + let node_store = NodeBlockStore::open_db_with_genesis(path, None).unwrap(); + + let result = node_store.get_block_at_id(42); + assert!(result.is_err()); + } + + #[test] + fn test_put_snapshot_at_block_id() { + let temp_dir = tempdir().unwrap(); + let path = temp_dir.path(); + + let genesis_block = create_genesis_block(); + let node_store = NodeBlockStore::open_db_with_genesis(path, Some(genesis_block)).unwrap(); + + let id = 3; + let accounts_ser = vec![1, 2, 3, 4]; + let comm_ser = vec![5, 6, 7, 8]; + let txs_ser = vec![9, 10, 11, 12]; + let nullifiers_ser = vec![13, 14, 15, 16]; + + node_store + .put_snapshot_at_block_id( + id, + accounts_ser.clone(), + comm_ser.clone(), + txs_ser.clone(), + nullifiers_ser.clone(), + ) + .unwrap(); + + assert_eq!(node_store.dbio.get_snapshot_block_id().unwrap(), id); + assert_eq!( + node_store.dbio.get_snapshot_account().unwrap(), + accounts_ser + ); + assert_eq!(node_store.dbio.get_snapshot_commitment().unwrap(), comm_ser); + assert_eq!(node_store.dbio.get_snapshot_transaction().unwrap(), txs_ser); + assert_eq!( + node_store.dbio.get_snapshot_nullifier().unwrap(), + nullifiers_ser + ); + } } diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index 9ca6cfde..f28a2ae6 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -1,7 +1,4 @@ -use std::{ - collections::{BTreeMap, HashMap, HashSet}, - path::Path, -}; +use std::collections::{BTreeMap, HashMap, HashSet}; use accounts::account_core::{Account, AccountAddress}; use anyhow::Result; @@ -13,10 +10,11 @@ use common::{ utxo_commitment::UTXOCommitment, }; use k256::AffinePoint; +use log::{info, warn}; use public_context::PublicSCContext; use utxo::utxo_core::UTXO; -use crate::ActionData; +use crate::{config::NodeConfig, ActionData}; pub mod accounts_store; pub mod block_store; @@ -28,6 +26,7 @@ pub struct NodeChainStore { pub nullifier_store: HashSet, pub utxo_commitments_store: UTXOCommitmentsMerkleTree, pub pub_tx_store: PublicTransactionMerkleTree, + pub node_config: NodeConfig, } impl NodeChainStore { @@ -41,7 +40,7 @@ impl NodeChainStore { //Sequencer should panic if unable to open db, //as fixing this issue may require actions non-native to program scope let block_store = - NodeBlockStore::open_db_with_genesis(&home_dir.join("rocksdb"), Some(genesis_block)) + NodeBlockStore::open_db_with_genesis(&config.home.join("rocksdb"), Some(genesis_block)) .unwrap(); if let Ok(temp_block_id) = block_store.get_snapshot_block_id() { @@ -65,6 +64,8 @@ impl NodeChainStore { } pub fn dissect_insert_block(&mut self, block: Block) -> Result<()> { + let block_id = block.block_id; + for tx in &block.transactions { if !tx.execution_input.is_empty() { let public_action = serde_json::from_slice::(&tx.execution_input); @@ -148,6 +149,47 @@ impl NodeChainStore { self.block_store.put_block_at_id(block)?; + //Snapshot + if block_id % self.node_config.shapshot_frequency_in_blocks == 0 { + //Serializing all important data structures + + //If we fail serialization, it is not the reason to stop running + //Logging on warn level in this cases + + if let Ok(accounts_ser) = serde_json::to_vec(&self.acc_map).inspect_err(|err| { + warn!("Failed to serialize accounts data {err:#?}"); + }) { + if let Ok(comm_ser) = + serde_json::to_vec(&self.utxo_commitments_store).inspect_err(|err| { + warn!("Failed to serialize commitments {err:#?}"); + }) + { + if let Ok(txs_ser) = serde_json::to_vec(&self.pub_tx_store).inspect_err(|err| { + warn!("Failed to serialize transactions {err:#?}"); + }) { + if let Ok(nullifiers_ser) = serde_json::to_vec(&self.nullifier_store) + .inspect_err(|err| { + warn!("Failed to serialize nullifiers {err:#?}"); + }) + { + let snapshot_trace = self.block_store.put_snapshot_at_block_id( + block_id, + accounts_ser, + comm_ser, + txs_ser, + nullifiers_ser, + ); + + info!( + "Snapshot executed at {:?} with results {snapshot_trace:#?}", + block_id + ); + } + } + } + } + } + Ok(()) } diff --git a/node_core/src/config.rs b/node_core/src/config.rs index d92e358d..935a803f 100644 --- a/node_core/src/config.rs +++ b/node_core/src/config.rs @@ -49,4 +49,6 @@ pub struct NodeConfig { pub port: u16, ///Gas config pub gas_config: GasConfig, + ///Frequency of snapshots + pub shapshot_frequency_in_blocks: u64, } diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index c143f593..3708b828 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -94,7 +94,7 @@ impl NodeCore { let client = Arc::new(SequencerClient::new(config.clone())?); let genesis_id = client.get_genesis_id().await?; - info!("Gesesis id is {genesis_id:?}"); + info!("Genesis id is {genesis_id:?}"); let genesis_block = client.get_block(genesis_id.genesis_id).await?.block; diff --git a/node_runner/configs/debug/node_config.json b/node_runner/configs/debug/node_config.json index f8c064e2..c948b823 100644 --- a/node_runner/configs/debug/node_config.json +++ b/node_runner/configs/debug/node_config.json @@ -12,5 +12,6 @@ "gas_cost_deploy": 1000, "gas_limit_deploy": 30000000, "gas_limit_runtime": 30000000 - } + }, + "shapshot_frequency_in_blocks": 10 } \ No newline at end of file