From 0e8ab4d27d34bc67570d1daf6793e64911ef5acd Mon Sep 17 00:00:00 2001 From: Aditya Kulkarni Date: Tue, 17 Sep 2019 13:26:45 -0700 Subject: [PATCH] Read UTXOs from walletTx --- src/lightclient.rs | 81 ++++------------------------------------------ src/lightwallet.rs | 40 ++++++++++------------- 2 files changed, 23 insertions(+), 98 deletions(-) diff --git a/src/lightclient.rs b/src/lightclient.rs index fa87d46..6fa15b6 100644 --- a/src/lightclient.rs +++ b/src/lightclient.rs @@ -273,7 +273,7 @@ impl LightClient { }); // Collect UTXOs - let utxos = self.wallet.utxos.read().unwrap().iter() + let utxos = self.wallet.get_utxos().iter() .map(|utxo| { object!{ "created_in_block" => utxo.height, @@ -457,6 +457,11 @@ impl LightClient { // Get the end height to scan to. let mut end_height = std::cmp::min(last_scanned_height + 1000, last_block); + // If there's nothing to scan, just return + if last_scanned_height == last_block { + return "".to_string(); + } + // Count how many bytes we've downloaded let bytes_downloaded = Arc::new(AtomicUsize::new(0)); @@ -553,20 +558,6 @@ impl LightClient { }); }; - // Finally, fetch the UTXOs - - // Get all the UTXOs for our transparent addresses, clearing out the current list - self.wallet.clear_utxos(); - // Fetch UTXOs - self.wallet.tkeys.iter() - .map( |sk| LightWallet::address_from_sk(&sk)) - .for_each( |taddr| { - let wallet = self.wallet.clone(); - self.fetch_utxos(taddr, move |utxo| { - wallet.add_utxo(&utxo); - }); - }); - responses.join("\n") } @@ -637,66 +628,6 @@ impl LightClient { tokio::runtime::current_thread::Runtime::new().unwrap().block_on(say_hello).unwrap(); } - pub fn fetch_utxos(&self, address: String, c: F) - where F : Fn(crate::lightwallet::Utxo) { - let uri: http::Uri = self.server.parse().unwrap(); - - let dst = Destination::try_from_uri(uri.clone()).unwrap(); - let connector = util::Connector::new(HttpConnector::new(4)); - let settings = client::Builder::new().http2_only(true).clone(); - let mut make_client = client::Connect::with_builder(connector, settings); - - let say_hello = make_client - .make_service(dst) - .map_err(|e| panic!("connect error: {:?}", e)) - .and_then(move |conn| { - - let conn = tower_request_modifier::Builder::new() - .set_origin(uri) - .build(conn) - .unwrap(); - - // Wait until the client is ready... - CompactTxStreamer::new(conn) - .ready() - .map_err(|e| eprintln!("streaming error {:?}", e)) - }) - .and_then(move |mut client| { - - let br = Request::new(TransparentAddress{ address }); - client - .get_utxos(br) - .map_err(|e| { - eprintln!("RouteChat request failed; err={:?}", e); - }) - .and_then(move |response| { - let inbound = response.into_inner(); - inbound.for_each(move |b| { - let mut txid_bytes = [0u8; 32]; - txid_bytes.copy_from_slice(&b.txid); - - let u = crate::lightwallet::Utxo { - address: b.address.unwrap().address, - txid: TxId {0: txid_bytes}, - output_index: b.output_index, - script: b.script.to_vec(), - height: b.height as i32, - value: b.value, - spent: None, - unconfirmed_spent: None, - }; - - c(u); - - Ok(()) - }) - .map_err(|e| eprintln!("gRPC inbound stream error: {:?}", e)) - }) - }); - - tokio::runtime::current_thread::Runtime::new().unwrap().block_on(say_hello).unwrap(); - } - pub fn fetch_transparent_txids(&self, address: String, start_height: u64, end_height: u64,c: F) where F : Fn(&[u8], u64) { diff --git a/src/lightwallet.rs b/src/lightwallet.rs index b032007..9ce5ac2 100644 --- a/src/lightwallet.rs +++ b/src/lightwallet.rs @@ -469,6 +469,7 @@ impl WalletTx { let txid = TxId{0: txid_bytes}; let notes = Vector::read(&mut reader, |r| SaplingNoteData::read(r))?; + let utxos = Vector::read(&mut reader, |r| Utxo::read(r))?; let total_shielded_value_spent = reader.read_u64::()?; let total_transparent_value_spent = reader.read_u64::()?; @@ -477,7 +478,7 @@ impl WalletTx { block, txid, notes, - utxos: vec![], + utxos, total_shielded_value_spent, total_transparent_value_spent }) @@ -491,6 +492,7 @@ impl WalletTx { writer.write_all(&self.txid.0)?; Vector::write(&mut writer, &self.notes, |w, nd| nd.write(w))?; + Vector::write(&mut writer, &self.utxos, |w, u| u.write(w))?; writer.write_u64::(self.total_shielded_value_spent)?; writer.write_u64::(self.total_transparent_value_spent)?; @@ -539,10 +541,6 @@ pub struct LightWallet { // Transparent keys. TODO: Make it not pubic pub tkeys: Vec, - // Current UTXOs that can be spent. - // TODO: Remove this, and read from txs.values().utxos - pub utxos: Arc>>, - blocks: Arc>>, pub txs: Arc>>, } @@ -597,7 +595,6 @@ impl LightWallet { extfvks: vec![extfvk], address: vec![address], tkeys: vec![tpk], - utxos: Arc::new(RwLock::new(vec![])), blocks: Arc::new(RwLock::new(vec![])), txs: Arc::new(RwLock::new(HashMap::new())), }) @@ -627,8 +624,6 @@ impl LightWallet { reader.read_exact(&mut tpk_bytes)?; let tpk = secp256k1::SecretKey::from_slice(&tpk_bytes).unwrap(); - let utxos = Vector::read(&mut reader, |r| Utxo::read(r))?; - let blocks = Vector::read(&mut reader, |r| BlockData::read(r))?; let txs_tuples = Vector::read(&mut reader, |r| { @@ -645,7 +640,6 @@ impl LightWallet { extfvks: extfvks, address: addresses, tkeys: vec![tpk], - utxos: Arc::new(RwLock::new(utxos)), blocks: Arc::new(RwLock::new(blocks)), txs: Arc::new(RwLock::new(txs)) }) @@ -667,8 +661,6 @@ impl LightWallet { // TODO: This only writes the first key for now writer.write_all(&self.tkeys[0][..])?; - Vector::write(&mut writer, &self.utxos.read().unwrap(), |w, u| u.write(w))?; - Vector::write(&mut writer, &self.blocks.read().unwrap(), |w, b| b.write(w))?; // The hashmap, write as a set of tuples @@ -829,8 +821,20 @@ impl LightWallet { .sum::() } + // Get all (unspent) utxos. Unconfirmed spent utxos are included + pub fn get_utxos(&self) -> Vec { + let txs = self.txs.read().unwrap(); + + txs.values() + .flat_map(|tx| { + tx.utxos.iter().filter(|utxo| utxo.spent.is_none()) + }) + .map(|utxo| utxo.clone()) + .collect::>() + } + pub fn tbalance(&self, addr: Option) -> u64 { - self.utxos.read().unwrap().iter() + self.get_utxos().iter() .filter(|utxo| { match addr.clone() { Some(a) => utxo.address == a, @@ -1006,16 +1010,6 @@ impl LightWallet { } } - pub fn clear_utxos(&self) { - let mut utxos = self.utxos.write().unwrap(); - utxos.clear(); - } - - pub fn add_utxo(&self, utxo: &Utxo) { - let mut utxos = self.utxos.write().unwrap(); - utxos.push(utxo.clone()); - } - pub fn scan_block(&self, block: &[u8]) -> bool { let block: CompactBlock = match parse_from_bytes(block) { Ok(block) => block, @@ -1240,7 +1234,7 @@ impl LightWallet { // Specifically, if you send an outgoing transaction that is sent to a shielded address, // ZecWallet will add all your t-address funds into that transaction, and send them to your shielded // address as change. - let tinputs = self.utxos.read().unwrap().iter() + let tinputs = self.get_utxos().iter() .map(|utxo| { let outpoint: OutPoint = utxo.to_outpoint();