Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make addresses append only #430

Merged
merged 32 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
8409730
add append-only-vec dependency
zancas Aug 9, 2023
f787dc6
WalletCapability is not clone, and has AOV fields
zancas Aug 9, 2023
84a68df
use AppendOnlyVec
zancas Aug 9, 2023
c0aaad1
need slice for write so collect to a &Vec, and leverage Deref impl
zancas Aug 9, 2023
fe62784
fix spurious keybind
zancas Aug 9, 2023
df90f5a
remove RwLock
zancas Aug 9, 2023
549ae3c
wc isn't an RwLock anymore
zancas Aug 9, 2023
1cab6a4
rm more rwlock and now-spurious alias
zancas Aug 9, 2023
b2b6925
rm many more locks
zancas Aug 9, 2023
984829d
implement more changes implied by append_only addresses
zancas Aug 9, 2023
c11b6f8
rm unneeded muts
zancas Aug 9, 2023
fd56e14
use default for WalletCapability
zancas Aug 9, 2023
d0a301e
AtomicBool addresses_lock, default constructor
zancas Aug 9, 2023
4dee418
experiment with naked default over explicit constructors
zancas Aug 9, 2023
1bc0c25
remove increment of not existent
zancas Aug 10, 2023
90c5c58
handle lock release in error case
zancas Aug 10, 2023
608114c
unpack error and insert lock release
zancas Aug 10, 2023
f6e8953
add lock after address push
zancas Aug 10, 2023
d57fb29
remove unused
zancas Aug 10, 2023
62666b4
remove unused, silence warning
zancas Aug 10, 2023
6dd3fb3
remove references to locks from tests
zancas Aug 10, 2023
dcad5fb
fix clippy errors
zancas Aug 10, 2023
dc5e1a5
make temp var ident clearer
zancas Aug 10, 2023
6298beb
minor test vector tweaks
zancas Aug 10, 2023
caaacae
handle previously missed ?
zancas Aug 10, 2023
130ee60
make local address_for_diversification
zancas Aug 10, 2023
e5e5d6c
add sanity check
zancas Aug 10, 2023
ff2db4b
remove alias to self.addresses.len(), except for stash for sanity check
zancas Aug 10, 2023
4f76f54
pass coherence test
zancas Aug 11, 2023
8117813
only make a new fvk once per new_address call
zancas Aug 11, 2023
026d91b
cleaner
zancas Aug 11, 2023
6b36dce
clean up conditions, and only generate sapling diversifier if necessary
zancas Aug 11, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 2 additions & 13 deletions zingo-testutils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,15 @@ pub fn build_fvks_from_wallet_capability(wallet_capability: &WalletCapability) -
let t_fvk = Fvk::P2pkh(t_fvk_bytes);
[o_fvk, s_fvk, t_fvk]
}
pub async fn build_fvk_client_and_capability(
fvks: &[&Fvk],
zingoconfig: &ZingoConfig,
) -> (LightClient, WalletCapability) {
pub async fn build_fvk_client(fvks: &[&Fvk], zingoconfig: &ZingoConfig) -> LightClient {
let ufvk = zcash_address::unified::Encoding::encode(
&<Ufvk as zcash_address::unified::Encoding>::try_from_items(
fvks.iter().copied().cloned().collect(),
)
.unwrap(),
&zcash_address::Network::Regtest,
);
let viewkey_client =
LightClient::create_unconnected(zingoconfig, WalletBase::Ufvk(ufvk), 0).unwrap();
let watch_wc = viewkey_client
.wallet
.wallet_capability()
.read()
.await
.clone();
(viewkey_client, watch_wc)
LightClient::create_unconnected(zingoconfig, WalletBase::Ufvk(ufvk), 0).unwrap()
}

async fn get_synced_wallet_height(client: &LightClient) -> Result<u32, String> {
Expand Down
41 changes: 12 additions & 29 deletions zingocli/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#![cfg(feature = "local_env")]
pub mod darkside;
use std::{fs::File, path::Path};
use zingo_testutils::{self, build_fvk_client_and_capability, data};
use zingo_testutils::{self, build_fvk_client, data};

use bip0039::Mnemonic;
use data::seeds::HOSPITAL_MUSEUM_SEED;
Expand Down Expand Up @@ -377,12 +377,7 @@ async fn test_scanning_in_watch_only_mode() {
check_client_balances!(original_recipient, o: sent_o_value s: sent_s_value t: sent_t_value);

// Extract viewing keys
let wallet_capability = original_recipient
.wallet
.wallet_capability()
.read()
.await
.clone();
let wallet_capability = original_recipient.wallet.wallet_capability().clone();
let [o_fvk, s_fvk, t_fvk] =
zingo_testutils::build_fvks_from_wallet_capability(&wallet_capability);
let fvks_sets = vec![
Expand All @@ -399,7 +394,8 @@ async fn test_scanning_in_watch_only_mode() {
log::info!(" sapling fvk: {}", fvks.contains(&&s_fvk));
log::info!(" transparent fvk: {}", fvks.contains(&&t_fvk));

let (watch_client, watch_wc) = build_fvk_client_and_capability(fvks, &zingo_config).await;
let watch_client = build_fvk_client(fvks, &zingo_config).await;
let watch_wc = watch_client.wallet.wallet_capability();
// assert empty wallet before rescan
let balance = watch_client.do_balance().await;
check_expected_balance_with_fvks(fvks, balance, 0, 0, 0);
Expand Down Expand Up @@ -1069,10 +1065,9 @@ async fn handling_of_nonregenerated_diversified_addresses_after_seed_restore() {
.build_newseed_client(seed_phrase_of_recipient1, 0, false)
.await;
let mut expected_unspent_sapling_notes = json::object! {

"created_in_block" => 2,
"datetime" => 1666631643,
"created_in_txid" => "4eeaca8d292f07f9cbe26a276f7658e75f0ef956fb21646e3907e912c5af1ec5",
"datetime" => 0,
"created_in_txid" => "",
"value" => 14_000,
"unconfirmed" => false,
"is_change" => false,
Expand All @@ -1081,7 +1076,6 @@ async fn handling_of_nonregenerated_diversified_addresses_after_seed_restore() {
"spent" => JsonValue::Null,
"spent_at_height" => JsonValue::Null,
"unconfirmed_spent" => JsonValue::Null,

};
let original_recipient_address = "\
uregtest1qtqr46fwkhmdn336uuyvvxyrv0l7trgc0z9clpryx6vtladnpyt4wvq99p59f4rcyuvpmmd0hm4k5vv6j\
Expand All @@ -1092,10 +1086,10 @@ async fn handling_of_nonregenerated_diversified_addresses_after_seed_restore() {
&get_base_address!(recipient1, "unified"),
&original_recipient_address
);
let recipient_addr = recipient1.do_new_address("tz").await.unwrap();
let recipient1_diversified_addr = recipient1.do_new_address("tz").await.unwrap();
faucet
.do_send(vec![(
recipient_addr[0].as_str().unwrap(),
recipient1_diversified_addr[0].as_str().unwrap(),
14_000,
Some("foo".to_string()),
)])
Expand Down Expand Up @@ -1521,7 +1515,7 @@ async fn load_wallet_from_v26_dat_file() {
assert_eq!(wallet.mnemonic(), Some(&expected_mnemonic));

let expected_wc = WalletCapability::new_from_phrase(&config, &expected_mnemonic, 0).unwrap();
let wc = wallet.wallet_capability().read().await.clone();
let wc = wallet.wallet_capability();

// We don't want the WalletCapability to impl. `Eq` (because it stores secret keys)
// so we have to compare each component instead
Expand Down Expand Up @@ -1556,7 +1550,7 @@ async fn load_wallet_from_v26_dat_file() {
);

assert_eq!(wc.addresses().len(), 3);
for addr in wc.addresses() {
for addr in wc.addresses().iter() {
assert!(addr.orchard().is_some());
assert!(addr.sapling().is_some());
assert!(addr.transparent().is_some());
Expand Down Expand Up @@ -2031,12 +2025,7 @@ async fn sapling_incoming_sapling_outgoing() {
addresses[0]["receivers"]["sapling"],
encode_payment_address(
recipient.config().chain.hrp_sapling_payment_address(),
recipient
.wallet
.wallet_capability()
.read()
.await
.addresses()[0]
recipient.wallet.wallet_capability().addresses()[0]
.sapling()
.unwrap()
),
Expand All @@ -2054,13 +2043,7 @@ async fn sapling_incoming_sapling_outgoing() {
assert_eq!(faucet_sent_transaction["amount"].as_u64().unwrap(), value);
assert_eq!(
faucet_sent_transaction["address"],
recipient
.wallet
.wallet_capability()
.read()
.await
.addresses()[0]
.encode(&recipient.config().chain)
recipient.wallet.wallet_capability().addresses()[0].encode(&recipient.config().chain)
);
assert_eq!(faucet_sent_transaction["block_height"].as_u64().unwrap(), 2);
} else {
Expand Down
1 change: 1 addition & 0 deletions zingolib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ nonempty = "0.7.0"
tracing-subscriber = "0.3.15"
tracing = "0.1.36"
indoc = "2.0.1"
append-only-vec = { git = "https://github.com/zancas/append-only-vec.git", branch = "add_debug_impl" }

[dev-dependencies]
portpicker = "0.1.0"
Expand Down
67 changes: 32 additions & 35 deletions zingolib/src/blaze/fetch_full_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ use zingoconfig::{ChainType, ZingoConfig};
#[derive(Clone)]
pub struct TransactionContext {
pub(crate) config: ZingoConfig,
pub(crate) key: Arc<RwLock<WalletCapability>>,
pub(crate) key: Arc<WalletCapability>,
pub transaction_metadata_set: Arc<RwLock<TransactionMetadataSet>>,
}

impl TransactionContext {
pub fn new(
config: &ZingoConfig,
key: Arc<RwLock<WalletCapability>>,
key: Arc<WalletCapability>,
transaction_metadata_set: Arc<RwLock<TransactionMetadataSet>>,
) -> Self {
Self {
Expand Down Expand Up @@ -116,7 +116,7 @@ impl TransactionContext {
// Remember if this is an outgoing Tx. Useful for when we want to grab the outgoing metadata.
let mut is_outgoing_transaction = false;
// Collect our t-addresses for easy checking
let taddrs_set = self.key.read().await.get_all_taddrs(&self.config);
let taddrs_set = self.key.get_all_taddrs(&self.config);
// Process t-address outputs
// If this transaction in outgoing, i.e., we received sent some money in this transaction, then we need to grab all transparent outputs
// that don't belong to us as the outgoing metadata
Expand Down Expand Up @@ -450,7 +450,6 @@ impl TransactionContext {
// 1. There's more than one way to be "spent".
// 2. It's possible for a "nullifier" to be in the wallet's spent list, but never in the global ledger.
// <https://github.com/zingolabs/zingolib/issues/65>
let unified_spend_capability = self.key.read().await;
let domain_tagged_outputs =
<FnGenBundle<D> as zingo_traits::Bundle<D>>::from_transaction(transaction)
.into_iter()
Expand All @@ -464,8 +463,8 @@ impl TransactionContext {
.collect::<Vec<_>>();

let (Ok(ivk), Ok(ovk)) = (
D::wc_to_ivk(&unified_spend_capability),
D::wc_to_ovk(&unified_spend_capability),
D::wc_to_ivk(&self.key),
D::wc_to_ovk(&self.key),
) else {
// skip scanning if wallet has not viewing capability
return;
Expand Down Expand Up @@ -541,36 +540,34 @@ impl TransactionContext {
match Memo::from_bytes(&memo_bytes.to_bytes()) {
Err(_) => None,
Ok(memo) => {
if unified_spend_capability.addresses().iter().any(
|unified_address| {
[
unified_address
.transparent()
.cloned()
.map(RecipientAddress::from),
unified_address
.sapling()
.cloned()
.map(RecipientAddress::from),
unified_address.orchard().cloned().map(
|orchard_receiver| {
RecipientAddress::from(
UnifiedAddress::from_receivers(
Some(orchard_receiver),
None,
None,
)
.unwrap(),
if self.key.addresses().iter().any(|unified_address| {
[
unified_address
.transparent()
.cloned()
.map(RecipientAddress::from),
unified_address
.sapling()
.cloned()
.map(RecipientAddress::from),
unified_address.orchard().cloned().map(
|orchard_receiver| {
RecipientAddress::from(
UnifiedAddress::from_receivers(
Some(orchard_receiver),
None,
None,
)
},
),
]
.into_iter()
.flatten()
.map(|addr| addr.encode(&self.config.chain))
.any(|addr| addr == address)
},
) {
.unwrap(),
)
},
),
]
.into_iter()
.flatten()
.map(|addr| addr.encode(&self.config.chain))
.any(|addr| addr == address)
}) {
if let Memo::Text(_) = memo {
Some(OutgoingTxData {
to_address: address,
Expand Down
11 changes: 3 additions & 8 deletions zingolib/src/blaze/fetch_taddr_transactions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ use tokio::join;
use tokio::sync::mpsc::unbounded_channel;
use tokio::sync::mpsc::UnboundedReceiver;
use tokio::sync::oneshot;
use tokio::{
sync::{mpsc::UnboundedSender, RwLock},
task::JoinHandle,
};
use tokio::{sync::mpsc::UnboundedSender, task::JoinHandle};

use zcash_primitives::consensus::BlockHeight;
use zcash_primitives::consensus::BranchId;
Expand All @@ -19,7 +16,7 @@ use zcash_primitives::transaction::Transaction;
use zingoconfig::ZingoConfig;

pub struct FetchTaddrTransactions {
wc: Arc<RwLock<WalletCapability>>,
wc: Arc<WalletCapability>,
config: Arc<ZingoConfig>,
}

Expand All @@ -30,7 +27,7 @@ pub type FetchTaddrRequest = (Vec<String>, u64, u64);
pub type FetchTaddrResponse = Result<RawTransaction, String>;

impl FetchTaddrTransactions {
pub fn new(wc: Arc<RwLock<WalletCapability>>, config: Arc<ZingoConfig>) -> Self {
pub fn new(wc: Arc<WalletCapability>, config: Arc<ZingoConfig>) -> Self {
Self { wc, config }
}

Expand All @@ -49,8 +46,6 @@ impl FetchTaddrTransactions {
let config = self.config.clone();
tokio::spawn(async move {
let taddrs = wc
.read()
.await
.addresses()
.iter()
.filter_map(|ua| ua.transparent())
Expand Down
13 changes: 6 additions & 7 deletions zingolib/src/blaze/trial_decryptions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ use zingoconfig::ZingoConfig;
use super::syncdata::BlazeSyncData;

pub struct TrialDecryptions {
wc: Arc<RwLock<WalletCapability>>,
wc: Arc<WalletCapability>,
transaction_metadata_set: Arc<RwLock<TransactionMetadataSet>>,
config: Arc<ZingoConfig>,
}

impl TrialDecryptions {
pub fn new(
config: Arc<ZingoConfig>,
wc: Arc<RwLock<WalletCapability>>,
wc: Arc<WalletCapability>,
transaction_metadata_set: Arc<RwLock<TransactionMetadataSet>>,
) -> Self {
Self {
Expand Down Expand Up @@ -83,8 +83,8 @@ impl TrialDecryptions {
let mut workers = FuturesUnordered::new();
let mut cbs = vec![];

let sapling_ivk = SaplingIvk::try_from(&*wc.read().await).ok();
let orchard_ivk = orchard::keys::IncomingViewingKey::try_from(&*wc.read().await).ok();
let sapling_ivk = SaplingIvk::try_from(&*wc).ok();
let orchard_ivk = orchard::keys::IncomingViewingKey::try_from(&*wc).ok();

while let Some(cb) = receiver.recv().await {
cbs.push(cb);
Expand Down Expand Up @@ -145,7 +145,7 @@ impl TrialDecryptions {
async fn trial_decrypt_batch(
config: Arc<ZingoConfig>,
compact_blocks: Vec<CompactBlock>,
wc: Arc<RwLock<WalletCapability>>,
wc: Arc<WalletCapability>,
bsync_data: Arc<RwLock<BlazeSyncData>>,
sapling_ivk: Option<SaplingIvk>,
orchard_ivk: Option<OrchardIvk>,
Expand Down Expand Up @@ -260,7 +260,7 @@ impl TrialDecryptions {
ivk: D::IncomingViewingKey,
height: BlockHeight,
config: &zingoconfig::ZingoConfig,
wc: &Arc<RwLock<WalletCapability>>,
wc: &Arc<WalletCapability>,
bsync_data: &Arc<RwLock<BlazeSyncData>>,
transaction_metadata_set: &Arc<RwLock<TransactionMetadataSet>>,
detected_transaction_id_sender: &UnboundedSender<(
Expand Down Expand Up @@ -295,7 +295,6 @@ impl TrialDecryptions {
let config = config.clone();

workers.push(tokio::spawn(async move {
let wc = wc.read().await;
let Ok(fvk) = D::wc_to_fvk(&wc) else {
// skip any scanning if the wallet doesn't have viewing capability
return Ok::<_, String>(());
Expand Down
6 changes: 2 additions & 4 deletions zingolib/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@ impl Command for WalletKindCommand {
if lightclient.do_seed_phrase().await.is_ok() {
object! {"kind" => "Seeded"}.pretty(4)
} else {
let capability_arc = lightclient.wallet.wallet_capability();
let capability = capability_arc.read().await;
let capability = lightclient.wallet.wallet_capability();
object! {
"kind" => "Loaded from key",
"transparent" => capability.transparent.kind_str(),
Expand Down Expand Up @@ -612,8 +611,7 @@ impl Command for ExportUfvkCommand {
}

fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String {
let key = RT.block_on(lightclient.wallet.transaction_context.key.read());
let ufvk_res = key.ufvk();
let ufvk_res = lightclient.wallet.transaction_context.key.ufvk();
match ufvk_res {
Ok(ufvk) => {
use zcash_address::unified::Encoding as _;
Expand Down
Loading
Loading