feat: periodic snapshooting

This commit is contained in:
Oleksandr Pravdyvyi 2025-05-29 12:00:50 +03:00
parent 0d577da288
commit 66def746e6
8 changed files with 99 additions and 9 deletions

View File

@ -16,6 +16,7 @@ use crate::key_management::{
pub type PublicKey = AffinePoint; pub type PublicKey = AffinePoint;
pub type AccountAddress = TreeHashType; pub type AccountAddress = TreeHashType;
#[derive(Debug, Serialize)]
pub struct Account { pub struct Account {
pub key_holder: AddressKeyHolder, pub key_holder: AddressKeyHolder,
pub address: AccountAddress, pub address: AccountAddress,

View File

@ -6,6 +6,7 @@ use ephemeral_key_holder::EphemeralKeyHolder;
use k256::AffinePoint; use k256::AffinePoint;
use log::info; use log::info;
use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder};
use serde::Serialize;
use crate::account_core::PublicKey; use crate::account_core::PublicKey;
@ -13,7 +14,7 @@ pub mod constants_types;
pub mod ephemeral_key_holder; pub mod ephemeral_key_holder;
pub mod secret_holders; pub mod secret_holders;
#[derive(Clone)] #[derive(Debug, Serialize, Clone)]
///Entrypoint to key management ///Entrypoint to key management
pub struct AddressKeyHolder { pub struct AddressKeyHolder {
//Will be useful in future //Will be useful in future

View File

@ -2,6 +2,7 @@ use common::merkle_tree_public::TreeHashType;
use elliptic_curve::PrimeField; use elliptic_curve::PrimeField;
use k256::{AffinePoint, FieldBytes, Scalar}; use k256::{AffinePoint, FieldBytes, Scalar};
use rand::{rngs::OsRng, RngCore}; use rand::{rngs::OsRng, RngCore};
use serde::Serialize;
use sha2::{digest::FixedOutput, Digest}; use sha2::{digest::FixedOutput, Digest};
use super::constants_types::{NULLIFIER_SECRET_CONST, VIEWING_SECRET_CONST}; use super::constants_types::{NULLIFIER_SECRET_CONST, VIEWING_SECRET_CONST};
@ -13,13 +14,13 @@ pub struct SeedHolder {
seed: Scalar, seed: Scalar,
} }
#[derive(Debug, Clone)] #[derive(Debug, Serialize, Clone)]
///Secret spending key holder. Produces `UTXOSecretKeyHolder` objects. ///Secret spending key holder. Produces `UTXOSecretKeyHolder` objects.
pub struct TopSecretKeyHolder { pub struct TopSecretKeyHolder {
pub secret_spending_key: Scalar, pub secret_spending_key: Scalar,
} }
#[derive(Debug, Clone)] #[derive(Debug, Serialize, Clone)]
///Nullifier secret key and viewing secret key holder. Produces public keys. Can produce address. Can produce shared secret for recepient. ///Nullifier secret key and viewing secret key holder. Produces public keys. Can produce address. Can produce shared secret for recepient.
pub struct UTXOSecretKeyHolder { pub struct UTXOSecretKeyHolder {
pub nullifier_secret_key: Scalar, pub nullifier_secret_key: Scalar,

View File

@ -2,6 +2,7 @@ use std::path::Path;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use common::block::Block; use common::block::Block;
use log::warn;
use storage::sc_db_utils::{DataBlob, DataBlobChangeVariant}; use storage::sc_db_utils::{DataBlob, DataBlobChangeVariant};
use storage::RocksDBIO; use storage::RocksDBIO;
@ -56,6 +57,35 @@ impl NodeBlockStore {
pub fn get_sc_sc_state(&self, sc_addr: &str) -> Result<Vec<DataBlob>> { pub fn get_sc_sc_state(&self, sc_addr: &str) -> Result<Vec<DataBlob>> {
Ok(self.dbio.get_sc_sc_state(sc_addr)?) Ok(self.dbio.get_sc_sc_state(sc_addr)?)
} }
pub fn put_snapshot_at_block_id(
&self,
id: u64,
accounts_ser: Vec<u8>,
comm_ser: Vec<u8>,
txs_ser: Vec<u8>,
nullifiers_ser: Vec<u8>,
) -> Result<()> {
self.dbio
.put_snapshot_block_id_db(id)
.inspect_err(|err| warn!("Failed to store snapshot block id with error {err:#?}"))?;
self.dbio
.put_snapshot_account_db(accounts_ser)
.inspect_err(|err| warn!("Failed to store snapshot accounts with error {err:#?}"))?;
self.dbio
.put_snapshot_commitement_db(comm_ser)
.inspect_err(|err| warn!("Failed to store snapshot commitments with error {err:#?}"))?;
self.dbio
.put_snapshot_transaction_db(txs_ser)
.inspect_err(|err| {
warn!("Failed to store snapshot transactions with error {err:#?}")
})?;
self.dbio
.put_snapshot_account_db(nullifiers_ser)
.inspect_err(|err| warn!("Failed to store snapshot nullifiers with error {err:#?}"))?;
Ok(())
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -13,10 +13,11 @@ use common::{
utxo_commitment::UTXOCommitment, utxo_commitment::UTXOCommitment,
}; };
use k256::AffinePoint; use k256::AffinePoint;
use log::{info, warn};
use public_context::PublicSCContext; use public_context::PublicSCContext;
use utxo::utxo_core::UTXO; use utxo::utxo_core::UTXO;
use crate::ActionData; use crate::{config::NodeConfig, ActionData};
pub mod accounts_store; pub mod accounts_store;
pub mod block_store; pub mod block_store;
@ -28,10 +29,11 @@ pub struct NodeChainStore {
pub nullifier_store: HashSet<UTXONullifier>, pub nullifier_store: HashSet<UTXONullifier>,
pub utxo_commitments_store: UTXOCommitmentsMerkleTree, pub utxo_commitments_store: UTXOCommitmentsMerkleTree,
pub pub_tx_store: PublicTransactionMerkleTree, pub pub_tx_store: PublicTransactionMerkleTree,
pub node_config: NodeConfig,
} }
impl NodeChainStore { impl NodeChainStore {
pub fn new_with_genesis(home_dir: &Path, genesis_block: Block) -> Self { pub fn new_with_genesis(config: NodeConfig, genesis_block: Block) -> Self {
let acc_map = HashMap::new(); let acc_map = HashMap::new();
let nullifier_store = HashSet::new(); let nullifier_store = HashSet::new();
let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]); let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]);
@ -40,7 +42,7 @@ impl NodeChainStore {
//Sequencer should panic if unable to open db, //Sequencer should panic if unable to open db,
//as fixing this issue may require actions non-native to program scope //as fixing this issue may require actions non-native to program scope
let block_store = 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(); .unwrap();
Self { Self {
@ -49,10 +51,13 @@ impl NodeChainStore {
nullifier_store, nullifier_store,
utxo_commitments_store, utxo_commitments_store,
pub_tx_store, pub_tx_store,
node_config: config,
} }
} }
pub fn dissect_insert_block(&mut self, block: Block) -> Result<()> { pub fn dissect_insert_block(&mut self, block: Block) -> Result<()> {
let block_id = block.block_id;
for tx in &block.transactions { for tx in &block.transactions {
if !tx.execution_input.is_empty() { if !tx.execution_input.is_empty() {
let public_action = serde_json::from_slice::<ActionData>(&tx.execution_input); let public_action = serde_json::from_slice::<ActionData>(&tx.execution_input);
@ -136,6 +141,55 @@ impl NodeChainStore {
self.block_store.put_block_at_id(block)?; 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 snapshot, it is not the reason to stop running
//Logging on warn level in this cases
let accounts_ser = serde_json::to_vec(&self.acc_map).inspect_err(|err| {
warn!("Failed to serialize accounts data {err:#?}");
});
let comm_tree_serialized = serde_json::to_vec(&self.utxo_commitments_store)
.inspect_err(|err| {
warn!("Failed to serialize commitments {err:#?}");
});
let tx_tree_serialized = serde_json::to_vec(&self.pub_tx_store).inspect_err(|err| {
warn!("Failed to serialize transactions {err:#?}");
});
let nullifiers_serialized =
serde_json::to_vec(&self.nullifier_store).inspect_err(|err| {
warn!("Failed to serialize nullifiers {err:#?}");
});
match (
accounts_ser,
comm_tree_serialized,
tx_tree_serialized,
nullifiers_serialized,
) {
(Ok(accounts_ser), Ok(comm_ser), Ok(txs_ser), Ok(nullifiers_ser)) => {
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
);
}
_ => warn!("Failed to serialize node data for snapshot"),
}
}
Ok(()) Ok(())
} }

View File

@ -49,4 +49,6 @@ pub struct NodeConfig {
pub port: u16, pub port: u16,
///Gas config ///Gas config
pub gas_config: GasConfig, pub gas_config: GasConfig,
///Frequency of snapshots
pub shapshot_frequency_in_blocks: u64,
} }

View File

@ -94,11 +94,11 @@ impl NodeCore {
let client = Arc::new(SequencerClient::new(config.clone())?); let client = Arc::new(SequencerClient::new(config.clone())?);
let genesis_id = client.get_genesis_id().await?; 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; let genesis_block = client.get_block(genesis_id.genesis_id).await?.block;
let mut storage = NodeChainStore::new_with_genesis(&config.home, genesis_block); let mut storage = NodeChainStore::new_with_genesis(config.clone(), genesis_block);
pre_start::setup_empty_sc_states(&storage).await?; pre_start::setup_empty_sc_states(&storage).await?;

View File

@ -12,5 +12,6 @@
"gas_cost_deploy": 1000, "gas_cost_deploy": 1000,
"gas_limit_deploy": 30000000, "gas_limit_deploy": 30000000,
"gas_limit_runtime": 30000000 "gas_limit_runtime": 30000000
} },
"shapshot_frequency_in_blocks": 10
} }