diff --git a/.editorconfig b/.editorconfig index 12f32366ab..67dd02fce8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,3 +5,62 @@ root = true [*.md] indent_style = space +[*] +cpp_indent_braces=false +cpp_indent_multi_line_relative_to=innermost_parenthesis +cpp_indent_within_parentheses=indent +cpp_indent_preserve_within_parentheses=false +cpp_indent_case_labels=false +cpp_indent_case_contents=true +cpp_indent_case_contents_when_block=false +cpp_indent_lambda_braces_when_parameter=true +cpp_indent_goto_labels=one_left +cpp_indent_preprocessor=leftmost_column +cpp_indent_access_specifiers=false +cpp_indent_namespace_contents=true +cpp_indent_preserve_comments=false +cpp_new_line_before_open_brace_namespace=ignore +cpp_new_line_before_open_brace_type=ignore +cpp_new_line_before_open_brace_function=ignore +cpp_new_line_before_open_brace_block=ignore +cpp_new_line_before_open_brace_lambda=ignore +cpp_new_line_scope_braces_on_separate_lines=false +cpp_new_line_close_brace_same_line_empty_type=false +cpp_new_line_close_brace_same_line_empty_function=false +cpp_new_line_before_catch=true +cpp_new_line_before_else=true +cpp_new_line_before_while_in_do_while=false +cpp_space_before_function_open_parenthesis=remove +cpp_space_within_parameter_list_parentheses=false +cpp_space_between_empty_parameter_list_parentheses=false +cpp_space_after_keywords_in_control_flow_statements=true +cpp_space_within_control_flow_statement_parentheses=false +cpp_space_before_lambda_open_parenthesis=false +cpp_space_within_cast_parentheses=false +cpp_space_after_cast_close_parenthesis=false +cpp_space_within_expression_parentheses=false +cpp_space_before_block_open_brace=true +cpp_space_between_empty_braces=false +cpp_space_before_initializer_list_open_brace=false +cpp_space_within_initializer_list_braces=true +cpp_space_preserve_in_initializer_list=true +cpp_space_before_open_square_bracket=false +cpp_space_within_square_brackets=false +cpp_space_before_empty_square_brackets=false +cpp_space_between_empty_square_brackets=false +cpp_space_group_square_brackets=true +cpp_space_within_lambda_brackets=false +cpp_space_between_empty_lambda_brackets=false +cpp_space_before_comma=false +cpp_space_after_comma=true +cpp_space_remove_around_member_operators=true +cpp_space_before_inheritance_colon=true +cpp_space_before_constructor_colon=true +cpp_space_remove_before_semicolon=true +cpp_space_after_semicolon=false +cpp_space_remove_around_unary_operator=true +cpp_space_around_binary_operator=insert +cpp_space_around_assignment_operator=insert +cpp_space_pointer_reference_alignment=left +cpp_space_around_ternary_operator=insert +cpp_wrap_preserve_blocks=one_liners diff --git a/zcash_client_memory/src/error.rs b/zcash_client_memory/src/error.rs index b7a754db62..80faa02ca2 100644 --- a/zcash_client_memory/src/error.rs +++ b/zcash_client_memory/src/error.rs @@ -3,7 +3,6 @@ use zcash_protocol::memo; use crate::mem_wallet::AccountId; - type Type = AddressGenerationError; #[derive(Debug, thiserror::Error)] diff --git a/zcash_client_memory/src/mem_wallet/mod.rs b/zcash_client_memory/src/mem_wallet/mod.rs index b1f88de2b3..1ebe2319e8 100644 --- a/zcash_client_memory/src/mem_wallet/mod.rs +++ b/zcash_client_memory/src/mem_wallet/mod.rs @@ -17,7 +17,7 @@ use zip32::{fingerprint::SeedFingerprint, DiversifierIndex, Scope}; use zcash_primitives::{ block::BlockHash, consensus::{BlockHeight, Network}, - transaction::{Transaction, TxId}, + transaction::{components::OutPoint, Transaction, TxId}, }; use zcash_protocol::{ memo::{self, Memo, MemoBytes}, @@ -90,6 +90,14 @@ pub struct MemoryWalletDb { accounts: Vec, blocks: BTreeMap, tx_idx: HashMap, + + /// Tracks transparent outputs received by this wallet indexed by their OutPoint which defines the + /// transaction and index where the output was created + transparent_received_outputs: HashMap, + + /// Tracks spends of received outputs. In thix case the TxId is the spending transaction + /// from this wallet. + transparent_received_output_spends: HashMap, sapling_spends: BTreeMap, #[cfg(feature = "orchard")] orchard_spends: BTreeMap, @@ -113,6 +121,8 @@ impl MemoryWalletDb { accounts: Vec::new(), blocks: BTreeMap::new(), tx_idx: HashMap::new(), + transparent_received_outputs: HashMap::new(), + transparent_received_output_spends: HashMap::new(), sapling_spends: BTreeMap::new(), #[cfg(feature = "orchard")] orchard_spends: BTreeMap::new(), @@ -231,3 +241,10 @@ impl ViewingKey { } } } + +#[derive(Debug, Clone)] +struct TransparentReceivedOutput { + output: WalletTransparentOutput, + account_id: AccountId, + tx_id: TxId, +} diff --git a/zcash_client_memory/src/mem_wallet/wallet_read.rs b/zcash_client_memory/src/mem_wallet/wallet_read.rs index 5d03aec73d..0b23aaba4f 100644 --- a/zcash_client_memory/src/mem_wallet/wallet_read.rs +++ b/zcash_client_memory/src/mem_wallet/wallet_read.rs @@ -12,6 +12,16 @@ use std::{ use zcash_keys::keys::{AddressGenerationError, DerivationError, UnifiedIncomingViewingKey}; use zip32::{fingerprint::SeedFingerprint, DiversifierIndex, Scope}; +use std::ops::Add; +use zcash_client_backend::{ + address::UnifiedAddress, + data_api::{ + chain::ChainState, Account as _, AccountPurpose, AccountSource, SeedRelevance, + TransactionDataRequest, TransactionStatus, + }, + keys::{UnifiedAddressRequest, UnifiedFullViewingKey, UnifiedSpendingKey}, + wallet::{NoteId, WalletSpend, WalletTransparentOutput, WalletTx}, +}; use zcash_primitives::{ block::BlockHash, consensus::{BlockHeight, Network}, @@ -23,21 +33,12 @@ use zcash_protocol::{ ShieldedProtocol::{Orchard, Sapling}, }; -use zcash_client_backend::{ - address::UnifiedAddress, - data_api::{ - chain::ChainState, Account as _, AccountPurpose, AccountSource, SeedRelevance, - TransactionDataRequest, TransactionStatus, - }, - keys::{UnifiedAddressRequest, UnifiedFullViewingKey, UnifiedSpendingKey}, - wallet::{NoteId, WalletSpend, WalletTransparentOutput, WalletTx}, -}; - use zcash_client_backend::data_api::{ chain::CommitmentTreeRoot, scanning::ScanRange, AccountBirthday, BlockMetadata, DecryptedTransaction, NullifierQuery, ScannedBlock, SentTransaction, WalletCommitmentTrees, WalletRead, WalletSummary, WalletWrite, SAPLING_SHARD_HEIGHT, }; +use zcash_primitives::transaction::components::OutPoint; #[cfg(feature = "transparent-inputs")] use { @@ -45,7 +46,7 @@ use { zcash_primitives::legacy::TransparentAddress, }; -use super::{Account, AccountId, MemoryWalletDb}; +use super::{Account, AccountId, MemoryWalletDb, TransparentReceivedOutput}; use crate::error::Error; impl WalletRead for MemoryWalletDb { @@ -234,10 +235,42 @@ impl WalletRead for MemoryWalletDb { #[cfg(feature = "transparent-inputs")] fn get_transparent_balances( &self, - _account: Self::AccountId, - _max_height: BlockHeight, + account: Self::AccountId, + max_height: BlockHeight, ) -> Result, Self::Error> { - Ok(HashMap::new()) + // scan all transparent outputs and return those in a tx belonging to this account + // as a map between the address and the total value received + Ok(self + .transparent_received_outputs + .iter() + .filter(|(_, output)| output.account_id == account) // that belong to this account + .filter(|(outpoint, output)| { + // where the tx creating the output is mined + if let Some(height) = self.tx_idx.get(&output.tx_id) { + height <= &max_height + } else { + false + } + }) + .filter(|(outpoint, _)| { + // that are unspent + !self + .transparent_received_output_spends + .contains_key(&outpoint) + }) + .fold( + HashMap::new(), + |mut res, (_, TransparentReceivedOutput { output, .. })| { + let addr = output.recipient_address().clone(); + let zats = res + .get(&addr) + .unwrap_or(&Zatoshis::ZERO) + .add(output.value()) + .expect("Can always add a non-negative value to zero"); + res.insert(addr, zats); + res + }, + )) } fn transaction_data_requests(&self) -> Result, Self::Error> { diff --git a/zcash_client_memory/src/mem_wallet/wallet_write.rs b/zcash_client_memory/src/mem_wallet/wallet_write.rs index 13cd57dffe..d4fd3349a9 100644 --- a/zcash_client_memory/src/mem_wallet/wallet_write.rs +++ b/zcash_client_memory/src/mem_wallet/wallet_write.rs @@ -59,7 +59,8 @@ impl WalletWrite for MemoryWalletDb { .transpose()? .unwrap_or(zip32::AccountId::ZERO); - let usk = UnifiedSpendingKey::from_seed(&self.network, seed.expose_secret(), account_index)?; + let usk = + UnifiedSpendingKey::from_seed(&self.network, seed.expose_secret(), account_index)?; let ufvk = usk.to_unified_full_viewing_key(); let account = Account { account_id: AccountId(self.accounts.len() as u32), diff --git a/zcash_primitives/src/transaction/components/transparent.rs b/zcash_primitives/src/transaction/components/transparent.rs index e2c82fd848..d39df64fc0 100644 --- a/zcash_primitives/src/transaction/components/transparent.rs +++ b/zcash_primitives/src/transaction/components/transparent.rs @@ -92,7 +92,7 @@ impl Bundle { } } -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct OutPoint { hash: TxId, n: u32,