From 8800d1339d594414ac288483b41a15d6b54d55ca Mon Sep 17 00:00:00 2001 From: AntiochP <30642645+antiochp@users.noreply.github.com> Date: Wed, 27 Sep 2017 19:03:59 -0400 Subject: [PATCH] Wallet: key fingerprint as string (#142) * wallet key fingerprint as hex string * use lowercase hex in util::to_hex for consistency with various crypto libs, add some tests for util::to_hex and util::from_hex * filter wallet info based on ext_key fingerprint * cleanup format for fingerprints and output status --- util/src/hex.rs | 23 +++++++++++++++++++++-- wallet/src/extkey.rs | 34 +++++++++------------------------- wallet/src/info.rs | 6 ++++-- wallet/src/types.rs | 14 +++++++++++++- 4 files changed, 47 insertions(+), 30 deletions(-) diff --git a/util/src/hex.rs b/util/src/hex.rs index 56d215474..d70a1d810 100644 --- a/util/src/hex.rs +++ b/util/src/hex.rs @@ -1,4 +1,4 @@ -// Copyright 2016 The Grin Developers +// Copyright 2017 The Grin Developers // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -24,7 +24,7 @@ use std::num; pub fn to_hex(bytes: Vec) -> String { let mut s = String::new(); for byte in bytes { - write!(&mut s, "{:02X}", byte).expect("Unable to write"); + write!(&mut s, "{:02x}", byte).expect("Unable to write"); } s } @@ -44,3 +44,22 @@ pub fn from_hex(hex_str: String) -> Result, num::ParseIntError> { fn split_n(s: &str, n: usize) -> Vec<&str> { (0 .. (s.len() - n + 1)/2 + 1).map(|i| &s[2*i .. 2*i + n]).collect() } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_to_hex() { + assert_eq!(to_hex(vec![0, 0, 0, 0]), "00000000"); + assert_eq!(to_hex(vec![10, 11, 12, 13]), "0a0b0c0d"); + assert_eq!(to_hex(vec![0, 0, 0, 255]), "000000ff"); + } + + #[test] + fn test_from_hex() { + assert_eq!(from_hex("00000000".to_string()).unwrap(), vec![0, 0, 0, 0]); + assert_eq!(from_hex("0a0b0c0d".to_string()).unwrap(), vec![10, 11, 12, 13]); + assert_eq!(from_hex("000000ff".to_string()).unwrap(), vec![0, 0, 0, 255]); + } +} diff --git a/wallet/src/extkey.rs b/wallet/src/extkey.rs index 7fe8a3596..05a74e72f 100644 --- a/wallet/src/extkey.rs +++ b/wallet/src/extkey.rs @@ -18,6 +18,8 @@ use std::{error, fmt}; use std::cmp::min; +use util; + use byteorder::{ByteOrder, BigEndian}; use blake2::blake2b::blake2b; use secp::Secp256k1; @@ -54,8 +56,8 @@ impl error::Error for Error { } } -#[derive(Serialize, Deserialize, Clone)] -pub struct Fingerprint([u8; 4]); +#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)] +pub struct Fingerprint(String); impl Fingerprint { fn from_bytes(bytes: &[u8]) -> Fingerprint { @@ -63,38 +65,20 @@ impl Fingerprint { for i in 0..min(4, bytes.len()) { fingerprint[i] = bytes[i]; } - Fingerprint(fingerprint) + Fingerprint(util::to_hex(fingerprint.to_vec())) } fn zero() -> Fingerprint { - Fingerprint([0; 4]) + Fingerprint::from_bytes(&[0; 4]) } } -impl PartialEq for Fingerprint { - fn eq(&self, other: &Self) -> bool { - self.0.as_ref() == other.0.as_ref() +impl fmt::Display for Fingerprint { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + f.write_str(&self.0) } } -impl ::std::fmt::Display for Fingerprint { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - for i in self.0.iter().cloned() { - try!(write!(f, "{:02x}", i)); - } - write!(f, "") - } -} - -impl ::std::fmt::Debug for Fingerprint { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - try!(write!(f, "{}(", stringify!(Fingerprint))); - for i in self.0.iter().cloned() { - try!(write!(f, "{:02x}", i)); - } - write!(f, ")") - } -} #[derive(Serialize, Deserialize, Clone)] pub struct Identifier([u8; 20]); diff --git a/wallet/src/info.rs b/wallet/src/info.rs index 80364c271..d990807fa 100644 --- a/wallet/src/info.rs +++ b/wallet/src/info.rs @@ -27,11 +27,13 @@ pub fn show_info(config: &WalletConfig, ext_key: &ExtendedKey) { println!("Outputs - "); println!("fingerprint, n_child, height, lock_height, status, value"); println!("----------------------------------"); - for out in &mut wallet_data.outputs { + for out in &mut wallet_data.outputs + .iter() + .filter(|o| o.fingerprint == ext_key.fingerprint ) { let key = ext_key.derive(&secp, out.n_child).unwrap(); println!( - "{}, {}, {}, {}, {:?}, {}", + "{}, {}, {}, {}, {}, {}", key.identifier().fingerprint(), out.n_child, out.height, diff --git a/wallet/src/types.rs b/wallet/src/types.rs index cee81a5ae..178dde979 100644 --- a/wallet/src/types.rs +++ b/wallet/src/types.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::{num, thread, time}; +use std::{fmt, num, thread, time}; use std::convert::From; use std::fs::{self, File, OpenOptions}; use std::io::Write; @@ -114,6 +114,18 @@ pub enum OutputStatus { Spent, } +impl fmt::Display for OutputStatus { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + OutputStatus::Unconfirmed => write!(f, "Unconfirmed"), + OutputStatus::Unspent => write!(f, "Unspent"), + OutputStatus::Immature => write!(f, "Immature"), + OutputStatus::Locked => write!(f, "Locked"), + OutputStatus::Spent => write!(f, "Spent"), + } + } +} + /// Information about an output that's being tracked by the wallet. Must be /// enough to reconstruct the commitment associated with the ouput when the /// root private key is known.