From 76aa0c05a6621cb76041f5d64b5da3760e4b649d Mon Sep 17 00:00:00 2001 From: Milap Sheth Date: Fri, 4 Oct 2024 07:38:30 -0400 Subject: [PATCH] fix(ampd): stellar tx receipt query and event check (#647) --- ampd/src/handlers/stellar_verify_msg.rs | 20 ++++++-- .../handlers/stellar_verify_verifier_set.rs | 6 ++- ampd/src/stellar/verifier.rs | 47 +++++++++++-------- 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/ampd/src/handlers/stellar_verify_msg.rs b/ampd/src/handlers/stellar_verify_msg.rs index 8532e0275..7de378a12 100644 --- a/ampd/src/handlers/stellar_verify_msg.rs +++ b/ampd/src/handlers/stellar_verify_msg.rs @@ -11,7 +11,8 @@ use events::Event; use events_derive::try_from; use prost_types::Any; use router_api::ChainName; -use serde::Deserialize; +use serde::de::Error as DeserializeError; +use serde::{Deserialize, Deserializer}; use serde_with::{serde_as, DisplayFromStr}; use stellar_xdr::curr::{ScAddress, ScBytes, ScString}; use tokio::sync::watch::Receiver; @@ -26,9 +27,22 @@ use crate::stellar::http_client::Client; use crate::stellar::verifier::verify_message; use crate::types::TMAddress; +pub fn deserialize_tx_id<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let tx_id = String::deserialize(deserializer)?; + + tx_id + .strip_prefix("0x") + .map(String::from) + .ok_or(D::Error::custom(Error::DeserializeEvent)) +} + #[serde_as] #[derive(Deserialize, Debug, Clone)] pub struct Message { + #[serde(deserialize_with = "deserialize_tx_id")] pub tx_id: String, pub event_index: u32, pub destination_address: ScString, @@ -129,7 +143,7 @@ impl EventHandler for Handler { let message_ids = messages .iter() - .map(|message| format!("{}-{}", message.tx_id, message.event_index)) + .map(|message| format!("{}-{}", message.tx_id.clone(), message.event_index)) .collect::>(); let votes = info_span!( @@ -316,7 +330,7 @@ mod tests { }, messages: (0..2) .map(|i| TxEventConfirmation { - tx_id: format!("{:x}", Hash::random()).parse().unwrap(), + tx_id: format!("0x{:x}", Hash::random()).parse().unwrap(), event_index: i, source_address: ScAddress::Contract(stellar_xdr::curr::Hash::from( Hash::random().0, diff --git a/ampd/src/handlers/stellar_verify_verifier_set.rs b/ampd/src/handlers/stellar_verify_verifier_set.rs index 82b4ff4a5..a7eb57f57 100644 --- a/ampd/src/handlers/stellar_verify_verifier_set.rs +++ b/ampd/src/handlers/stellar_verify_verifier_set.rs @@ -18,6 +18,7 @@ use tracing::{info, info_span}; use valuable::Valuable; use voting_verifier::msg::ExecuteMsg; +use super::stellar_verify_msg::deserialize_tx_id; use crate::event_processor::EventHandler; use crate::handlers::errors::Error; use crate::handlers::errors::Error::DeserializeEvent; @@ -27,6 +28,7 @@ use crate::types::TMAddress; #[derive(Deserialize, Debug)] pub struct VerifierSetConfirmation { + #[serde(deserialize_with = "deserialize_tx_id")] pub tx_id: String, pub event_index: u32, pub verifier_set: VerifierSet, @@ -117,7 +119,7 @@ impl EventHandler for Handler { let vote = info_span!( "verify a new verifier set", poll_id = poll_id.to_string(), - id = format!("{}-{}", verifier_set.tx_id, verifier_set.event_index), + id = format!("0x{}-{}", verifier_set.tx_id, verifier_set.event_index), ) .in_scope(|| { info!("ready to verify verifier set in poll",); @@ -291,7 +293,7 @@ mod tests { .collect(), }, verifier_set: VerifierSetConfirmation { - tx_id: format!("{:x}", Hash::random()).parse().unwrap(), + tx_id: format!("0x{:x}", Hash::random()).parse().unwrap(), event_index: 0, verifier_set: build_verifier_set(KeyType::Ed25519, &ed25519_test_data::signers()), }, diff --git a/ampd/src/stellar/verifier.rs b/ampd/src/stellar/verifier.rs index fa4280bb7..f0b62f981 100644 --- a/ampd/src/stellar/verifier.rs +++ b/ampd/src/stellar/verifier.rs @@ -48,11 +48,11 @@ impl PartialEq for VerifierSetConfirmation { fn eq(&self, event: &ContractEventBody) -> bool { let ContractEventBody::V0(body) = event; - if body.topics.len() != 3 { + if body.topics.len() != 1 { return false; } - let [symbol, _, signer_hash] = &body.topics[..] else { + let [symbol] = &body.topics[..] else { return false; }; @@ -60,12 +60,21 @@ impl PartialEq for VerifierSetConfirmation { ScSymbol(StringM::from_str(TOPIC_ROTATED).expect("must convert str to ScSymbol")) .into(); + let rotated_signers = match &body.data { + ScVal::Vec(Some(data)) if data.len() == 1 => { + let [rotated_signers] = &data[..] else { + return false; + }; + rotated_signers.clone() + } + _ => return false, + }; + WeightedSigners::try_from(&self.verifier_set) .ok() - .and_then(|signers| signers.hash().ok()) - .and_then(|hash| ScVal::try_from(hash).ok()) - .map_or(false, |hash| { - symbol == &expected_topic && signer_hash == &hash + .and_then(|signers| ScVal::try_from(signers).ok()) + .map_or(false, |signers: ScVal| { + symbol == &expected_topic && signers == rotated_signers }) } } @@ -138,7 +147,7 @@ mod test { use stellar::WeightedSigners; use stellar_xdr::curr::{ AccountId, BytesM, ContractEvent, ContractEventBody, ContractEventType, ContractEventV0, - PublicKey, ScAddress, ScBytes, ScString, ScSymbol, ScVal, StringM, Uint256, + PublicKey, ScAddress, ScBytes, ScString, ScSymbol, ScVal, ScVec, StringM, Uint256, }; use crate::handlers::stellar_verify_msg::Message; @@ -293,7 +302,7 @@ mod test { let signing_key = SigningKey::generate(&mut OsRng); let msg = Message { - tx_id: Hash::random().to_string(), + tx_id: format!("{:x}", Hash::random()), event_index: 0, source_address: ScAddress::Account(AccountId(PublicKey::PublicKeyTypeEd25519( Uint256::from(signing_key.verifying_key().to_bytes()), @@ -351,7 +360,7 @@ mod test { let threshold = Uint128::new(2u128); let verifier_set_confirmation = VerifierSetConfirmation { - tx_id: Hash::random().to_string(), + tx_id: format!("{:x}", Hash::random()), event_index: 0, verifier_set: VerifierSet { signers: signers @@ -363,21 +372,19 @@ mod test { }, }; - let weighted_signers = - WeightedSigners::try_from(&verifier_set_confirmation.verifier_set).unwrap(); - let signer_hash = weighted_signers.hash().unwrap(); + let weighted_signers: ScVal = + WeightedSigners::try_from(&verifier_set_confirmation.verifier_set) + .unwrap() + .try_into() + .unwrap(); let event_body = ContractEventBody::V0(ContractEventV0 { - topics: vec![ - ScVal::Symbol(ScSymbol(StringM::from_str(TOPIC_ROTATED).unwrap())), - ScVal::Bytes(ScBytes( - BytesM::try_from(Hash::random().to_fixed_bytes()).unwrap(), - )), - ScVal::try_from(signer_hash).unwrap(), - ] + topics: vec![ScVal::Symbol(ScSymbol( + StringM::from_str(TOPIC_ROTATED).unwrap(), + ))] .try_into() .unwrap(), - data: ScVal::Vec(None), + data: ScVal::Vec(Some(ScVec::try_from(vec![weighted_signers]).unwrap())), }); let event = ContractEvent {