This commit is contained in:
Aditya Kulkarni
2019-09-17 14:09:20 -07:00
parent 51658fe645
commit c6634d2436
4 changed files with 67 additions and 69 deletions

View File

@@ -27,7 +27,7 @@ impl Command for SyncCommand {
} }
fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String { fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String {
lightclient.do_sync() lightclient.do_sync(true)
} }
} }
@@ -116,7 +116,7 @@ impl Command for InfoCommand {
} }
fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String { fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String {
lightclient.do_sync(); lightclient.do_sync(true);
lightclient.do_info() lightclient.do_info()
} }
} }
@@ -139,7 +139,7 @@ impl Command for BalanceCommand {
} }
fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String { fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String {
lightclient.do_sync(); lightclient.do_sync(true);
format!("{}", lightclient.do_address().pretty(2)) format!("{}", lightclient.do_address().pretty(2))
} }
@@ -181,7 +181,7 @@ impl Command for SendCommand {
let memo = if args.len() == 3 { Some(args[2].to_string()) } else {None}; let memo = if args.len() == 3 { Some(args[2].to_string()) } else {None};
lightclient.do_sync(); lightclient.do_sync(true);
lightclient.do_send(args[0], value, memo) lightclient.do_send(args[0], value, memo)
} }
@@ -249,7 +249,7 @@ impl Command for TransactionsCommand {
} }
fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String { fn exec(&self, _args: &[&str], lightclient: &LightClient) -> String {
lightclient.do_sync(); lightclient.do_sync(true);
format!("{}", lightclient.do_list_transactions().pretty(2)) format!("{}", lightclient.do_list_transactions().pretty(2))
} }
@@ -289,7 +289,7 @@ impl Command for NotesCommand {
false false
}; };
lightclient.do_sync(); lightclient.do_sync(true);
format!("{}", lightclient.do_list_notes(all_notes).pretty(2)) format!("{}", lightclient.do_list_notes(all_notes).pretty(2))
} }

View File

