From 6bced517644b1ab3879aa35d5c4695edb5f3bcb2 Mon Sep 17 00:00:00 2001 From: Oleksandr Pravdyvyi Date: Tue, 12 Aug 2025 14:35:10 +0300 Subject: [PATCH] fix: AccountAddress wrapped into struct --- accounts/src/account_core/address.rs | 53 +++++++-- accounts/src/account_core/mod.rs | 20 ++-- accounts/src/key_management/mod.rs | 10 +- sc_core/src/proofs_circuits.rs | 5 +- sc_core/src/public_context.rs | 9 +- sequencer_core/src/lib.rs | 41 ++++--- .../src/sequencer_store/accounts_store.rs | 105 ++++++++++++------ sequencer_rpc/src/process.rs | 3 +- wallet/src/chain_storage/accounts_store.rs | 2 +- wallet/src/helperfunctions.rs | 4 +- wallet/src/lib.rs | 4 +- zkvm/src/lib.rs | 6 +- 12 files changed, 172 insertions(+), 90 deletions(-) diff --git a/accounts/src/account_core/address.rs b/accounts/src/account_core/address.rs index 2fadacd..a25ba0d 100644 --- a/accounts/src/account_core/address.rs +++ b/accounts/src/account_core/address.rs @@ -1,17 +1,44 @@ -use common::transaction::SignaturePublicKey; +use common::transaction::{SignaturePublicKey, Tag}; +use serde::{Deserialize, Serialize}; use tiny_keccak::{Hasher, Keccak}; -// TODO: Consider wrapping `AccountAddress` in a struct. +#[derive( + Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Default, +)] +pub struct AccountAddress(pub(crate) [u8; 32]); -pub type AccountAddress = [u8; 32]; +impl AccountAddress { + pub fn new(value: [u8; 32]) -> Self { + Self(value) + } -/// Returns the address associated with a public key -pub fn from_public_key(public_key: &SignaturePublicKey) -> AccountAddress { - let mut address = [0; 32]; - let mut keccak_hasher = Keccak::v256(); - keccak_hasher.update(&public_key.to_sec1_bytes()); - keccak_hasher.finalize(&mut address); - address + pub fn tag(&self) -> Tag { + self.0[0] + } + + pub fn raw_addr(&self) -> [u8; 32] { + self.0 + } +} + +impl TryFrom> for AccountAddress { + type Error = Vec; + + fn try_from(value: Vec) -> Result { + let addr_val: [u8; 32] = value.try_into()?; + + Ok(AccountAddress::new(addr_val)) + } +} + +impl From<&SignaturePublicKey> for AccountAddress { + fn from(value: &SignaturePublicKey) -> Self { + let mut address = [0; 32]; + let mut keccak_hasher = Keccak::v256(); + keccak_hasher.update(&value.to_sec1_bytes()); + keccak_hasher.finalize(&mut address); + AccountAddress::new(address) + } } #[cfg(test)] @@ -19,7 +46,6 @@ mod tests { use common::transaction::SignaturePrivateKey; use super::*; - use crate::account_core::address; #[test] fn test_address_key_equal_keccak_pub_sign_key() { @@ -31,6 +57,9 @@ mod tests { keccak_hasher.update(&public_key.to_sec1_bytes()); keccak_hasher.finalize(&mut expected_address); - assert_eq!(expected_address, address::from_public_key(public_key)); + assert_eq!( + AccountAddress::new(expected_address), + AccountAddress::from(public_key) + ); } } diff --git a/accounts/src/account_core/mod.rs b/accounts/src/account_core/mod.rs index f586019..de3f5aa 100644 --- a/accounts/src/account_core/mod.rs +++ b/accounts/src/account_core/mod.rs @@ -114,7 +114,7 @@ impl AccountPublicMask { } pub fn make_tag(&self) -> Tag { - self.address[0] + self.address.tag() } } @@ -122,7 +122,7 @@ impl Account { pub fn new() -> Self { let key_holder = AddressKeyHolder::new_os_random(); let public_key = *key_holder.get_pub_account_signing_key().verifying_key(); - let address = address::from_public_key(&public_key); + let address = AccountAddress::from(&public_key); let balance = 0; let nonce = 0; let utxos = HashMap::new(); @@ -139,7 +139,7 @@ impl Account { pub fn new_with_balance(balance: u64) -> Self { let key_holder = AddressKeyHolder::new_os_random(); let public_key = *key_holder.get_pub_account_signing_key().verifying_key(); - let address = address::from_public_key(&public_key); + let address = AccountAddress::from(&public_key); let nonce = 0; let utxos = HashMap::new(); @@ -191,7 +191,7 @@ impl Account { privacy_flag: bool, ) -> Result<()> { let asset_utxo = UTXO::new( - self.address, + self.address.raw_addr(), serde_json::to_vec(&asset)?, amount, privacy_flag, @@ -204,12 +204,16 @@ impl Account { pub fn log(&self) { info!("Keys generated"); - info!("Account address is {:?}", hex::encode(self.address)); + //use HexString + info!( + "Account address is {:?}", + hex::encode(self.address.raw_addr()) + ); info!("Account balance is {:?}", self.balance); } pub fn make_tag(&self) -> Tag { - self.address[0] + self.address.tag() } ///Produce account public mask @@ -247,8 +251,8 @@ mod tests { #[test] fn test_add_new_utxo_outputs() { let mut account = Account::new(); - let utxo1 = generate_dummy_utxo(account.address, 100); - let utxo2 = generate_dummy_utxo(account.address, 200); + let utxo1 = generate_dummy_utxo(account.address.raw_addr(), 100); + let utxo2 = generate_dummy_utxo(account.address.raw_addr(), 200); let result = account.add_new_utxo_outputs(vec![utxo1.clone(), utxo2.clone()]); diff --git a/accounts/src/key_management/mod.rs b/accounts/src/key_management/mod.rs index c1a78fb..8558c50 100644 --- a/accounts/src/key_management/mod.rs +++ b/accounts/src/key_management/mod.rs @@ -120,7 +120,10 @@ mod tests { use elliptic_curve::point::AffineCoordinates; use k256::{AffinePoint, ProjectivePoint, Scalar}; - use crate::{account_core::address, key_management::ephemeral_key_holder::EphemeralKeyHolder}; + use crate::{ + account_core::address::AccountAddress, + key_management::ephemeral_key_holder::EphemeralKeyHolder, + }; use super::*; @@ -347,7 +350,7 @@ mod tests { let verifying_key = signing_key.verifying_key(); - let address = address::from_public_key(verifying_key); + let address = AccountAddress::from(verifying_key); println!("======Prerequisites======"); println!(); @@ -373,7 +376,8 @@ mod tests { println!("======Public data======"); println!(); - println!("Address{:?}", hex::encode(address)); + //Use HexString + println!("Address{:?}", hex::encode(address.raw_addr())); println!( "Nulifier public key {:?}", hex::encode(serde_json::to_vec(&nullifer_public_key).unwrap()) diff --git a/sc_core/src/proofs_circuits.rs b/sc_core/src/proofs_circuits.rs index 08ce431..9e2f580 100644 --- a/sc_core/src/proofs_circuits.rs +++ b/sc_core/src/proofs_circuits.rs @@ -1,3 +1,4 @@ +use accounts::account_core::address::AccountAddress; use bincode; use common::merkle_tree_public::merkle_tree::UTXOCommitmentsMerkleTree; use rand::{thread_rng, RngCore}; @@ -82,7 +83,7 @@ pub fn private_circuit( for in_utxo in input_utxos { let nullifier_public_key = public_context .account_masks - .get(&in_utxo.owner) + .get(&AccountAddress::new(in_utxo.owner)) .unwrap() .nullifier_public_key; @@ -125,7 +126,7 @@ pub fn deshielded_circuit( for in_utxo in input_utxos { let nullifier_public_key = public_context .account_masks - .get(&in_utxo.owner) + .get(&AccountAddress::new(in_utxo.owner)) .unwrap() .nullifier_public_key; diff --git a/sc_core/src/public_context.rs b/sc_core/src/public_context.rs index e225513..aab9ede 100644 --- a/sc_core/src/public_context.rs +++ b/sc_core/src/public_context.rs @@ -28,7 +28,12 @@ impl Serialize for PublicSCContext { where S: serde::Serializer, { - let mut account_masks_keys: Vec<[u8; 32]> = self.account_masks.keys().cloned().collect(); + let mut account_masks_keys: Vec<[u8; 32]> = self + .account_masks + .keys() + .cloned() + .map(|addr| addr.raw_addr()) + .collect(); account_masks_keys.sort(); let mut account_mask_values: Vec = @@ -111,7 +116,7 @@ mod tests { account_masks.insert(acc_3.address, acc_3.make_account_public_mask()); PublicSCContext { - caller_address, + caller_address: AccountAddress::new(caller_address), caller_balance: 100, account_masks, comitment_store_root, diff --git a/sequencer_core/src/lib.rs b/sequencer_core/src/lib.rs index 810166d..fd15b0e 100644 --- a/sequencer_core/src/lib.rs +++ b/sequencer_core/src/lib.rs @@ -1,6 +1,6 @@ use std::fmt::Display; -use accounts::account_core::address::{self, AccountAddress}; +use accounts::account_core::address::AccountAddress; use anyhow::Result; use common::{ block::HashableBlockData, @@ -135,10 +135,10 @@ impl SequencerCore { if let Ok(native_transfer_action) = serde_json::from_slice::(execution_input) { - let signer_address = address::from_public_key(&tx.transaction().public_key); + let signer_address = AccountAddress::from(&tx.transaction().public_key); //Correct sender check - if native_transfer_action.from != signer_address { + if AccountAddress::new(native_transfer_action.from) != signer_address { return Err(TransactionMalformationErrorKind::IncorrectSender); } } @@ -219,8 +219,7 @@ impl SequencerCore { serde_json::from_slice::(execution_input) { // Nonce check - let signer_addres = - address::from_public_key(&mempool_tx.auth_tx.transaction().public_key); + let signer_addres = AccountAddress::from(&mempool_tx.auth_tx.transaction().public_key); if self.store.acc_store.get_account_nonce(&signer_addres) != native_transfer_action.nonce { @@ -230,11 +229,11 @@ impl SequencerCore { let from_balance = self .store .acc_store - .get_account_balance(&native_transfer_action.from); + .get_account_balance(&AccountAddress::new(native_transfer_action.from)); let to_balance = self .store .acc_store - .get_account_balance(&native_transfer_action.to); + .get_account_balance(&AccountAddress::new(native_transfer_action.to)); //Balance check if from_balance < native_transfer_action.balance_to_move { @@ -242,11 +241,11 @@ impl SequencerCore { } self.store.acc_store.set_account_balance( - &native_transfer_action.from, + &AccountAddress::new(native_transfer_action.from), from_balance - native_transfer_action.balance_to_move, ); self.store.acc_store.set_account_balance( - &native_transfer_action.to, + &AccountAddress::new(native_transfer_action.to), to_balance + native_transfer_action.balance_to_move, ); @@ -620,19 +619,25 @@ mod tests { 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 acc1: AccountAddress = + hex::decode(sequencer.sequencer_config.initial_accounts[0].addr.clone()) + .unwrap() + .try_into() + .unwrap(); + let acc2: AccountAddress = + hex::decode(sequencer.sequencer_config.initial_accounts[1].addr.clone()) + .unwrap() + .try_into() + .unwrap(); let sign_key1 = create_signing_key_for_account1(); let tx = common::test_utils::create_dummy_transaction_native_token_transfer( - acc1, 0, acc2, 100, sign_key1, + acc1.raw_addr(), + 0, + acc2.raw_addr(), + 100, + sign_key1, ); sequencer diff --git a/sequencer_core/src/sequencer_store/accounts_store.rs b/sequencer_core/src/sequencer_store/accounts_store.rs index 4f02220..b7012cf 100644 --- a/sequencer_core/src/sequencer_store/accounts_store.rs +++ b/sequencer_core/src/sequencer_store/accounts_store.rs @@ -155,30 +155,38 @@ mod tests { #[test] fn test_zero_balance_account_data_creation() { - let new_acc = AccountPublicData::new([1; 32]); + let address = AccountAddress::new([1; 32]); + + let new_acc = AccountPublicData::new(address); assert_eq!(new_acc.balance, 0); - assert_eq!(new_acc.address, [1; 32]); + assert_eq!(new_acc.address, address); } #[test] fn test_zero_nonce_account_data_creation() { - let new_acc = AccountPublicData::new([1; 32]); + let address = AccountAddress::new([1; 32]); + + let new_acc = AccountPublicData::new(address); assert_eq!(new_acc.nonce, 0); } #[test] fn test_non_zero_balance_account_data_creation() { - let new_acc = AccountPublicData::new_with_balance([1; 32], 10); + let address = AccountAddress::new([1; 32]); + + let new_acc = AccountPublicData::new_with_balance(address, 10); assert_eq!(new_acc.balance, 10); - assert_eq!(new_acc.address, [1; 32]); + assert_eq!(new_acc.address, address); } #[test] fn test_zero_nonce_account_data_creation_with_balance() { - let new_acc = AccountPublicData::new_with_balance([1; 32], 10); + let address = AccountAddress::new([1; 32]); + + let new_acc = AccountPublicData::new_with_balance(address, 10); assert_eq!(new_acc.nonce, 0); } @@ -192,94 +200,117 @@ mod tests { #[test] fn account_sequencer_store_register_acc() { + let address = AccountAddress::new([1; 32]); + let mut seq_acc_store = SequencerAccountsStore::default(); - seq_acc_store.register_account([1; 32]); + seq_acc_store.register_account(address); - assert!(seq_acc_store.contains_account(&[1; 32])); + assert!(seq_acc_store.contains_account(&address)); - let acc_balance = seq_acc_store.get_account_balance(&[1; 32]); + let acc_balance = seq_acc_store.get_account_balance(&address); assert_eq!(acc_balance, 0); } #[test] fn account_sequencer_store_unregister_acc_not_present() { + let address1 = AccountAddress::new([1; 32]); + let address2 = AccountAddress::new([2; 32]); + let mut seq_acc_store = SequencerAccountsStore::default(); - seq_acc_store.register_account([1; 32]); + seq_acc_store.register_account(address1); - let rem_res = seq_acc_store.unregister_account([2; 32]).unwrap(); + let rem_res = seq_acc_store.unregister_account(address2).unwrap(); assert!(rem_res.is_none()); } #[test] fn account_sequencer_store_unregister_acc_not_zero_balance() { - let mut seq_acc_store = SequencerAccountsStore::new(&[([1; 32], 12), ([2; 32], 100)]); + let address1 = AccountAddress::new([1; 32]); + let address2 = AccountAddress::new([2; 32]); - let rem_res = seq_acc_store.unregister_account([1; 32]); + let mut seq_acc_store = SequencerAccountsStore::new(&[(address1, 12), (address2, 100)]); + + let rem_res = seq_acc_store.unregister_account(address1); assert!(rem_res.is_err()); } #[test] fn account_sequencer_store_unregister_acc() { + let address = AccountAddress::new([1; 32]); + let mut seq_acc_store = SequencerAccountsStore::default(); - seq_acc_store.register_account([1; 32]); + seq_acc_store.register_account(address); - assert!(seq_acc_store.contains_account(&[1; 32])); + assert!(seq_acc_store.contains_account(&address)); - seq_acc_store.unregister_account([1; 32]).unwrap().unwrap(); + seq_acc_store.unregister_account(address).unwrap().unwrap(); - assert!(!seq_acc_store.contains_account(&[1; 32])); + assert!(!seq_acc_store.contains_account(&address)); } #[test] fn account_sequencer_store_with_preset_accounts_1() { - let seq_acc_store = SequencerAccountsStore::new(&[([1; 32], 12), ([2; 32], 100)]); + let address1 = AccountAddress::new([1; 32]); + let address2 = AccountAddress::new([2; 32]); - assert!(seq_acc_store.contains_account(&[1; 32])); - assert!(seq_acc_store.contains_account(&[2; 32])); + let seq_acc_store = SequencerAccountsStore::new(&[(address1, 12), (address2, 100)]); - let acc_balance = seq_acc_store.get_account_balance(&[1; 32]); + assert!(seq_acc_store.contains_account(&address1)); + assert!(seq_acc_store.contains_account(&address2)); + + let acc_balance = seq_acc_store.get_account_balance(&address1); assert_eq!(acc_balance, 12); - let acc_balance = seq_acc_store.get_account_balance(&[2; 32]); + let acc_balance = seq_acc_store.get_account_balance(&address2); assert_eq!(acc_balance, 100); } #[test] fn account_sequencer_store_with_preset_accounts_2() { + let address1 = AccountAddress::new([6; 32]); + let address2 = AccountAddress::new([7; 32]); + let address3 = AccountAddress::new([8; 32]); + let seq_acc_store = - SequencerAccountsStore::new(&[([6; 32], 120), ([7; 32], 15), ([8; 32], 10)]); + SequencerAccountsStore::new(&[(address1, 120), (address2, 15), (address3, 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])); + assert!(seq_acc_store.contains_account(&address1)); + assert!(seq_acc_store.contains_account(&address2)); + assert!(seq_acc_store.contains_account(&address3)); - let acc_balance = seq_acc_store.get_account_balance(&[6; 32]); + let acc_balance = seq_acc_store.get_account_balance(&address1); 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(&address2); 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(&address3); 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 address1 = AccountAddress::new([6; 32]); + let address2 = AccountAddress::new([7; 32]); + let address3 = AccountAddress::new([8; 32]); - let acc_balance = seq_acc_store.get_account_balance(&[9; 32]); + let address4 = AccountAddress::new([9; 32]); + + let seq_acc_store = + SequencerAccountsStore::new(&[(address1, 120), (address2, 15), (address3, 10)]); + + let acc_balance = seq_acc_store.get_account_balance(&address4); assert_eq!(acc_balance, 0); } @@ -293,19 +324,21 @@ mod tests { #[test] fn account_sequencer_store_set_balance_to_unknown_account() { + let address = AccountAddress::new([1; 32]); + let mut seq_acc_store = SequencerAccountsStore::default(); - let ret = seq_acc_store.set_account_balance(&[1; 32], 100); + let ret = seq_acc_store.set_account_balance(&address, 100); assert_eq!(ret, 0); - assert!(seq_acc_store.contains_account(&[1; 32])); - assert_eq!(seq_acc_store.get_account_balance(&[1; 32]), 100); + assert!(seq_acc_store.contains_account(&address)); + assert_eq!(seq_acc_store.get_account_balance(&address), 100); } #[test] fn test_increase_nonce() { let mut account_store = SequencerAccountsStore::default(); - let address = [1; 32]; + let address = AccountAddress::new([1; 32]); let first_nonce = account_store.increase_nonce(&address); assert_eq!(first_nonce, 0); let second_nonce = account_store.increase_nonce(&address); diff --git a/sequencer_rpc/src/process.rs b/sequencer_rpc/src/process.rs index eadfe55..c2b59bf 100644 --- a/sequencer_rpc/src/process.rs +++ b/sequencer_rpc/src/process.rs @@ -1,3 +1,4 @@ +use accounts::account_core::address::AccountAddress; use actix_web::Error as HttpError; use sequencer_core::config::AccountInitialData; use serde_json::Value; @@ -72,7 +73,7 @@ impl JsonHandler { { let mut acc_store = self.sequencer_state.lock().await; - acc_store.register_account(acc_req.address); + acc_store.register_account(AccountAddress::new(acc_req.address)); } let helperstruct = RegisterAccountResponse { diff --git a/wallet/src/chain_storage/accounts_store.rs b/wallet/src/chain_storage/accounts_store.rs index cd46a6f..36d657a 100644 --- a/wallet/src/chain_storage/accounts_store.rs +++ b/wallet/src/chain_storage/accounts_store.rs @@ -82,7 +82,7 @@ mod tests { let mut store = WalletAccountsStore::new(); let account_addr: [u8; 32] = pad_to_32("nonexistent".to_string().as_bytes()); - store.unregister_account(account_addr); + store.unregister_account(AccountAddress::new(account_addr)); assert!(store.accounts.is_empty()); } diff --git a/wallet/src/helperfunctions.rs b/wallet/src/helperfunctions.rs index a66b1e0..e36215d 100644 --- a/wallet/src/helperfunctions.rs +++ b/wallet/src/helperfunctions.rs @@ -1,6 +1,6 @@ use std::{fs::File, io::BufReader, path::PathBuf, str::FromStr}; -use accounts::account_core::Account; +use accounts::account_core::{address::AccountAddress, Account}; use anyhow::{anyhow, Result}; use crate::{config::WalletConfig, HOME_DIR_ENV_VAR}; @@ -20,7 +20,7 @@ pub fn fetch_config() -> Result { } //ToDo: Replace with structures conversion in future -pub fn produce_account_addr_from_hex(hex_str: String) -> Result<[u8; 32]> { +pub fn produce_account_addr_from_hex(hex_str: String) -> Result { hex::decode(hex_str)? .try_into() .map_err(|_| anyhow!("Failed conversion to 32 bytes")) diff --git a/wallet/src/lib.rs b/wallet/src/lib.rs index 9c17751..b8d23d4 100644 --- a/wallet/src/lib.rs +++ b/wallet/src/lib.rs @@ -86,9 +86,9 @@ impl WalletCore { let tx: TransactionBody = sc_core::transaction_payloads_tools::create_public_transaction_payload( serde_json::to_vec(&PublicNativeTokenSend { - from, + from: from.raw_addr(), nonce, - to, + to: to.raw_addr(), balance_to_move, }) .unwrap(), diff --git a/zkvm/src/lib.rs b/zkvm/src/lib.rs index 0fbae70..3048370 100644 --- a/zkvm/src/lib.rs +++ b/zkvm/src/lib.rs @@ -187,7 +187,7 @@ pub fn prove_send_utxo_shielded( return Err(ExecutionFailureKind::AmountMismatchError); } - let temp_utxo_to_spend = UTXO::new(owner, vec![], amount, true); + let temp_utxo_to_spend = UTXO::new(owner.raw_addr(), vec![], amount, true); let utxo_payload = temp_utxo_to_spend.into_payload(); let mut builder = ExecutorEnv::builder(); @@ -561,7 +561,7 @@ mod tests { let utxo_exec = execute_mint_utxo(amount, owner, randomness).expect("execution failed"); assert_eq!(utxo_exec.amount, amount); - assert_eq!(utxo_exec.owner, owner); + assert_eq!(utxo_exec.owner, owner.raw_addr()); } #[test] @@ -571,7 +571,7 @@ mod tests { let (utxo, _) = prove_mint_utxo(amount, owner).expect("proof failed"); assert_eq!(utxo.amount, amount); - assert_eq!(utxo.owner, owner); + assert_eq!(utxo.owner, owner.raw_addr()); } #[test]