Skip to content

Commit

Permalink
Add pub const fn new to Address
Browse files Browse the repository at this point in the history
  • Loading branch information
kpob committed Jun 6, 2024
1 parent cdf5479 commit 5630ed5
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 1 deletion.
53 changes: 52 additions & 1 deletion core/src/address.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Better address representation for Casper.
use crate::prelude::*;
use crate::AddressError::ZeroAddress;
use crate::{prelude::*, utils, ExecutionError, OdraResult};
use crate::{AddressError, OdraError, VmError};
use casper_types::{
account::AccountHash,
Expand All @@ -9,6 +9,14 @@ use casper_types::{
};
use serde::{Deserialize, Serialize};

const ADDRESS_HASH_LENGTH: usize = 64;
/// An address has format `hash-<64-byte-hash>`.
const CONTRACT_STR_LENGTH: usize = 69;
/// An address has format `contract-package-wasm<64-byte-hash>`.
const LEGACY_CONTRACT_STR_LENGTH: usize = 85;
/// An address has format `account-hash-<64-byte-hash>`.
const ACCOUNT_STR_LENGTH: usize = 77;

/// An enum representing an [`AccountHash`] or a [`ContractPackageHash`].
#[derive(PartialOrd, Ord, PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum Address {
Expand All @@ -19,6 +27,35 @@ pub enum Address {
}

impl Address {
/// Creates a new `Address` from a hex-encoded string.
pub const fn new(input: &'static str) -> OdraResult<Self> {
let src: &[u8] = input.as_bytes();
let src_len: usize = src.len();

// fail fast if the input is too short
if src_len < ADDRESS_HASH_LENGTH {
return Err(OdraError::ExecutionError(
ExecutionError::AddressCreationFailed
));
}
// skip the prefix, process the last 64 bytes
if let Ok(dst) = utils::decode_hex_32(src, src_len - ADDRESS_HASH_LENGTH) {
// depending on the length of the input, we can determine the type of address
match src_len {
LEGACY_CONTRACT_STR_LENGTH => Ok(Self::Contract(ContractPackageHash::new(dst))),
ACCOUNT_STR_LENGTH => Ok(Self::Account(AccountHash::new(dst))),
CONTRACT_STR_LENGTH => Ok(Self::Contract(ContractPackageHash::new(dst))),
_ => Err(OdraError::ExecutionError(
ExecutionError::AddressCreationFailed
))
}
} else {
Err(OdraError::ExecutionError(
ExecutionError::AddressCreationFailed
))
}
}

/// Returns the inner account hash if `self` is the `Account` variant.
pub fn as_account_hash(&self) -> Option<&AccountHash> {
if let Self::Account(v) = self {
Expand Down Expand Up @@ -202,6 +239,20 @@ mod tests {
ContractPackageHash::from_formatted_str(CONTRACT_PACKAGE_HASH).unwrap()
}

#[test]
fn test_casper_address_new() {
let address = Address::new(CONTRACT_PACKAGE_HASH).unwrap();
assert!(address.is_contract());
assert_eq!(
address.as_contract_package_hash().unwrap(),
&mock_contract_package_hash()
);

let address = Address::new(ACCOUNT_HASH).unwrap();
assert!(!address.is_contract());
assert_eq!(address.as_account_hash().unwrap(), &mock_account_hash());
}

#[test]
fn test_casper_address_account_hash_conversion() {
let account_hash = mock_account_hash();
Expand Down
33 changes: 33 additions & 0 deletions core/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,39 @@ pub fn hex_to_slice(src: &[u8], dst: &mut [u8]) {
}
}

pub(crate) const fn decode_hex_32(input: &[u8], start: usize) -> Result<[u8; 32], &'static str> {
let mut output = [0u8; 32];
let mut i = 0;
let mut j = 0;

while i < 64 {
let high_value = match hex_char_to_value(input[start + i]) {
Ok(v) => v,
Err(e) => return Err(e)
};

let low_value = match hex_char_to_value(input[start + i + 1]) {
Ok(v) => v,
Err(e) => return Err(e)
};

output[j] = (high_value << 4) | low_value;
i += 2;
j += 1;
}

Ok(output)
}

const fn hex_char_to_value(c: u8) -> Result<u8, &'static str> {
match c {
b'0'..=b'9' => Ok(c - b'0'),
b'a'..=b'f' => Ok(c - b'a' + 10),
b'A'..=b'F' => Ok(c - b'A' + 10),
_ => Err("Invalid character in input")
}
}

#[cfg(test)]
mod tests {
use super::event_absolute_position;
Expand Down

0 comments on commit 5630ed5

Please sign in to comment.