diff --git a/sdk/src/signature.rs b/sdk/src/signature.rs index 996653aef4..7b73d4ec73 100644 --- a/sdk/src/signature.rs +++ b/sdk/src/signature.rs @@ -11,7 +11,9 @@ use std::error; use std::fmt; use std::fs::{self, File}; use std::io::Write; +use std::mem; use std::path::Path; +use std::str::FromStr; pub type Keypair = ed25519_dalek::Keypair; @@ -70,6 +72,27 @@ impl fmt::Display for Signature { } } +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum ParseSignatureError { + WrongSize, + Invalid, +} + +impl FromStr for Signature { + type Err = ParseSignatureError; + + fn from_str(s: &str) -> Result { + let bytes = bs58::decode(s) + .into_vec() + .map_err(|_| ParseSignatureError::Invalid)?; + if bytes.len() != mem::size_of::() { + Err(ParseSignatureError::WrongSize) + } else { + Ok(Signature::new(&bytes)) + } + } +} + pub trait KeypairUtil { fn new() -> Self; fn pubkey(&self) -> Pubkey; @@ -145,4 +168,39 @@ mod tests { fs::remove_file(&outfile).unwrap(); assert!(!Path::new(&outfile).exists()); } + + #[test] + fn test_signature_fromstr() { + let signature = Keypair::new().sign_message(&[0u8]); + + let mut signature_base58_str = bs58::encode(signature).into_string(); + + assert_eq!(signature_base58_str.parse::(), Ok(signature)); + + signature_base58_str.push_str(&bs58::encode(signature.0).into_string()); + assert_eq!( + signature_base58_str.parse::(), + Err(ParseSignatureError::WrongSize) + ); + + signature_base58_str.truncate(signature_base58_str.len() / 2); + assert_eq!(signature_base58_str.parse::(), Ok(signature)); + + signature_base58_str.truncate(signature_base58_str.len() / 2); + assert_eq!( + signature_base58_str.parse::(), + Err(ParseSignatureError::WrongSize) + ); + + let mut signature_base58_str = bs58::encode(signature.0).into_string(); + assert_eq!(signature_base58_str.parse::(), Ok(signature)); + + // throw some non-base58 stuff in there + signature_base58_str.replace_range(..1, "I"); + assert_eq!( + signature_base58_str.parse::(), + Err(ParseSignatureError::Invalid) + ); + } + }