diff --git a/core/src/core/block.rs b/core/src/core/block.rs index b0c520477..0cd9ff149 100644 --- a/core/src/core/block.rs +++ b/core/src/core/block.rs @@ -344,8 +344,8 @@ impl Block { ..time::now_utc() }, previous: prev.hash(), - total_difficulty: prev.pow.clone().to_difficulty() - + prev.total_difficulty.clone(), + total_difficulty: prev.pow.clone().to_difficulty() + + prev.total_difficulty.clone(), ..Default::default() }, inputs: inputs, @@ -466,9 +466,7 @@ impl Block { } if k.lock_height > self.header.height { - return Err(Error::KernelLockHeight { - lock_height: k.lock_height, - }); + return Err(Error::KernelLockHeight { lock_height: k.lock_height }); } } @@ -494,17 +492,18 @@ impl Block { } // Validate the coinbase outputs generated by miners. Entails 2 main checks: - // - // * That the sum of all coinbase-marked outputs equal the supply. - // * That the sum of blinding factors for all coinbase-marked outputs match - // the coinbase-marked kernels. + // + // * That the sum of all coinbase-marked outputs equal the supply. + // * That the sum of blinding factors for all coinbase-marked outputs match + // the coinbase-marked kernels. fn verify_coinbase(&self, secp: &Secp256k1) -> Result<(), Error> { - let cb_outs = filter_map_vec!(self.outputs, |out| { - if out.features.contains(COINBASE_OUTPUT) { - Some(out.commitment()) - } else { - None - } + let cb_outs = filter_map_vec!(self.outputs, |out| if out.features.contains( + COINBASE_OUTPUT, + ) + { + Some(out.commitment()) + } else { + None }); let cb_kerns = filter_map_vec!(self.kernels, |k| if k.features.contains(COINBASE_KERNEL) { Some(k.excess) @@ -585,14 +584,14 @@ mod test { use util::secp; // utility to create a block without worrying about the key or previous - // header + // header fn new_block(txs: Vec<&Transaction>, keychain: &Keychain) -> Block { let key_id = keychain.derive_key_id(1).unwrap(); Block::new(&BlockHeader::default(), txs, keychain, &key_id).unwrap() } // utility producing a transaction that spends an output with the provided - // value and blinding key + // value and blinding key fn txspend1i1o( v: u64, keychain: &Keychain, @@ -652,7 +651,7 @@ mod test { let b = new_block(vec![&mut btx1, &mut btx2, &mut btx3], &keychain); // block should have been automatically compacted (including reward - // output) and should still be valid + // output) and should still be valid b.validate(&keychain.secp()).unwrap(); assert_eq!(b.inputs.len(), 3); assert_eq!(b.outputs.len(), 3); @@ -660,7 +659,7 @@ mod test { #[test] // builds 2 different blocks with a tx spending another and check if merging - // occurs + // occurs fn mergeable_blocks() { let keychain = Keychain::from_random_seed().unwrap(); let key_id1 = keychain.derive_key_id(1).unwrap(); @@ -713,14 +712,14 @@ mod test { assert_eq!(coinbase_kernels.len(), 1); // the block should be valid here (single coinbase output with corresponding - // txn kernel) + // txn kernel) assert_eq!(b.validate(&keychain.secp()), Ok(())); } #[test] // test that flipping the COINBASE_OUTPUT flag on the output features - // invalidates the block and specifically it causes verify_coinbase to fail - // additionally verifying the merkle_inputs_outputs also fails + // invalidates the block and specifically it causes verify_coinbase to fail + // additionally verifying the merkle_inputs_outputs also fails fn remove_coinbase_output_flag() { let keychain = Keychain::from_random_seed().unwrap(); let mut b = new_block(vec![], &keychain); @@ -742,7 +741,7 @@ mod test { #[test] // test that flipping the COINBASE_KERNEL flag on the kernel features - // invalidates the block and specifically it causes verify_coinbase to fail + // invalidates the block and specifically it causes verify_coinbase to fail fn remove_coinbase_kernel_flag() { let keychain = Keychain::from_random_seed().unwrap(); let mut b = new_block(vec![], &keychain); diff --git a/core/src/core/build.rs b/core/src/core/build.rs index 64964011f..aeeba36eb 100644 --- a/core/src/core/build.rs +++ b/core/src/core/build.rs @@ -40,8 +40,7 @@ pub struct Context<'a> { /// Function type returned by the transaction combinators. Transforms a /// (Transaction, BlindSum) pair into another, provided some context. -pub type Append = for<'a> Fn(&'a mut Context, (Transaction, BlindSum)) - -> (Transaction, BlindSum); +pub type Append = for<'a> Fn(&'a mut Context, (Transaction, BlindSum)) -> (Transaction, BlindSum); /// Adds an input with the provided value and blinding key to the transaction /// being built. @@ -133,11 +132,10 @@ pub fn transaction( keychain: &keychain::Keychain, ) -> Result<(Transaction, BlindingFactor), keychain::Error> { let mut ctx = Context { keychain }; - let (mut tx, sum) = elems - .iter() - .fold((Transaction::empty(), BlindSum::new()), |acc, elem| { - elem(&mut ctx, acc) - }); + let (mut tx, sum) = elems.iter().fold( + (Transaction::empty(), BlindSum::new()), + |acc, elem| elem(&mut ctx, acc), + ); let blind_sum = ctx.keychain.blind_sum(&sum)?; let msg = secp::Message::from_slice(&kernel_sig_msg(tx.fee, tx.lock_height))?; let sig = ctx.keychain.sign_with_blinding(&msg, &blind_sum)?; diff --git a/core/src/core/hash.rs b/core/src/core/hash.rs index f758ceb94..9e5dec361 100644 --- a/core/src/core/hash.rs +++ b/core/src/core/hash.rs @@ -153,9 +153,7 @@ impl HashWriter { impl Default for HashWriter { fn default() -> HashWriter { - HashWriter { - state: Blake2b::new(32), - } + HashWriter { state: Blake2b::new(32) } } } @@ -204,8 +202,7 @@ impl VerifySortOrder for Vec { .map(|item| item.hash()) .collect::>() .windows(2) - .any(|pair| pair[0] > pair[1]) - { + .any(|pair| pair[0] > pair[1]) { true => Err(ser::Error::BadlySorted), false => Ok(()), } diff --git a/core/src/core/mod.rs b/core/src/core/mod.rs index 0888738db..a0167a0b2 100644 --- a/core/src/core/mod.rs +++ b/core/src/core/mod.rs @@ -25,6 +25,8 @@ pub mod transaction; use std::fmt; use std::cmp::Ordering; +use std::num::ParseFloatError; +use consensus::GRIN_BASE; use util::secp::{self, Secp256k1}; use util::secp::pedersen::*; @@ -53,7 +55,7 @@ pub trait Committed { let mut output_commits = map_vec!(self.outputs_committed(), |out| out.commitment()); // add the overage as output commitment if positive, as an input commitment if - // negative + // negative let overage = self.overage(); if overage != 0 { let over_commit = secp.commit_value(overage.abs() as u64).unwrap(); @@ -182,6 +184,22 @@ impl Writeable for Proof { } } +/// Common method for parsing an amount from human-readable, and converting +/// to internally-compatible u64 + +pub fn amount_from_hr_string(amount: &str) -> Result { + let amount = amount.parse::()?; + Ok((amount * GRIN_BASE as f64) as u64) +} + +/// Common method for converting an amount to a human-readable string + +pub fn amount_to_hr_string(amount: u64) -> String { + let amount = (amount as f64 / GRIN_BASE as f64) as f64; + let places = (GRIN_BASE as f64).log(10.0) as usize + 1; + String::from(format!("{:.*}", places, amount)) +} + #[cfg(test)] mod test { use super::*; @@ -192,6 +210,27 @@ mod test { use keychain; use keychain::{BlindingFactor, Keychain}; + #[test] + pub fn test_amount_to_hr() { + assert!(50123456789 == amount_from_hr_string("50.123456789").unwrap()); + assert!(50 == amount_from_hr_string(".000000050").unwrap()); + assert!(1 == amount_from_hr_string(".000000001").unwrap()); + assert!(0 == amount_from_hr_string(".0000000009").unwrap()); + assert!(500_000_000_000 == amount_from_hr_string("500").unwrap()); + assert!( + 5_000_000_000_000_000_000 == amount_from_hr_string("5000000000.00000000000").unwrap() + ); + } + + #[test] + pub fn test_hr_to_amount() { + assert!("50.123456789" == amount_to_hr_string(50123456789)); + assert!("0.000000050" == amount_to_hr_string(50)); + assert!("0.000000001" == amount_to_hr_string(1)); + assert!("500.000000000" == amount_to_hr_string(500_000_000_000)); + assert!("5000000000.000000000" == amount_to_hr_string(5_000_000_000_000_000_000)); + } + #[test] #[should_panic(expected = "InvalidSecretKey")] fn test_zero_commit_fails() { @@ -308,11 +347,11 @@ mod test { { // Alice gets 2 of her pre-existing outputs to send 5 coins to Bob, they - // become inputs in the new transaction + // become inputs in the new transaction let (in1, in2) = (input(4, key_id1), input(3, key_id2)); // Alice builds her transaction, with change, which also produces the sum - // of blinding factors before they're obscured. + // of blinding factors before they're obscured. let (tx, sum) = build::transaction(vec![in1, in2, output(1, key_id3), with_fee(2)], &keychain) .unwrap(); @@ -321,8 +360,8 @@ mod test { } // From now on, Bob only has the obscured transaction and the sum of - // blinding factors. He adds his output, finalizes the transaction so it's - // ready for broadcast. + // blinding factors. He adds his output, finalizes the transaction so it's + // ready for broadcast. let (tx_final, _) = build::transaction( vec![ initial_tx(tx_alice), @@ -382,7 +421,7 @@ mod test { let key_id3 = keychain.derive_key_id(3).unwrap(); // first check we can add a timelocked tx where lock height matches current block height - // and that the resulting block is valid + // and that the resulting block is valid let tx1 = build::transaction( vec![ input(5, key_id1.clone()), @@ -421,9 +460,7 @@ mod test { &key_id3.clone(), ).unwrap(); match b.validate(keychain.secp()) { - Err(KernelLockHeight { - lock_height: height, - }) => { + Err(KernelLockHeight { lock_height: height }) => { assert_eq!(height, 2); } _ => panic!("expecting KernelLockHeight error here"), diff --git a/core/src/core/pmmr.rs b/core/src/core/pmmr.rs index 346f2d8a4..7fad68b13 100644 --- a/core/src/core/pmmr.rs +++ b/core/src/core/pmmr.rs @@ -267,14 +267,14 @@ where let mut pos = elmt_pos; // we look ahead one position in the MMR, if the expected node has a higher - // height it means we have to build a higher peak by summing with a previous - // sibling. we do it iteratively in case the new peak itself allows the - // creation of another parent. + // height it means we have to build a higher peak by summing with a previous + // sibling. we do it iteratively in case the new peak itself allows the + // creation of another parent. while bintree_postorder_height(pos + 1) > height { let left_sibling = bintree_jump_left_sibling(pos); - let left_hashsum = self.backend - .get(left_sibling) - .expect("missing left sibling in tree, should not have been pruned"); + let left_hashsum = self.backend.get(left_sibling).expect( + "missing left sibling in tree, should not have been pruned", + ); current_hashsum = left_hashsum + current_hashsum; to_append.push(current_hashsum.clone()); @@ -293,8 +293,8 @@ where /// well as the consumer-provided index of when the change occurred. pub fn rewind(&mut self, position: u64, index: u32) -> Result<(), String> { // identify which actual position we should rewind to as the provided - // position is a leaf, which may had some parent that needs to exist - // afterward for the MMR to be valid + // position is a leaf, which may had some parent that needs to exist + // afterward for the MMR to be valid let mut pos = position; while bintree_postorder_height(pos + 1) > 0 { pos += 1; @@ -320,7 +320,7 @@ where } // loop going up the tree, from node to parent, as long as we stay inside - // the tree. + // the tree. let mut to_prune = vec![]; let mut current = position; while current + 1 < self.last_pos { @@ -332,7 +332,7 @@ where to_prune.push(current); // if we have a pruned sibling, we can continue up the tree - // otherwise we're done + // otherwise we're done if let None = self.backend.get(sibling) { current = parent; } else { @@ -357,13 +357,13 @@ where let mut last_leaf = self.last_pos; let size = self.unpruned_size(); // Special case that causes issues in bintree functions, - // just return + // just return if size == 1 { return_vec.push(self.backend.get(last_leaf).unwrap()); return return_vec; } // if size is even, we're already at the bottom, otherwise - // we need to traverse down to it (reverse post-order direction) + // we need to traverse down to it (reverse post-order direction) if size % 2 == 1 { last_leaf = bintree_rightmost(self.last_pos); } @@ -503,21 +503,19 @@ pub struct PruneList { impl PruneList { /// Instantiate a new empty prune list pub fn new() -> PruneList { - PruneList { - pruned_nodes: vec![], - } + PruneList { pruned_nodes: vec![] } } /// Computes by how many positions a node at pos should be shifted given the /// number of nodes that have already been pruned before it. pub fn get_shift(&self, pos: u64) -> Option { // get the position where the node at pos would fit in the pruned list, if - // it's already pruned, nothing to skip + // it's already pruned, nothing to skip match self.pruned_pos(pos) { None => None, Some(idx) => { // skip by the number of elements pruned in the preceding subtrees, - // which is the sum of the size of each subtree + // which is the sum of the size of each subtree Some( self.pruned_nodes[0..(idx as usize)] .iter() @@ -559,8 +557,8 @@ impl PruneList { Err(idx) => { if self.pruned_nodes.len() > idx { // the node at pos can't be a child of lower position nodes by MMR - // construction but can be a child of the next node, going up parents - // from pos to make sure it's not the case + // construction but can be a child of the next node, going up parents + // from pos to make sure it's not the case let next_peak_pos = self.pruned_nodes[idx]; let mut cursor = pos; loop { @@ -586,13 +584,13 @@ impl PruneList { /// of the range. fn peaks(num: u64) -> Vec { // detecting an invalid mountain range, when siblings exist but no parent - // exists + // exists if bintree_postorder_height(num + 1) > bintree_postorder_height(num) { return vec![]; } // our top peak is always on the leftmost side of the tree and leftmost trees - // have for index a binary values with all 1s (i.e. 11, 111, 1111, etc.) + // have for index a binary values with all 1s (i.e. 11, 111, 1111, etc.) let mut top = 1; while (top - 1) <= num { top = top << 1; @@ -605,7 +603,7 @@ fn peaks(num: u64) -> Vec { let mut peaks = vec![top]; // going down the range, next peaks are right neighbors of the top. if one - // doesn't exist yet, we go down to a smaller peak to the left + // doesn't exist yet, we go down to a smaller peak to the left let mut peak = top; 'outer: loop { peak = bintree_jump_right_sibling(peak); @@ -845,9 +843,9 @@ mod test { type Sum = u64; fn sum(&self) -> u64 { // sums are not allowed to overflow, so we use this simple - // non-injective "sum" function that will still be homomorphic - self.0[0] as u64 * 0x1000 + self.0[1] as u64 * 0x100 + self.0[2] as u64 * 0x10 - + self.0[3] as u64 + // non-injective "sum" function that will still be homomorphic + self.0[0] as u64 * 0x1000 + self.0[1] as u64 * 0x100 + self.0[2] as u64 * 0x10 + + self.0[3] as u64 } fn sum_len() -> usize { 8 @@ -897,8 +895,8 @@ mod test { // two elements pmmr.push(elems[1], None::).unwrap(); - let sum2 = HashSum::from_summable(1, &elems[0], None::) - + HashSum::from_summable(2, &elems[1], None::); + let sum2 = HashSum::from_summable(1, &elems[0], None::) + + HashSum::from_summable(2, &elems[1], None::); assert_eq!(pmmr.root(), sum2); assert_eq!(pmmr.unpruned_size(), 3); @@ -910,9 +908,9 @@ mod test { // four elements pmmr.push(elems[3], None::).unwrap(); - let sum4 = sum2 - + (HashSum::from_summable(4, &elems[2], None::) - + HashSum::from_summable(5, &elems[3], None::)); + let sum4 = sum2 + + (HashSum::from_summable(4, &elems[2], None::) + + HashSum::from_summable(5, &elems[3], None::)); assert_eq!(pmmr.root(), sum4); assert_eq!(pmmr.unpruned_size(), 7); @@ -924,9 +922,9 @@ mod test { // six elements pmmr.push(elems[5], None::).unwrap(); - let sum6 = sum4.clone() - + (HashSum::from_summable(8, &elems[4], None::) - + HashSum::from_summable(9, &elems[5], None::)); + let sum6 = sum4.clone() + + (HashSum::from_summable(8, &elems[4], None::) + + HashSum::from_summable(9, &elems[5], None::)); assert_eq!(pmmr.root(), sum6.clone()); assert_eq!(pmmr.unpruned_size(), 10); @@ -938,11 +936,11 @@ mod test { // eight elements pmmr.push(elems[7], None::).unwrap(); - let sum8 = sum4 - + ((HashSum::from_summable(8, &elems[4], None::) - + HashSum::from_summable(9, &elems[5], None::)) - + (HashSum::from_summable(11, &elems[6], None::) - + HashSum::from_summable(12, &elems[7], None::))); + let sum8 = sum4 + + ((HashSum::from_summable(8, &elems[4], None::) + + HashSum::from_summable(9, &elems[5], None::)) + + (HashSum::from_summable(11, &elems[6], None::) + + HashSum::from_summable(12, &elems[7], None::))); assert_eq!(pmmr.root(), sum8); assert_eq!(pmmr.unpruned_size(), 15); @@ -991,8 +989,7 @@ mod test { let res = pmmr.get_last_n_insertions(19); assert!( - res[0].sum == 4 && res[1].sum == 3 && res[2].sum == 2 && res[3].sum == 1 - && res.len() == 4 + res[0].sum == 4 && res[1].sum == 3 && res[2].sum == 2 && res[3].sum == 1 && res.len() == 4 ); pmmr.push(elems[5], None::).unwrap(); @@ -1002,8 +999,7 @@ mod test { let res = pmmr.get_last_n_insertions(7); assert!( - res[0].sum == 9 && res[1].sum == 8 && res[2].sum == 7 && res[3].sum == 6 - && res.len() == 7 + res[0].sum == 9 && res[1].sum == 8 && res[2].sum == 7 && res[3].sum == 6 && res.len() == 7 ); } diff --git a/core/src/core/target.rs b/core/src/core/target.rs index 4aab75ff4..673f6e559 100644 --- a/core/src/core/target.rs +++ b/core/src/core/target.rs @@ -63,9 +63,7 @@ impl Difficulty { let mut in_vec = h.to_vec(); in_vec.truncate(8); let num = BigEndian::read_u64(&in_vec); - Difficulty { - num: max_target / num, - } + Difficulty { num: max_target / num } } /// Converts the difficulty into a u64 @@ -83,36 +81,28 @@ impl fmt::Display for Difficulty { impl Add for Difficulty { type Output = Difficulty; fn add(self, other: Difficulty) -> Difficulty { - Difficulty { - num: self.num + other.num, - } + Difficulty { num: self.num + other.num } } } impl Sub for Difficulty { type Output = Difficulty; fn sub(self, other: Difficulty) -> Difficulty { - Difficulty { - num: self.num - other.num, - } + Difficulty { num: self.num - other.num } } } impl Mul for Difficulty { type Output = Difficulty; fn mul(self, other: Difficulty) -> Difficulty { - Difficulty { - num: self.num * other.num, - } + Difficulty { num: self.num * other.num } } } impl Div for Difficulty { type Output = Difficulty; fn div(self, other: Difficulty) -> Difficulty { - Difficulty { - num: self.num / other.num, - } + Difficulty { num: self.num / other.num } } } @@ -167,8 +157,6 @@ impl<'de> de::Visitor<'de> for DiffVisitor { &"a value number", )); }; - Ok(Difficulty { - num: num_in.unwrap(), - }) + Ok(Difficulty { num: num_in.unwrap() }) } } diff --git a/core/src/core/transaction.rs b/core/src/core/transaction.rs index e6c827814..499232de5 100644 --- a/core/src/core/transaction.rs +++ b/core/src/core/transaction.rs @@ -129,8 +129,9 @@ impl Writeable for TxKernel { impl Readable for TxKernel { fn read(reader: &mut Reader) -> Result { - let features = - KernelFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?; + let features = KernelFeatures::from_bits(reader.read_u8()?).ok_or( + ser::Error::CorruptedData, + )?; Ok(TxKernel { features: features, @@ -483,8 +484,9 @@ impl Writeable for Output { /// an Output from a binary stream. impl Readable for Output { fn read(reader: &mut Reader) -> Result { - let features = - OutputFeatures::from_bits(reader.read_u8()?).ok_or(ser::Error::CorruptedData)?; + let features = OutputFeatures::from_bits(reader.read_u8()?).ok_or( + ser::Error::CorruptedData, + )?; Ok(Output { features: features, @@ -520,11 +522,13 @@ impl Output { /// value from the range proof and the commitment pub fn recover_value(&self, keychain: &Keychain, key_id: &Identifier) -> Option { match keychain.rewind_range_proof(key_id, self.commit, self.proof) { - Ok(proof_info) => if proof_info.success { - Some(proof_info.value) - } else { - None - }, + Ok(proof_info) => { + if proof_info.success { + Some(proof_info.value) + } else { + None + } + } Err(_) => None, } } @@ -542,9 +546,7 @@ impl Summable for SumCommit { type Sum = SumCommit; fn sum(&self) -> SumCommit { - SumCommit { - commit: self.commit.clone(), - } + SumCommit { commit: self.commit.clone() } } fn sum_len() -> usize { @@ -563,9 +565,7 @@ impl Readable for SumCommit { fn read(reader: &mut Reader) -> Result { let commit = Commitment::read(reader)?; - Ok(SumCommit { - commit: commit, - }) + Ok(SumCommit { commit: commit }) } } @@ -574,15 +574,17 @@ impl ops::Add for SumCommit { fn add(self, other: SumCommit) -> SumCommit { let secp = static_secp_instance(); - let sum = match secp.lock().unwrap() - .commit_sum(vec![self.commit.clone(), other.commit.clone()], vec![]) - { + let sum = match secp.lock().unwrap().commit_sum( + vec![ + self.commit.clone(), + other.commit.clone(), + ], + vec![], + ) { Ok(s) => s, Err(_) => Commitment::from_vec(vec![1; 33]), }; - SumCommit { - commit: sum, - } + SumCommit { commit: sum } } } diff --git a/src/bin/grin.rs b/src/bin/grin.rs index 231dfdb07..e2ea8ce75 100644 --- a/src/bin/grin.rs +++ b/src/bin/grin.rs @@ -201,7 +201,7 @@ fn main() { provided, the command will attempt to contact the receiver at that \ address and send the transaction directly.") .arg(Arg::with_name("amount") - .help("Amount to send in the smallest denomination") + .help("Number of coins to send with optional fraction, e.g. 12.423") .index(1)) .arg(Arg::with_name("minimum_confirmations") .help("Minimum number of confirmations required for an output to be spendable.") @@ -220,7 +220,7 @@ fn main() { key. Similar to send but burns an output to allow single-party \ transactions.") .arg(Arg::with_name("amount") - .help("Amount to burn in the smallest denomination") + .help("Number of coins to burn") .index(1)) .arg(Arg::with_name("minimum_confirmations") .help("Minimum number of confirmations required for an output to be spendable.") @@ -389,9 +389,9 @@ fn wallet_command(wallet_args: &ArgMatches) { ("send", Some(send_args)) => { let amount = send_args .value_of("amount") - .expect("Amount to send required") - .parse() - .expect("Could not parse amount as a whole number."); + .expect("Amount to send required"); + let amount = core::core::amount_from_hr_string(amount) + .expect("Could not parse amount as a number with optional decimal point."); let minimum_confirmations: u64 = send_args .value_of("minimum_confirmations") .unwrap_or("1") @@ -401,20 +401,25 @@ fn wallet_command(wallet_args: &ArgMatches) { if let Some(d) = send_args.value_of("dest") { dest = d; } - wallet::issue_send_tx( + let result=wallet::issue_send_tx( &wallet_config, &keychain, amount, minimum_confirmations, dest.to_string(), - ).unwrap(); + ); + match result { + Ok(_) => {}, //success messaged logged internally + Err(wallet::Error::NotEnoughFunds(_)) => {}, + Err(e) => panic!(e), + }; } ("burn", Some(send_args)) => { let amount = send_args .value_of("amount") - .expect("Amount to burn required") - .parse() - .expect("Could not parse amount as a whole number."); + .expect("Amount to burn required"); + let amount = core::core::amount_from_hr_string(amount) + .expect("Could not parse amount as number with optional decimal point."); let minimum_confirmations: u64 = send_args .value_of("minimum_confirmations") .unwrap_or("1") diff --git a/wallet/src/client.rs b/wallet/src/client.rs index 55045a1c0..f7f250fad 100644 --- a/wallet/src/client.rs +++ b/wallet/src/client.rs @@ -69,7 +69,14 @@ fn single_send_partial_tx(url: &str, partial_tx: &JSONPartialTx) -> Result<(), E req.set_body(json); let work = client.request(req); - let _ = core.run(work)?; + let _ = core.run(work).and_then(|res|{ + if res.status()==hyper::StatusCode::Ok { + info!(LOGGER, "Transaction sent successfully"); + } else { + error!(LOGGER, "Error sending transaction - status: {}", res.status()); + } + Ok(()) + })?; Ok(()) } diff --git a/wallet/src/info.rs b/wallet/src/info.rs index c4a9e05c8..9408e77c2 100644 --- a/wallet/src/info.rs +++ b/wallet/src/info.rs @@ -14,6 +14,7 @@ use checker; use keychain::Keychain; +use core::core; use types::{WalletConfig, WalletData}; pub fn show_info(config: &WalletConfig, keychain: &Keychain) { @@ -51,7 +52,7 @@ pub fn show_info(config: &WalletConfig, keychain: &Keychain) { out.status, out.is_coinbase, out.num_confirmations(current_height), - out.value, + core::amount_to_hr_string(out.value), ); } }); diff --git a/wallet/src/sender.rs b/wallet/src/sender.rs index 33522a4f0..8b3dcfea5 100644 --- a/wallet/src/sender.rs +++ b/wallet/src/sender.rs @@ -17,7 +17,7 @@ use serde_json; use api; use client; use checker; -use core::core::{build, Transaction}; +use core::core::{build, Transaction, amount_to_hr_string}; use core::ser; use keychain::{BlindingFactor, Identifier, Keychain}; use receiver::TxWrapper; @@ -88,10 +88,18 @@ fn build_send_tx( })?; // build transaction skeleton with inputs and change - let mut parts = inputs_and_change(&coins, config, keychain, key_id, amount)?; + let parts = inputs_and_change(&coins, config, keychain, key_id, amount); + + if let Err(p) = parts { + let total: u64 = coins.iter().map(|c| c.value).sum(); + error!(LOGGER, "Transaction not sent - Not enough funds (Max: {})", amount_to_hr_string(total)); + return Err(p); + } + + let mut parts=parts.unwrap(); // This is more proof of concept than anything but here we set lock_height - // on tx being sent (based on current chain height via api). + // on tx being sent (based on current chain height via api). parts.push(build::with_lock_height(lock_height)); let (tx, blind) = build::transaction(parts, &keychain)?;