3030#![ feature( mutex_unlock) ]
3131mod tinydancer;
3232use std:: {
33+ f32:: consts:: E ,
3334 fs:: { self , File , OpenOptions } ,
3435 io,
3536 path:: { Path , PathBuf } ,
37+ thread:: sleep,
38+ time:: Duration ,
3639} ;
3740
38- use sampler:: ArchiveConfig ;
41+ use crossterm:: style:: Stylize ;
42+ use sampler:: { pull_and_verify_shreds, ArchiveConfig } ;
3943use serde:: { Deserialize , Serialize } ;
4044use serde_json:: Value ;
41- use tinydancer:: { Cluster , TinyDancer , TinyDancerConfig } ;
45+ use spinoff:: { spinners, Color , Spinner } ;
46+ use tinydancer:: { endpoint, Cluster , TinyDancer , TinyDancerConfig } ;
4247mod macros;
48+ use colored:: Colorize ;
4349mod rpc_wrapper;
4450mod sampler;
4551mod ui;
@@ -76,6 +82,11 @@ pub enum Commands {
7682 #[ clap( required = false , default_value_t = 10000000 ) ]
7783 shred_archive_duration : u64 ,
7884 } ,
85+ /// Verify the samples for a single slot
86+ Verify {
87+ #[ clap( long, required = false , default_value = "0" ) ]
88+ slot : usize ,
89+ } ,
7990 /// Stream the client logs to your terminal
8091 Logs {
8192 #[ clap( long, required = false , default_value = "client.log" ) ]
@@ -158,27 +169,44 @@ async fn main() {
158169 Commands :: Config ( sub_config) => match sub_config {
159170 ConfigSubcommands :: Get => {
160171 let home_path = std:: env:: var ( "HOME" ) . unwrap ( ) ;
161- std:: process:: Command :: new ( "cat" )
162- . arg ( home_path + "/.config/tinydancer/config.json" )
163- . spawn ( )
164- . expect ( "Config not set" ) ;
172+ let is_existing = home_path. clone ( ) + "/.config/tinydancer/config.json" ;
173+ let path = Path :: new ( & is_existing) ;
174+ if path. exists ( ) {
175+ std:: process:: Command :: new ( "cat" )
176+ . arg ( home_path + "/.config/tinydancer/config.json" )
177+ . spawn ( )
178+ . expect ( "Config not set" ) ;
179+ } else {
180+ println ! (
181+ "{} {}" ,
182+ "Initialise a config first using:" . to_string( ) . yellow( ) ,
183+ "tinydancer set config" . to_string( ) . green( )
184+ ) ;
185+ }
165186 }
166187 ConfigSubcommands :: Set { log_path, cluster } => {
167188 // println!("{:?}", fs::create_dir_all("~/.config/tinydancer"));
168189
169190 let home_path = std:: env:: var ( "HOME" ) . unwrap ( ) ;
170-
171- std:: process:: Command :: new ( "mkdir" )
172- . arg ( home_path. clone ( ) + "/.config/tinydancer" )
173- . stdout ( std:: process:: Stdio :: null ( ) )
174- . spawn ( )
175- . expect ( "couldnt make dir" ) ;
176- // home_path.push_str("/config.json");
177- std:: process:: Command :: new ( "touch" )
178- . arg ( home_path. clone ( ) + "/.config/tinydancer/config.json" )
179- . stdout ( std:: process:: Stdio :: null ( ) )
180- . spawn ( )
181- . expect ( "couldnt make file" ) ;
191+ let is_existing = home_path. clone ( ) + "/.config/tinydancer" ;
192+ let path = Path :: new ( & is_existing) ;
193+ if !path. exists ( ) {
194+ std:: process:: Command :: new ( "mkdir" )
195+ . arg ( home_path. clone ( ) + "/.config/tinydancer" )
196+ . stdout ( std:: process:: Stdio :: null ( ) )
197+ . spawn ( )
198+ . expect ( "couldnt make dir" ) ;
199+ }
200+ let is_existing = home_path. clone ( ) + "/.config/tinydancer/config.json" ;
201+ let path = Path :: new ( & is_existing) ;
202+ if !path. exists ( ) {
203+ std:: process:: Command :: new ( "touch" )
204+ . arg ( home_path. clone ( ) + "/.config/tinydancer/config.json" )
205+ . stdout ( std:: process:: Stdio :: null ( ) )
206+ . spawn ( )
207+ . expect ( "couldnt make file" ) ;
208+ }
209+ sleep ( Duration :: from_secs ( 1 ) ) ;
182210 loop {
183211 let mut config_file = {
184212 let home_path = std:: env:: var ( "HOME" ) . unwrap ( ) ;
@@ -200,6 +228,7 @@ async fn main() {
200228 serde_json:: to_string_pretty ( & config_file) . unwrap ( ) ,
201229 )
202230 . unwrap ( ) ;
231+ break ;
203232 }
204233 Err ( _) => {
205234 std:: fs:: write (
@@ -217,6 +246,58 @@ async fn main() {
217246 }
218247 }
219248 } ,
249+ Commands :: Verify { slot } => {
250+ let mut spinner = Spinner :: new (
251+ spinners:: Dots ,
252+ format ! ( "Verifying Shreds for Slot {}" , slot) ,
253+ Color :: Green ,
254+ ) ;
255+ let home_path = std:: env:: var ( "HOME" ) . unwrap ( ) ;
256+ let is_existing = home_path. clone ( ) + "/.config/tinydancer/config.json" ;
257+ let path = Path :: new ( & is_existing) ;
258+ if path. exists ( ) {
259+ let mut config_file = {
260+ let home_path = std:: env:: var ( "HOME" ) . unwrap ( ) ;
261+
262+ let text =
263+ std:: fs:: read_to_string ( home_path + "/.config/tinydancer/config.json" )
264+ . unwrap ( ) ;
265+
266+ serde_json:: from_str :: < ConfigSchema > ( & text)
267+ } ;
268+ // println!("path {:?}", config_file);
269+ match config_file {
270+ Ok ( config_file) => {
271+ let is_verified =
272+ pull_and_verify_shreds ( slot, get_endpoint ( config_file. cluster ) ) . await ;
273+ println ! ( "out: {:?}" , is_verified) ;
274+ if is_verified {
275+ println ! (
276+ "Slot {} is {} ✓" ,
277+ slot. to_string( ) . yellow( ) ,
278+ "Valid" . to_string( ) . green( )
279+ ) ;
280+ } else {
281+ println ! (
282+ "Slot {} is not {} ❌" ,
283+ slot. to_string( ) . yellow( ) ,
284+ "Valid" . to_string( ) . red( )
285+ ) ;
286+ }
287+ }
288+ Err ( e) => {
289+ tiny_logger:: logs:: error!( "{}" , e) ;
290+ println ! ( "e {:?}" , e) ;
291+ }
292+ } ;
293+ } else {
294+ println ! (
295+ "{} {}" ,
296+ "Initialise a config first using:" . to_string( ) . yellow( ) ,
297+ "tinydancer set config" . to_string( ) . green( )
298+ ) ;
299+ }
300+ }
220301 }
221302}
222303
@@ -228,6 +309,14 @@ pub fn get_cluster(cluster: String) -> Cluster {
228309 _ => Cluster :: Custom ( cluster) ,
229310 }
230311}
312+ pub fn get_endpoint ( cluster : String ) -> String {
313+ match cluster. as_str ( ) {
314+ "Mainnet" => "https://api.mainnet-beta.solana.com" . to_owned ( ) ,
315+ "Devnet" => "https://api.devnet.solana.com" . to_owned ( ) ,
316+ "Localnet" => "http://0.0.0.0:8899" . to_owned ( ) ,
317+ _ => "http://0.0.0.0:8899" . to_owned ( ) ,
318+ }
319+ }
231320
232321#[ derive( Debug , Serialize , Deserialize ) ]
233322#[ serde( rename_all = "camelCase" ) ]
0 commit comments