ave_core/evaluation/compiler/
contract_compiler.rs1use std::path::PathBuf;
2
3use async_trait::async_trait;
4use ave_actors::{
5 Actor, ActorContext, ActorError, ActorPath, Handler, Message,
6 NotPersistentActor,
7};
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10use tracing::{Span, debug, error, info_span};
11
12use ave_common::identity::{DigestIdentifier, HashAlgorithm, hash_borsh};
13
14use super::{CompilerResponse, CompilerSupport};
15use crate::metrics::try_core_metrics;
16
17#[derive(Clone, Debug, Serialize, Deserialize)]
18pub struct ContractCompiler {
19 contract: DigestIdentifier,
20 hash: HashAlgorithm,
21}
22
23impl ContractCompiler {
24 pub fn new(hash: HashAlgorithm) -> Self {
25 Self {
26 contract: DigestIdentifier::default(),
27 hash,
28 }
29 }
30}
31
32#[derive(Debug, Clone)]
33pub enum ContractCompilerMessage {
34 Compile {
35 contract: String,
36 contract_name: String,
37 initial_value: Value,
38 contract_path: PathBuf,
39 },
40}
41
42impl Message for ContractCompilerMessage {}
43
44impl NotPersistentActor for ContractCompiler {}
45
46#[async_trait]
47impl Actor for ContractCompiler {
48 type Event = ();
49 type Message = ContractCompilerMessage;
50 type Response = CompilerResponse;
51
52 fn get_span(id: &str, parent_span: Option<Span>) -> tracing::Span {
53 parent_span.map_or_else(
54 || info_span!("ContractCompiler", id),
55 |parent_span| {
56 info_span!(parent: parent_span, "ContractCompiler", id)
57 },
58 )
59 }
60}
61
62#[async_trait]
63impl Handler<Self> for ContractCompiler {
64 async fn handle_message(
65 &mut self,
66 _sender: ActorPath,
67 msg: ContractCompilerMessage,
68 ctx: &mut ActorContext<Self>,
69 ) -> Result<CompilerResponse, ActorError> {
70 match msg {
71 ContractCompilerMessage::Compile {
72 contract,
73 contract_name,
74 initial_value,
75 contract_path,
76 } => {
77 let contract_hash =
78 match hash_borsh(&*self.hash.hasher(), &contract) {
79 Ok(hash) => hash,
80 Err(e) => {
81 error!(
82 msg_type = "Compile",
83 error = %e,
84 "Failed to hash contract"
85 );
86 return Err(ActorError::FunctionalCritical {
87 description: format!(
88 "Can not hash contract: {}",
89 e
90 ),
91 });
92 }
93 };
94
95 if contract_hash != self.contract {
96 let (module, metadata) =
97 match CompilerSupport::compile_or_load_registered(
98 self.hash,
99 ctx,
100 &contract_name,
101 &contract,
102 &contract_path,
103 initial_value,
104 )
105 .await
106 {
107 Ok(result) => result,
108 Err(e) => {
109 error!(
110 msg_type = "Compile",
111 error = %e,
112 contract_name = %contract_name,
113 path = %contract_path.display(),
114 "Contract compilation or validation failed"
115 );
116 return Ok(CompilerResponse::Error(e));
117 }
118 };
119
120 {
121 let contracts =
122 CompilerSupport::contracts_helper(ctx).await?;
123 let mut contracts = contracts.write().await;
124 contracts.insert(contract_name.clone(), module);
125 }
126
127 self.contract = metadata.contract_hash.clone();
128
129 debug!(
130 msg_type = "Compile",
131 contract_name = %contract_name,
132 contract_hash = %metadata.contract_hash,
133 "Contract compiled and validated successfully"
134 );
135 } else {
136 if let Some(metrics) = try_core_metrics() {
137 metrics.observe_contract_prepare(
138 "registered",
139 "skipped",
140 std::time::Duration::default(),
141 );
142 }
143 debug!(
144 msg_type = "Compile",
145 contract_name = %contract_name,
146 "Contract already compiled, skipping"
147 );
148 }
149
150 Ok(CompilerResponse::Ok)
151 }
152 }
153 }
154}