Skip to main content

cargo_tangle/command/run/
tangle.rs

1use alloy_primitives::Address;
2use blueprint_manager::config::{
3    BlueprintManagerConfig, BlueprintManagerContext, Paths, SourceType,
4};
5use blueprint_manager::executor::run_blueprint_manager;
6use blueprint_runner::config::{BlueprintEnvironment, ProtocolSettings};
7use blueprint_runner::tangle::config::TangleProtocolSettings;
8use color_eyre::eyre::Result;
9use dialoguer::console::style;
10use indicatif::{ProgressBar, ProgressStyle};
11use std::path::PathBuf;
12use std::time::Duration;
13use tokio::signal;
14use url::Url;
15
16#[derive(Clone)]
17pub struct RunOpts {
18    pub http_rpc_url: Url,
19    pub ws_rpc_url: Url,
20    pub blueprint_id: u64,
21    pub service_id: Option<u64>,
22    pub tangle_contract: Address,
23    pub staking_contract: Address,
24    pub status_registry_contract: Address,
25    pub keystore_path: String,
26    pub data_dir: Option<PathBuf>,
27    pub allow_unchecked_attestations: bool,
28    pub registration_mode: bool,
29    pub registration_capture_only: bool,
30    pub preferred_source: SourceType,
31    pub use_vm: bool,
32    pub dry_run: bool,
33    pub shutdown_after: Option<Duration>,
34}
35
36pub async fn run_blueprint(opts: RunOpts) -> Result<()> {
37    let mut blueprint_config = BlueprintEnvironment::default();
38    blueprint_config.http_rpc_endpoint = opts.http_rpc_url;
39    blueprint_config.ws_rpc_endpoint = opts.ws_rpc_url;
40    blueprint_config.keystore_uri = opts.keystore_path;
41    blueprint_config.data_dir = opts.data_dir.unwrap_or_else(|| PathBuf::from("./data"));
42    blueprint_config.registration_mode = opts.registration_mode;
43    blueprint_config.registration_capture_only = opts.registration_capture_only;
44    blueprint_config.dry_run = opts.dry_run;
45    blueprint_config.protocol_settings = ProtocolSettings::Tangle(TangleProtocolSettings {
46        blueprint_id: opts.blueprint_id,
47        service_id: opts.service_id,
48        tangle_contract: opts.tangle_contract,
49        staking_contract: opts.staking_contract,
50        status_registry_contract: opts.status_registry_contract,
51    });
52
53    #[allow(unused_mut)]
54    let mut blueprint_manager_config = BlueprintManagerConfig {
55        paths: Paths {
56            keystore_uri: blueprint_config.keystore_uri.clone(),
57            data_dir: blueprint_config.data_dir.clone(),
58            ..Default::default()
59        },
60        verbose: 2,
61        pretty: true,
62        instance_id: Some(format!("Blueprint-{}", opts.blueprint_id)),
63        allow_unchecked_attestations: opts.allow_unchecked_attestations,
64        preferred_source: opts.preferred_source,
65        ..Default::default()
66    };
67
68    #[cfg(feature = "vm-debug")]
69    {
70        blueprint_manager_config.vm_sandbox_options.no_vm = !opts.use_vm;
71    }
72
73    let ctx = BlueprintManagerContext::new(blueprint_manager_config).await?;
74
75    println!(
76        "{}",
77        style(format!(
78            "Starting blueprint manager for blueprint ID: {}",
79            opts.blueprint_id
80        ))
81        .cyan()
82        .bold()
83    );
84
85    let shutdown_after = opts.shutdown_after;
86    let shutdown_signal = async move {
87        if let Some(duration) = shutdown_after {
88            tokio::select! {
89                _ = signal::ctrl_c() => {
90                    println!(
91                        "{}",
92                        style("Received shutdown signal, stopping blueprint manager")
93                            .yellow()
94                            .bold()
95                    );
96                }
97                _ = tokio::time::sleep(duration) => {
98                    println!(
99                        "{}",
100                        style("Auto-shutdown window elapsed, stopping blueprint manager")
101                            .yellow()
102                            .bold()
103                    );
104                }
105            }
106        } else {
107            let _ = signal::ctrl_c().await;
108            println!(
109                "{}",
110                style("Received shutdown signal, stopping blueprint manager")
111                    .yellow()
112                    .bold()
113            );
114        }
115    };
116
117    println!(
118        "{}",
119        style("Preparing Blueprint to run, this may take a few minutes...").cyan()
120    );
121
122    let pb = ProgressBar::new_spinner();
123    pb.set_style(
124        ProgressStyle::default_spinner()
125            .tick_chars("⠁⠂⠄⡀⢀⠠⠐⠈ ")
126            .template("{spinner:.blue} {msg}")
127            .unwrap(),
128    );
129    pb.set_message("Initializing Blueprint");
130    pb.enable_steady_tick(Duration::from_millis(100));
131
132    let mut handle = run_blueprint_manager(ctx, blueprint_config, shutdown_signal).await?;
133
134    pb.finish_with_message("Blueprint initialized successfully!");
135
136    println!(
137        "{}",
138        style("Starting blueprint execution...").green().bold()
139    );
140    handle.start()?;
141
142    println!(
143        "{}",
144        style("Blueprint is running. Press Ctrl+C to stop.").cyan()
145    );
146    handle.await?;
147
148    println!("{}", style("Blueprint manager has stopped").green());
149    Ok(())
150}