@@ -274,6 +274,7 @@ impl LightClient {
// Collect UTXOs // Collect UTXOs
let utxos = self.wallet.get_utxos().iter() let utxos = self.wallet.get_utxos().iter()
.filter(|utxo| utxo.unconfirmed_spent.is_none()) // Filter out unconfirmed from the list of utxos
.map(|utxo| { .map(|utxo| {
object!{ object!{
"created_in_block" => utxo.height, "created_in_block" => utxo.height,
@@ -289,25 +290,20 @@ impl LightClient {
.collect::<Vec<JsonValue>>(); .collect::<Vec<JsonValue>>();
// Collect pending UTXOs // Collect pending UTXOs
let pending_utxos = self.wallet.txs.read().unwrap().iter() let pending_utxos = self.wallet.get_utxos().iter()
.flat_map( |(txid, wtx)| { .filter(|utxo| utxo.unconfirmed_spent.is_some()) // Filter to include only unconfirmed utxos
wtx.utxos.iter().filter_map(move |utxo| .map(|utxo|
if utxo.unconfirmed_spent.is_some() { object!{
Some(object!{ "created_in_block" => utxo.height,
"created_in_block" => wtx.block, "created_in_txid" => format!("{}", utxo.txid),
"created_in_txid" => format!("{}", txid),
"value" => utxo.value, "value" => utxo.value,
"scriptkey" => hex::encode(utxo.script.clone()), "scriptkey" => hex::encode(utxo.script.clone()),
"is_change" => false, // TODO: Identify notes as change "is_change" => false, // TODO: Identify notes as change
"address" => utxo.address.clone(), "address" => utxo.address.clone(),
"spent" => utxo.spent.map(|spent_txid| format!("{}", spent_txid)), "spent" => utxo.spent.map(|spent_txid| format!("{}", spent_txid)),
"unconfirmed_spent" => utxo.unconfirmed_spent.map(|spent_txid| format!("{}", spent_txid)), "unconfirmed_spent" => utxo.unconfirmed_spent.map(|spent_txid| format!("{}", spent_txid)),
})
} else {
None
} }
) )
})
.collect::<Vec<JsonValue>>();; .collect::<Vec<JsonValue>>();;
let mut res = object!{ let mut res = object!{
@@ -430,13 +426,13 @@ impl LightClient {
self.set_wallet_initial_state(); self.set_wallet_initial_state();
// Then, do a sync, which will force a full rescan from the initial state // Then, do a sync, which will force a full rescan from the initial state
let response = self.do_sync(); let response = self.do_sync(true);
info!("Rescan finished"); info!("Rescan finished");
response response
} }
pub fn do_sync(&self) -> String { pub fn do_sync(&self, print_updates: bool) -> String {
// Sync is 3 parts // Sync is 3 parts
// 1. Get the latest block // 1. Get the latest block
// 2. Get all the blocks that we don't have // 2. Get all the blocks that we don't have
@@ -471,7 +467,7 @@ impl LightClient {
let local_bytes_downloaded = bytes_downloaded.clone(); let local_bytes_downloaded = bytes_downloaded.clone();
// Show updates only if we're syncing a lot of blocks // Show updates only if we're syncing a lot of blocks
if end_height - last_scanned_height > 100 { if print_updates && end_height - last_scanned_height > 100 {
print!("Syncing {}/{}\r", last_scanned_height, last_block); print!("Syncing {}/{}\r", last_scanned_height, last_block);
io::stdout().flush().ok().expect("Could not flush stdout"); io::stdout().flush().ok().expect("Could not flush stdout");
} }
@@ -506,7 +502,9 @@ impl LightClient {
end_height = last_block; end_height = last_block;
} }
} }
println!(); // Print a new line, to finalize the syncing updates if print_updates{
println!(""); // New line to finish up the updates
}
let mut responses = vec![]; let mut responses = vec![];

View File

@@ -1235,24 +1235,9 @@ impl LightWallet {
// ZecWallet will add all your t-address funds into that transaction, and send them to your shielded // ZecWallet will add all your t-address funds into that transaction, and send them to your shielded
// address as change. // address as change.
let tinputs = self.get_utxos().iter() let tinputs = self.get_utxos().iter()
.map(|utxo| { .filter(|utxo| utxo.unconfirmed_spent.is_none()) // Remove any unconfirmed spends
let outpoint: OutPoint = utxo.to_outpoint(); .map(|utxo| utxo.clone())
.collect::<Vec<Utxo>>();
// Mark this utxo as uncofirmed spent
let mut txs = self.txs.write().unwrap();
let mut spent_utxo = txs.get_mut(&utxo.txid).unwrap().utxos.iter_mut()
.find(|u| utxo.txid == u.txid && utxo.output_index == u.output_index)
.unwrap();
spent_utxo.unconfirmed_spent = Some(utxo.txid);
let coin = TxOut {
value: Amount::from_u64(utxo.value).unwrap(),
script_pubkey: Script { 0: utxo.script.clone() },
};
(outpoint, coin)
})
.collect::<Vec<(OutPoint, TxOut)>>();
if let Err(e) = match to { if let Err(e) = match to {
address::RecipientAddress::Shielded(_) => { address::RecipientAddress::Shielded(_) => {
@@ -1261,20 +1246,28 @@ impl LightWallet {
let sk = self.tkeys[0]; let sk = self.tkeys[0];
// Add all tinputs // Add all tinputs
tinputs.iter().map( |(outpoint, coin)| { tinputs.iter()
.map(|utxo| {
let outpoint: OutPoint = utxo.to_outpoint();
let coin = TxOut {
value: Amount::from_u64(utxo.value).unwrap(),
script_pubkey: Script { 0: utxo.script.clone() },
};
builder.add_transparent_input(sk, outpoint.clone(), coin.clone()) builder.add_transparent_input(sk, outpoint.clone(), coin.clone())
}).collect::<Result<Vec<_>, _>>() })
} .collect::<Result<Vec<_>, _>>()
_ => {Ok(vec![])} },
_ => Ok(vec![])
} { } {
eprintln!("Error adding transparent inputs: {:?}", e); eprintln!("Error adding transparent inputs: {:?}", e);
return None; return None;
} }
// Confirm we were able to select sufficient value // Confirm we were able to select sufficient value
// TODO: If we're sending to a t-address, we could also use t-address inputs
let selected_value = notes.iter().map(|selected| selected.note.value).sum::<u64>() let selected_value = notes.iter().map(|selected| selected.note.value).sum::<u64>()
+ tinputs.iter().map::<u64, _>(|(_, coin)| coin.value.into()).sum::<u64>(); + tinputs.iter().map::<u64, _>(|utxo| utxo.value.into()).sum::<u64>();
if selected_value < u64::from(target_value) { if selected_value < u64::from(target_value) {
eprintln!( eprintln!(
@@ -1329,19 +1322,26 @@ impl LightWallet {
println!("Transaction ID: {}", tx.txid()); println!("Transaction ID: {}", tx.txid());
// Mark notes as spent. // Mark notes as spent.
// TODO: This is only a non-confirmed spend, and the note should be marked as such. {
// Mark sapling notes as unconfirmed spent
let mut txs = self.txs.write().unwrap(); let mut txs = self.txs.write().unwrap();
for selected in notes { for selected in notes {
let mut spent_note = txs let mut spent_note = txs.get_mut(&selected.txid).unwrap()
.get_mut(&selected.txid) .notes.iter_mut()
.unwrap()
.notes
.iter_mut()
.find(|nd| &nd.nullifier[..] == &selected.nullifier[..]) .find(|nd| &nd.nullifier[..] == &selected.nullifier[..])
.unwrap(); .unwrap();
spent_note.unconfirmed_spent = Some(tx.txid()); spent_note.unconfirmed_spent = Some(tx.txid());
} }
// Mark this utxo as unconfirmed spent
for utxo in tinputs {
let mut spent_utxo = txs.get_mut(&utxo.txid).unwrap().utxos.iter_mut()
.find(|u| utxo.txid == u.txid && utxo.output_index == u.output_index)
.unwrap();
spent_utxo.unconfirmed_spent = Some(tx.txid());
}
}
// Return the encoded transaction, so the caller can send it. // Return the encoded transaction, so the caller can send it.
let mut raw_tx = vec![]; let mut raw_tx = vec![];
tx.write(&mut raw_tx).unwrap(); tx.write(&mut raw_tx).unwrap();

View File

@@ -70,7 +70,7 @@ pub fn main() {
info!("{}", lightclient.do_info()); info!("{}", lightclient.do_info());
// At startup, run a sync // At startup, run a sync
let sync_update = lightclient.do_sync(); let sync_update = lightclient.do_sync(true);
println!("{}", sync_update); println!("{}", sync_update);
let (command_tx, command_rx) = std::sync::mpsc::channel::<(String, Vec<String>)>(); let (command_tx, command_rx) = std::sync::mpsc::channel::<(String, Vec<String>)>();
@@ -91,8 +91,8 @@ pub fn main() {
} }
}, },
Err(_) => { Err(_) => {
// Timeout. Do a sync to keep the wallet up-to-date // Timeout. Do a sync to keep the wallet up-to-date. False to whether to print updates on the console
lc.do_sync(); lc.do_sync(false);
} }
} }
} }