gevulot_rs/
lib.rs

1/// This module contains the base client implementation.
2pub mod base_client;
3/// This module contains various builders for constructing messages.
4pub mod builders;
5/// This module contains the client implementation for Gevulot.
6pub mod gevulot_client;
7/// This module contains the client implementation for managing pins.
8pub mod pin_client;
9/// This module contains the client implementation for sudo functionality.
10pub mod sudo_client;
11/// This module contains the client implementation for managing tasks.
12pub mod task_client;
13/// This module contains the client implementation for managing workers.
14pub mod worker_client;
15/// This module contains the client implementation for managing workflows.
16pub mod workflow_client;
17
18pub mod models;
19pub mod runtime_config;
20
21pub mod error;
22pub mod event_fetcher;
23pub mod events;
24pub mod gov_client;
25/// This module contains the signer implementation.
26pub mod signer;
27
28/// This module contains the protocol buffer definitions.
29pub mod proto {
30    // We can't do anything with clippy errors inside extrenal generated code,
31    // so just ignore them.
32    #[allow(clippy::all)]
33    pub mod cosmos {
34        pub mod base {
35            pub mod query {
36                pub mod v1beta1 {
37                    tonic::include_proto!("cosmos.base.query.v1beta1");
38                }
39            }
40        }
41
42        pub mod app {
43            pub mod v1alpha1 {
44                tonic::include_proto!("cosmos.app.v1alpha1");
45            }
46        }
47    }
48
49    #[allow(clippy::all)]
50    pub mod cosmos_proto {
51        tonic::include_proto!("cosmos_proto");
52    }
53
54    #[allow(clippy::all)]
55    // Code examples in generated code are not compiling
56    // and we don't want them to crash doc-tests.
57    #[cfg(not(doctest))]
58    pub mod google {
59        tonic::include_proto!("google.api");
60    }
61
62    pub mod gevulot {
63        #![allow(clippy::module_inception)]
64        pub mod gevulot {
65            tonic::include_proto!("gevulot.gevulot");
66            pub mod module {
67                tonic::include_proto!("gevulot.gevulot.module");
68            }
69        }
70    }
71}
72
73pub use cosmrs::tendermint::abci::Event;
74pub use cosmrs::tendermint::block::Height;
75pub use error::{Error, Result};
76pub use event_fetcher::{EventFetcher, EventHandler};
77pub use events::GevulotEvent;
78pub use gevulot_client::{GevulotClient, GevulotClientBuilder};
79
80#[cfg(test)]
81mod tests {
82    use cosmrs::tendermint::block::Height;
83
84    use self::builders::ByteUnit::{Byte, Gigabyte};
85
86    use super::*;
87
88    /// Helper function to read Alice's seed and address from files.
89    fn alice() -> (String, String) {
90        let seed_path = "../../.dev-node/alice_seed.txt";
91        let seed = std::fs::read_to_string(seed_path).expect("Unable to read seed file");
92        let address_path = "../../.dev-node/alice_address.txt";
93        let address = std::fs::read_to_string(address_path).expect("Unable to read address file");
94        (seed.trim().to_string(), address.trim().to_string())
95    }
96
97    #[tokio::test]
98    #[ignore]
99    async fn test_event_fetching() {
100        pretty_env_logger::init();
101
102        struct EventLogger;
103
104        impl event_fetcher::EventHandler for EventLogger {
105            async fn handle_event(
106                &mut self,
107                event: &crate::Event,
108                block_height: crate::Height,
109            ) -> crate::Result<()> {
110                match events::GevulotEvent::from_cosmos(event, block_height) {
111                    Ok(e) => println!("{:?}", e),
112                    Err(e) => println!("Error: {:?}", e),
113                }
114                Ok(())
115            }
116        }
117
118        let mut fetcher = event_fetcher::EventFetcher::new(
119            "http://127.0.0.1:26657",
120            Some(Height::from(0u32)),
121            tokio::time::Duration::from_secs(5),
122            EventLogger {},
123        );
124
125        fetcher.start_fetching().await.unwrap();
126    }
127
128    /// End-to-end test for the Gevulot client.
129    #[tokio::test]
130    #[ignore]
131    async fn test_e2e() {
132        let (mnemonic, address) = alice();
133
134        let mut cli = GevulotClientBuilder::new()
135            .endpoint("http://127.0.0.1:9090") // default endpoint
136            .gas_price(0.025) // default gas price
137            .gas_multiplier(1.2) // default gas multiplier
138            .mnemonic(mnemonic.as_str())
139            .build()
140            .await
141            .unwrap();
142
143        // Register a worker
144        let worker_msg = builders::MsgCreateWorkerBuilder::default()
145            .creator(address.clone())
146            .name("test_worker".to_string())
147            .cpus(1000)
148            .gpus(1000)
149            .memory((32, Gigabyte).into())
150            .disk((128, Gigabyte).into())
151            .into_message()
152            .expect("Failed to build worker message");
153
154        let worker_id = cli.workers.create(worker_msg).await.unwrap().id;
155
156        // Create a pin
157        let pin_msg = builders::MsgCreatePinBuilder::default()
158            .creator(address.clone())
159            .cid(Some(
160                "QmSWeBJYvDqKUFG3om4gsrKGf379zk8Jq5tYXpDp7Xo".to_string(),
161            ))
162            .bytes((32, Byte).into())
163            .time(3600)
164            .redundancy(1)
165            .name("test".to_string())
166            .into_message()
167            .expect("Failed to build pin message");
168
169        cli.pins.create(pin_msg).await.unwrap();
170
171        // Delete the pin
172        let delete_pin_msg = builders::MsgDeletePinBuilder::default()
173            .creator(address.clone())
174            .cid("QmSWeBJYvDqKUFG3om4gsrKGf379zk8Jq5tYXpDp7Xo".to_string())
175            .into_message()
176            .expect("Failed to build pin message");
177
178        cli.pins.delete(delete_pin_msg).await.unwrap();
179
180        // Announce worker exit
181        let announce_exit_msg = builders::MsgAnnounceWorkerExitBuilder::default()
182            .creator(address.clone())
183            .worker_id(worker_id.clone())
184            .into_message()
185            .expect("Failed to build worker message");
186
187        cli.workers.announce_exit(announce_exit_msg).await.unwrap();
188
189        {
190            // Wait for 10 blocks to be mined
191            let mut base_client = cli.base_client.write().await;
192            let current_block = base_client.current_block().await.unwrap();
193            let current_height = current_block
194                .header
195                .as_ref()
196                .ok_or("Header not found")
197                .unwrap()
198                .height;
199            base_client
200                .wait_for_block(current_height + 10)
201                .await
202                .unwrap();
203        }
204
205        // Delete the worker
206        let delete_worker_msg = builders::MsgDeleteWorkerBuilder::default()
207            .creator(address.clone())
208            .id(worker_id.clone())
209            .into_message()
210            .expect("Failed to build worker message");
211
212        cli.workers.delete(delete_worker_msg).await.unwrap();
213    }
214}