Skip to content

Commit

Permalink
fix: contact service tari address support (#6478)
Browse files Browse the repository at this point in the history
Description
---
Contact service still assumes that the node_id and tari address are the
same. This changes contact service to check the tari address.

Motivation and Context
---
This allows a user to update the address of a contact without having to
delete the contact. It will look at the address given and update the
address accordingly.

How Has This Been Tested?
---
Manual
  • Loading branch information
SWvheerden authored Aug 20, 2024
1 parent 7357433 commit 7909a75
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ impl ContactsTab {
Span::raw(" field, "),
Span::styled("K", Style::default().add_modifier(Modifier::BOLD)),
Span::raw(" to edit "),
Span::styled("Emoji ID", Style::default().add_modifier(Modifier::BOLD)),
Span::styled("Tari Address", Style::default().add_modifier(Modifier::BOLD)),
Span::raw(" field, "),
Span::styled("Enter", Style::default().add_modifier(Modifier::BOLD)),
Span::raw(" to save Contact."),
Expand Down Expand Up @@ -239,12 +239,10 @@ impl ContactsTab {
self.edit_contact_mode = ContactInputMode::None;
self.show_edit_contact = false;

if let Err(_e) = Handle::current()
if let Err(e) = Handle::current()
.block_on(app_state.upsert_contact(self.alias_field.clone(), self.address_field.clone()))
{
self.error_message = Some(
"Invalid Tari address or Emoji ID provided\n Press Enter to continue.".to_string(),
);
self.error_message = Some(e.to_string() + "\nPress Enter to continue.");
}

self.alias_field = "".to_string();
Expand Down
41 changes: 41 additions & 0 deletions base_layer/common_types/src/tari_address/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ impl TariAddressFeatures {
pub fn as_u8(&self) -> u8 {
self.0
}

pub fn combine_features(&self, other: TariAddressFeatures) -> TariAddressFeatures {
TariAddressFeatures(self.0 | other.0)
}
}

impl Default for TariAddressFeatures {
Expand Down Expand Up @@ -118,6 +122,8 @@ pub enum TariAddressError {
CannotRecoverFeature,
#[error("Could not recover TariAddress from string")]
InvalidAddressString,
#[error("Could not create TariAddress: {0}")]
CreationError(String),
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
Expand Down Expand Up @@ -152,6 +158,41 @@ impl TariAddress {
TariAddress::Single(SingleAddress::new_with_interactive_only(spend_key, network))
}

pub fn combine_addresses(one: &TariAddress, two: &TariAddress) -> Result<TariAddress, TariAddressError> {
if one.comms_public_key() != two.comms_public_key() {
return Err(TariAddressError::CreationError("Public keys do not match".to_string()));
}
if one.network() != two.network() {
return Err(TariAddressError::CreationError("Networks do not match".to_string()));
}
if let TariAddress::Dual(one) = one {
if let TariAddress::Dual(two) = two {
if one.public_view_key() != two.public_view_key() {
return Err(TariAddressError::CreationError("View keys do not match".to_string()));
}
}
}
match (one, two) {
(TariAddress::Dual(one), _) => Ok(TariAddress::new_dual_address(
one.public_view_key().clone(),
one.public_spend_key().clone(),
one.network(),
one.features().combine_features(two.features()),
)),
(_, TariAddress::Dual(two)) => Ok(TariAddress::new_dual_address(
two.public_view_key().clone(),
one.public_spend_key().clone(),
one.network(),
one.features().combine_features(two.features()),
)),
(_, _) => Ok(TariAddress::new_single_address(
one.public_spend_key().clone(),
one.network(),
one.features().combine_features(two.features()),
)),
}
}

/// Gets the bytes size of the Tari Address
pub fn get_size(&self) -> usize {
match self {
Expand Down
11 changes: 9 additions & 2 deletions base_layer/contacts/src/contacts_service/storage/sqlite_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ where TContactServiceDbConnection: PooledDbConnection<Error = SqliteStorageError
}
},
DbKeyValuePair::Contact(k, c) => {
if ContactSql::find_by_address_and_update(&mut conn, &k.to_vec(), UpdateContact {
if ContactSql::find_by_node_id_and_update(&mut conn, &c.node_id.to_vec(), UpdateContact {
alias: Some(c.clone().alias),
last_seen: None,
latency: None,
Expand All @@ -165,6 +165,13 @@ where TContactServiceDbConnection: PooledDbConnection<Error = SqliteStorageError
.is_err()
{
ContactSql::from(c).commit(&mut conn)?;
} else {
let stored_contact = ContactSql::find_by_node_id(&c.node_id.to_vec(), &mut conn)?;
let stored_address = TariAddress::from_bytes(stored_contact.address.as_slice())
.map_err(|_| ContactsServiceStorageError::ConversionError)?;
let new_address = TariAddress::combine_addresses(&stored_address, &k)
.map_err(|_| ContactsServiceStorageError::ConversionError)?;
ContactSql::set_address_of_node_id(&c.node_id.to_vec(), &new_address.to_vec(), &mut conn)?;
}
},
DbKeyValuePair::LastSeen(..) => return Err(ContactsServiceStorageError::OperationNotSupported),
Expand Down Expand Up @@ -274,7 +281,7 @@ mod test {
.iter()
.any(|v| v == &ContactSql::from(contacts[0].clone())));

let _c = ContactSql::find_by_address_and_update(&mut conn, &contacts[1].address.to_vec(), UpdateContact {
let _c = ContactSql::find_by_node_id_and_update(&mut conn, &contacts[1].node_id.to_vec(), UpdateContact {
alias: Some("Fred".to_string()),
last_seen: None,
latency: None,
Expand Down
20 changes: 9 additions & 11 deletions base_layer/contacts/src/contacts_service/storage/types/contacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,16 @@ impl ContactSql {
.first::<ContactSql>(conn)?)
}

/// Find a particular Contact by their address, and update it if it exists, returning the affected record
pub fn find_by_address_and_update(
conn: &mut SqliteConnection,
/// updates the address field of the contact
pub fn set_address_of_node_id(
node_id: &[u8],
address: &[u8],
updated_contact: UpdateContact,
) -> Result<ContactSql, ContactsServiceStorageError> {
// Note: `get_result` not implemented for SQLite
diesel::update(contacts::table.filter(contacts::address.eq(address)))
.set(updated_contact)
.execute(conn)
.num_rows_affected_or_not_found(1)?;
ContactSql::find_by_address(address, conn)
conn: &mut SqliteConnection,
) -> Result<(), ContactsServiceStorageError> {
diesel::update(contacts::table.filter(contacts::node_id.eq(node_id)))
.set(contacts::address.eq(address))
.execute(conn)?;
Ok(())
}

/// Find a particular Contact by their address, and delete it if it exists, returning the affected record
Expand Down
2 changes: 1 addition & 1 deletion base_layer/contacts/src/contacts_service/types/contact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl Contact {
) -> Self {
Self {
alias,
node_id: NodeId::from_key(address.public_spend_key()),
node_id: NodeId::from_key(address.comms_public_key()),
address,
last_seen,
latency,
Expand Down
4 changes: 4 additions & 0 deletions base_layer/wallet_ffi/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,10 @@ impl From<TariAddressError> for LibWalletError {
code: 708,
message: format!("{:?}", e),
},
TariAddressError::CreationError(_) => Self {
code: 708,
message: format!("{:?}", e),
},
}
}
}
Expand Down

0 comments on commit 7909a75

Please sign in to comment.