From 14b35a93c0f843e4b60258d46a082b9ae801d356 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Wed, 16 Jul 2025 12:31:47 +0300 Subject: [PATCH 01/13] feat: new public transaction kind --- common/src/lib.rs | 1 + common/src/public_transfer_receipts.rs | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 common/src/public_transfer_receipts.rs diff --git a/common/src/lib.rs b/common/src/lib.rs index 46868d9..0a911f5 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -5,6 +5,7 @@ pub mod block; pub mod commitment; pub mod merkle_tree_public; pub mod nullifier; +pub mod public_transfer_receipts; pub mod rpc_primitives; pub mod transaction; pub mod utxo_commitment; diff --git a/common/src/public_transfer_receipts.rs b/common/src/public_transfer_receipts.rs new file mode 100644 index 0000000..c865a03 --- /dev/null +++ b/common/src/public_transfer_receipts.rs @@ -0,0 +1,10 @@ +use serde::{Deserialize, Serialize}; + +use crate::merkle_tree_public::TreeHashType; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct PublicNativeTokenSend { + pub from: TreeHashType, + pub to: TreeHashType, + pub moved_balance: u64, +} From 9097762a530aa86ff5f656147c528d16321962b6 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Thu, 17 Jul 2025 11:47:38 +0300 Subject: [PATCH 02/13] feat: node side of public native token transfer 1 --- node_core/src/chain_storage/mod.rs | 15 ++++++++++ node_core/src/lib.rs | 48 +++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index f6b1343..481cba8 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -7,6 +7,7 @@ use common::{ block::Block, merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, nullifier::UTXONullifier, + public_transfer_receipts::PublicNativeTokenSend, utxo_commitment::UTXOCommitment, }; use k256::AffinePoint; @@ -158,6 +159,20 @@ impl NodeChainStore { } _ => {} } + } else { + let native_transfer = + serde_json::from_slice::(&tx.execution_input); + + if let Ok(transfer) = native_transfer { + if let Some(acc_sender) = self.acc_map.get_mut(&transfer.from) { + //Can panic, we depend on sequencer maintaining chain consistency here + acc_sender.balance -= transfer.moved_balance; + + if let Some(acc_rec) = self.acc_map.get_mut(&transfer.to) { + acc_rec.balance += transfer.moved_balance; + } + } + } } } diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 49f1285..4c36260 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -3,7 +3,7 @@ use std::sync::{ Arc, }; -use common::ExecutionFailureKind; +use common::{public_transfer_receipts::PublicNativeTokenSend, ExecutionFailureKind}; use accounts::account_core::{Account, AccountAddress}; use anyhow::Result; @@ -943,6 +943,52 @@ impl NodeCore { Ok(self.sequencer_client.send_tx(tx, tx_roots).await?) } + pub async fn send_public_native_token_transfer( + &self, + from: AccountAddress, + to: AccountAddress, + moved_balance: u64, + ) -> Result { + let tx_roots = self.get_roots().await; + + let public_context = { + let read_guard = self.storage.read().await; + + read_guard.produce_context(from) + }; + + let (tweak, secret_r, commitment) = pedersen_commitment_vec( + //Will not panic, as public context is serializable + public_context.produce_u64_list_from_context().unwrap(), + ); + + let sc_addr = hex::encode([0; 32]); + + //Native does not change its state + let state_changes: Vec = vec![]; + let new_len = 0; + let state_changes = (serde_json::to_value(state_changes).unwrap(), new_len); + + let tx: Transaction = + sc_core::transaction_payloads_tools::create_public_transaction_payload( + serde_json::to_vec(&PublicNativeTokenSend { + from, + to, + moved_balance, + }) + .unwrap(), + commitment, + tweak, + secret_r, + sc_addr, + state_changes, + ) + .into(); + tx.log(); + + Ok(self.sequencer_client.send_tx(tx, tx_roots).await?) + } + pub async fn send_private_send_tx( &self, utxo: UTXO, From 9f8724ee4c66270fa9f8412faf6ef39cbc534128 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 22 Jul 2025 15:22:20 +0300 Subject: [PATCH 03/13] feat: native token transactions 2 --- node_core/src/chain_storage/mod.rs | 2 +- node_core/src/lib.rs | 25 ++++++++-- sequencer_core/src/lib.rs | 48 +++++++++++++++++++ .../src/sequencer_store/accounts_store.rs | 19 ++++++++ 4 files changed, 90 insertions(+), 4 deletions(-) diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index 84f4f11..e852672 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -161,7 +161,7 @@ impl NodeChainStore { } } else { let native_transfer = - serde_json::from_slice::(&tx.execution_input); + serde_json::from_slice::(&tx.body().execution_input); if let Ok(transfer) = native_transfer { if let Some(acc_sender) = self.acc_map.get_mut(&transfer.from) { diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 03334b7..71538bc 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -3,7 +3,9 @@ use std::sync::{ Arc, }; -use common::{transaction::Transaction, ExecutionFailureKind}; +use common::{ + public_transfer_receipts::PublicNativeTokenSend, transaction::Transaction, ExecutionFailureKind, +}; use accounts::{ account_core::{Account, AccountAddress}, @@ -977,7 +979,7 @@ impl NodeCore { let new_len = 0; let state_changes = (serde_json::to_value(state_changes).unwrap(), new_len); - let tx: Transaction = + let tx: TransactionBody = sc_core::transaction_payloads_tools::create_public_transaction_payload( serde_json::to_vec(&PublicNativeTokenSend { from, @@ -994,7 +996,24 @@ impl NodeCore { .into(); tx.log(); - Ok(self.sequencer_client.send_tx(tx, tx_roots).await?) + { + let read_guard = self.storage.read().await; + + let account = read_guard.acc_map.get(&from); + + if let Some(account) = account { + let key_to_sign_transaction = account.key_holder.get_pub_account_signing_key(); + + let signed_transaction = Transaction::new(tx, key_to_sign_transaction); + + Ok(self + .sequencer_client + .send_tx(signed_transaction, tx_roots) + .await?) + } else { + Err(ExecutionFailureKind::AmountMismatchError) + } + } } pub async fn send_private_send_tx( diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 40ff1a2..761d5a1 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -6,6 +6,7 @@ use common::{ block::{Block, HashableBlockData}, merkle_tree_public::TreeHashType, nullifier::UTXONullifier, + public_transfer_receipts::PublicNativeTokenSend, transaction::{AuthenticatedTransaction, Transaction, TransactionBody, TxKind}, utxo_commitment::UTXOCommitment, }; @@ -37,6 +38,9 @@ pub enum TransactionMalformationErrorKind { ChainStateFurtherThanTransactionState { tx: TreeHashType }, FailedToInsert { tx: TreeHashType, details: String }, InvalidSignature, + AccountNotFound { tx: TreeHashType, acc: TreeHashType }, + BalanceMismatch { tx: TreeHashType }, + FailedToDecode { tx: TreeHashType }, } impl Display for TransactionMalformationErrorKind { @@ -102,6 +106,50 @@ impl SequencerCore { ); } + //Balance check + if let Ok(native_transfer_action) = + serde_json::from_slice::(&execution_input) + { + if let Some(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, + }); + } + } else { + return Err(TransactionMalformationErrorKind::AccountNotFound { + tx: tx_hash, + acc: native_transfer_action.from, + }); + } + } else { + return Err(TransactionMalformationErrorKind::FailedToDecode { tx: tx_hash }); + } + //Sanity check match tx_kind { TxKind::Public => { diff --git a/sequencer_core/src/sequencer_store/accounts_store.rs b/sequencer_core/src/sequencer_store/accounts_store.rs index 853247f..48cd012 100644 --- a/sequencer_core/src/sequencer_store/accounts_store.rs +++ b/sequencer_core/src/sequencer_store/accounts_store.rs @@ -61,6 +61,25 @@ impl SequencerAccountsStore { self.accounts.get(account_addr).map(|acc| acc.balance) } + ///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 { + let acc_data = self.accounts.get_mut(account_addr); + + acc_data.map(|data| { + let old_bal = data.balance; + + data.balance = new_balance; + + old_bal + }) + } + ///Remove account from storage /// /// Fails, if `balance` is != 0 From 5b2af29efd6dbf6fd053e352786b4dbc1e35cfae Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Wed, 23 Jul 2025 15:16:53 +0300 Subject: [PATCH 04/13] 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 } ] From 95fec478976c33d216700265588453f84dfb295d Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Thu, 24 Jul 2025 09:14:38 +0300 Subject: [PATCH 05/13] fix: merge lint test fixes --- common/src/rpc_primitives/requests.rs | 2 + node_core/src/lib.rs | 5 +- sequencer_core/src/lib.rs | 56 +++++++++---------- .../src/sequencer_store/accounts_store.rs | 18 +++--- sequencer_rpc/src/process.rs | 53 +++++++++++------- 5 files changed, 72 insertions(+), 62 deletions(-) diff --git a/common/src/rpc_primitives/requests.rs b/common/src/rpc_primitives/requests.rs index 9b62923..159c4f6 100644 --- a/common/src/rpc_primitives/requests.rs +++ b/common/src/rpc_primitives/requests.rs @@ -36,6 +36,8 @@ pub struct GetLastBlockRequest {} #[derive(Serialize, Deserialize, Debug)] pub struct GetInitialTestnetAccountsRequest {} + +#[derive(Serialize, Deserialize, Debug)] pub struct GetAccountBalanceRequest { pub address: String, } diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 7e4342a..456e409 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -972,7 +972,7 @@ impl NodeCore { let sc_addr = hex::encode([0; 32]); - //Native does not change its state + //Native contract does not change its state let state_changes: Vec = vec![]; let new_len = 0; let state_changes = (serde_json::to_value(state_changes).unwrap(), new_len); @@ -990,8 +990,7 @@ impl NodeCore { secret_r, sc_addr, state_changes, - ) - .into(); + ); tx.log(); { diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 8307f04..d99a782 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -111,35 +111,6 @@ impl SequencerCore { ); } - //Balance check - if let Ok(native_transfer_action) = - serde_json::from_slice::(&execution_input) - { - let from_balance = self - .store - .acc_store - .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::BalanceMismatch { tx: tx_hash }); - } - } else { - return Err(TransactionMalformationErrorKind::FailedToDecode { tx: tx_hash }); - } - //Sanity check match tx_kind { TxKind::Public => { @@ -206,6 +177,33 @@ impl SequencerCore { ); } + //Balance check + if let Ok(native_transfer_action) = + serde_json::from_slice::(execution_input) + { + let from_balance = self + .store + .acc_store + .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::BalanceMismatch { tx: tx_hash }); + } + } + Ok(tx) } diff --git a/sequencer_core/src/sequencer_store/accounts_store.rs b/sequencer_core/src/sequencer_store/accounts_store.rs index 6f09eaa..f44b5fe 100644 --- a/sequencer_core/src/sequencer_store/accounts_store.rs +++ b/sequencer_core/src/sequencer_store/accounts_store.rs @@ -170,7 +170,7 @@ mod tests { let acc1 = Account::new_with_balance(12); let acc2 = Account::new_with_balance(100); - let acc1_addr = acc1.address.clone(); + let acc1_addr = acc1.address; let mut seq_acc_store = SequencerAccountsStore::new(&[acc1, acc2]); @@ -197,8 +197,8 @@ mod tests { let acc1 = Account::new_with_balance(12); let acc2 = Account::new_with_balance(100); - let acc1_addr = acc1.address.clone(); - let acc2_addr = acc2.address.clone(); + let acc1_addr = acc1.address; + let acc2_addr = acc2.address; let seq_acc_store = SequencerAccountsStore::new(&[acc1, acc2]); @@ -220,9 +220,9 @@ mod tests { let acc2 = Account::new_with_balance(15); let acc3 = Account::new_with_balance(10); - let acc1_addr = acc1.address.clone(); - let acc2_addr = acc2.address.clone(); - let acc3_addr = acc3.address.clone(); + let acc1_addr = acc1.address; + let acc2_addr = acc2.address; + let acc3_addr = acc3.address; let seq_acc_store = SequencerAccountsStore::new(&[acc1, acc2, acc3]); @@ -230,15 +230,15 @@ mod tests { 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]); + let acc_balance = seq_acc_store.get_account_balance(&acc1_addr); assert_eq!(acc_balance, 120); - let acc_balance = seq_acc_store.get_account_balance(&[7; 32]); + let acc_balance = seq_acc_store.get_account_balance(&acc2_addr); assert_eq!(acc_balance, 15); - let acc_balance = seq_acc_store.get_account_balance(&[8; 32]); + let acc_balance = seq_acc_store.get_account_balance(&acc3_addr); assert_eq!(acc_balance, 10); } diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index a867b2f..4375f9c 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -137,6 +137,8 @@ impl JsonHandler { respond(helperstruct) } + /// Returns the initial accounts for testnet + /// ToDo: Useful only for testnet and needs to be removed later async fn get_initial_testnet_accounts(&self, request: Request) -> Result { let _get_initial_testnet_accounts_request = GetInitialTestnetAccountsRequest::parse(Some(request.params))?; @@ -153,6 +155,8 @@ impl JsonHandler { }; respond(accounts_for_serialization) + } + /// Returns the balance of the account at the given address. /// The address must be a valid hex string of the correct length. async fn process_get_account_balance(&self, request: Request) -> Result { @@ -165,8 +169,7 @@ impl JsonHandler { let balance = { let state = self.sequencer_state.lock().await; state.store.acc_store.get_account_balance(&address) - } - .unwrap_or(0); + }; let helperstruct = GetAccountBalanceResponse { balance }; @@ -193,6 +196,7 @@ mod tests { use std::sync::Arc; use crate::{rpc_handler, JsonHandler}; + use accounts::account_core::Account; use common::rpc_primitives::RpcPollingConfig; use sequencer_core::{ config::{AccountInitialData, SequencerConfig}, @@ -206,14 +210,8 @@ mod tests { let tempdir = tempdir().unwrap(); let home = tempdir.path().to_path_buf(); let initial_accounts = vec![ - AccountInitialData { - addr: "cafe".repeat(16).to_string(), - balance: 100, - }, - AccountInitialData { - addr: "feca".repeat(16).to_string(), - balance: 200, - }, + AccountInitialData { balance: 100 }, + AccountInitialData { balance: 200 }, ]; SequencerConfig { @@ -228,14 +226,24 @@ mod tests { } } - fn json_handler_for_tests() -> JsonHandler { + fn json_handler_for_tests() -> (JsonHandler, Vec) { let config = sequencer_config_for_tests(); - let sequencer_core = Arc::new(Mutex::new(SequencerCore::start_from_config(config))); - JsonHandler { - polling_config: RpcPollingConfig::default(), - sequencer_state: sequencer_core, - } + let sequencer_core = SequencerCore::start_from_config(config); + let initial_accounts = sequencer_core + .store + .testnet_initial_accounts_full_data + .clone(); + + let sequencer_core = Arc::new(Mutex::new(sequencer_core)); + + ( + JsonHandler { + polling_config: RpcPollingConfig::default(), + sequencer_state: sequencer_core, + }, + initial_accounts, + ) } async fn call_rpc_handler_with_json(handler: JsonHandler, request_json: Value) -> Value { @@ -261,7 +269,7 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_non_existent_account() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", @@ -283,7 +291,7 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_invalid_hex() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", @@ -306,7 +314,7 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_invalid_length() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", @@ -329,11 +337,14 @@ mod tests { #[actix_web::test] async fn test_get_account_balance_for_existing_account() { - let json_handler = json_handler_for_tests(); + let (json_handler, initial_accounts) = json_handler_for_tests(); + + let acc1_addr = hex::encode(initial_accounts[0].address); + let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_account_balance", - "params": { "address": "cafe".repeat(16) }, + "params": { "address": acc1_addr }, "id": 1 }); let expected_response = serde_json::json!({ From 41b65521f9d293f9d3d8937b3efb62ae65c8f4ac Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Thu, 24 Jul 2025 16:05:27 +0300 Subject: [PATCH 06/13] fix: comments fix 1 --- ...ransfer_receipts.rs => execution_input.rs} | 2 +- common/src/lib.rs | 2 +- node_core/src/chain_storage/mod.rs | 6 +- node_core/src/lib.rs | 6 +- sequencer_core/src/lib.rs | 59 ++++++++++--------- .../src/sequencer_store/accounts_store.rs | 6 +- 6 files changed, 42 insertions(+), 39 deletions(-) rename common/src/{public_transfer_receipts.rs => execution_input.rs} (88%) diff --git a/common/src/public_transfer_receipts.rs b/common/src/execution_input.rs similarity index 88% rename from common/src/public_transfer_receipts.rs rename to common/src/execution_input.rs index c865a03..d1f282a 100644 --- a/common/src/public_transfer_receipts.rs +++ b/common/src/execution_input.rs @@ -6,5 +6,5 @@ use crate::merkle_tree_public::TreeHashType; pub struct PublicNativeTokenSend { pub from: TreeHashType, pub to: TreeHashType, - pub moved_balance: u64, + pub balance_to_move: u64, } diff --git a/common/src/lib.rs b/common/src/lib.rs index fb364c7..1722218 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -3,9 +3,9 @@ use serde::Deserialize; pub mod block; pub mod commitment; +pub mod execution_input; pub mod merkle_tree_public; pub mod nullifier; -pub mod public_transfer_receipts; pub mod rpc_primitives; pub mod transaction; pub mod utxo_commitment; diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index 5fac66c..126574f 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -5,9 +5,9 @@ use anyhow::Result; use block_store::NodeBlockStore; use common::{ block::Block, + execution_input::PublicNativeTokenSend, merkle_tree_public::merkle_tree::{PublicTransactionMerkleTree, UTXOCommitmentsMerkleTree}, nullifier::UTXONullifier, - public_transfer_receipts::PublicNativeTokenSend, utxo_commitment::UTXOCommitment, }; use k256::AffinePoint; @@ -166,10 +166,10 @@ impl NodeChainStore { if let Ok(transfer) = native_transfer { if let Some(acc_sender) = self.acc_map.get_mut(&transfer.from) { //Can panic, we depend on sequencer maintaining chain consistency here - acc_sender.balance -= transfer.moved_balance; + acc_sender.balance -= transfer.balance_to_move; if let Some(acc_rec) = self.acc_map.get_mut(&transfer.to) { - acc_rec.balance += transfer.moved_balance; + acc_rec.balance += transfer.balance_to_move; } } } diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index 456e409..b914bcf 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -4,7 +4,7 @@ use std::sync::{ }; use common::{ - public_transfer_receipts::PublicNativeTokenSend, transaction::Transaction, ExecutionFailureKind, + execution_input::PublicNativeTokenSend, transaction::Transaction, ExecutionFailureKind, }; use accounts::{ @@ -955,7 +955,7 @@ impl NodeCore { &self, from: AccountAddress, to: AccountAddress, - moved_balance: u64, + balance_to_move: u64, ) -> Result { let tx_roots = self.get_roots().await; @@ -982,7 +982,7 @@ impl NodeCore { serde_json::to_vec(&PublicNativeTokenSend { from, to, - moved_balance, + balance_to_move, }) .unwrap(), commitment, diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index d99a782..d22841a 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -4,9 +4,9 @@ use accounts::account_core::AccountAddress; use anyhow::Result; use common::{ block::{Block, HashableBlockData}, + execution_input::PublicNativeTokenSend, merkle_tree_public::TreeHashType, nullifier::UTXONullifier, - public_transfer_receipts::PublicNativeTokenSend, transaction::{AuthenticatedTransaction, Transaction, TransactionBody, TxKind}, utxo_commitment::UTXOCommitment, }; @@ -177,33 +177,6 @@ impl SequencerCore { ); } - //Balance check - if let Ok(native_transfer_action) = - serde_json::from_slice::(execution_input) - { - let from_balance = self - .store - .acc_store - .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::BalanceMismatch { tx: tx_hash }); - } - } - Ok(tx) } @@ -233,9 +206,12 @@ impl SequencerCore { let TransactionBody { ref utxo_commitments_created_hashes, ref nullifier_created_hashes, + execution_input, .. } = mempool_tx.auth_tx.transaction().body(); + let tx_hash = *mempool_tx.auth_tx.hash(); + for utxo_comm in utxo_commitments_created_hashes { self.store .utxo_commitments_store @@ -252,6 +228,33 @@ impl SequencerCore { .pub_tx_store .add_tx(mempool_tx.auth_tx.transaction()); + //Balance check + if let Ok(native_transfer_action) = + serde_json::from_slice::(execution_input) + { + let from_balance = self + .store + .acc_store + .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.balance_to_move { + self.store.acc_store.set_account_balance( + &native_transfer_action.from, + from_balance - native_transfer_action.balance_to_move, + ); + self.store.acc_store.set_account_balance( + &native_transfer_action.to, + to_balance + native_transfer_action.balance_to_move, + ); + } else { + return Err(TransactionMalformationErrorKind::BalanceMismatch { tx: tx_hash }); + } + } + Ok(()) } diff --git a/sequencer_core/src/sequencer_store/accounts_store.rs b/sequencer_core/src/sequencer_store/accounts_store.rs index f44b5fe..ae27302 100644 --- a/sequencer_core/src/sequencer_store/accounts_store.rs +++ b/sequencer_core/src/sequencer_store/accounts_store.rs @@ -66,17 +66,17 @@ impl SequencerAccountsStore { ///Update `account_addr` balance, /// - /// returns 0, if account address not found, othervise returns previous balance + /// returns 0, if account address not found, otherwise 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; + let old_balance = data.balance; data.balance = new_balance; - old_bal + old_balance }) .unwrap_or(0) } From 494ff2ac71e95c6f85b1f99799ea407b697cb8d8 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Thu, 24 Jul 2025 17:31:53 +0300 Subject: [PATCH 07/13] fix: ToDo doc --- node_core/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/node_core/src/lib.rs b/node_core/src/lib.rs index b914bcf..a8ca0b9 100644 --- a/node_core/src/lib.rs +++ b/node_core/src/lib.rs @@ -951,6 +951,8 @@ impl NodeCore { // Ok(self.sequencer_client.send_tx(tx, tx_roots).await?) // } + // ToDo: Currently untested due to need for end-to-end integration tests. + // Add integration tests to cover this functionality pub async fn send_public_native_token_transfer( &self, from: AccountAddress, From d232cecbb0eda3465704fb9c179409488660039a Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Fri, 25 Jul 2025 10:00:27 +0300 Subject: [PATCH 08/13] fix: comments fix 2 --- Cargo.lock | 16 + Cargo.toml | 1 + common/src/transaction.rs | 4 +- sequencer_core/Cargo.toml | 1 + sequencer_core/src/config.rs | 13 +- sequencer_core/src/lib.rs | 513 +++++++++++++++++- .../src/sequencer_store/accounts_store.rs | 65 +-- sequencer_core/src/sequencer_store/mod.rs | 13 +- sequencer_rpc/src/process.rs | 261 ++++++++- .../configs/debug/sequencer_config.json | 232 +++++++- 10 files changed, 1020 insertions(+), 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9bca0c7..c3e27f2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1141,6 +1141,12 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + [[package]] name = "crypto-bigint" version = "0.5.5" @@ -4371,6 +4377,7 @@ dependencies = [ "serde", "serde_json", "storage", + "tiny-keccak", ] [[package]] @@ -4859,6 +4866,15 @@ dependencies = [ "time-core", ] +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + [[package]] name = "tinystr" version = "0.8.1" diff --git a/Cargo.toml b/Cargo.toml index f2bcab8..daaeeaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ tempfile = "3.14.0" light-poseidon = "0.3.0" ark-bn254 = "0.5.0" ark-ff = "0.5.0" +tiny-keccak = { version = "2.0.2", features = ["keccak"]} rocksdb = { version = "0.21.0", default-features = false, features = [ "snappy", diff --git a/common/src/transaction.rs b/common/src/transaction.rs index 26dc670..78e1930 100644 --- a/common/src/transaction.rs +++ b/common/src/transaction.rs @@ -235,8 +235,8 @@ pub type SignaturePrivateKey = SigningKey; #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] pub struct Transaction { body: TransactionBody, - signature: TransactionSignature, - public_key: VerifyingKey, + pub signature: TransactionSignature, + pub public_key: VerifyingKey, } impl Transaction { diff --git a/sequencer_core/Cargo.toml b/sequencer_core/Cargo.toml index 14c047c..0c676e0 100644 --- a/sequencer_core/Cargo.toml +++ b/sequencer_core/Cargo.toml @@ -13,6 +13,7 @@ serde.workspace = true rand.workspace = true elliptic-curve.workspace = true k256.workspace = true +tiny-keccak.workspace = true [dependencies.storage] path = "../storage" diff --git a/sequencer_core/src/config.rs b/sequencer_core/src/config.rs index d7937d5..aa40351 100644 --- a/sequencer_core/src/config.rs +++ b/sequencer_core/src/config.rs @@ -1,15 +1,8 @@ +use accounts::account_core::AccountForSerialization; use serde::{Deserialize, Serialize}; use std::path::PathBuf; -// - -#[derive(Debug, Serialize, Deserialize, Clone)] -///Helperstruct for account serialization -pub struct AccountInitialData { - pub balance: u64, -} - -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] pub struct SequencerConfig { ///Home dir of sequencer storage pub home: PathBuf, @@ -26,5 +19,5 @@ pub struct SequencerConfig { ///Port to listen pub port: u16, ///List of initial accounts data - pub initial_accounts: Vec, + pub initial_accounts: Vec, } diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index d22841a..d3a108d 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -15,6 +15,7 @@ use mempool::MemPool; use mempool_transaction::MempoolTransaction; use sequencer_store::SequecerChainStore; use serde::{Deserialize, Serialize}; +use tiny_keccak::{Hasher, Keccak}; pub mod config; pub mod mempool_transaction; @@ -38,6 +39,7 @@ pub enum TransactionMalformationErrorKind { ChainStateFurtherThanTransactionState { tx: TreeHashType }, FailedToInsert { tx: TreeHashType, details: String }, InvalidSignature, + IncorrectSender, BalanceMismatch { tx: TreeHashType }, FailedToDecode { tx: TreeHashType }, } @@ -140,6 +142,20 @@ impl SequencerCore { _ => {} }; + //Correct sender check + if let Ok(native_transfer_action) = + serde_json::from_slice::(execution_input) + { + let mut output = [0; 32]; + let mut keccak_hasher = Keccak::v256(); + keccak_hasher.update(&tx.transaction().signature.to_bytes()); + keccak_hasher.finalize(&mut output); + + if native_transfer_action.from != output { + return Err(TransactionMalformationErrorKind::IncorrectSender); + } + } + //Tree checks let tx_tree_check = self.store.pub_tx_store.get_tx(tx_hash).is_some(); let nullifier_tree_check = nullifier_created_hashes.iter().any(|nullifier_hash| { @@ -303,18 +319,17 @@ impl SequencerCore { #[cfg(test)] mod tests { - use crate::config::AccountInitialData; - use super::*; use std::path::PathBuf; + use accounts::account_core::AccountForSerialization; use common::transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind}; use mempool_transaction::MempoolTransaction; use rand::Rng; use secp256k1_zkp::Tweak; fn setup_sequencer_config_variable_initial_accounts( - initial_accounts: Vec, + initial_accounts: Vec, ) -> SequencerConfig { let mut rng = rand::thread_rng(); let random_u8: u8 = rng.gen(); @@ -334,10 +349,243 @@ mod tests { } fn setup_sequencer_config() -> SequencerConfig { - let initial_accounts = vec![ - AccountInitialData { balance: 10 }, - AccountInitialData { balance: 100 }, - ]; + let initial_acc1 = serde_json::from_str(r#"{ + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "balance": 10, + "key_holder": { + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", + "pub_account_signing_key": [ + 244, + 88, + 134, + 61, + 35, + 209, + 229, + 101, + 85, + 35, + 140, + 140, + 192, + 226, + 83, + 83, + 190, + 189, + 110, + 8, + 89, + 127, + 147, + 142, + 157, + 204, + 51, + 109, + 189, + 92, + 144, + 68 + ], + "top_secret_key_holder": { + "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", + "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" + }, + "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" + }, + "utxos": {} + }"#).unwrap(); + + let initial_acc2 = serde_json::from_str(r#"{ + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "balance": 100, + "key_holder": { + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", + "pub_account_signing_key": [ + 136, + 105, + 9, + 53, + 180, + 145, + 64, + 5, + 235, + 174, + 62, + 211, + 206, + 116, + 185, + 24, + 214, + 62, + 244, + 64, + 224, + 59, + 120, + 150, + 30, + 249, + 160, + 46, + 189, + 254, + 47, + 244 + ], + "top_secret_key_holder": { + "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", + "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" + }, + "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" + }, + "utxos": {} + }"#).unwrap(); + + let initial_accounts = vec![initial_acc1, initial_acc2]; setup_sequencer_config_variable_initial_accounts(initial_accounts) } @@ -389,8 +637,8 @@ mod tests { assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); assert_eq!(sequencer.sequencer_config.port, 8080); - let acc1_addr = sequencer.store.testnet_initial_accounts_full_data[0].address; - let acc2_addr = sequencer.store.testnet_initial_accounts_full_data[1].address; + let acc1_addr = config.initial_accounts[0].address; + let acc2_addr = config.initial_accounts[1].address; assert!(sequencer.store.acc_store.contains_account(&acc1_addr)); assert!(sequencer.store.acc_store.contains_account(&acc2_addr)); @@ -406,19 +654,252 @@ mod tests { } #[test] - fn test_start_different_intial_accounts() { - let initial_accounts = vec![ - AccountInitialData { balance: 1000 }, - AccountInitialData { balance: 1000 }, - ]; + fn test_start_different_intial_accounts_balances() { + let initial_acc1 = serde_json::from_str(r#"{ + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "balance": 1000, + "key_holder": { + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", + "pub_account_signing_key": [ + 244, + 88, + 134, + 61, + 35, + 209, + 229, + 101, + 85, + 35, + 140, + 140, + 192, + 226, + 83, + 83, + 190, + 189, + 110, + 8, + 89, + 127, + 147, + 142, + 157, + 204, + 51, + 109, + 189, + 92, + 144, + 68 + ], + "top_secret_key_holder": { + "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", + "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" + }, + "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" + }, + "utxos": {} + }"#).unwrap(); + + let initial_acc2 = serde_json::from_str(r#"{ + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "balance": 1000, + "key_holder": { + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", + "pub_account_signing_key": [ + 136, + 105, + 9, + 53, + 180, + 145, + 64, + 5, + 235, + 174, + 62, + 211, + 206, + 116, + 185, + 24, + 214, + 62, + 244, + 64, + 224, + 59, + 120, + 150, + 30, + 249, + 160, + 46, + 189, + 254, + 47, + 244 + ], + "top_secret_key_holder": { + "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", + "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" + }, + "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" + }, + "utxos": {} + }"#).unwrap(); + + let initial_accounts = vec![initial_acc1, initial_acc2]; let intial_accounts_len = initial_accounts.len(); let config = setup_sequencer_config_variable_initial_accounts(initial_accounts); let sequencer = SequencerCore::start_from_config(config.clone()); - let acc1_addr = sequencer.store.testnet_initial_accounts_full_data[0].address; - let acc2_addr = sequencer.store.testnet_initial_accounts_full_data[1].address; + let acc1_addr = config.initial_accounts[0].address; + let acc2_addr = config.initial_accounts[1].address; assert!(sequencer.store.acc_store.contains_account(&acc1_addr)); assert!(sequencer.store.acc_store.contains_account(&acc2_addr)); diff --git a/sequencer_core/src/sequencer_store/accounts_store.rs b/sequencer_core/src/sequencer_store/accounts_store.rs index ae27302..3944d03 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::{Account, AccountAddress}; +use accounts::account_core::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: &[Account]) -> Self { + pub fn new(initial_accounts: &[(AccountAddress, u64)]) -> Self { let mut accounts = HashMap::new(); - for account in initial_accounts { + for (account_addr, balance) in initial_accounts { accounts.insert( - account.address, - AccountPublicData::new_with_balance(account.address, account.balance), + *account_addr, + AccountPublicData::new_with_balance(*account_addr, *balance), ); } @@ -167,14 +167,9 @@ mod tests { #[test] fn account_sequencer_store_unregister_acc_not_zero_balance() { - let acc1 = Account::new_with_balance(12); - let acc2 = Account::new_with_balance(100); + let mut seq_acc_store = SequencerAccountsStore::new(&[([1; 32], 12), ([2; 32], 100)]); - let acc1_addr = acc1.address; - - let mut seq_acc_store = SequencerAccountsStore::new(&[acc1, acc2]); - - let rem_res = seq_acc_store.unregister_account(acc1_addr); + let rem_res = seq_acc_store.unregister_account([1; 32]); assert!(rem_res.is_err()); } @@ -194,62 +189,46 @@ mod tests { #[test] fn account_sequencer_store_with_preset_accounts_1() { - let acc1 = Account::new_with_balance(12); - let acc2 = Account::new_with_balance(100); + let seq_acc_store = SequencerAccountsStore::new(&[([1; 32], 12), ([2; 32], 100)]); - let acc1_addr = acc1.address; - let acc2_addr = acc2.address; + assert!(seq_acc_store.contains_account(&[1; 32])); + assert!(seq_acc_store.contains_account(&[2; 32])); - 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); + let acc_balance = seq_acc_store.get_account_balance(&[1; 32]); assert_eq!(acc_balance, 12); - let acc_balance = seq_acc_store.get_account_balance(&acc2_addr); + let acc_balance = seq_acc_store.get_account_balance(&[2; 32]); assert_eq!(acc_balance, 100); } #[test] fn account_sequencer_store_with_preset_accounts_2() { - 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(&[([6; 32], 120), ([7; 32], 15), ([8; 32], 10)]); - let acc1_addr = acc1.address; - let acc2_addr = acc2.address; - let acc3_addr = acc3.address; + 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 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(&acc1_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(&acc2_addr); + 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(&acc3_addr); + 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 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 seq_acc_store = + SequencerAccountsStore::new(&[([6; 32], 120), ([7; 32], 15), ([8; 32], 10)]); let acc_balance = seq_acc_store.get_account_balance(&[9; 32]); diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs index 7748475..3a74fb3 100644 --- a/sequencer_core/src/sequencer_store/mod.rs +++ b/sequencer_core/src/sequencer_store/mod.rs @@ -1,6 +1,6 @@ use std::{collections::HashSet, path::Path}; -use accounts::account_core::Account; +use accounts::account_core::AccountForSerialization; use accounts_store::SequencerAccountsStore; use block_store::SequecerBlockStore; use common::{ @@ -10,8 +10,6 @@ use common::{ }; use rand::{rngs::OsRng, RngCore}; -use crate::config::AccountInitialData; - pub mod accounts_store; pub mod block_store; @@ -21,8 +19,6 @@ 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 { @@ -30,11 +26,11 @@ impl SequecerChainStore { home_dir: &Path, genesis_id: u64, is_genesis_random: bool, - initial_accounts: &[AccountInitialData], + initial_accounts: &[AccountForSerialization], ) -> Self { - let accs_pregenerated: Vec = initial_accounts + let accs_pregenerated: Vec<_> = initial_accounts .iter() - .map(|acc_data| Account::new_with_balance(acc_data.balance)) + .map(|acc| (acc.address, acc.balance)) .collect(); let acc_store = SequencerAccountsStore::new(&accs_pregenerated); @@ -74,7 +70,6 @@ impl SequecerChainStore { nullifier_store, utxo_commitments_store, pub_tx_store, - testnet_initial_accounts_full_data: accs_pregenerated, } } } diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 4375f9c..b1237ad 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -146,12 +146,7 @@ impl JsonHandler { 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() + state.sequencer_config.initial_accounts.clone() }; respond(accounts_for_serialization) @@ -198,10 +193,7 @@ mod tests { use crate::{rpc_handler, JsonHandler}; use accounts::account_core::Account; use common::rpc_primitives::RpcPollingConfig; - use sequencer_core::{ - config::{AccountInitialData, SequencerConfig}, - SequencerCore, - }; + use sequencer_core::{config::SequencerConfig, SequencerCore}; use serde_json::Value; use tempfile::tempdir; use tokio::sync::Mutex; @@ -209,10 +201,243 @@ mod tests { fn sequencer_config_for_tests() -> SequencerConfig { let tempdir = tempdir().unwrap(); let home = tempdir.path().to_path_buf(); - let initial_accounts = vec![ - AccountInitialData { balance: 100 }, - AccountInitialData { balance: 200 }, - ]; + let initial_acc1 = serde_json::from_str(r#"{ + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "balance": 100, + "key_holder": { + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", + "pub_account_signing_key": [ + 244, + 88, + 134, + 61, + 35, + 209, + 229, + 101, + 85, + 35, + 140, + 140, + 192, + 226, + 83, + 83, + 190, + 189, + 110, + 8, + 89, + 127, + 147, + 142, + 157, + 204, + 51, + 109, + 189, + 92, + 144, + 68 + ], + "top_secret_key_holder": { + "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", + "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" + }, + "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" + }, + "utxos": {} + }"#).unwrap(); + + let initial_acc2 = serde_json::from_str(r#"{ + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "balance": 200, + "key_holder": { + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", + "pub_account_signing_key": [ + 136, + 105, + 9, + 53, + 180, + 145, + 64, + 5, + 235, + 174, + 62, + 211, + 206, + 116, + 185, + 24, + 214, + 62, + 244, + 64, + 224, + 59, + 120, + 150, + 30, + 249, + 160, + 46, + 189, + 254, + 47, + 244 + ], + "top_secret_key_holder": { + "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", + "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" + }, + "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" + }, + "utxos": {} + }"#).unwrap(); + + let initial_accounts = vec![initial_acc1, initial_acc2]; SequencerConfig { home, @@ -231,9 +456,11 @@ mod tests { let sequencer_core = SequencerCore::start_from_config(config); let initial_accounts = sequencer_core - .store - .testnet_initial_accounts_full_data - .clone(); + .sequencer_config + .initial_accounts + .iter() + .map(|acc_ser| acc_ser.clone().into()) + .collect(); let sequencer_core = Arc::new(Mutex::new(sequencer_core)); diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index 1f121ef..b707b85 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -8,10 +8,238 @@ "port": 3040, "initial_accounts": [ { - "balance": 10 + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "balance": 100, + "key_holder": { + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", + "pub_account_signing_key": [ + 244, + 88, + 134, + 61, + 35, + 209, + 229, + 101, + 85, + 35, + 140, + 140, + 192, + 226, + 83, + 83, + 190, + 189, + 110, + 8, + 89, + 127, + 147, + 142, + 157, + 204, + 51, + 109, + 189, + 92, + 144, + 68 + ], + "top_secret_key_holder": { + "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", + "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" + }, + "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" + }, + "utxos": {} }, { - "balance": 100 + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "balance": 1000, + "key_holder": { + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", + "pub_account_signing_key": [ + 136, + 105, + 9, + 53, + 180, + 145, + 64, + 5, + 235, + 174, + 62, + 211, + 206, + 116, + 185, + 24, + 214, + 62, + 244, + 64, + 224, + 59, + 120, + 150, + 30, + 249, + 160, + 46, + 189, + 254, + 47, + 244 + ], + "top_secret_key_holder": { + "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", + "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" + }, + "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" + }, + "utxos": {} } ] } \ No newline at end of file From 7695e8e46ed0c4543349a8e9242875803a269261 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Fri, 25 Jul 2025 10:09:34 +0300 Subject: [PATCH 09/13] fix: merge fix --- Cargo.lock | 2 +- sequencer_rpc/src/process.rs | 57 ++++++++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f810fd..b1d2f8a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4377,8 +4377,8 @@ dependencies = [ "serde", "serde_json", "storage", - "tiny-keccak", "tempfile", + "tiny-keccak", ] [[package]] diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 40283b6..41d2261 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -2,12 +2,17 @@ use accounts::account_core::AccountForSerialization; use actix_web::Error as HttpError; use serde_json::Value; -use common::rpc_primitives::{ - errors::RpcError, - message::{Message, Request}, - parser::RpcRequest, - requests::GetInitialTestnetAccountsRequest, - requests::{GetAccountBalanceRequest, GetAccountBalanceResponse}, +use common::{ + merkle_tree_public::TreeHashType, + rpc_primitives::{ + errors::RpcError, + message::{Message, Request}, + parser::RpcRequest, + requests::{ + GetAccountBalanceRequest, GetAccountBalanceResponse, GetInitialTestnetAccountsRequest, + GetTransactionByHashRequest, GetTransactionByHashResponse, + }, + }, }; use common::rpc_primitives::requests::{ @@ -213,7 +218,10 @@ mod tests { use crate::{rpc_handler, JsonHandler}; use accounts::account_core::Account; - use common::rpc_primitives::RpcPollingConfig; + use common::{ + rpc_primitives::RpcPollingConfig, + transaction::{SignaturePrivateKey, Transaction, TransactionBody}, + }; use sequencer_core::{config::SequencerConfig, SequencerCore}; use serde_json::Value; use tempfile::tempdir; @@ -475,7 +483,7 @@ mod tests { fn json_handler_for_tests() -> (JsonHandler, Vec) { let config = sequencer_config_for_tests(); - let sequencer_core = SequencerCore::start_from_config(config); + let mut sequencer_core = SequencerCore::start_from_config(config); let initial_accounts = sequencer_core .sequencer_config .initial_accounts @@ -483,6 +491,31 @@ mod tests { .map(|acc_ser| acc_ser.clone().into()) .collect(); + let tx_body = TransactionBody { + tx_kind: common::transaction::TxKind::Public, + execution_input: Default::default(), + execution_output: Default::default(), + utxo_commitments_spent_hashes: Default::default(), + utxo_commitments_created_hashes: Default::default(), + nullifier_created_hashes: Default::default(), + execution_proof_private: Default::default(), + encoded_data: Default::default(), + ephemeral_pub_key: Default::default(), + commitment: Default::default(), + tweak: Default::default(), + secret_r: Default::default(), + sc_addr: Default::default(), + state_changes: Default::default(), + }; + let tx = Transaction::new(tx_body, SignaturePrivateKey::from_slice(&[1; 32]).unwrap()); + + sequencer_core + .push_tx_into_mempool_pre_check(tx, [[0; 32]; 2]) + .unwrap(); + sequencer_core + .produce_new_block_with_mempool_transactions() + .unwrap(); + let sequencer_core = Arc::new(Mutex::new(sequencer_core)); ( @@ -610,7 +643,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_non_existent_hash() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_transaction_by_hash", @@ -632,7 +665,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_invalid_hex() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_transaction_by_hash", @@ -656,7 +689,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_invalid_length() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_transaction_by_hash", @@ -680,7 +713,7 @@ mod tests { #[actix_web::test] async fn test_get_transaction_by_hash_for_existing_transaction() { - let json_handler = json_handler_for_tests(); + let (json_handler, _) = json_handler_for_tests(); let request = serde_json::json!({ "jsonrpc": "2.0", "method": "get_transaction_by_hash", From e0b1ec165cdf7b0dcb62c503f29148dbce2a71e4 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Fri, 25 Jul 2025 10:46:32 +0300 Subject: [PATCH 10/13] fix: fmt commit --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index daaeeaf..a271e5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ tempfile = "3.14.0" light-poseidon = "0.3.0" ark-bn254 = "0.5.0" ark-ff = "0.5.0" -tiny-keccak = { version = "2.0.2", features = ["keccak"]} +tiny-keccak = { version = "2.0.2", features = ["keccak"] } rocksdb = { version = "0.21.0", default-features = false, features = [ "snappy", From c546af7865893c40fb74db495d775bf3e3ae6962 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Fri, 25 Jul 2025 19:46:23 +0300 Subject: [PATCH 11/13] fix: correct sender check fix --- sequencer_core/src/lib.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index d3a108d..87075d6 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -148,7 +148,7 @@ impl SequencerCore { { let mut output = [0; 32]; let mut keccak_hasher = Keccak::v256(); - keccak_hasher.update(&tx.transaction().signature.to_bytes()); + keccak_hasher.update(&tx.transaction().public_key.to_sec1_bytes()); keccak_hasher.finalize(&mut output); if native_transfer_action.from != output { @@ -228,22 +228,6 @@ impl SequencerCore { let tx_hash = *mempool_tx.auth_tx.hash(); - for utxo_comm in utxo_commitments_created_hashes { - self.store - .utxo_commitments_store - .add_tx(&UTXOCommitment { hash: *utxo_comm }); - } - - for nullifier in nullifier_created_hashes.iter() { - self.store.nullifier_store.insert(UTXONullifier { - utxo_hash: *nullifier, - }); - } - - self.store - .pub_tx_store - .add_tx(mempool_tx.auth_tx.transaction()); - //Balance check if let Ok(native_transfer_action) = serde_json::from_slice::(execution_input) @@ -271,6 +255,22 @@ impl SequencerCore { } } + for utxo_comm in utxo_commitments_created_hashes { + self.store + .utxo_commitments_store + .add_tx(&UTXOCommitment { hash: *utxo_comm }); + } + + for nullifier in nullifier_created_hashes.iter() { + self.store.nullifier_store.insert(UTXONullifier { + utxo_hash: *nullifier, + }); + } + + self.store + .pub_tx_store + .add_tx(mempool_tx.auth_tx.transaction()); + Ok(()) } From 5d7d6278eef1379ab69147cc93bc7062f2ebaf28 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 29 Jul 2025 14:20:03 +0300 Subject: [PATCH 12/13] fix: updates and tests --- Cargo.lock | 1 + accounts/Cargo.toml | 1 + accounts/src/account_core/mod.rs | 4 +- accounts/src/key_management/mod.rs | 48 +- accounts/src/key_management/secret_holders.rs | 12 - node_core/src/chain_storage/mod.rs | 243 ++++++ node_core/src/config.rs | 3 + node_runner/configs/debug/node_config.json | 238 +++++- sequencer_core/src/config.rs | 11 +- sequencer_core/src/lib.rs | 744 ++++++------------ .../src/sequencer_store/accounts_store.rs | 29 +- sequencer_core/src/sequencer_store/mod.rs | 19 +- sequencer_rpc/src/process.rs | 278 +------ .../configs/debug/sequencer_config.json | 235 +----- 14 files changed, 857 insertions(+), 1009 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b1d2f8a..ea0a22e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -19,6 +19,7 @@ dependencies = [ "serde", "serde_json", "sha2", + "tiny-keccak", "utxo", ] diff --git a/accounts/Cargo.toml b/accounts/Cargo.toml index 682d8ac..ffd500a 100644 --- a/accounts/Cargo.toml +++ b/accounts/Cargo.toml @@ -16,6 +16,7 @@ elliptic-curve.workspace = true hex.workspace = true aes-gcm.workspace = true lazy_static.workspace = true +tiny-keccak.workspace = true [dependencies.utxo] path = "../utxo" diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index b1b4a91..e698b49 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -16,7 +16,7 @@ use crate::key_management::{ pub type PublicKey = AffinePoint; pub type AccountAddress = TreeHashType; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Account { pub key_holder: AddressKeyHolder, pub address: AccountAddress, @@ -24,7 +24,7 @@ pub struct Account { pub utxos: HashMap, } -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, Debug)] pub struct AccountForSerialization { pub key_holder: AddressKeyHolder, pub address: AccountAddress, diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index 6fa1462..a5a3e4b 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -7,6 +7,7 @@ use log::info; use rand::{rngs::OsRng, RngCore}; use secret_holders::{SeedHolder, TopSecretKeyHolder, UTXOSecretKeyHolder}; use serde::{Deserialize, Serialize}; +use tiny_keccak::{Hasher, Keccak}; use crate::account_core::PublicKey; pub type PublicAccountSigningKey = [u8; 32]; @@ -15,7 +16,7 @@ pub mod constants_types; pub mod ephemeral_key_holder; pub mod secret_holders; -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, Debug)] ///Entrypoint to key management pub struct AddressKeyHolder { //Will be useful in future @@ -37,7 +38,6 @@ impl AddressKeyHolder { let utxo_secret_key_holder = top_secret_key_holder.produce_utxo_secret_holder(); - let address = utxo_secret_key_holder.generate_address(); let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key(); let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key(); @@ -47,6 +47,17 @@ impl AddressKeyHolder { bytes }; + //Address is a Keccak(verification_key) + let field_bytes = FieldBytes::from_slice(&pub_account_signing_key); + let signing_key = SigningKey::from_bytes(field_bytes).unwrap(); + + let verifying_key = signing_key.verifying_key(); + + let mut address = [0; 32]; + let mut keccak_hasher = Keccak::v256(); + keccak_hasher.update(&verifying_key.to_sec1_bytes()); + keccak_hasher.finalize(&mut address); + Self { top_secret_key_holder, utxo_secret_key_holder, @@ -332,6 +343,21 @@ mod tests { ); } + #[test] + fn test_address_key_equal_keccak_pub_sign_key() { + let address_key_holder = AddressKeyHolder::new_os_random(); + let signing_key = address_key_holder.get_pub_account_signing_key(); + + let verifying_key = signing_key.verifying_key(); + + let mut address = [0; 32]; + let mut keccak_hasher = Keccak::v256(); + keccak_hasher.update(&verifying_key.to_sec1_bytes()); + keccak_hasher.finalize(&mut address); + + assert_eq!(address, address_key_holder.address); + } + #[test] fn key_generation_test() { let seed_holder = SeedHolder::new_os_random(); @@ -339,10 +365,26 @@ mod tests { let utxo_secret_key_holder = top_secret_key_holder.produce_utxo_secret_holder(); - let address = utxo_secret_key_holder.generate_address(); let nullifer_public_key = utxo_secret_key_holder.generate_nullifier_public_key(); let viewing_public_key = utxo_secret_key_holder.generate_viewing_public_key(); + let pub_account_signing_key = { + let mut bytes = [0; 32]; + OsRng.fill_bytes(&mut bytes); + bytes + }; + + //Address is a Keccak(verification_key) + let field_bytes = FieldBytes::from_slice(&pub_account_signing_key); + let signing_key = SigningKey::from_bytes(field_bytes).unwrap(); + + let verifying_key = signing_key.verifying_key(); + + let mut address = [0; 32]; + let mut keccak_hasher = Keccak::v256(); + keccak_hasher.update(&verifying_key.to_sec1_bytes()); + keccak_hasher.finalize(&mut address); + println!("======Prerequisites======"); println!(); diff --git a/accounts/src/key_management/secret_holders.rs b/accounts/src/key_management/secret_holders.rs index 45fd792..47342ec 100644 --- a/accounts/src/key_management/secret_holders.rs +++ b/accounts/src/key_management/secret_holders.rs @@ -98,16 +98,4 @@ impl UTXOSecretKeyHolder { pub fn generate_viewing_public_key(&self) -> AffinePoint { (AffinePoint::GENERATOR * self.viewing_secret_key).into() } - - pub fn generate_address(&self) -> TreeHashType { - let npk = self.generate_nullifier_public_key(); - let vpk = self.generate_viewing_public_key(); - - let mut hasher = sha2::Sha256::new(); - - hasher.update(serde_json::to_vec(&npk).unwrap()); - hasher.update(serde_json::to_vec(&vpk).unwrap()); - - ::from(hasher.finalize_fixed()) - } } diff --git a/node_core/src/chain_storage/mod.rs b/node_core/src/chain_storage/mod.rs index 126574f..985014b 100644 --- a/node_core/src/chain_storage/mod.rs +++ b/node_core/src/chain_storage/mod.rs @@ -304,6 +304,248 @@ mod tests { use std::path::PathBuf; use tempfile::tempdir; + fn create_initial_accounts() -> Vec { + let initial_acc1 = serde_json::from_str(r#"{ + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "balance": 100, + "key_holder": { + "address": [ + 244, + 55, + 238, + 205, + 74, + 115, + 179, + 192, + 65, + 186, + 166, + 169, + 221, + 45, + 6, + 57, + 200, + 65, + 195, + 70, + 118, + 252, + 206, + 100, + 215, + 250, + 72, + 230, + 19, + 71, + 217, + 249 + ], + "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", + "pub_account_signing_key": [ + 244, + 88, + 134, + 61, + 35, + 209, + 229, + 101, + 85, + 35, + 140, + 140, + 192, + 226, + 83, + 83, + 190, + 189, + 110, + 8, + 89, + 127, + 147, + 142, + 157, + 204, + 51, + 109, + 189, + 92, + 144, + 68 + ], + "top_secret_key_holder": { + "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", + "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" + }, + "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" + }, + "utxos": {} + }"#).unwrap(); + + let initial_acc2 = serde_json::from_str(r#"{ + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "balance": 200, + "key_holder": { + "address": [ + 72, + 169, + 70, + 237, + 1, + 96, + 35, + 157, + 25, + 15, + 83, + 18, + 52, + 206, + 202, + 63, + 48, + 59, + 173, + 76, + 78, + 7, + 254, + 229, + 28, + 45, + 194, + 79, + 6, + 89, + 58, + 85 + ], + "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", + "pub_account_signing_key": [ + 136, + 105, + 9, + 53, + 180, + 145, + 64, + 5, + 235, + 174, + 62, + 211, + 206, + 116, + 185, + 24, + 214, + 62, + 244, + 64, + 224, + 59, + 120, + 150, + 30, + 249, + 160, + 46, + 189, + 254, + 47, + 244 + ], + "top_secret_key_holder": { + "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", + "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" + }, + "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" + }, + "utxos": {} + }"#).unwrap(); + + let initial_accounts = vec![initial_acc1, initial_acc2]; + + initial_accounts + } + fn create_genesis_block() -> Block { Block { block_id: 0, @@ -361,6 +603,7 @@ mod tests { port: 8000, gas_config: create_sample_gas_config(), shapshot_frequency_in_blocks: 1, + initial_accounts: create_initial_accounts(), } } diff --git a/node_core/src/config.rs b/node_core/src/config.rs index 935a803..e2ddf83 100644 --- a/node_core/src/config.rs +++ b/node_core/src/config.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; +use accounts::account_core::Account; use serde::{Deserialize, Serialize}; use zkvm::gas_calculator::GasCalculator; @@ -51,4 +52,6 @@ pub struct NodeConfig { pub gas_config: GasConfig, ///Frequency of snapshots pub shapshot_frequency_in_blocks: u64, + ///Initial accounts for wallet + pub initial_accounts: Vec, } diff --git a/node_runner/configs/debug/node_config.json b/node_runner/configs/debug/node_config.json index c948b82..6c39f15 100644 --- a/node_runner/configs/debug/node_config.json +++ b/node_runner/configs/debug/node_config.json @@ -13,5 +13,241 @@ "gas_limit_deploy": 30000000, "gas_limit_runtime": 30000000 }, - "shapshot_frequency_in_blocks": 10 + "shapshot_frequency_in_blocks": 10, + "initial_accounts": [ + { + "address": [ + 13, + 150, + 223, + 204, + 65, + 64, + 25, + 56, + 12, + 157, + 222, + 12, + 211, + 220, + 229, + 170, + 201, + 15, + 181, + 68, + 59, + 248, + 113, + 16, + 135, + 65, + 174, + 175, + 222, + 85, + 42, + 215 + ], + "balance": 10000, + "key_holder": { + "address": [ + 13, + 150, + 223, + 204, + 65, + 64, + 25, + 56, + 12, + 157, + 222, + 12, + 211, + 220, + 229, + 170, + 201, + 15, + 181, + 68, + 59, + 248, + 113, + 16, + 135, + 65, + 174, + 175, + 222, + 85, + 42, + 215 + ], + "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", + "pub_account_signing_key": [ + 133, + 143, + 177, + 187, + 252, + 66, + 237, + 236, + 234, + 252, + 244, + 138, + 5, + 151, + 3, + 99, + 217, + 231, + 112, + 217, + 77, + 211, + 58, + 218, + 176, + 68, + 99, + 53, + 152, + 228, + 198, + 190 + ], + "top_secret_key_holder": { + "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", + "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" + }, + "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" + }, + "utxos": {} + }, + { + "address": [ + 151, + 72, + 112, + 233, + 190, + 141, + 10, + 192, + 138, + 168, + 59, + 63, + 199, + 167, + 166, + 134, + 41, + 29, + 135, + 50, + 80, + 138, + 186, + 152, + 179, + 96, + 128, + 243, + 156, + 44, + 243, + 100 + ], + "balance": 20000, + "key_holder": { + "address": [ + 151, + 72, + 112, + 233, + 190, + 141, + 10, + 192, + 138, + 168, + 59, + 63, + 199, + 167, + 166, + 134, + 41, + 29, + 135, + 50, + 80, + 138, + 186, + 152, + 179, + 96, + 128, + 243, + 156, + 44, + 243, + 100 + ], + "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", + "pub_account_signing_key": [ + 54, + 90, + 62, + 225, + 71, + 225, + 228, + 148, + 143, + 53, + 210, + 23, + 137, + 158, + 171, + 156, + 48, + 7, + 139, + 52, + 117, + 242, + 214, + 7, + 99, + 29, + 122, + 184, + 59, + 116, + 144, + 107 + ], + "top_secret_key_holder": { + "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" + }, + "utxo_secret_key_holder": { + "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", + "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" + }, + "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" + }, + "utxos": {} + } + ] } \ No newline at end of file diff --git a/sequencer_core/src/config.rs b/sequencer_core/src/config.rs index aa40351..2dda687 100644 --- a/sequencer_core/src/config.rs +++ b/sequencer_core/src/config.rs @@ -1,7 +1,14 @@ -use accounts::account_core::AccountForSerialization; use serde::{Deserialize, Serialize}; 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, +} + #[derive(Clone, Serialize, Deserialize)] pub struct SequencerConfig { ///Home dir of sequencer storage @@ -19,5 +26,5 @@ pub struct SequencerConfig { ///Port to listen pub port: u16, ///List of initial accounts data - pub initial_accounts: Vec, + pub initial_accounts: Vec, } diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 87075d6..f827501 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -28,7 +28,7 @@ pub struct SequencerCore { pub chain_height: u64, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum TransactionMalformationErrorKind { PublicTransactionChangedPrivateData { tx: TreeHashType }, PrivateTransactionChangedPublicData { tx: TreeHashType }, @@ -142,7 +142,7 @@ impl SequencerCore { _ => {} }; - //Correct sender check + //Native transfers checks if let Ok(native_transfer_action) = serde_json::from_slice::(execution_input) { @@ -151,9 +151,20 @@ impl SequencerCore { keccak_hasher.update(&tx.transaction().public_key.to_sec1_bytes()); keccak_hasher.finalize(&mut output); + //Correct sender check if native_transfer_action.from != output { return Err(TransactionMalformationErrorKind::IncorrectSender); } + + let from_balance = self + .store + .acc_store + .get_account_balance(&native_transfer_action.from); + + //Balance check + if from_balance < native_transfer_action.balance_to_move { + return Err(TransactionMalformationErrorKind::BalanceMismatch { tx: tx_hash }); + } } //Tree checks @@ -226,9 +237,7 @@ impl SequencerCore { .. } = mempool_tx.auth_tx.transaction().body(); - let tx_hash = *mempool_tx.auth_tx.hash(); - - //Balance check + //Balance move if let Ok(native_transfer_action) = serde_json::from_slice::(execution_input) { @@ -241,18 +250,14 @@ impl SequencerCore { .acc_store .get_account_balance(&native_transfer_action.to); - if from_balance >= native_transfer_action.balance_to_move { - self.store.acc_store.set_account_balance( - &native_transfer_action.from, - from_balance - native_transfer_action.balance_to_move, - ); - self.store.acc_store.set_account_balance( - &native_transfer_action.to, - to_balance + native_transfer_action.balance_to_move, - ); - } else { - return Err(TransactionMalformationErrorKind::BalanceMismatch { tx: tx_hash }); - } + self.store.acc_store.set_account_balance( + &native_transfer_action.from, + from_balance - native_transfer_action.balance_to_move, + ); + self.store.acc_store.set_account_balance( + &native_transfer_action.to, + to_balance + native_transfer_action.balance_to_move, + ); } for utxo_comm in utxo_commitments_created_hashes { @@ -319,17 +324,19 @@ impl SequencerCore { #[cfg(test)] mod tests { + use crate::config::AccountInitialData; + use super::*; use std::path::PathBuf; - use accounts::account_core::AccountForSerialization; use common::transaction::{SignaturePrivateKey, Transaction, TransactionBody, TxKind}; + use k256::{ecdsa::SigningKey, FieldBytes}; use mempool_transaction::MempoolTransaction; use rand::Rng; use secp256k1_zkp::Tweak; fn setup_sequencer_config_variable_initial_accounts( - initial_accounts: Vec, + initial_accounts: Vec, ) -> SequencerConfig { let mut rng = rand::thread_rng(); let random_u8: u8 = rng.gen(); @@ -349,241 +356,25 @@ mod tests { } fn setup_sequencer_config() -> SequencerConfig { - let initial_acc1 = serde_json::from_str(r#"{ - "address": [ - 244, - 55, - 238, - 205, - 74, - 115, - 179, - 192, - 65, - 186, - 166, - 169, - 221, - 45, - 6, - 57, - 200, - 65, - 195, - 70, - 118, - 252, - 206, - 100, - 215, - 250, - 72, - 230, - 19, - 71, - 217, - 249 - ], - "balance": 10, - "key_holder": { - "address": [ - 244, - 55, - 238, - 205, - 74, - 115, - 179, - 192, - 65, - 186, - 166, - 169, - 221, - 45, - 6, - 57, - 200, - 65, - 195, - 70, - 118, - 252, - 206, - 100, - 215, - 250, - 72, - 230, - 19, - 71, - 217, - 249 - ], - "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", - "pub_account_signing_key": [ - 244, - 88, - 134, - 61, - 35, - 209, - 229, - 101, - 85, - 35, - 140, - 140, - 192, - 226, - 83, - 83, - 190, - 189, - 110, - 8, - 89, - 127, - 147, - 142, - 157, - 204, - 51, - 109, - 189, - 92, - 144, - 68 - ], - "top_secret_key_holder": { - "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" - }, - "utxo_secret_key_holder": { - "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", - "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" - }, - "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" - }, - "utxos": {} - }"#).unwrap(); + let acc1_addr = vec![ + 13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181, + 68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 85, 42, 215, + ]; - let initial_acc2 = serde_json::from_str(r#"{ - "address": [ - 72, - 169, - 70, - 237, - 1, - 96, - 35, - 157, - 25, - 15, - 83, - 18, - 52, - 206, - 202, - 63, - 48, - 59, - 173, - 76, - 78, - 7, - 254, - 229, - 28, - 45, - 194, - 79, - 6, - 89, - 58, - 85 - ], - "balance": 100, - "key_holder": { - "address": [ - 72, - 169, - 70, - 237, - 1, - 96, - 35, - 157, - 25, - 15, - 83, - 18, - 52, - 206, - 202, - 63, - 48, - 59, - 173, - 76, - 78, - 7, - 254, - 229, - 28, - 45, - 194, - 79, - 6, - 89, - 58, - 85 - ], - "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", - "pub_account_signing_key": [ - 136, - 105, - 9, - 53, - 180, - 145, - 64, - 5, - 235, - 174, - 62, - 211, - 206, - 116, - 185, - 24, - 214, - 62, - 244, - 64, - 224, - 59, - 120, - 150, - 30, - 249, - 160, - 46, - 189, - 254, - 47, - 244 - ], - "top_secret_key_holder": { - "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" - }, - "utxo_secret_key_holder": { - "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", - "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" - }, - "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" - }, - "utxos": {} - }"#).unwrap(); + let acc2_addr = vec![ + 151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29, + 135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 44, 243, 100, + ]; + + let initial_acc1 = AccountInitialData { + addr: hex::encode(acc1_addr), + balance: 10000, + }; + + let initial_acc2 = AccountInitialData { + addr: hex::encode(acc2_addr), + balance: 20000, + }; let initial_accounts = vec![initial_acc1, initial_acc2]; @@ -616,6 +407,59 @@ mod tests { Transaction::new(body, SignaturePrivateKey::random(&mut rng)) } + fn create_dummy_transaction_native_token_transfer( + from: [u8; 32], + to: [u8; 32], + balance_to_move: u64, + signing_key: SigningKey, + ) -> Transaction { + let mut rng = rand::thread_rng(); + + let native_token_transfer = PublicNativeTokenSend { + from, + to, + balance_to_move, + }; + + let body = TransactionBody { + tx_kind: TxKind::Public, + execution_input: serde_json::to_vec(&native_token_transfer).unwrap(), + execution_output: vec![], + utxo_commitments_spent_hashes: vec![], + utxo_commitments_created_hashes: vec![], + nullifier_created_hashes: vec![], + execution_proof_private: "".to_string(), + encoded_data: vec![], + ephemeral_pub_key: vec![10, 11, 12], + commitment: vec![], + tweak: Tweak::new(&mut rng), + secret_r: [0; 32], + sc_addr: "sc_addr".to_string(), + state_changes: (serde_json::Value::Null, 0), + }; + Transaction::new(body, signing_key) + } + + fn create_signing_key_for_account1() -> SigningKey { + let pub_sign_key_acc1 = [ + 133, 143, 177, 187, 252, 66, 237, 236, 234, 252, 244, 138, 5, 151, 3, 99, 217, 231, + 112, 217, 77, 211, 58, 218, 176, 68, 99, 53, 152, 228, 198, 190, + ]; + + let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc1); + SigningKey::from_bytes(field_bytes).unwrap() + } + + fn create_signing_key_for_account2() -> SigningKey { + let pub_sign_key_acc2 = [ + 54, 90, 62, 225, 71, 225, 228, 148, 143, 53, 210, 23, 137, 158, 171, 156, 48, 7, 139, + 52, 117, 242, 214, 7, 99, 29, 122, 184, 59, 116, 144, 107, + ]; + + let field_bytes = FieldBytes::from_slice(&pub_sign_key_acc2); + SigningKey::from_bytes(field_bytes).unwrap() + } + fn common_setup(sequencer: &mut SequencerCore) { let tx = create_dummy_transaction(vec![[9; 32]], vec![[7; 32]], vec![[8; 32]]); let mempool_tx = MempoolTransaction { @@ -637,259 +481,49 @@ mod tests { assert_eq!(sequencer.sequencer_config.max_num_tx_in_block, 10); assert_eq!(sequencer.sequencer_config.port, 8080); - let acc1_addr = config.initial_accounts[0].address; - let acc2_addr = config.initial_accounts[1].address; + let acc1_addr = hex::decode(config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2_addr = hex::decode(config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); assert!(sequencer.store.acc_store.contains_account(&acc1_addr)); assert!(sequencer.store.acc_store.contains_account(&acc2_addr)); assert_eq!( - 10, + 10000, sequencer.store.acc_store.get_account_balance(&acc1_addr) ); assert_eq!( - 100, + 20000, sequencer.store.acc_store.get_account_balance(&acc2_addr) ); } #[test] fn test_start_different_intial_accounts_balances() { - let initial_acc1 = serde_json::from_str(r#"{ - "address": [ - 244, - 55, - 238, - 205, - 74, - 115, - 179, - 192, - 65, - 186, - 166, - 169, - 221, - 45, - 6, - 57, - 200, - 65, - 195, - 70, - 118, - 252, - 206, - 100, - 215, - 250, - 72, - 230, - 19, - 71, - 217, - 249 - ], - "balance": 1000, - "key_holder": { - "address": [ - 244, - 55, - 238, - 205, - 74, - 115, - 179, - 192, - 65, - 186, - 166, - 169, - 221, - 45, - 6, - 57, - 200, - 65, - 195, - 70, - 118, - 252, - 206, - 100, - 215, - 250, - 72, - 230, - 19, - 71, - 217, - 249 - ], - "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", - "pub_account_signing_key": [ - 244, - 88, - 134, - 61, - 35, - 209, - 229, - 101, - 85, - 35, - 140, - 140, - 192, - 226, - 83, - 83, - 190, - 189, - 110, - 8, - 89, - 127, - 147, - 142, - 157, - 204, - 51, - 109, - 189, - 92, - 144, - 68 - ], - "top_secret_key_holder": { - "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" - }, - "utxo_secret_key_holder": { - "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", - "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" - }, - "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" - }, - "utxos": {} - }"#).unwrap(); + let acc1_addr = vec![ + 13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181, + 68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 42, 42, 42, + ]; - let initial_acc2 = serde_json::from_str(r#"{ - "address": [ - 72, - 169, - 70, - 237, - 1, - 96, - 35, - 157, - 25, - 15, - 83, - 18, - 52, - 206, - 202, - 63, - 48, - 59, - 173, - 76, - 78, - 7, - 254, - 229, - 28, - 45, - 194, - 79, - 6, - 89, - 58, - 85 - ], - "balance": 1000, - "key_holder": { - "address": [ - 72, - 169, - 70, - 237, - 1, - 96, - 35, - 157, - 25, - 15, - 83, - 18, - 52, - 206, - 202, - 63, - 48, - 59, - 173, - 76, - 78, - 7, - 254, - 229, - 28, - 45, - 194, - 79, - 6, - 89, - 58, - 85 - ], - "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", - "pub_account_signing_key": [ - 136, - 105, - 9, - 53, - 180, - 145, - 64, - 5, - 235, - 174, - 62, - 211, - 206, - 116, - 185, - 24, - 214, - 62, - 244, - 64, - 224, - 59, - 120, - 150, - 30, - 249, - 160, - 46, - 189, - 254, - 47, - 244 - ], - "top_secret_key_holder": { - "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" - }, - "utxo_secret_key_holder": { - "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", - "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" - }, - "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" - }, - "utxos": {} - }"#).unwrap(); + let acc2_addr = vec![ + 151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29, + 135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 42, 42, 42, + ]; + + let initial_acc1 = AccountInitialData { + addr: hex::encode(acc1_addr), + balance: 10000, + }; + + let initial_acc2 = AccountInitialData { + addr: hex::encode(acc2_addr), + balance: 20000, + }; let initial_accounts = vec![initial_acc1, initial_acc2]; @@ -898,8 +532,14 @@ mod tests { let config = setup_sequencer_config_variable_initial_accounts(initial_accounts); let sequencer = SequencerCore::start_from_config(config.clone()); - let acc1_addr = config.initial_accounts[0].address; - let acc2_addr = config.initial_accounts[1].address; + let acc1_addr = hex::decode(config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2_addr = hex::decode(config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); assert!(sequencer.store.acc_store.contains_account(&acc1_addr)); assert!(sequencer.store.acc_store.contains_account(&acc2_addr)); @@ -907,11 +547,11 @@ mod tests { assert_eq!(sequencer.store.acc_store.len(), intial_accounts_len); assert_eq!( - 1000, + 10000, sequencer.store.acc_store.get_account_balance(&acc1_addr) ); assert_eq!( - 1000, + 20000, sequencer.store.acc_store.get_account_balance(&acc2_addr) ); } @@ -941,6 +581,120 @@ mod tests { assert!(result.is_ok()); } + #[test] + fn test_transaction_pre_check_native_transfer_valid() { + let config = setup_sequencer_config(); + let mut sequencer = SequencerCore::start_from_config(config); + + common_setup(&mut sequencer); + + let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + + let sign_key1 = create_signing_key_for_account1(); + + let tx = create_dummy_transaction_native_token_transfer(acc1, acc2, 10, sign_key1); + let tx_roots = sequencer.get_tree_roots(); + let result = sequencer.transaction_pre_check(tx, tx_roots); + + assert!(result.is_ok()); + } + + #[test] + fn test_transaction_pre_check_native_transfer_other_signature() { + let config = setup_sequencer_config(); + let mut sequencer = SequencerCore::start_from_config(config); + + common_setup(&mut sequencer); + + let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + + let sign_key2 = create_signing_key_for_account2(); + + let tx = create_dummy_transaction_native_token_transfer(acc1, acc2, 10, sign_key2); + let tx_roots = sequencer.get_tree_roots(); + let result = sequencer.transaction_pre_check(tx, tx_roots); + + assert_eq!( + result.err().unwrap(), + TransactionMalformationErrorKind::IncorrectSender + ); + } + + #[test] + fn test_transaction_pre_check_native_transfer_sent_too_much() { + let config = setup_sequencer_config(); + let mut sequencer = SequencerCore::start_from_config(config); + + common_setup(&mut sequencer); + + let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + + let sign_key1 = create_signing_key_for_account1(); + + let tx = create_dummy_transaction_native_token_transfer(acc1, acc2, 10000000, sign_key1); + let tx_roots = sequencer.get_tree_roots(); + let result = sequencer.transaction_pre_check(tx, tx_roots); + + let is_failed_at_balance_mismatch = matches!( + result.err().unwrap(), + TransactionMalformationErrorKind::BalanceMismatch { tx: _ } + ); + + assert!(is_failed_at_balance_mismatch); + } + + #[test] + fn test_transaction_execute_native_transfer() { + let config = setup_sequencer_config(); + let mut sequencer = SequencerCore::start_from_config(config); + + common_setup(&mut sequencer); + + let acc1 = hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2 = hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + + let sign_key1 = create_signing_key_for_account1(); + + let tx = create_dummy_transaction_native_token_transfer(acc1, acc2, 100, sign_key1); + + sequencer + .execute_check_transaction_on_state(&tx.into_authenticated().unwrap().into()) + .unwrap(); + + let bal_from = sequencer.store.acc_store.get_account_balance(&acc1); + let bal_to = sequencer.store.acc_store.get_account_balance(&acc2); + + assert_eq!(bal_from, 9900); + assert_eq!(bal_to, 20100); + } + #[test] fn test_push_tx_into_mempool_fails_mempool_full() { let config = SequencerConfig { diff --git a/sequencer_core/src/sequencer_store/accounts_store.rs b/sequencer_core/src/sequencer_store/accounts_store.rs index 3944d03..8dd2070 100644 --- a/sequencer_core/src/sequencer_store/accounts_store.rs +++ b/sequencer_core/src/sequencer_store/accounts_store.rs @@ -67,18 +67,22 @@ impl SequencerAccountsStore { ///Update `account_addr` balance, /// /// returns 0, if account address not found, otherwise returns previous balance + /// + /// Also, if account was not previously found, sets it with zero 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_balance = data.balance; + if let Some(acc_data) = acc_data { + let old_balance = acc_data.balance; - data.balance = new_balance; + acc_data.balance = new_balance; - old_balance - }) - .unwrap_or(0) + old_balance + } else { + self.register_account(*account_addr); + + 0 + } } ///Remove account from storage @@ -241,4 +245,15 @@ mod tests { assert!(seq_acc_store.is_empty()); } + + #[test] + fn account_sequencer_store_set_balance_to_unknown_account() { + let mut seq_acc_store = SequencerAccountsStore::default(); + + let ret = seq_acc_store.set_account_balance(&[1; 32], 100); + + assert_eq!(ret, 0); + assert!(seq_acc_store.contains_account(&[1; 32])); + assert_eq!(seq_acc_store.get_account_balance(&[1; 32]), 0); + } } diff --git a/sequencer_core/src/sequencer_store/mod.rs b/sequencer_core/src/sequencer_store/mod.rs index 3a74fb3..a85fd23 100644 --- a/sequencer_core/src/sequencer_store/mod.rs +++ b/sequencer_core/src/sequencer_store/mod.rs @@ -1,6 +1,5 @@ use std::{collections::HashSet, path::Path}; -use accounts::account_core::AccountForSerialization; use accounts_store::SequencerAccountsStore; use block_store::SequecerBlockStore; use common::{ @@ -10,6 +9,8 @@ use common::{ }; use rand::{rngs::OsRng, RngCore}; +use crate::config::AccountInitialData; + pub mod accounts_store; pub mod block_store; @@ -26,14 +27,22 @@ impl SequecerChainStore { home_dir: &Path, genesis_id: u64, is_genesis_random: bool, - initial_accounts: &[AccountForSerialization], + initial_accounts: &[AccountInitialData], ) -> Self { - let accs_pregenerated: Vec<_> = initial_accounts + let init_accs: Vec<_> = initial_accounts .iter() - .map(|acc| (acc.address, acc.balance)) + .map(|acc_data| { + ( + hex::decode(acc_data.addr.clone()) + .unwrap() + .try_into() + .unwrap(), + acc_data.balance, + ) + }) .collect(); - let acc_store = SequencerAccountsStore::new(&accs_pregenerated); + let acc_store = SequencerAccountsStore::new(&init_accs); let nullifier_store = HashSet::new(); let utxo_commitments_store = UTXOCommitmentsMerkleTree::new(vec![]); let pub_tx_store = PublicTransactionMerkleTree::new(vec![]); diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index 41d2261..d606f4c 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -1,5 +1,5 @@ -use accounts::account_core::AccountForSerialization; use actix_web::Error as HttpError; +use sequencer_core::config::AccountInitialData; use serde_json::Value; use common::{ @@ -149,13 +149,13 @@ impl JsonHandler { let _get_initial_testnet_accounts_request = GetInitialTestnetAccountsRequest::parse(Some(request.params))?; - let accounts_for_serialization: Vec = { + let initial_accounts: Vec = { let state = self.sequencer_state.lock().await; state.sequencer_config.initial_accounts.clone() }; - respond(accounts_for_serialization) + respond(initial_accounts) } /// Returns the balance of the account at the given address. @@ -217,12 +217,14 @@ mod tests { use std::sync::Arc; use crate::{rpc_handler, JsonHandler}; - use accounts::account_core::Account; use common::{ rpc_primitives::RpcPollingConfig, transaction::{SignaturePrivateKey, Transaction, TransactionBody}, }; - use sequencer_core::{config::SequencerConfig, SequencerCore}; + use sequencer_core::{ + config::{AccountInitialData, SequencerConfig}, + SequencerCore, + }; use serde_json::Value; use tempfile::tempdir; use tokio::sync::Mutex; @@ -230,241 +232,25 @@ mod tests { fn sequencer_config_for_tests() -> SequencerConfig { let tempdir = tempdir().unwrap(); let home = tempdir.path().to_path_buf(); - let initial_acc1 = serde_json::from_str(r#"{ - "address": [ - 244, - 55, - 238, - 205, - 74, - 115, - 179, - 192, - 65, - 186, - 166, - 169, - 221, - 45, - 6, - 57, - 200, - 65, - 195, - 70, - 118, - 252, - 206, - 100, - 215, - 250, - 72, - 230, - 19, - 71, - 217, - 249 - ], - "balance": 100, - "key_holder": { - "address": [ - 244, - 55, - 238, - 205, - 74, - 115, - 179, - 192, - 65, - 186, - 166, - 169, - 221, - 45, - 6, - 57, - 200, - 65, - 195, - 70, - 118, - 252, - 206, - 100, - 215, - 250, - 72, - 230, - 19, - 71, - 217, - 249 - ], - "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", - "pub_account_signing_key": [ - 244, - 88, - 134, - 61, - 35, - 209, - 229, - 101, - 85, - 35, - 140, - 140, - 192, - 226, - 83, - 83, - 190, - 189, - 110, - 8, - 89, - 127, - 147, - 142, - 157, - 204, - 51, - 109, - 189, - 92, - 144, - 68 - ], - "top_secret_key_holder": { - "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" - }, - "utxo_secret_key_holder": { - "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", - "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" - }, - "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" - }, - "utxos": {} - }"#).unwrap(); + let acc1_addr = vec![ + 13, 150, 223, 204, 65, 64, 25, 56, 12, 157, 222, 12, 211, 220, 229, 170, 201, 15, 181, + 68, 59, 248, 113, 16, 135, 65, 174, 175, 222, 85, 42, 215, + ]; - let initial_acc2 = serde_json::from_str(r#"{ - "address": [ - 72, - 169, - 70, - 237, - 1, - 96, - 35, - 157, - 25, - 15, - 83, - 18, - 52, - 206, - 202, - 63, - 48, - 59, - 173, - 76, - 78, - 7, - 254, - 229, - 28, - 45, - 194, - 79, - 6, - 89, - 58, - 85 - ], - "balance": 200, - "key_holder": { - "address": [ - 72, - 169, - 70, - 237, - 1, - 96, - 35, - 157, - 25, - 15, - 83, - 18, - 52, - 206, - 202, - 63, - 48, - 59, - 173, - 76, - 78, - 7, - 254, - 229, - 28, - 45, - 194, - 79, - 6, - 89, - 58, - 85 - ], - "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", - "pub_account_signing_key": [ - 136, - 105, - 9, - 53, - 180, - 145, - 64, - 5, - 235, - 174, - 62, - 211, - 206, - 116, - 185, - 24, - 214, - 62, - 244, - 64, - 224, - 59, - 120, - 150, - 30, - 249, - 160, - 46, - 189, - 254, - 47, - 244 - ], - "top_secret_key_holder": { - "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" - }, - "utxo_secret_key_holder": { - "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", - "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" - }, - "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" - }, - "utxos": {} - }"#).unwrap(); + let acc2_addr = vec![ + 151, 72, 112, 233, 190, 141, 10, 192, 138, 168, 59, 63, 199, 167, 166, 134, 41, 29, + 135, 50, 80, 138, 186, 152, 179, 96, 128, 243, 156, 44, 243, 100, + ]; + + let initial_acc1 = AccountInitialData { + addr: hex::encode(acc1_addr), + balance: 10000, + }; + + let initial_acc2 = AccountInitialData { + addr: hex::encode(acc2_addr), + balance: 20000, + }; let initial_accounts = vec![initial_acc1, initial_acc2]; @@ -480,16 +266,12 @@ mod tests { } } - fn json_handler_for_tests() -> (JsonHandler, Vec) { + fn json_handler_for_tests() -> (JsonHandler, Vec) { let config = sequencer_config_for_tests(); let mut sequencer_core = SequencerCore::start_from_config(config); - let initial_accounts = sequencer_core - .sequencer_config - .initial_accounts - .iter() - .map(|acc_ser| acc_ser.clone().into()) - .collect(); + + let initial_accounts = sequencer_core.sequencer_config.initial_accounts.clone(); let tx_body = TransactionBody { tx_kind: common::transaction::TxKind::Public, @@ -620,7 +402,7 @@ mod tests { async fn test_get_account_balance_for_existing_account() { let (json_handler, initial_accounts) = json_handler_for_tests(); - let acc1_addr = hex::encode(initial_accounts[0].address); + let acc1_addr = initial_accounts[0].addr.clone(); let request = serde_json::json!({ "jsonrpc": "2.0", @@ -632,7 +414,7 @@ mod tests { "id": 1, "jsonrpc": "2.0", "result": { - "balance": 100 + "balance": 10000 } }); diff --git a/sequencer_runner/configs/debug/sequencer_config.json b/sequencer_runner/configs/debug/sequencer_config.json index b707b85..010a9ba 100644 --- a/sequencer_runner/configs/debug/sequencer_config.json +++ b/sequencer_runner/configs/debug/sequencer_config.json @@ -7,239 +7,6 @@ "block_create_timeout_millis": 10000, "port": 3040, "initial_accounts": [ - { - "address": [ - 244, - 55, - 238, - 205, - 74, - 115, - 179, - 192, - 65, - 186, - 166, - 169, - 221, - 45, - 6, - 57, - 200, - 65, - 195, - 70, - 118, - 252, - 206, - 100, - 215, - 250, - 72, - 230, - 19, - 71, - 217, - 249 - ], - "balance": 100, - "key_holder": { - "address": [ - 244, - 55, - 238, - 205, - 74, - 115, - 179, - 192, - 65, - 186, - 166, - 169, - 221, - 45, - 6, - 57, - 200, - 65, - 195, - 70, - 118, - 252, - 206, - 100, - 215, - 250, - 72, - 230, - 19, - 71, - 217, - 249 - ], - "nullifer_public_key": "03A340BECA9FAAB444CED0140681D72EA1318B5C611704FEE017DA9836B17DB718", - "pub_account_signing_key": [ - 244, - 88, - 134, - 61, - 35, - 209, - 229, - 101, - 85, - 35, - 140, - 140, - 192, - 226, - 83, - 83, - 190, - 189, - 110, - 8, - 89, - 127, - 147, - 142, - 157, - 204, - 51, - 109, - 189, - 92, - 144, - 68 - ], - "top_secret_key_holder": { - "secret_spending_key": "7BC46784DB1BC67825D8F029436846712BFDF9B5D79EA3AB11D39A52B9B229D4" - }, - "utxo_secret_key_holder": { - "nullifier_secret_key": "BB54A8D3C9C51B82C431082D1845A74677B0EF829A11B517E1D9885DE3139506", - "viewing_secret_key": "AD923E92F6A5683E30140CEAB2702AFB665330C1EE4EFA70FAF29767B6B52BAF" - }, - "viewing_public_key": "0361220C5D277E7A1709340FD31A52600C1432B9C45B9BCF88A43581D58824A8B6" - }, - "utxos": {} - }, - { - "address": [ - 72, - 169, - 70, - 237, - 1, - 96, - 35, - 157, - 25, - 15, - 83, - 18, - 52, - 206, - 202, - 63, - 48, - 59, - 173, - 76, - 78, - 7, - 254, - 229, - 28, - 45, - 194, - 79, - 6, - 89, - 58, - 85 - ], - "balance": 1000, - "key_holder": { - "address": [ - 72, - 169, - 70, - 237, - 1, - 96, - 35, - 157, - 25, - 15, - 83, - 18, - 52, - 206, - 202, - 63, - 48, - 59, - 173, - 76, - 78, - 7, - 254, - 229, - 28, - 45, - 194, - 79, - 6, - 89, - 58, - 85 - ], - "nullifer_public_key": "02172F50274DE67C4087C344F5D58E11DF761D90285B095060E0994FAA6BCDE271", - "pub_account_signing_key": [ - 136, - 105, - 9, - 53, - 180, - 145, - 64, - 5, - 235, - 174, - 62, - 211, - 206, - 116, - 185, - 24, - 214, - 62, - 244, - 64, - 224, - 59, - 120, - 150, - 30, - 249, - 160, - 46, - 189, - 254, - 47, - 244 - ], - "top_secret_key_holder": { - "secret_spending_key": "80A186737C8D38B4288A03F0F589957D9C040D79C19F3E0CC4BA80F8494E5179" - }, - "utxo_secret_key_holder": { - "nullifier_secret_key": "746928E63F0984F6F4818933493CE9C067562D9CB932FDC06D82C86CDF6D7122", - "viewing_secret_key": "89176CF4BC9E673807643FD52110EF99D4894335AFB10D881AC0B5041FE1FCB7" - }, - "viewing_public_key": "026072A8F83FEC3472E30CDD4767683F30B91661D25B1040AD9A5FC2E01D659F99" - }, - "utxos": {} - } + ] } \ No newline at end of file From e72df20b6026d104f857c9e59867ab5150b9c085 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 29 Jul 2025 15:04:38 +0300 Subject: [PATCH 13/13] fix: test fix --- sequencer_core/src/lib.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index f827501..3786a2b 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -155,16 +155,6 @@ impl SequencerCore { if native_transfer_action.from != output { return Err(TransactionMalformationErrorKind::IncorrectSender); } - - let from_balance = self - .store - .acc_store - .get_account_balance(&native_transfer_action.from); - - //Balance check - if from_balance < native_transfer_action.balance_to_move { - return Err(TransactionMalformationErrorKind::BalanceMismatch { tx: tx_hash }); - } } //Tree checks @@ -237,6 +227,8 @@ impl SequencerCore { .. } = mempool_tx.auth_tx.transaction().body(); + let tx_hash = *mempool_tx.auth_tx.hash(); + //Balance move if let Ok(native_transfer_action) = serde_json::from_slice::(execution_input) @@ -250,6 +242,11 @@ impl SequencerCore { .acc_store .get_account_balance(&native_transfer_action.to); + //Balance check + if from_balance < native_transfer_action.balance_to_move { + return Err(TransactionMalformationErrorKind::BalanceMismatch { tx: tx_hash }); + } + self.store.acc_store.set_account_balance( &native_transfer_action.from, from_balance - native_transfer_action.balance_to_move, @@ -656,6 +653,10 @@ mod tests { let tx_roots = sequencer.get_tree_roots(); let result = sequencer.transaction_pre_check(tx, tx_roots); + //Passed pre-check + assert!(result.is_ok()); + + let result = sequencer.execute_check_transaction_on_state(&result.unwrap().into()); let is_failed_at_balance_mismatch = matches!( result.err().unwrap(), TransactionMalformationErrorKind::BalanceMismatch { tx: _ }