Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
codabrink committed Oct 1, 2024
1 parent 8e9c489 commit 0e47839
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 179 deletions.
1 change: 1 addition & 0 deletions mls_validation_service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ path = "src/main.rs"
clap = { version = "4.4.6", features = ["derive"] }
ed25519-dalek = { workspace = true, features = ["digest"] }
env_logger = "0.11"
ethers = { workspace = true }
futures = { workspace = true }
hex = { workspace = true }
log = { workspace = true }
Expand Down
187 changes: 8 additions & 179 deletions mls_validation_service/src/handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use tonic::{Request, Response, Status};
use xmtp_id::{
associations::{
self, try_map_vec, unverified::UnverifiedIdentityUpdate, AccountId, AssociationError,
DeserializationError, IdentityUpdate, MemberIdentifier, SignatureError,
DeserializationError, SignatureError,
},
scw_verifier::SmartContractSignatureVerifier,
};
Expand All @@ -20,10 +20,6 @@ use xmtp_proto::xmtp::{
mls_validation::v1::{
validate_group_messages_response::ValidationResponse as ValidateGroupMessageValidationResponse,
validate_inbox_id_key_packages_response::Response as ValidateInboxIdKeyPackageResponse,
validate_inbox_ids_request::ValidationRequest as InboxIdValidationRequest,
validate_inbox_ids_response::ValidationResponse as InboxIdValidationResponse,
validate_key_packages_response::ValidationResponse as ValidateKeyPackagesValidationResponse,
validate_key_packages_response::ValidationResponse as ValidateKeyPackageValidationResponse,
validation_api_server::ValidationApi, GetAssociationStateRequest,
GetAssociationStateResponse, ValidateGroupMessagesRequest, ValidateGroupMessagesResponse,
ValidateInboxIdKeyPackagesResponse, ValidateInboxIdsRequest, ValidateInboxIdsResponse,
Expand Down Expand Up @@ -64,56 +60,18 @@ impl ValidationService {
impl ValidationApi for ValidationService {
async fn validate_inbox_ids(
&self,
request: tonic::Request<ValidateInboxIdsRequest>,
_request: tonic::Request<ValidateInboxIdsRequest>,
) -> Result<tonic::Response<ValidateInboxIdsResponse>, tonic::Status> {
let ValidateInboxIdsRequest { requests } = request.into_inner();
let responses: Vec<_> = requests
.into_iter()
.map(|r| validate_inbox_id(r, &*self.scw_verifier))
.collect();

let responses: Vec<InboxIdValidationResponse> = join_all(responses)
.await
.into_iter()
.map(|res| res.map_err(InboxIdValidationResponse::from))
.map(|r| r.unwrap_or_else(|e| e))
.collect();
Ok(Response::new(ValidateInboxIdsResponse { responses }))
// Stubbed for v2 nodes
unimplemented!()
}

async fn validate_key_packages(
&self,
request: tonic::Request<ValidateKeyPackagesRequest>,
_request: tonic::Request<ValidateKeyPackagesRequest>,
) -> std::result::Result<tonic::Response<ValidateKeyPackagesResponse>, tonic::Status> {
let out: Vec<ValidateKeyPackagesValidationResponse> = request
.into_inner()
.key_packages
.into_iter()
.map(
|kp| match validate_key_package(kp.key_package_bytes_tls_serialized) {
Ok(res) => ValidateKeyPackageValidationResponse {
is_ok: true,
error_message: "".to_string(),
installation_id: res.installation_id,
account_address: res.account_address,
credential_identity_bytes: res.credential_identity_bytes,
expiration: res.expiration,
},
Err(e) => ValidateKeyPackageValidationResponse {
is_ok: false,
error_message: e,
installation_id: vec![],
account_address: "".to_string(),
credential_identity_bytes: vec![],
expiration: 0,
},
},
)
.collect();

Ok(Response::new(ValidateKeyPackagesResponse {
responses: out,
}))
// Stubbed out for v2 nodes
unimplemented!()
}

async fn validate_group_messages(
Expand Down Expand Up @@ -194,124 +152,6 @@ impl ValidationApi for ValidationService {
}
}

/// Error type for inbox ID validation
/// Each variant requires carrying the ID that failed to validate
/// The error variant itself becomes the failed version of `InboxIdValidationResponse` but allows
/// us to write normal rust in `validate_inbox_id`
#[derive(thiserror::Error, Debug)]
enum InboxIdValidationError {
#[error("Inbox ID {id} failed to validate")]
Deserialization {
id: String,
source: DeserializationError,
},
#[error("Valid association state could not be found for inbox {id}, {source}")]
Association {
id: String,
source: AssociationError,
},
#[error("Missing Credential")]
MissingCredential,
#[error("Inbox {id} is not associated with member {member}")]
MemberNotAssociated {
id: String,
member: MemberIdentifier,
},
#[error(
"Given Inbox Id, {credential_inbox_id} does not match resulting inbox id, {state_inbox_id}"
)]
InboxIdDoesNotMatch {
credential_inbox_id: String,
state_inbox_id: String,
},
}

impl InboxIdValidationError {
pub fn inbox_id(&self) -> String {
match self {
InboxIdValidationError::Deserialization { id, .. } => id.clone(),
InboxIdValidationError::MissingCredential => "null".to_string(),
InboxIdValidationError::Association { id, .. } => id.clone(),
InboxIdValidationError::MemberNotAssociated { id, .. } => id.clone(),
InboxIdValidationError::InboxIdDoesNotMatch {
credential_inbox_id,
..
} => credential_inbox_id.clone(),
}
}
}

impl From<InboxIdValidationError> for InboxIdValidationResponse {
fn from(err: InboxIdValidationError) -> Self {
InboxIdValidationResponse {
is_ok: false,
error_message: err.to_string(),
inbox_id: err.inbox_id(),
}
}
}

async fn validate_inbox_id(
request: InboxIdValidationRequest,
scw_verifier: &dyn SmartContractSignatureVerifier,
) -> Result<InboxIdValidationResponse, InboxIdValidationError> {
let InboxIdValidationRequest {
credential,
installation_public_key,
identity_updates,
} = request;

if credential.is_none() {
return Err(InboxIdValidationError::MissingCredential);
}

let inbox_id = credential.expect("checked for empty credential").inbox_id;

let unverified_identity_updates: Vec<UnverifiedIdentityUpdate> = try_map_vec(identity_updates)
.map_err(|e| InboxIdValidationError::Deserialization {
source: e,
id: inbox_id.clone(),
})?;
let identity_updates: Vec<IdentityUpdate> = try_join_all(
unverified_identity_updates
.iter()
.map(|u| u.to_verified(scw_verifier))
.collect::<Vec<_>>(),
)
.await
.unwrap();

let state = associations::get_state(identity_updates).map_err(|e| {
InboxIdValidationError::Association {
source: e,
id: inbox_id.clone(),
}
})?;

// this is defensive and should not happen.
// The only way an inbox id is different is if xmtp-node-go hands over identity updates with a different inbox id.
// which is a bug.
if state.inbox_id().as_ref() != *inbox_id {
return Err(InboxIdValidationError::InboxIdDoesNotMatch {
credential_inbox_id: inbox_id.clone(),
state_inbox_id: state.inbox_id().clone(),
});
}

let member = MemberIdentifier::Installation(installation_public_key);
if state.get(&member).is_none() {
return Err(InboxIdValidationError::MemberNotAssociated {
id: inbox_id,
member,
});
}
Ok(InboxIdValidationResponse {
is_ok: true,
error_message: "".to_string(),
inbox_id,
})
}

#[derive(thiserror::Error, Debug)]
enum ValidateInboxIdKeyPackageError {
#[error("XMTP Key Package failed {0}")]
Expand Down Expand Up @@ -357,7 +197,7 @@ async fn verify_smart_contract_wallet_signatures(
AccountId::new_evm(sig.chain_id, sig.account_id),
[0; 32],
sig.signature.into(),
Some(BlockNumber::Number(U64([sig.block_number]))),
Some(BlockNumber::Number(U64::from(sig.block_number))),
));
}

Expand Down Expand Up @@ -425,17 +265,6 @@ fn validate_group_message(message: Vec<u8>) -> Result<ValidateGroupMessageResult
})
}

struct ValidateKeyPackageResult {
installation_id: Vec<u8>,
account_address: String,
credential_identity_bytes: Vec<u8>,
expiration: u64,
}

fn validate_key_package(_key_package_bytes: Vec<u8>) -> Result<ValidateKeyPackageResult, String> {
unimplemented!()
}

#[cfg(test)]
mod tests {
use ed25519_dalek::SigningKey;
Expand Down

0 comments on commit 0e47839

Please sign in to comment.