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

Dev plus stable #838

Merged
merged 13 commits into from
Mar 12, 2024
72 changes: 63 additions & 9 deletions darkside-tests/tests/network_interruption_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,79 @@ use std::{
collections::HashMap,
sync::{
atomic::{AtomicBool, Ordering},
Arc,
Arc, Mutex,
},
time::Duration,
};

use darkside_tests::utils::{
create_chainbuild_file, load_chainbuild_file,
scenarios::{DarksideScenario, DarksideSender},
use darkside_tests::{
constants::DARKSIDE_SEED,
utils::{
create_chainbuild_file, load_chainbuild_file, prepare_darksidewalletd,
scenarios::{DarksideScenario, DarksideSender},
DarksideHandler,
},
};
use json::JsonValue;
use tokio::time::sleep;
use zingo_testutils::start_proxy_and_connect_lightclient;
use zingo_testutils::{scenarios::setup::ClientBuilder, start_proxy_and_connect_lightclient};
use zingoconfig::RegtestNetwork;
use zingolib::{
get_base_address,
lightclient::PoolBalances,
testvectors::seeds,
wallet::{data::summaries::ValueTransferKind, Pool},
};

#[ignore]
#[tokio::test]
async fn interrupt_initial_tree_fetch() {
let darkside_handler = DarksideHandler::new(None);

let server_id = zingoconfig::construct_lightwalletd_uri(Some(format!(
"http://127.0.0.1:{}",
darkside_handler.grpc_port
)));
prepare_darksidewalletd(server_id.clone(), true)
.await
.unwrap();
let regtest_network = RegtestNetwork::all_upgrades_active();
let light_client = ClientBuilder::new(server_id, darkside_handler.darkside_dir.clone())
.build_client(DARKSIDE_SEED.to_string(), 0, true, regtest_network)
.await;
let mut cond_log =
HashMap::<&'static str, Box<dyn Fn(Arc<AtomicBool>) + Send + Sync + 'static>>::new();
let (sender, receiver) = std::sync::mpsc::channel();
let sender = Arc::new(Mutex::new(sender));
cond_log.insert(
"get_tree_state",
Box::new(move |_online| {
println!("acquiring lcok");
match sender.clone().lock() {
Ok(mutguard) => {
println!("acquired lock");
mutguard.send(()).unwrap();
println!("Ending proxy");
}
Err(poisoned_thread) => panic!("{}", poisoned_thread),
};
}),
);
let (proxy_handle, _proxy_status) =
start_proxy_and_connect_lightclient(&light_client, cond_log);

let receiver = Arc::new(Mutex::new(receiver));
println!("made receiver");
std::thread::spawn(move || {
receiver.lock().unwrap().recv().unwrap();
proxy_handle.abort();
println!("aborted proxy");
});
println!("spawned abortion task");
let result = light_client.do_sync(true).await;
assert_eq!(result.unwrap_err(),"status: Unavailable, message: \"error trying to connect: tcp connect error: Connection refused (os error 111)\", details: [], metadata: MetadataMap { headers: {} }");
}

// Verifies that shielded transactions correctly mark notes as change
// Also verifies:
// - send-to-self value transfer is created
Expand Down Expand Up @@ -104,7 +158,7 @@ async fn shielded_note_marked_as_change_test() {

// setup gRPC network interrupt conditions
let mut conditional_logic =
HashMap::<&'static str, Box<dyn Fn(&Arc<AtomicBool>) + Send + Sync>>::new();
HashMap::<&'static str, Box<dyn Fn(Arc<AtomicBool>) + Send + Sync>>::new();
// conditional_logic.insert(
// "get_block_range",
// Box::new(|online: &Arc<AtomicBool>| {
Expand All @@ -114,20 +168,20 @@ async fn shielded_note_marked_as_change_test() {
// );
conditional_logic.insert(
"get_tree_state",
Box::new(|online: &Arc<AtomicBool>| {
Box::new(|online: Arc<AtomicBool>| {
println!("Turning off, as we received get_tree_state call");
online.store(false, Ordering::Relaxed);
}),
);
conditional_logic.insert(
"get_transaction",
Box::new(|online: &Arc<AtomicBool>| {
Box::new(|online: Arc<AtomicBool>| {
println!("Turning off, as we received get_transaction call");
online.store(false, Ordering::Relaxed);
}),
);

let proxy_status =
let (_proxy_handle, proxy_status) =
start_proxy_and_connect_lightclient(scenario.get_lightclient(0), conditional_logic);
tokio::task::spawn(async move {
loop {
Expand Down
13 changes: 13 additions & 0 deletions integration-tests/tests/integrations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ fn check_view_capability_bounds(
}

mod fast {
use zcash_address::unified::Encoding;
use zingolib::wallet::WalletBase;

use super::*;
#[tokio::test]
async fn utxos_are_not_prematurely_confirmed() {
Expand Down Expand Up @@ -549,6 +552,16 @@ mod fast {
assert!(addr.transparent().is_some());
}

let ufvk = wc.ufvk().unwrap();
let ufvk_string = ufvk.encode(&config.chain.to_zcash_address_network());
let ufvk_base = WalletBase::Ufvk(ufvk_string.clone());
let view_wallet =
LightWallet::new(config.clone(), ufvk_base, wallet.get_birthday().await).unwrap();
let v_wc = view_wallet.wallet_capability();
let vv = v_wc.ufvk().unwrap();
let vv_string = vv.encode(&config.chain.to_zcash_address_network());
assert_eq!(ufvk_string, vv_string);

let client = LightClient::create_from_wallet_async(wallet, config)
.await
.unwrap();
Expand Down
4 changes: 2 additions & 2 deletions zingo-testutils/src/grpc_proxy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub struct ProxyServer {
pub lightwalletd_uri: http::Uri,
pub online: Arc<AtomicBool>,
#[allow(clippy::type_complexity)]
pub conditional_operations: HashMap<&'static str, Box<dyn Fn(&Arc<AtomicBool>) + Send + Sync>>,
pub conditional_operations: HashMap<&'static str, Box<dyn Fn(Arc<AtomicBool>) + Send + Sync>>,
}

impl ProxyServer {
Expand Down Expand Up @@ -93,7 +93,7 @@ impl ProxyServer {

fn passthrough_helper(&self, name: &str) {
if let Some(fun) = self.conditional_operations.get(name) {
fun(&self.online)
fun(self.online.clone())
}
}
pub fn new(lightwalletd_uri: http::Uri) -> Self {
Expand Down
14 changes: 9 additions & 5 deletions zingo-testutils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use std::string::String;
use std::sync::atomic::AtomicBool;
use std::sync::Arc;
use std::time::Duration;
use tokio::task::JoinHandle;
use zcash_address::unified::{Fvk, Ufvk};
use zingolib::wallet::keys::unified::WalletCapability;
use zingolib::wallet::WalletBase;
Expand Down Expand Up @@ -1083,24 +1084,27 @@ pub mod scenarios {
#[allow(clippy::type_complexity)]
pub fn start_proxy_and_connect_lightclient(
client: &LightClient,
conditional_operations: HashMap<&'static str, Box<dyn Fn(&Arc<AtomicBool>) + Send + Sync>>,
) -> Arc<AtomicBool> {
conditional_operations: HashMap<&'static str, Box<dyn Fn(Arc<AtomicBool>) + Send + Sync>>,
) -> (
JoinHandle<Result<(), tonic::transport::Error>>,
Arc<AtomicBool>,
) {
let proxy_online = Arc::new(std::sync::atomic::AtomicBool::new(true));
let proxy_port = portpicker::pick_unused_port().unwrap();
let proxy_uri = format!("http://localhost:{proxy_port}");
let _proxy_handle = ProxyServer {
let proxy_handle = ProxyServer {
lightwalletd_uri: client.get_server_uri(),
online: proxy_online.clone(),
conditional_operations,
}
.serve(proxy_port);
client.set_server(proxy_uri.parse().unwrap());
proxy_online
(proxy_handle, proxy_online)
}

pub async fn check_proxy_server_works() {
let (_regtest_manager, _cph, ref faucet) = scenarios::faucet_default().await;
let proxy_status = start_proxy_and_connect_lightclient(faucet, HashMap::new());
let (_proxy_handle, proxy_status) = start_proxy_and_connect_lightclient(faucet, HashMap::new());
proxy_status.store(false, std::sync::atomic::Ordering::Relaxed);
tokio::task::spawn(async move {
sleep(Duration::from_secs(5)).await;
Expand Down
26 changes: 16 additions & 10 deletions zingolib/src/blaze/block_management_reorg_detection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,17 +322,23 @@ impl BlockManagementData {
existing_blocks: Arc<RwLock<Vec<BlockData>>>,
transaction_metadata_set: Arc<RwLock<TransactionMetadataSet>>,
) {
// First, pop the first block (which is the top block) in the existing_blocks.
let top_wallet_block = existing_blocks.write().await.drain(0..1).next().unwrap();
if top_wallet_block.height != reorg_height {
panic!("Wrong block reorg'd");
}
let mut existing_blocks_writelock = existing_blocks.write().await;
if existing_blocks_writelock.len() != 0 {
// First, pop the first block (which is the top block) in the existing_blocks.
let top_wallet_block = existing_blocks_writelock
.drain(0..1)
.next()
.expect("there to be blocks");
if top_wallet_block.height != reorg_height {
panic!("Wrong block reorg'd");
}

// Remove all wallet transactions at the height
transaction_metadata_set
.write()
.await
.remove_txns_at_height(reorg_height);
// Remove all wallet transactions at the height
transaction_metadata_set
.write()
.await
.remove_txns_at_height(reorg_height);
}
}

/// Ingest the incoming blocks, handle any reorgs, then populate the block data
Expand Down
6 changes: 3 additions & 3 deletions zingolib/src/lightclient.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1386,8 +1386,7 @@ impl LightClient {
self.get_server_uri(),
last_synced_height,
)
.await
.unwrap();
.await?;
self.wallet.initiate_witness_trees(trees).await;
};

Expand Down Expand Up @@ -1447,9 +1446,10 @@ impl LightClient {
let mut res = Err("No batches were run!".to_string());
for (batch_num, batch_latest_block) in latest_block_batches.into_iter().enumerate() {
res = self.sync_nth_batch(batch_latest_block, batch_num).await;
if res.is_err() {
if let Err(ref err) = res {
// If something went wrong during a batch, reset the wallet state to
// how it was before the latest batch
println!("sync hit error {}. Rolling back", err);
BlockManagementData::invalidate_block(
self.wallet.last_synced_height().await,
self.wallet.blocks.clone(),
Expand Down
27 changes: 12 additions & 15 deletions zingolib/src/wallet/keys/unified.rs
Original file line number Diff line number Diff line change
Expand Up @@ -162,24 +162,21 @@ impl WalletCapability {
}
}

pub(crate) fn ufvk(&self) -> Result<Ufvk, zcash_address::unified::ParseError> {
let o_fvk = Fvk::Orchard(
orchard::keys::FullViewingKey::try_from(self)
.unwrap()
.to_bytes(),
);
pub fn ufvk(&self) -> Result<Ufvk, std::string::String> {
let o_fvk = Fvk::Orchard(orchard::keys::FullViewingKey::try_from(self)?.to_bytes());
let s_fvk = Fvk::Sapling(
sapling_crypto::zip32::DiversifiableFullViewingKey::try_from(self)
.unwrap()
.to_bytes(),
sapling_crypto::zip32::DiversifiableFullViewingKey::try_from(self)?.to_bytes(),
);
let mut t_fvk_bytes = [0u8; 65];
let t_ext_pk: ExtendedPubKey = self.try_into().unwrap();
t_fvk_bytes[0..32].copy_from_slice(&t_ext_pk.chain_code[..]);
t_fvk_bytes[32..65].copy_from_slice(&t_ext_pk.public_key.serialize()[..]);
let t_fvk = Fvk::P2pkh(t_fvk_bytes);
use zcash_address::unified::Encoding as _;
Ufvk::try_from_items(vec![o_fvk, s_fvk, t_fvk])
let possible_transparent_key: Result<ExtendedPubKey, String> = self.try_into();
if let Ok(t_ext_pk) = possible_transparent_key {
t_fvk_bytes[0..32].copy_from_slice(&t_ext_pk.chain_code[..]);
t_fvk_bytes[32..65].copy_from_slice(&t_ext_pk.public_key.serialize()[..]);
let t_fvk = Fvk::P2pkh(t_fvk_bytes);
Ufvk::try_from_items(vec![o_fvk, s_fvk, t_fvk]).map_err(|e| e.to_string())
} else {
Ufvk::try_from_items(vec![o_fvk, s_fvk]).map_err(|e| e.to_string())
}
}

pub fn new_address(
Expand Down
Loading