Skip to content

Commit

Permalink
add accessor functions for tari address in FFI
Browse files Browse the repository at this point in the history
Swap 0 to be turtle for mainnet
  • Loading branch information
SWvheerden committed Jul 2, 2024
1 parent fb2de35 commit d1d7bc7
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 8 deletions.
14 changes: 7 additions & 7 deletions base_layer/common_types/src/emoji.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ use crate::{
/// use tari_common_types::emoji::EmojiId;
///
/// // Construct an emoji ID from an emoji string (this can fail)
/// let emoji_string = "🌴🦀🔌📌🚑🌰🎓🌴🐊🐌🔒💡🐜📜👛🍵👛🐽🎂🐻🦋🍓👶🐭🐼🏀🎪💔💵🥑🔋🎒🥊";
/// let emoji_string = "🌴🦀🔌📌🚑🌰🎓🌴🐊🐌🔒💡🐜📜👛🍵👛🐽🎂🐻🐢🍓👶🐭🐼🏀🎪💔💵🥑🔋🎒🥊";
/// let emoji_id_from_emoji_string = EmojiId::from_str(emoji_string);
/// assert!(emoji_id_from_emoji_string.is_ok());
///
Expand All @@ -68,7 +68,7 @@ use crate::{
/// assert_eq!(emoji_id_from_public_key.to_string(), emoji_string);
///
/// // Oh no! We swapped the first two emoji characters by mistake, so this should fail
/// let invalid_emoji_string = "🦀🌴🔌📌🚑🌰🎓🌴🐊🐌🔒💡🐜📜👛🍵👛🐽🎂🐻🦋🍓👶🐭🐼🏀🎪💔💵🥑🔋🎒🥊";
/// let invalid_emoji_string = "🦀🌴🔌📌🚑🌰🎓🌴🐊🐌🔒💡🐜📜👛🍵👛🐽🎂🐻🐢🍓👶🐭🐼🏀🎪💔💵🥑🔋🎒🥊";
/// assert!(EmojiId::from_str(invalid_emoji_string).is_err());
/// ```
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
Expand All @@ -79,13 +79,13 @@ const DATA_BYTES: usize = 32; // number of bytes used for the key data

// The emoji table, mapping byte values to emoji characters
pub const EMOJI: [char; DICT_SIZE] = [
'🦋', '📟', '🌈', '🌊', '🎯', '🐋', '🌙', '🤔', '🌕', '⭐', '🎋', '🌰', '🌴', '🌵', '🌲', '🌸', '🌹', '🌻', '🌽',
'🐢', '📟', '🌈', '🌊', '🎯', '🐋', '🌙', '🤔', '🌕', '⭐', '🎋', '🌰', '🌴', '🌵', '🌲', '🌸', '🌹', '🌻', '🌽',
'🍀', '🍁', '🍄', '🥑', '🍆', '🍇', '🍈', '🍉', '🍊', '🍋', '🍌', '🍍', '🍎', '🍐', '🍑', '🍒', '🍓', '🍔', '🍕',
'🍗', '🍚', '🍞', '🍟', '🥝', '🍣', '🍦', '🍩', '🍪', '🍫', '🍬', '🍭', '🍯', '🥐', '🍳', '🥄', '🍵', '🍶', '🍷',
'🍸', '🍾', '🍺', '🍼', '🎀', '🎁', '🎂', '🎃', '🤖', '🎈', '🎉', '🎒', '🎓', '🎠', '🎡', '🎢', '🎣', '🎤', '🎥',
'🎧', '🎨', '🎩', '🎪', '🎬', '🎭', '🎮', '🎰', '🎱', '🎲', '🎳', '🎵', '🎷', '🎸', '🎹', '🎺', '🎻', '🎼', '🎽',
'🎾', '🎿', '🏀', '🏁', '🏆', '🏈', '⚽', '🏠', '🏥', '🏦', '🏭', '🏰', '🐀', '🐉', '🐊', '🐌', '🐍', '🦁', '🐐',
'🐑', '🐔', '🙈', '🐗', '🐘', '🐙', '🐚', '🐛', '🐜', '🐝', '🐞', '🐢', '🐣', '🐨', '🦀', '🐪', '🐬', '🐭', '🐮',
'🐑', '🐔', '🙈', '🐗', '🐘', '🐙', '🐚', '🐛', '🐜', '🐝', '🐞', '🦋', '🐣', '🐨', '🦀', '🐪', '🐬', '🐭', '🐮',
'🐯', '🐰', '🦆', '🦂', '🐴', '🐵', '🐶', '🐷', '🐸', '🐺', '🐻', '🐼', '🐽', '🐾', '👀', '👅', '👑', '👒', '🧢',
'💅', '👕', '👖', '👗', '👘', '👙', '💃', '👛', '👞', '👟', '👠', '🥊', '👢', '👣', '🤡', '👻', '👽', '👾', '🤠',
'👃', '💄', '💈', '💉', '💊', '💋', '👂', '💍', '💎', '💐', '💔', '🔒', '🧩', '💡', '💣', '💤', '💦', '💨', '💩',
Expand Down Expand Up @@ -232,23 +232,23 @@ mod test {
/// Test invalid size
fn invalid_size() {
// This emoji string is too short to be a valid emoji ID
let emoji_string = "🌴🦀🔌📌🚑🌰🎓🌴🐊🐌🔒💡🐜📜👛🍵👛🐽🎂🐻🦋🍓👶🐭🐼🏀🎪💔💵🥑🔋🎒";
let emoji_string = "🌴🦀🔌📌🚑🌰🎓🌴🐊🐌🔒💡🐜📜👛🍵👛🐽🎂🐻🐢🍓👶🐭🐼🏀🎪💔💵🥑🔋🎒";
assert_eq!(EmojiId::from_str(emoji_string), Err(EmojiIdError::InvalidSize));
}

#[test]
/// Test invalid emoji
fn invalid_emoji() {
// This emoji string contains an invalid emoji character
let emoji_string = "🌴🦀🔌📌🚑🌰🎓🌴🐊🐌🔒💡🐜📜👛🍵👛🐽🎂🐻🦋🍓👶🐭🐼🏀🎪💔💵🥑🔋🎒🎅";
let emoji_string = "🌴🦀🔌📌🚑🌰🎓🌴🐊🐌🔒💡🐜📜👛🍵👛🐽🎂🐻🐢🍓👶🐭🐼🏀🎪💔💵🥑🔋🎒🎅";
assert_eq!(EmojiId::from_str(emoji_string), Err(EmojiIdError::InvalidEmoji));
}

#[test]
/// Test invalid checksum
fn invalid_checksum() {
// This emoji string contains an invalid checksum
let emoji_string = "🌴🦀🔌📌🚑🌰🎓🌴🐊🐌🔒💡🐜📜👛🍵👛🐽🎂🐻🦋🍓👶🐭🐼🏀🎪💔💵🥑🔋🎒🎒";
let emoji_string = "🌴🦀🔌📌🚑🌰🎓🌴🐊🐌🔒💡🐜📜👛🍵👛🐽🎂🐻🐢🍓👶🐭🐼🏀🎪💔💵🥑🔋🎒🎒";
assert_eq!(EmojiId::from_str(emoji_string), Err(EmojiIdError::InvalidChecksum));
}

Expand Down
19 changes: 19 additions & 0 deletions base_layer/common_types/src/tari_address/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub mod dual_address;
mod single_address;

use std::{
fmt,
fmt::{Display, Error, Formatter},
str::FromStr,
};
Expand Down Expand Up @@ -75,6 +76,18 @@ impl Default for TariAddressFeatures {
}
}

impl fmt::Display for TariAddressFeatures {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.contains(TariAddressFeatures::INTERACTIVE) {
write!(f, "Interactive,")?;
}
if self.contains(TariAddressFeatures::ONE_SIDED) {
write!(f, "One-sided,")?;
}
Ok(())
}
}

#[derive(Debug, Error, PartialEq)]
pub enum TariAddressError {
#[error("Invalid size")]
Expand Down Expand Up @@ -165,6 +178,12 @@ impl TariAddress {
}
}

/// Gets the checksum from the Tari Address
pub fn checksum(&self) -> u8 {
let bytes = self.to_vec();
bytes[bytes.len()]
}

/// Convert Tari Address to an emoji string
pub fn to_emoji_string(&self) -> String {
// Convert the public key to bytes and compute the checksum
Expand Down
152 changes: 151 additions & 1 deletion base_layer/wallet_ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,157 @@ pub unsafe extern "C" fn tari_address_network(address: *mut TariWalletAddress, e
CString::into_raw(result)
}

/// Returns the u8 representation of a TariWalletAddress's network
///
/// ## Arguments
/// `address` - The pointer to a TariWalletAddress
/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
/// as an out parameter.
///
/// ## Returns
/// `u8` - Returns u8 representing the network. On failure, returns 0. This may be valid so always check the error out
///
/// # Safety
/// The ```string_destroy``` method must be called when finished with a string from rust to prevent a memory leak
#[no_mangle]
pub unsafe extern "C" fn tari_address_network_u8(address: *mut TariWalletAddress, error_out: *mut c_int) -> u8 {
let mut error = 0;
ptr::swap(error_out, &mut error as *mut c_int);
if address.is_null() {
error = LibWalletError::from(InterfaceError::NullError("address".to_string())).code;
ptr::swap(error_out, &mut error as *mut c_int);
return 0;
}
address
.as_ref()
.expect("Address should not be empty")
.network()
.as_byte()
}

/// Returns the u8 representation of a TariWalletAddress's checksum
///
/// ## Arguments
/// `address` - The pointer to a TariWalletAddress
/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
/// as an out parameter.
///
/// ## Returns
/// `u8` - Returns u8 representing the checksum.. On failure, returns 0. This may be valid so always check the error out
///
/// # Safety
/// The ```string_destroy``` method must be called when finished with a string from rust to prevent a memory leak
#[no_mangle]
pub unsafe extern "C" fn tari_address_checksum_u8(address: *mut TariWalletAddress, error_out: *mut c_int) -> u8 {
let mut error = 0;
ptr::swap(error_out, &mut error as *mut c_int);
if address.is_null() {
error = LibWalletError::from(InterfaceError::NullError("address".to_string())).code;
ptr::swap(error_out, &mut error as *mut c_int);
return 0;
}
address.as_ref().expect("Address should not be empty").checksum()
}

/// Creates a char array from a TariWalletAddress's features
///
/// ## Arguments
/// `address` - The pointer to a TariWalletAddress
/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
/// as an out parameter.
///
/// ## Returns
/// `*mut c_char` - Returns a pointer to a char array. Note that it returns empty
/// if there was an error from TariWalletAddress
///
/// # Safety
/// The ```string_destroy``` method must be called when finished with a string from rust to prevent a memory leak
#[no_mangle]
pub unsafe extern "C" fn tari_address_features(address: *mut TariWalletAddress, error_out: *mut c_int) -> *mut c_char {
let mut error = 0;
let mut result = CString::new("").expect("Blank CString will not fail.");
ptr::swap(error_out, &mut error as *mut c_int);
if address.is_null() {
error = LibWalletError::from(InterfaceError::NullError("address".to_string())).code;
ptr::swap(error_out, &mut error as *mut c_int);
return CString::into_raw(result);
}
let network_string = address
.as_ref()
.expect("Address should not be empty")
.features()
.to_string();
result = CString::new(network_string).expect("string will not fail.");
CString::into_raw(result)
}

/// Creates a public key from a TariWalletAddress's view key
///
/// ## Arguments
/// `address` - The pointer to a TariWalletAddress
/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
/// as an out parameter.
///
/// ## Returns
/// `*mut TariPublicKey` - Returns a pointer to a TariPublicKey. Note that it returns null
///
/// # Safety
/// The ```string_destroy``` method must be called when finished with a string from rust to prevent a memory leak
#[no_mangle]
pub unsafe extern "C" fn tari_address_view_key(
address: *mut TariWalletAddress,
error_out: *mut c_int,
) -> *mut TariPublicKey {
let mut error = 0;
ptr::swap(error_out, &mut error as *mut c_int);
if address.is_null() {
error = LibWalletError::from(InterfaceError::NullError("address".to_string())).code;
ptr::swap(error_out, &mut error as *mut c_int);
return ptr::null_mut();
}
let view_key = address.as_ref().expect("Address should not be empty").public_view_key();
match view_key {
Some(key) => Box::into_raw(Box::new(key.clone())),
None => {
error!(target: LOG_TARGET, "Error reading view key from Tari Address");
error = 1;
ptr::swap(error_out, &mut error as *mut c_int);
ptr::null_mut()
},
}
}

/// Creates a public key from a TariWalletAddress's spend key
///
/// ## Arguments
/// `address` - The pointer to a TariWalletAddress
/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
/// as an out parameter.
///
/// ## Returns
/// `*mut TariPublicKey` - Returns a pointer to a TariPublicKey. Note that it returns null
///
/// # Safety
/// The ```string_destroy``` method must be called when finished with a string from rust to prevent a memory leak
#[no_mangle]
pub unsafe extern "C" fn tari_address_spend_key(
address: *mut TariWalletAddress,
error_out: *mut c_int,
) -> *mut TariPublicKey {
let mut error = 0;
ptr::swap(error_out, &mut error as *mut c_int);
if address.is_null() {
error = LibWalletError::from(InterfaceError::NullError("address".to_string())).code;
ptr::swap(error_out, &mut error as *mut c_int);
return ptr::null_mut();
}
let spend_key = address
.as_ref()
.expect("Address should not be empty")
.public_spend_key();
Box::into_raw(Box::new(spend_key.clone()))
}

/// Creates a TariWalletAddress from a char array in emoji format
///
/// ## Arguments
Expand Down Expand Up @@ -4913,7 +5064,6 @@ pub unsafe extern "C" fn transport_config_destroy(transport: *mut TariTransportC
/// `database_path` - The database path char array pointer which. This is the folder path where the
/// database files will be created and the application has write access to
/// `discovery_timeout_in_secs`: specify how long the Discovery Timeout for the wallet is.
/// `network`: name of network to connect to. Valid values are: esmeralda, dibbler, igor, localnet, mainnet, stagenet
/// `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
/// as an out parameter.
///
Expand Down
52 changes: 52 additions & 0 deletions base_layer/wallet_ffi/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,58 @@ char *tari_address_to_emoji_id(TariWalletAddress *address,
char *tari_address_network(TariWalletAddress *address,
int *error_out);

/**
* Creates a char array from a TariWalletAddress's features
*
* ## Arguments
* `address` - The pointer to a TariWalletAddress
* `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
* as an out parameter.
*
* ## Returns
* `*mut c_char` - Returns a pointer to a char array. Note that it returns empty
* if there was an error from TariWalletAddress
*
* # Safety
* The ```string_destroy``` method must be called when finished with a string from rust to prevent a memory leak
*/
char *tari_address_features(TariWalletAddress *address,
int *error_out);

/**
* Creates a public key from a TariWalletAddress's view key
*
* ## Arguments
* `address` - The pointer to a TariWalletAddress
* `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
* as an out parameter.
*
* ## Returns
* `*mut TariPublicKey` - Returns a pointer to a TariPublicKey. Note that it returns null
*
* # Safety
* The ```string_destroy``` method must be called when finished with a string from rust to prevent a memory leak
*/
TariPublicKey *tari_address_view_key(TariWalletAddress *address,
int *error_out);

/**
* Creates a public key from a TariWalletAddress's spend key
*
* ## Arguments
* `address` - The pointer to a TariWalletAddress
* `error_out` - Pointer to an int which will be modified to an error code should one occur, may not be null. Functions
* as an out parameter.
*
* ## Returns
* `*mut TariPublicKey` - Returns a pointer to a TariPublicKey. Note that it returns null
*
* # Safety
* The ```string_destroy``` method must be called when finished with a string from rust to prevent a memory leak
*/
TariPublicKey *tari_address_spend_key(TariWalletAddress *address,
int *error_out);

/**
* Creates a TariWalletAddress from a char array in emoji format
*
Expand Down

0 comments on commit d1d7bc7

Please sign in to comment.