1use std::collections::HashMap;
2
3use async_trait::async_trait;
4use ave_actors::{
5 Actor, ActorContext, ActorError, ActorPath, Event, Handler,
6 LightPersistence, Message, PersistentActor, Response,
7};
8use borsh::{BorshDeserialize, BorshSerialize};
9use serde::{Deserialize, Serialize};
10use tracing::{Span, error, info_span};
11
12use crate::{
13 db::Storable,
14 evaluation::compiler::ContractArtifactRecord,
15 model::common::{emit_fail, purge_storage},
16};
17
18#[derive(
19 Default,
20 Clone,
21 Debug,
22 Serialize,
23 Deserialize,
24 BorshSerialize,
25 BorshDeserialize,
26)]
27pub struct ContractRegister {
28 contracts: HashMap<String, ContractArtifactRecord>,
29}
30
31impl ContractRegister {
32 pub fn new() -> Self {
33 Self::default()
34 }
35}
36
37#[derive(Debug, Clone)]
38pub enum ContractRegisterMessage {
39 PurgeStorage,
40 GetMetadata {
41 contract_name: String,
42 },
43 ListContracts,
44 DeleteMetadata {
45 contract_name: String,
46 },
47 SetMetadata {
48 contract_name: String,
49 metadata: ContractArtifactRecord,
50 },
51}
52
53impl Message for ContractRegisterMessage {
54 fn is_critical(&self) -> bool {
55 matches!(
56 self,
57 Self::PurgeStorage
58 | Self::SetMetadata { .. }
59 | Self::DeleteMetadata { .. }
60 )
61 }
62}
63
64#[derive(Debug, Clone)]
65pub enum ContractRegisterResponse {
66 Metadata(Option<ContractArtifactRecord>),
67 Contracts(Vec<String>),
68 Ok,
69}
70
71impl Response for ContractRegisterResponse {}
72
73#[derive(
74 Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize,
75)]
76pub enum ContractRegisterEvent {
77 DeleteMetadata {
78 contract_name: String,
79 },
80 SetMetadata {
81 contract_name: String,
82 metadata: ContractArtifactRecord,
83 },
84}
85
86impl Event for ContractRegisterEvent {}
87
88#[async_trait]
89impl Actor for ContractRegister {
90 type Event = ContractRegisterEvent;
91 type Message = ContractRegisterMessage;
92 type Response = ContractRegisterResponse;
93
94 fn get_span(_id: &str, parent_span: Option<Span>) -> tracing::Span {
95 parent_span.map_or_else(
96 || info_span!("ContractRegister"),
97 |parent_span| info_span!(parent: parent_span, "ContractRegister"),
98 )
99 }
100
101 async fn pre_start(
102 &mut self,
103 ctx: &mut ActorContext<Self>,
104 ) -> Result<(), ActorError> {
105 let prefix = ctx.path().parent().key();
106 self.init_store("contract_register", Some(prefix), false, ctx)
107 .await
108 }
109}
110
111#[async_trait]
112impl Handler<Self> for ContractRegister {
113 async fn handle_message(
114 &mut self,
115 _sender: ActorPath,
116 msg: ContractRegisterMessage,
117 ctx: &mut ActorContext<Self>,
118 ) -> Result<ContractRegisterResponse, ActorError> {
119 match msg {
120 ContractRegisterMessage::PurgeStorage => {
121 purge_storage(ctx).await?;
122
123 Ok(ContractRegisterResponse::Ok)
124 }
125 ContractRegisterMessage::ListContracts => {
126 Ok(ContractRegisterResponse::Contracts(
127 self.contracts.keys().cloned().collect(),
128 ))
129 }
130 ContractRegisterMessage::GetMetadata { contract_name } => {
131 Ok(ContractRegisterResponse::Metadata(
132 self.contracts.get(&contract_name).cloned(),
133 ))
134 }
135 ContractRegisterMessage::DeleteMetadata { contract_name } => {
136 self.on_event(
137 ContractRegisterEvent::DeleteMetadata { contract_name },
138 ctx,
139 )
140 .await;
141
142 Ok(ContractRegisterResponse::Ok)
143 }
144 ContractRegisterMessage::SetMetadata {
145 contract_name,
146 metadata,
147 } => {
148 self.on_event(
149 ContractRegisterEvent::SetMetadata {
150 contract_name,
151 metadata,
152 },
153 ctx,
154 )
155 .await;
156
157 Ok(ContractRegisterResponse::Ok)
158 }
159 }
160 }
161
162 async fn on_event(
163 &mut self,
164 event: ContractRegisterEvent,
165 ctx: &mut ActorContext<Self>,
166 ) {
167 if let Err(e) = self.persist(&event, ctx).await {
168 error!(
169 event = ?event,
170 error = %e,
171 "Failed to persist contract register event"
172 );
173 emit_fail(ctx, e).await;
174 }
175 }
176}
177
178#[async_trait]
179impl PersistentActor for ContractRegister {
180 type Persistence = LightPersistence;
181 type InitParams = ();
182
183 fn create_initial(_params: Self::InitParams) -> Self {
184 Self::new()
185 }
186
187 fn apply(&mut self, event: &Self::Event) -> Result<(), ActorError> {
188 match event {
189 ContractRegisterEvent::DeleteMetadata { contract_name } => {
190 self.contracts.remove(contract_name);
191 }
192 ContractRegisterEvent::SetMetadata {
193 contract_name,
194 metadata,
195 } => {
196 self.contracts
197 .insert(contract_name.clone(), metadata.clone());
198 }
199 }
200
201 Ok(())
202 }
203}
204
205#[async_trait]
206impl Storable for ContractRegister {}