From 5b2af29efd6dbf6fd053e352786b4dbc1e35cfae Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Wed, 23 Jul 2025 15:16:53 +0300 Subject: [PATCH] fix: fixes and retrieval methods --- Cargo.lock | 1 + common/src/rpc_primitives/requests.rs | 4 + node_core/src/lib.rs | 7 + node_core/src/sequencer_client/mod.rs | 21 ++- sequencer_core/src/config.rs | 4 +- sequencer_core/src/lib.rs | 126 ++++-------------- .../src/sequencer_store/accounts_store.rs | 108 ++++++++------- sequencer_core/src/sequencer_store/mod.rs | 20 +-- sequencer_rpc/Cargo.toml | 3 + sequencer_rpc/src/process.rs | 23 ++++ .../configs/debug/sequencer_config.json | 2 - 11 files changed, 157 insertions(+), 162 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3d8593..7d6f17a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4363,6 +4363,7 @@ dependencies = [ name = "sequencer_rpc" version = "0.1.0" dependencies = [ + "accounts", "actix", "actix-cors", "actix-web", diff --git a/common/src/rpc_primitives/requests.rs b/common/src/rpc_primitives/requests.rs index 395badf..c2ea970 100644 --- a/common/src/rpc_primitives/requests.rs +++ b/common/src/rpc_primitives/requests.rs @@ -34,12 +34,16 @@ pub struct GetGenesisIdRequest {} #[derive(Serialize, Deserialize, Debug)] pub struct GetLastBlockRequest {} +#[derive(Serialize, Deserialize, Debug)] +pub struct GetInitialTestnetAccountsRequest {} + parse_request!(HelloRequest); parse_request!(RegisterAccountRequest); parse_request!(SendTxRequest); parse_request!(GetBlockDataRequest); parse_request!(GetGenesisIdRequest); parse_request!(GetLastBlockRequest); +parse_request!(GetInitialTestnetAccountsRequest); #[derive(Serialize, Deserialize, Debug)] pub struct HelloResponse { diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 71538bc..8590383 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -103,7 +103,14 @@ impl NodeCore { let genesis_block = client.get_block(genesis_id.genesis_id).await?.block; + let initial_accounts_ser = client.get_initial_testnet_accounts().await?; + let initial_accounts: Vec = + initial_accounts_ser.into_iter().map(Into::into).collect(); + let (mut storage, mut chain_height) = NodeChainStore::new(config.clone(), genesis_block)?; + for acc in initial_accounts { + storage.acc_map.insert(acc.address, acc); + } pre_start::setup_empty_sc_states(&storage).await?; diff --git a/node_core/src/sequencer_client/mod.rs b/node_core/src/sequencer_client/mod.rs index c348395..e24b840 100644 --- a/node_core/src/sequencer_client/mod.rs +++ b/node_core/src/sequencer_client/mod.rs @@ -1,8 +1,8 @@ -use accounts::account_core::Account; +use accounts::account_core::{Account, AccountForSerialization}; use anyhow::Result; use common::rpc_primitives::requests::{ GetBlockDataRequest, GetBlockDataResponse, GetGenesisIdRequest, GetGenesisIdResponse, - RegisterAccountRequest, RegisterAccountResponse, + GetInitialTestnetAccountsRequest, RegisterAccountRequest, RegisterAccountResponse, }; use common::transaction::Transaction; use common::{SequencerClientError, SequencerRpcError}; @@ -121,4 +121,21 @@ impl SequencerClient { Ok(resp_deser) } + + pub async fn get_initial_testnet_accounts( + &self, + ) -> Result, SequencerClientError> { + let acc_req = GetInitialTestnetAccountsRequest {}; + + let req = serde_json::to_value(acc_req).unwrap(); + + let resp = self + .call_method_with_payload("get_initial_testnet_accounts", req) + .await + .unwrap(); + + let resp_deser = serde_json::from_value(resp).unwrap(); + + Ok(resp_deser) + } } diff --git a/sequencer_core/src/config.rs b/sequencer_core/src/config.rs index 95ed7bc..d7937d5 100644 --- a/sequencer_core/src/config.rs +++ b/sequencer_core/src/config.rs @@ -6,8 +6,6 @@ use std::path::PathBuf; #[derive(Debug, Serialize, Deserialize, Clone)] ///Helperstruct for account serialization pub struct AccountInitialData { - ///Hex encoded `AccountAddress` - pub addr: String, pub balance: u64, } @@ -27,6 +25,6 @@ pub struct SequencerConfig { pub block_create_timeout_millis: u64, ///Port to listen pub port: u16, - ///List of pairs (account_address, initial_balance) + ///List of initial accounts data pub initial_accounts: Vec, } diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 761d5a1..12c91b6 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -38,7 +38,6 @@ pub enum TransactionMalformationErrorKind { ChainStateFurtherThanTransactionState { tx: TreeHashType }, FailedToInsert { tx: TreeHashType, details: String }, InvalidSignature, - AccountNotFound { tx: TreeHashType, acc: TreeHashType }, BalanceMismatch { tx: TreeHashType }, FailedToDecode { tx: TreeHashType }, } @@ -110,41 +109,26 @@ impl SequencerCore { if let Ok(native_transfer_action) = serde_json::from_slice::(&execution_input) { - if let Some(from_balance) = self + let from_balance = self .store .acc_store - .get_account_balance(&native_transfer_action.from) - { - if let Some(to_balance) = self - .store - .acc_store - .get_account_balance(&native_transfer_action.to) - { - if from_balance >= native_transfer_action.moved_balance { - self.store.acc_store.set_account_balance( - &native_transfer_action.from, - from_balance - native_transfer_action.moved_balance, - ); - self.store.acc_store.set_account_balance( - &native_transfer_action.to, - to_balance + native_transfer_action.moved_balance, - ); - } else { - return Err(TransactionMalformationErrorKind::BalanceMismatch { - tx: tx_hash, - }); - } - } else { - return Err(TransactionMalformationErrorKind::AccountNotFound { - tx: tx_hash, - acc: native_transfer_action.to, - }); - } + .get_account_balance(&native_transfer_action.from); + let to_balance = self + .store + .acc_store + .get_account_balance(&native_transfer_action.to); + + if from_balance >= native_transfer_action.moved_balance { + self.store.acc_store.set_account_balance( + &native_transfer_action.from, + from_balance - native_transfer_action.moved_balance, + ); + self.store.acc_store.set_account_balance( + &native_transfer_action.to, + to_balance + native_transfer_action.moved_balance, + ); } else { - return Err(TransactionMalformationErrorKind::AccountNotFound { - tx: tx_hash, - acc: native_transfer_action.from, - }); + return Err(TransactionMalformationErrorKind::BalanceMismatch { tx: tx_hash }); } } else { return Err(TransactionMalformationErrorKind::FailedToDecode { tx: tx_hash }); @@ -347,16 +331,8 @@ mod tests { fn setup_sequencer_config() -> SequencerConfig { let initial_accounts = vec![ - AccountInitialData { - addr: "bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117d09a8c" - .to_string(), - balance: 10, - }, - AccountInitialData { - addr: "20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1e376f31" - .to_string(), - balance: 100, - }, + AccountInitialData { balance: 10 }, + AccountInitialData { balance: 100 }, ]; setup_sequencer_config_variable_initial_accounts(initial_accounts) @@ -409,53 +385,27 @@ mod tests { assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); assert_eq!(sequencer.sequencer_config.port, 8080); - let acc1_addr: [u8; 32] = hex::decode( - "bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117d09a8c".to_string(), - ) - .unwrap() - .try_into() - .unwrap(); - let acc2_addr: [u8; 32] = hex::decode( - "20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1e376f31".to_string(), - ) - .unwrap() - .try_into() - .unwrap(); + let acc1_addr = sequencer.store.testnet_initial_accounts_full_data[0].address; + let acc2_addr = sequencer.store.testnet_initial_accounts_full_data[1].address; assert!(sequencer.store.acc_store.contains_account(&acc1_addr)); assert!(sequencer.store.acc_store.contains_account(&acc2_addr)); assert_eq!( 10, - sequencer - .store - .acc_store - .get_account_balance(&acc1_addr) - .unwrap() + sequencer.store.acc_store.get_account_balance(&acc1_addr) ); assert_eq!( 100, - sequencer - .store - .acc_store - .get_account_balance(&acc2_addr) - .unwrap() + sequencer.store.acc_store.get_account_balance(&acc2_addr) ); } #[test] fn test_start_different_intial_accounts() { let initial_accounts = vec![ - AccountInitialData { - addr: "bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117ffffff" - .to_string(), - balance: 1000, - }, - AccountInitialData { - addr: "20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1effffff" - .to_string(), - balance: 1000, - }, + AccountInitialData { balance: 1000 }, + AccountInitialData { balance: 1000 }, ]; let intial_accounts_len = initial_accounts.len(); @@ -463,18 +413,8 @@ mod tests { let config = setup_sequencer_config_variable_initial_accounts(initial_accounts); let sequencer = SequencerCore::start_from_config(config.clone()); - let acc1_addr: [u8; 32] = hex::decode( - "bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117ffffff".to_string(), - ) - .unwrap() - .try_into() - .unwrap(); - let acc2_addr: [u8; 32] = hex::decode( - "20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1effffff".to_string(), - ) - .unwrap() - .try_into() - .unwrap(); + let acc1_addr = sequencer.store.testnet_initial_accounts_full_data[0].address; + let acc2_addr = sequencer.store.testnet_initial_accounts_full_data[1].address; assert!(sequencer.store.acc_store.contains_account(&acc1_addr)); assert!(sequencer.store.acc_store.contains_account(&acc2_addr)); @@ -483,19 +423,11 @@ mod tests { assert_eq!( 1000, - sequencer - .store - .acc_store - .get_account_balance(&acc1_addr) - .unwrap() + sequencer.store.acc_store.get_account_balance(&acc1_addr) ); assert_eq!( 1000, - sequencer - .store - .acc_store - .get_account_balance(&acc2_addr) - .unwrap() + sequencer.store.acc_store.get_account_balance(&acc2_addr) ); } diff --git a/sequencer_core/src/sequencer_store/accounts_store.rs b/sequencer_core/src/sequencer_store/accounts_store.rs index 48cd012..7454770 100644 --- a/sequencer_core/src/sequencer_store/accounts_store.rs +++ b/sequencer_core/src/sequencer_store/accounts_store.rs @@ -1,4 +1,4 @@ -use accounts::account_core::AccountAddress; +use accounts::account_core::{Account, AccountAddress}; use anyhow::Result; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -28,13 +28,13 @@ pub struct SequencerAccountsStore { } impl SequencerAccountsStore { - pub fn new(initial_accounts: &[(AccountAddress, u64)]) -> Self { + pub fn new(initial_accounts: &[Account]) -> Self { let mut accounts = HashMap::new(); - for (account_addr, balance) in initial_accounts { + for account in initial_accounts { accounts.insert( - *account_addr, - AccountPublicData::new_with_balance(*account_addr, *balance), + account.address, + AccountPublicData::new_with_balance(account.address, account.balance), ); } @@ -56,28 +56,29 @@ impl SequencerAccountsStore { ///Check `account_addr` balance, /// - ///returns `None`, if account address not found - pub fn get_account_balance(&self, account_addr: &AccountAddress) -> Option { - self.accounts.get(account_addr).map(|acc| acc.balance) + ///returns 0, if account address not found + pub fn get_account_balance(&self, account_addr: &AccountAddress) -> u64 { + self.accounts + .get(account_addr) + .map(|acc| acc.balance) + .unwrap_or(0) } ///Update `account_addr` balance, /// - /// returns `None` if account address not found, othervise returns previous balance - pub fn set_account_balance( - &mut self, - account_addr: &AccountAddress, - new_balance: u64, - ) -> Option { + /// returns 0, if account address not found, othervise returns previous balance + pub fn set_account_balance(&mut self, account_addr: &AccountAddress, new_balance: u64) -> u64 { let acc_data = self.accounts.get_mut(account_addr); - acc_data.map(|data| { - let old_bal = data.balance; + acc_data + .map(|data| { + let old_bal = data.balance; - data.balance = new_balance; + data.balance = new_balance; - old_bal - }) + old_bal + }) + .unwrap_or(0) } ///Remove account from storage @@ -89,14 +90,10 @@ impl SequencerAccountsStore { &mut self, account_addr: AccountAddress, ) -> Result> { - if let Some(account_balance) = self.get_account_balance(&account_addr) { - if account_balance == 0 { - Ok(self.accounts.remove(&account_addr).map(|data| data.address)) - } else { - anyhow::bail!("Chain consistency violation: It is forbidden to remove account with nonzero balance"); - } + if self.get_account_balance(&account_addr) == 0 { + Ok(self.accounts.remove(&account_addr).map(|data| data.address)) } else { - Ok(None) + anyhow::bail!("Chain consistency violation: It is forbidden to remove account with nonzero balance"); } } @@ -147,7 +144,7 @@ mod tests { assert!(seq_acc_store.contains_account(&[1; 32])); - let acc_balance = seq_acc_store.get_account_balance(&[1; 32]).unwrap(); + let acc_balance = seq_acc_store.get_account_balance(&[1; 32]); assert_eq!(acc_balance, 0); } @@ -165,9 +162,14 @@ mod tests { #[test] fn account_sequencer_store_unregister_acc_not_zero_balance() { - let mut seq_acc_store = SequencerAccountsStore::new(&[([1; 32], 12), ([2; 32], 100)]); + let acc1 = Account::new_with_balance(12); + let acc2 = Account::new_with_balance(100); - let rem_res = seq_acc_store.unregister_account([1; 32]); + let acc1_addr = acc1.address.clone(); + + let mut seq_acc_store = SequencerAccountsStore::new(&[acc1, acc2]); + + let rem_res = seq_acc_store.unregister_account(acc1_addr); assert!(rem_res.is_err()); } @@ -187,49 +189,65 @@ mod tests { #[test] fn account_sequencer_store_with_preset_accounts_1() { - let seq_acc_store = SequencerAccountsStore::new(&[([1; 32], 12), ([2; 32], 100)]); + let acc1 = Account::new_with_balance(12); + let acc2 = Account::new_with_balance(100); - assert!(seq_acc_store.contains_account(&[1; 32])); - assert!(seq_acc_store.contains_account(&[2; 32])); + let acc1_addr = acc1.address.clone(); + let acc2_addr = acc2.address.clone(); - let acc_balance = seq_acc_store.get_account_balance(&[1; 32]).unwrap(); + let seq_acc_store = SequencerAccountsStore::new(&[acc1, acc2]); + + assert!(seq_acc_store.contains_account(&acc1_addr)); + assert!(seq_acc_store.contains_account(&acc2_addr)); + + let acc_balance = seq_acc_store.get_account_balance(&acc1_addr); assert_eq!(acc_balance, 12); - let acc_balance = seq_acc_store.get_account_balance(&[2; 32]).unwrap(); + let acc_balance = seq_acc_store.get_account_balance(&acc2_addr); assert_eq!(acc_balance, 100); } #[test] fn account_sequencer_store_with_preset_accounts_2() { - let seq_acc_store = - SequencerAccountsStore::new(&[([6; 32], 120), ([7; 32], 15), ([8; 32], 10)]); + let acc1 = Account::new_with_balance(120); + let acc2 = Account::new_with_balance(15); + let acc3 = Account::new_with_balance(10); - assert!(seq_acc_store.contains_account(&[6; 32])); - assert!(seq_acc_store.contains_account(&[7; 32])); - assert!(seq_acc_store.contains_account(&[8; 32])); + let acc1_addr = acc1.address.clone(); + let acc2_addr = acc2.address.clone(); + let acc3_addr = acc3.address.clone(); - let acc_balance = seq_acc_store.get_account_balance(&[6; 32]).unwrap(); + let seq_acc_store = SequencerAccountsStore::new(&[acc1, acc2, acc3]); + + assert!(seq_acc_store.contains_account(&acc1_addr)); + assert!(seq_acc_store.contains_account(&acc2_addr)); + assert!(seq_acc_store.contains_account(&acc3_addr)); + + let acc_balance = seq_acc_store.get_account_balance(&[6; 32]); assert_eq!(acc_balance, 120); - let acc_balance = seq_acc_store.get_account_balance(&[7; 32]).unwrap(); + let acc_balance = seq_acc_store.get_account_balance(&[7; 32]); assert_eq!(acc_balance, 15); - let acc_balance = seq_acc_store.get_account_balance(&[8; 32]).unwrap(); + let acc_balance = seq_acc_store.get_account_balance(&[8; 32]); assert_eq!(acc_balance, 10); } #[test] fn account_sequencer_store_fetch_unknown_account() { - let seq_acc_store = - SequencerAccountsStore::new(&[([6; 32], 120), ([7; 32], 15), ([8; 32], 10)]); + let acc1 = Account::new_with_balance(120); + let acc2 = Account::new_with_balance(15); + let acc3 = Account::new_with_balance(10); + + let seq_acc_store = SequencerAccountsStore::new(&[acc1, acc2, acc3]); let acc_balance = seq_acc_store.get_account_balance(&[9; 32]); - assert!(acc_balance.is_none()); + assert_eq!(acc_balance, 0); } } diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs index daffc91..7748475 100644 --- a/sequencer_core/src/sequencer_store/mod.rs +++ b/sequencer_core/src/sequencer_store/mod.rs @@ -1,5 +1,6 @@ use std::{collections::HashSet, path::Path}; +use accounts::account_core::Account; use accounts_store::SequencerAccountsStore; use block_store::SequecerBlockStore; use common::{ @@ -20,6 +21,8 @@ pub struct SequecerChainStore { pub nullifier_store: HashSet, pub utxo_commitments_store: UTXOCommitmentsMerkleTree, pub pub_tx_store: PublicTransactionMerkleTree, + //ToDo: For testing purposes, remove after testnet + pub testnet_initial_accounts_full_data: Vec, } impl SequecerChainStore { @@ -29,22 +32,12 @@ impl SequecerChainStore { is_genesis_random: bool, initial_accounts: &[AccountInitialData], ) -> Self { - let acc_data_decoded: Vec<([u8; 32], u64)> = initial_accounts + let accs_pregenerated: Vec = initial_accounts .iter() - .map(|acc_data| { - ( - //ToDo: Handle this error for direct error message - //Failure to produce account address is critical, so error handling is needed only for clarity - hex::decode(acc_data.addr.clone()) - .unwrap() - .try_into() - .unwrap(), - acc_data.balance, - ) - }) + .map(|acc_data| Account::new_with_balance(acc_data.balance)) .collect(); - let acc_store = SequencerAccountsStore::new(&acc_data_decoded); + let acc_store = SequencerAccountsStore::new(&accs_pregenerated); let nullifier_store = HashSet::new(); let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]); let pub_tx_store = PublicTransactionMerkleTree::new(vec![]); @@ -81,6 +74,7 @@ impl SequecerChainStore { nullifier_store, utxo_commitments_store, pub_tx_store, + testnet_initial_accounts_full_data: accs_pregenerated, } } } diff --git a/sequencer_rpc/Cargo.toml b/sequencer_rpc/Cargo.toml index d3b2e4f..43eeb13 100644 --- a/sequencer_rpc/Cargo.toml +++ b/sequencer_rpc/Cargo.toml @@ -20,6 +20,9 @@ tokio.workspace = true [dependencies.mempool] path = "../mempool" +[dependencies.accounts] +path = "../accounts" + [dependencies.consensus] path = "../consensus" diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index f9acbfb..790a65c 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -1,3 +1,4 @@ +use accounts::account_core::AccountForSerialization; use actix_web::Error as HttpError; use serde_json::Value; @@ -5,6 +6,7 @@ use common::rpc_primitives::{ errors::RpcError, message::{Message, Request}, parser::RpcRequest, + requests::GetInitialTestnetAccountsRequest, }; use common::rpc_primitives::requests::{ @@ -26,6 +28,8 @@ pub const HELLO_FROM_SEQUENCER: &str = "HELLO_FROM_SEQUENCER"; pub const SUCCESS: &str = "Success"; +pub const GET_INITIAL_TESTNET_ACCOUNTS: &str = "get_initial_testnet_accounts"; + impl JsonHandler { pub async fn process(&self, message: Message) -> Result { let id = message.id(); @@ -131,6 +135,24 @@ impl JsonHandler { respond(helperstruct) } + async fn get_initial_testnet_accounts(&self, request: Request) -> Result { + let _get_initial_testnet_accounts_request = + GetInitialTestnetAccountsRequest::parse(Some(request.params))?; + + let accounts_for_serialization: Vec = { + let state = self.sequencer_state.lock().await; + + state + .store + .testnet_initial_accounts_full_data + .iter() + .map(|acc| acc.clone().into()) + .collect() + }; + + respond(accounts_for_serialization) + } + pub async fn process_request_internal(&self, request: Request) -> Result { match request.method.as_ref() { HELLO => self.process_temp_hello(request).await, @@ -139,6 +161,7 @@ impl JsonHandler { GET_BLOCK => self.process_get_block_data(request).await, GET_GENESIS => self.process_get_genesis(request).await, GET_LAST_BLOCK => self.process_get_last_block(request).await, + GET_INITIAL_TESTNET_ACCOUNTS => self.get_initial_testnet_accounts(request).await, _ => Err(RpcErr(RpcError::method_not_found(request.method))), } } diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 18d1b72..1f121ef 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -8,11 +8,9 @@ "port": 3040, "initial_accounts": [ { - "addr": "bfd91e6703273a115ad7f099ef32f621243be69369d00ddef5d3a25117d09a8c", "balance": 10 }, { - "addr": "20573479053979b98d2ad09ef31a0750f22c77709bed51c4e64946bd1e376f31", "balance": 100 } ]