diff --git a/Cargo.lock b/Cargo.lock index 51a76a5..a69903f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3669,10 +3669,12 @@ dependencies = [ name = "sequencer_core" version = "0.1.0" dependencies = [ + "accounts", "anyhow", "env_logger", "log", "mempool", + "rand 0.8.5", "serde", "serde_json", "storage", diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index 6adb899..a04cc37 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -15,9 +15,12 @@ use crate::key_management::{ AddressKeyHolder, }; +pub type PublicKey = AffinePoint; +pub type AccountAddress = TreeHashType; + pub struct Account { pub key_holder: AddressKeyHolder, - pub address: TreeHashType, + pub address: AccountAddress, pub balance: u64, pub utxo_tree: UTXOSparseMerkleTree, } diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index fcfcedd..7305937 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -6,6 +6,8 @@ use k256::AffinePoint; use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; use storage::merkle_tree_public::TreeHashType; +use crate::account_core::PublicKey; + pub mod constants_types; pub mod ephemeral_key_holder; pub mod secret_holders; @@ -18,8 +20,8 @@ pub struct AddressKeyHolder { top_secret_key_holder: TopSecretKeyHolder, utxo_secret_key_holder: UTXOSecretKeyHolder, pub address: TreeHashType, - pub nullifer_public_key: AffinePoint, - pub viewing_public_key: AffinePoint, + pub nullifer_public_key: PublicKey, + pub viewing_public_key: PublicKey, } impl AddressKeyHolder { diff --git a/sequencer_core/Cargo.toml b/sequencer_core/Cargo.toml index 5d713ba..7f474b2 100644 --- a/sequencer_core/Cargo.toml +++ b/sequencer_core/Cargo.toml @@ -9,9 +9,13 @@ serde_json.workspace = true env_logger.workspace = true log.workspace = true serde.workspace = true +rand.workspace = true [dependencies.storage] path = "../storage" [dependencies.mempool] path = "../mempool" + +[dependencies.accounts] +path = "../accounts" diff --git a/sequencer_core/src/config.rs b/sequencer_core/src/config.rs new file mode 100644 index 0000000..0c14948 --- /dev/null +++ b/sequencer_core/src/config.rs @@ -0,0 +1,15 @@ +use std::path::PathBuf; + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct SequencerConfig { + ///Home dir of sequencer storage + pub home: PathBuf, + ///Genesis id + pub genesis_id: u64, + ///If `True`, then adds random sequence of bytes to genesis block + pub is_genesis_random: bool, + ///Maximum number of transactions in block + pub max_num_tx_in_block: usize, +} diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index e4fc834..3e45a55 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -1 +1,53 @@ +use anyhow::Result; +use config::SequencerConfig; +use mempool::MemPool; +use sequecer_store::SequecerChainStore; +use storage::block::{Block, HashableBlockData}; +use transaction_mempool::TransactionMempool; + +pub mod config; +pub mod sequecer_store; pub mod transaction_mempool; + +pub struct SequencerCore { + pub store: SequecerChainStore, + pub mempool: MemPool, + pub sequencer_config: SequencerConfig, + pub chain_height: u64, +} + +impl SequencerCore { + pub fn start_from_config(config: SequencerConfig) -> Self { + Self { + store: SequecerChainStore::new_with_genesis( + &config.home, + config.genesis_id, + config.is_genesis_random, + ), + mempool: MemPool::::default(), + chain_height: config.genesis_id, + sequencer_config: config, + } + } + + ///Produces new block from transaction outputs in mempool + pub fn produce_new_block_simple(&mut self) -> Result<()> { + let transactions = self + .mempool + .pop_size(self.sequencer_config.max_num_tx_in_block); + + let hashable_data = HashableBlockData { + block_id: self.chain_height + 1, + transactions: transactions.into_iter().map(|tx_mem| tx_mem.tx).collect(), + data: vec![], + }; + + let block = Block::produce_block_from_hashable_data(hashable_data); + + self.store.block_store.put_block_at_id(block)?; + + self.chain_height += 1; + + Ok(()) + } +} diff --git a/sequencer_core/src/sequecer_store/accounts_store.rs b/sequencer_core/src/sequecer_store/accounts_store.rs new file mode 100644 index 0000000..9ae56ce --- /dev/null +++ b/sequencer_core/src/sequecer_store/accounts_store.rs @@ -0,0 +1,38 @@ +use std::collections::HashMap; + +use accounts::account_core::{AccountAddress, PublicKey}; + +#[derive(Debug, Clone)] +pub struct AccountPublicData { + pub nullifier_public_key: PublicKey, + pub viewing_public_key: PublicKey, + pub address: AccountAddress, +} + +#[derive(Debug, Clone)] +pub struct SequencerAccountsStore { + pub accounts: HashMap, +} + +impl SequencerAccountsStore { + pub fn new() -> Self { + Self { + accounts: HashMap::new(), + } + } + + pub fn register_account(&mut self, account_pub_data: AccountPublicData) { + self.accounts + .insert(account_pub_data.address, account_pub_data); + } + + pub fn unregister_account(&mut self, account_addr: AccountAddress) { + self.accounts.remove(&account_addr); + } +} + +impl Default for SequencerAccountsStore { + fn default() -> Self { + Self::new() + } +} diff --git a/sequencer_core/src/sequecer_store/block_store.rs b/sequencer_core/src/sequecer_store/block_store.rs new file mode 100644 index 0000000..69c889a --- /dev/null +++ b/sequencer_core/src/sequecer_store/block_store.rs @@ -0,0 +1,33 @@ +use std::path::Path; + +use anyhow::Result; +use storage::{block::Block, RocksDBIO}; + +pub struct SequecerBlockStore { + dbio: RocksDBIO, +} + +impl SequecerBlockStore { + ///Starting database at the start of new chain. + /// Creates files if necessary. + /// + /// ATTENTION: Will overwrite genesis block. + pub fn open_db_with_genesis(location: &Path, genesis_block: Option) -> Result { + Ok(Self { + dbio: RocksDBIO::new(location, genesis_block)?, + }) + } + + ///Reopening existing database + pub fn open_db_restart(location: &Path) -> Result { + SequecerBlockStore::open_db_with_genesis(location, None) + } + + pub fn get_block_at_id(&self, id: u64) -> Result { + Ok(self.dbio.get_block(id)?) + } + + pub fn put_block_at_id(&self, block: Block) -> Result<()> { + Ok(self.dbio.put_block(block)?) + } +} diff --git a/sequencer_core/src/sequecer_store/mod.rs b/sequencer_core/src/sequecer_store/mod.rs new file mode 100644 index 0000000..9e34b9a --- /dev/null +++ b/sequencer_core/src/sequecer_store/mod.rs @@ -0,0 +1,60 @@ +use std::path::Path; + +use accounts_store::SequencerAccountsStore; +use block_store::SequecerBlockStore; +use rand::{rngs::OsRng, RngCore}; +use storage::{ + block::{Block, HashableBlockData}, + merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, + nullifier_sparse_merkle_tree::NullifierSparseMerkleTree, +}; + +pub mod accounts_store; +pub mod block_store; + +pub struct SequecerChainStore { + pub acc_store: SequencerAccountsStore, + pub block_store: SequecerBlockStore, + pub nullifier_store: NullifierSparseMerkleTree, + pub utxo_commitments_store: UTXOCommitmentsMerkleTree, + pub pub_tx_store: PublicTransactionMerkleTree, +} + +impl SequecerChainStore { + pub fn new_with_genesis(home_dir: &Path, genesis_id: u64, is_genesis_random: bool) -> Self { + let acc_store = SequencerAccountsStore::default(); + let nullifier_store = NullifierSparseMerkleTree::default(); + let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]); + let pub_tx_store = PublicTransactionMerkleTree::new(vec![]); + + let mut data = [0; 32]; + + if is_genesis_random { + OsRng.fill_bytes(&mut data); + } + + let hashable_data = HashableBlockData { + block_id: genesis_id, + transactions: vec![], + data: data.to_vec(), + }; + + let genesis_block = Block::produce_block_from_hashable_data(hashable_data); + + //Sequencer should panic if unable to open db, + //as fixing this issue may require actions non-native to program scope + let block_store = SequecerBlockStore::open_db_with_genesis( + &home_dir.join("rocksdb"), + Some(genesis_block), + ) + .unwrap(); + + Self { + acc_store, + block_store, + nullifier_store, + utxo_commitments_store, + pub_tx_store, + } + } +} diff --git a/storage/src/block.rs b/storage/src/block.rs index 954e5f0..3a974d2 100644 --- a/storage/src/block.rs +++ b/storage/src/block.rs @@ -1,6 +1,7 @@ +use rs_merkle::Hasher; use serde::{Deserialize, Serialize}; -use crate::transaction::Transaction; +use crate::{merkle_tree_public::hasher::OwnHasher, transaction::Transaction}; pub type BlockHash = [u8; 32]; pub type Data = Vec; @@ -14,3 +15,25 @@ pub struct Block { pub transactions: Vec, pub data: Data, } + +#[derive(Debug, Serialize, Deserialize)] +pub struct HashableBlockData { + pub block_id: BlockId, + pub transactions: Vec, + pub data: Data, +} + +impl Block { + pub fn produce_block_from_hashable_data(hashable_data: HashableBlockData) -> Self { + let data = serde_json::to_vec(&hashable_data).unwrap(); + + let hash = OwnHasher::hash(&data); + + Self { + block_id: hashable_data.block_id, + hash, + transactions: hashable_data.transactions, + data: hashable_data.data, + } + } +}