Skip to main content

ave_core/governance/
contract_register.rs

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 {}