use crate::contract::address::{hash, Addresser, AddresserError, ADDRESS_LENGTH};
pub struct DoubleKeyHashAddresser {
prefix: String,
first_hash_length: usize,
}
impl DoubleKeyHashAddresser {
pub fn new(
prefix: String,
first_hash_length: Option<usize>,
) -> Result<DoubleKeyHashAddresser, AddresserError> {
validate_lengths(prefix.len(), first_hash_length)?;
Ok(DoubleKeyHashAddresser {
prefix: prefix.clone(),
first_hash_length: first_hash_length.unwrap_or((ADDRESS_LENGTH - prefix.len()) / 2),
})
}
}
impl Addresser<(String, String)> for DoubleKeyHashAddresser {
fn compute(&self, key: &(String, String)) -> Result<String, AddresserError> {
let second_hash_length = ADDRESS_LENGTH - self.prefix.len() - self.first_hash_length;
let first_hash = &hash(self.first_hash_length, &key.0);
let second_hash = &hash(second_hash_length, &key.1);
Ok(String::from(&self.prefix) + first_hash + second_hash)
}
fn normalize(&self, key: &(String, String)) -> String {
key.0.to_string() + "_" + &key.1
}
}
fn validate_lengths(
prefix_length: usize,
first_length: Option<usize>,
) -> Result<(), AddresserError> {
if prefix_length > ADDRESS_LENGTH {
return Err(AddresserError {
message: format!(
"Prefix length ({}) is greater than total address length ({})",
prefix_length, ADDRESS_LENGTH
),
});
}
if let Some(length) = first_length {
if length + prefix_length > ADDRESS_LENGTH {
return Err(AddresserError {
message: format!(
"Length of prefix ({}) plus length of first address segment ({}) combined are \
greater than total address length ({})",
prefix_length, length, ADDRESS_LENGTH,
),
});
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_double_key_default_length() {
let addresser = DoubleKeyHashAddresser::new("prefix".to_string(), None)
.expect("Unable to construct DoubleKeyHashAddresser");
let key1 = "a";
let key1_hash = hash(32, key1);
let key2 = "b";
let key2_hash = hash(32, key2);
let addr = addresser
.compute(&(key1.to_string(), key2.to_string()))
.unwrap();
assert_eq!(addr[..6], "prefix".to_string());
assert_eq!(addr.len(), ADDRESS_LENGTH);
assert_eq!(addr[6..38], key1_hash[..32]);
assert_eq!(addr[38..], key2_hash[..32]);
let normalized = addresser.normalize(&(key1.to_string(), key2.to_string()));
assert_eq!(normalized, "a_b".to_string());
}
#[test]
fn test_double_key_custom_length() {
let addresser = DoubleKeyHashAddresser::new("prefix".to_string(), Some(16))
.expect("Unable to construct DoubleKeyHashAddresser");
let key1 = "a";
let key1_hash = hash(16, key1);
let key2 = "b";
let key2_hash = hash(48, key2);
let addr = addresser
.compute(&(key1.to_string(), key2.to_string()))
.unwrap();
assert_eq!(addr[..6], "prefix".to_string());
assert_eq!(addr.len(), ADDRESS_LENGTH);
assert_eq!(addr[6..22], key1_hash[..16]);
assert_eq!(addr[22..], key2_hash[..48]);
let normalized = addresser.normalize(&(key1.to_string(), key2.to_string()));
assert_eq!(normalized, "a_b".to_string());
}
#[test]
#[should_panic]
fn test_invalid_hash_length() {
let addresser = DoubleKeyHashAddresser::new("prefix".to_string(), Some(ADDRESS_LENGTH));
assert!(addresser.is_err());
addresser.unwrap();
}
#[test]
#[should_panic]
fn test_invalid_prefix_length() {
let addresser = DoubleKeyHashAddresser::new(
"prefixprefixprefixprefixprefixprefixprefixprefixprefixprefixprefixprefix".to_string(),
None,
);
assert!(addresser.is_err());
addresser.unwrap();
}
}