Skip to main content

ave_core/evaluation/compiler/
temp_compiler.rs

1use std::path::PathBuf;
2use std::time::Instant;
3
4use async_trait::async_trait;
5use ave_actors::{
6    Actor, ActorContext, ActorError, ActorPath, Handler, Message,
7    NotPersistentActor,
8};
9use serde::{Deserialize, Serialize};
10use serde_json::Value;
11use tokio::fs;
12use tracing::{Span, error, info_span};
13
14use ave_common::identity::HashAlgorithm;
15
16use super::{CompilerResponse, CompilerSupport};
17use crate::metrics::try_core_metrics;
18
19#[derive(Clone, Debug, Serialize, Deserialize)]
20pub struct TempCompiler {
21    hash: HashAlgorithm,
22}
23
24impl TempCompiler {
25    pub const fn new(hash: HashAlgorithm) -> Self {
26        Self { hash }
27    }
28}
29
30#[derive(Debug, Clone)]
31pub enum TempCompilerMessage {
32    Compile {
33        contract: String,
34        contract_name: String,
35        initial_value: Value,
36        contract_path: PathBuf,
37    },
38}
39
40impl Message for TempCompilerMessage {}
41
42impl NotPersistentActor for TempCompiler {}
43
44#[async_trait]
45impl Actor for TempCompiler {
46    type Event = ();
47    type Message = TempCompilerMessage;
48    type Response = CompilerResponse;
49
50    fn get_span(id: &str, parent_span: Option<Span>) -> tracing::Span {
51        parent_span.map_or_else(
52            || info_span!("TempCompiler", id),
53            |parent_span| info_span!(parent: parent_span, "TempCompiler", id),
54        )
55    }
56}
57
58#[async_trait]
59impl Handler<Self> for TempCompiler {
60    async fn handle_message(
61        &mut self,
62        _sender: ActorPath,
63        msg: TempCompilerMessage,
64        ctx: &mut ActorContext<Self>,
65    ) -> Result<CompilerResponse, ActorError> {
66        match msg {
67            TempCompilerMessage::Compile {
68                contract,
69                contract_name,
70                initial_value,
71                contract_path,
72            } => {
73                let started_at = Instant::now();
74                let _ = fs::remove_dir_all(&contract_path).await;
75                if let Err(e) = CompilerSupport::compile_fresh(
76                    self.hash,
77                    ctx,
78                    &contract,
79                    &contract_path,
80                    initial_value,
81                )
82                .await
83                {
84                    if let Some(metrics) = try_core_metrics() {
85                        metrics.observe_contract_prepare(
86                            "temporary",
87                            "error",
88                            started_at.elapsed(),
89                        );
90                    }
91                    error!(
92                        msg_type = "Compile",
93                        error = %e,
94                        contract_name = %contract_name,
95                        path = %contract_path.display(),
96                        "Temporary contract compilation or validation failed"
97                    );
98                    let _ = fs::remove_dir_all(&contract_path).await;
99                    return Ok(CompilerResponse::Error(e));
100                }
101
102                if let Some(metrics) = try_core_metrics() {
103                    metrics.observe_contract_prepare(
104                        "temporary",
105                        "recompiled",
106                        started_at.elapsed(),
107                    );
108                }
109
110                if let Err(e) = fs::remove_dir_all(&contract_path).await {
111                    error!(
112                        msg_type = "Compile",
113                        error = %e,
114                        path = %contract_path.display(),
115                        "Failed to remove temporal contract directory"
116                    );
117                }
118
119                Ok(CompilerResponse::Ok)
120            }
121        }
122    }
123}