diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 353cc1fba..41fff6412 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1835,10 +1835,12 @@ dependencies = [ "log", "optics-base", "optics-core", + "optics-test", "serde 1.0.123", "serde_json", "thiserror", "tokio", + "tokio-test", "tracing", "tracing-futures", "tracing-subscriber", diff --git a/rust/optics-test/src/mocks/replica.rs b/rust/optics-test/src/mocks/replica.rs index ec9a2ce50..84be7e600 100644 --- a/rust/optics-test/src/mocks/replica.rs +++ b/rust/optics-test/src/mocks/replica.rs @@ -14,52 +14,52 @@ use optics_core::{ mock! { pub ReplicaContract { // Replica - fn _destination_domain(&self) -> u32 {} + pub fn _destination_domain(&self) -> u32 {} - fn _next_pending(&self) -> Result, ChainCommunicationError> {} + pub fn _next_pending(&self) -> Result, ChainCommunicationError> {} - fn _can_confirm(&self) -> Result {} + pub fn _can_confirm(&self) -> Result {} - fn _confirm(&self) -> Result {} + pub fn _confirm(&self) -> Result {} - fn _previous_root(&self) -> Result {} + pub fn _previous_root(&self) -> Result {} - fn _last_processed(&self) -> Result {} + pub fn _last_processed(&self) -> Result {} - fn _prove(&self, proof: &Proof) -> Result {} + pub fn _prove(&self, proof: &Proof) -> Result {} - fn _process(&self, message: &StampedMessage) -> Result {} + pub fn _process(&self, message: &StampedMessage) -> Result {} - fn _prove_and_process( + pub fn _prove_and_process( &self, message: &StampedMessage, proof: &Proof, ) -> Result {} // Common - fn _name(&self) -> &str {} + pub fn _name(&self) -> &str {} - fn _status(&self, txid: H256) -> Result, ChainCommunicationError> {} + pub fn _status(&self, txid: H256) -> Result, ChainCommunicationError> {} - fn _updater(&self) -> Result {} + pub fn _updater(&self) -> Result {} - fn _state(&self) -> Result {} + pub fn _state(&self) -> Result {} - fn _current_root(&self) -> Result {} + pub fn _current_root(&self) -> Result {} - fn _signed_update_by_old_root( + pub fn _signed_update_by_old_root( &self, old_root: H256, ) -> Result, ChainCommunicationError> {} - fn _signed_update_by_new_root( + pub fn _signed_update_by_new_root( &self, new_root: H256, ) -> Result, ChainCommunicationError> {} - fn _update(&self, update: &SignedUpdate) -> Result {} + pub fn _update(&self, update: &SignedUpdate) -> Result {} - fn _double_update( + pub fn _double_update( &self, double: &DoubleUpdate, ) -> Result {} diff --git a/rust/relayer/Cargo.toml b/rust/relayer/Cargo.toml index c0ba090e5..4853114fb 100644 --- a/rust/relayer/Cargo.toml +++ b/rust/relayer/Cargo.toml @@ -21,3 +21,7 @@ tracing-subscriber = "0.2.15" optics-core = { path = "../optics-core" } optics-base = { path = "../optics-base" } + +[dev-dependencies] +tokio-test = "0.4.0" +optics-test = { path = "../optics-test" } diff --git a/rust/relayer/src/relayer.rs b/rust/relayer/src/relayer.rs index 5ed9aa00f..19dc34e9c 100644 --- a/rust/relayer/src/relayer.rs +++ b/rust/relayer/src/relayer.rs @@ -39,7 +39,7 @@ impl Relayer { } #[tracing::instrument(err)] - async fn poll_updates(home: Arc, replica: Arc) -> Result<()> { + async fn poll_and_relay_update(home: Arc, replica: Arc) -> Result<()> { // Get replica's current root let old_root = replica.current_root().await?; @@ -55,7 +55,7 @@ impl Relayer { } #[tracing::instrument(err)] - async fn poll_confirms(replica: Arc) -> Result<()> { + async fn poll_confirm(replica: Arc) -> Result<()> { // Check for pending update that can be confirmed let can_confirm = replica.can_confirm().await?; @@ -99,8 +99,8 @@ impl OpticsAgent for Relayer { loop { let (updated, confirmed) = tokio::join!( - Self::poll_updates(home.clone(), replica.clone()), - Self::poll_confirms(replica.clone()) + Self::poll_and_relay_update(home.clone(), replica.clone()), + Self::poll_confirm(replica.clone()) ); if let Err(ref e) = updated { @@ -116,3 +116,117 @@ impl OpticsAgent for Relayer { }) } } + +#[cfg(test)] +mod test { + use ethers::{core::types::H256, prelude::LocalWallet}; + use std::sync::Arc; + + use super::*; + use optics_core::{traits::TxOutcome, SignedUpdate, Update}; + use optics_test::mocks::{MockHomeContract, MockReplicaContract}; + + #[tokio::test] + async fn polls_and_relays_updates() { + let signer: LocalWallet = + "1111111111111111111111111111111111111111111111111111111111111111" + .parse() + .unwrap(); + + let first_root = H256::from([1; 32]); + let second_root = H256::from([2; 32]); + + let signed_update = Update { + origin_domain: 1, + previous_root: first_root, + new_root: second_root, + } + .sign_with(&signer) + .await + .expect("!sign"); + + let mut mock_home = MockHomeContract::new(); + let mut mock_replica = MockReplicaContract::new(); + + { + let signed_update = signed_update.clone(); + // home.signed_update_by_old_root(first_root) called once and + // returns mock value signed_update + mock_home + .expect__signed_update_by_old_root() + .withf(move |r: &H256| *r == first_root) + .times(1) + .return_once(move |_| Ok(Some(signed_update))); + } + { + let signed_update = signed_update.clone(); + // replica.current_root called once and returns mock value + // first_root + mock_replica + .expect__current_root() + .times(1) + .returning(move || Ok(first_root)); + // replica.update(signed_update) called once and returns + // mock default value + mock_replica + .expect__update() + .withf(move |s: &SignedUpdate| *s == signed_update) + .times(1) + .returning(|_| { + Ok(TxOutcome { + txid: H256::default(), + executed: true, + }) + }); + } + + let mut home: Arc = Arc::new(mock_home.into()); + let mut replica: Arc = Arc::new(mock_replica.into()); + Relayer::poll_and_relay_update(home.clone(), replica.clone()) + .await + .expect("Should have returned Ok(())"); + + let mock_home = Arc::get_mut(&mut home).unwrap(); + if let Homes::Mock(home) = mock_home { + home.checkpoint(); + } else { + panic!("Home should be mock variant!"); + } + + let mock_replica = Arc::get_mut(&mut replica).unwrap(); + if let Replicas::Mock(replica) = mock_replica { + replica.checkpoint(); + } else { + panic!("Replica should be mock variant!"); + } + } + + #[tokio::test] + async fn confirms_updates() { + let mut mock_replica = MockReplicaContract::new(); + // replica.can_confirm called once and returns mock true + mock_replica + .expect__can_confirm() + .times(1) + .returning(|| Ok(true)); + // replica.confirm called once and returns mock default + mock_replica.expect__confirm().times(1).returning(|| { + Ok(TxOutcome { + txid: H256::default(), + executed: true, + }) + }); + + let mut replica: Arc = Arc::new(mock_replica.into()); + Relayer::poll_confirm(replica.clone()) + .await + .expect("Should have returned Ok(())"); + + let mock_replica = Arc::get_mut(&mut replica).unwrap(); + if let Replicas::Mock(replica) = mock_replica { + replica.checkpoint(); + } else { + panic!("Replica should be mock variant!"); + } + } +} diff --git a/rust/updater/src/updater.rs b/rust/updater/src/updater.rs index a9fbb7490..d55c5e04e 100644 --- a/rust/updater/src/updater.rs +++ b/rust/updater/src/updater.rs @@ -121,7 +121,7 @@ mod test { use optics_test::mocks::MockHomeContract; #[tokio::test] - async fn polls_and_signs_update() { + async fn polls_and_submits_update() { let signer: LocalWallet = "1111111111111111111111111111111111111111111111111111111111111111" .parse() @@ -135,7 +135,7 @@ mod test { previous_root, new_root, }; - let signed_update = update.sign_with(&signer).await.unwrap(); + let signed_update = update.sign_with(&signer).await.expect("!sign"); let mut mock_home = MockHomeContract::new();