1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
//! Contains the data structures related to event  to send to approvers, or to validators if approval is not required.
use std::collections::HashSet;

use crate::{
    commons::{
        crypto::{KeyMaterial, KeyPair},
        errors::SubjectError,
    },
    identifier::{DigestIdentifier, KeyIdentifier},
    request::EventRequest,
    signature::{Signature, Signed},
    ApprovalResponse, Derivable, EvaluationRequest, EvaluationResponse,
};
use borsh::{BorshDeserialize, BorshSerialize};
use json_patch::diff;
use serde::{Deserialize, Serialize};
use serde_json::json;

use super::{
    approval::ApprovalRequest, evaluation::SubjectContext, state::generate_subject_id,
    value_wrapper::ValueWrapper, HashId,
};

/// A struct representing an event.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, BorshSerialize, BorshDeserialize)]
pub struct Event {
    /// The identifier of the subject of the event.
    pub subject_id: DigestIdentifier,
    /// The signed event request.
    pub event_request: Signed<EventRequest>,
    /// The sequence number of the event.
    pub sn: u64,
    /// The version of the governance contract.
    pub gov_version: u64,
    /// The patch to apply to the state.
    pub patch: ValueWrapper,
    /// The hash of the state after applying the patch.
    pub state_hash: DigestIdentifier,
    /// Whether the evaluation was successful and the result was validated against the schema.
    pub eval_success: bool,
    /// Whether approval is required for the event to be applied to the state.
    pub appr_required: bool,
    /// Whether the event has been approved.
    pub approved: bool,
    /// The hash of the previous event.
    pub hash_prev_event: DigestIdentifier,
    /// The set of evaluators who have evaluated the event.
    pub evaluators: HashSet<Signature>,
    /// The set of approvers who have approved the event.
    pub approvers: HashSet<Signature>,
}

impl Event {
    pub(crate) fn get_approval_hash(
        &self,
        gov_id: DigestIdentifier,
    ) -> Result<DigestIdentifier, SubjectError> {
        ApprovalRequest {
            event_request: self.event_request.clone(),
            sn: self.sn,
            gov_version: self.gov_version,
            patch: self.patch.clone(),
            state_hash: self.state_hash.clone(),
            hash_prev_event: self.hash_prev_event.clone(),
            gov_id,
        }
        .hash_id()
    }
}

impl HashId for Event {
    fn hash_id(&self) -> Result<DigestIdentifier, SubjectError> {
        DigestIdentifier::from_serializable_borsh(&self)
            .map_err(|_| SubjectError::SignatureCreationFails("HashId for Event Fails".to_string()))
    }
}

impl HashId for Signed<Event> {
    fn hash_id(&self) -> Result<DigestIdentifier, SubjectError> {
        DigestIdentifier::from_serializable_borsh(&self).map_err(|_| {
            SubjectError::SignatureCreationFails("HashId for Signed Event Fails".to_string())
        })
    }
}

impl Signed<Event> {
    pub fn from_genesis_request(
        event_request: Signed<EventRequest>,
        subject_keys: &KeyPair,
        gov_version: u64,
        init_state: &ValueWrapper,
    ) -> Result<Self, SubjectError> {
        let EventRequest::Create(start_request) = event_request.content.clone() else {
            return Err(SubjectError::NotCreateEvent)
        };
        let json_patch = serde_json::to_value(diff(&json!({}), &init_state.0)).map_err(|_| {
            SubjectError::CryptoError(String::from("Error converting patch to value"))
        })?;
        let public_key = KeyIdentifier::new(
            subject_keys.get_key_derivator(),
            &subject_keys.public_key_bytes(),
        );
        let subject_id = generate_subject_id(
            &start_request.namespace,
            &start_request.schema_id,
            public_key.to_str(),
            start_request.governance_id.to_str(),
            gov_version,
        )?;
        let state_hash = DigestIdentifier::from_serializable_borsh(init_state).map_err(|_| {
            SubjectError::CryptoError(String::from("Error converting state to hash"))
        })?;
        let content = Event {
            subject_id,
            event_request,
            sn: 0,
            gov_version,
            patch: ValueWrapper(json_patch),
            state_hash,
            eval_success: true,
            appr_required: false,
            approved: true,
            hash_prev_event: DigestIdentifier::default(),
            evaluators: HashSet::new(),
            approvers: HashSet::new(),
        };
        let subject_signature_event = Signature::new(&content, public_key.clone(), &subject_keys)
            .map_err(|_| {
            SubjectError::CryptoError(String::from("Error signing the hash of the proposal"))
        })?;
        Ok(Self {
            content,
            signature: subject_signature_event,
        })
    }

    pub fn verify_signatures(&self) -> Result<(), SubjectError> {
        // Verify event and event_request signatures
        self.signature.verify(&self.content)?;
        self.content.event_request.verify()
    }

    pub fn verify_eval_appr(
        &self,
        subject_context: SubjectContext,
        eval_sign_info: (&HashSet<KeyIdentifier>, u32, u32),
        appr_sign_info: (&HashSet<KeyIdentifier>, u32, u32),
    ) -> Result<(), SubjectError> {
        if !self.content.event_request.content.requires_eval_appr()
            && self.content.eval_success
            && self.content.approved
            && !self.content.appr_required
        {
            return Ok(());
        }
        let gov_id = subject_context.governance_id.clone();
        // Verify evaluators signatures
        let eval_request = EvaluationRequest {
            event_request: self.content.event_request.clone(),
            context: subject_context,
            sn: self.content.sn,
            gov_version: self.content.gov_version,
        };
        let eval_response = EvaluationResponse {
            patch: self.content.patch.clone(), // Esto no hace falta realmente
            eval_req_hash: eval_request.hash_id()?,
            state_hash: self.content.state_hash.clone(),
            eval_success: self.content.eval_success,
            appr_required: self.content.appr_required,
        };
        let mut evaluators = HashSet::new();
        for eval_signature in self.content.evaluators.iter() {
            if !evaluators.insert(eval_signature.signer.clone()) {
                return Err(SubjectError::RepeatedSignature(
                    "Repeated Signer in Evaluators".to_string(),
                ));
            }
            eval_signature.verify(&eval_response)?;
        }
        if !evaluators.is_subset(eval_sign_info.0) {
            return Err(SubjectError::SignersError(
                "Incorrect Evaluators signed".to_string(),
            ));
        }
        let quorum_size_eval = if self.content.eval_success {
            eval_sign_info.1
        } else {
            eval_sign_info.2
        };
        if evaluators.len() < quorum_size_eval as usize {
            return Err(SubjectError::SignersError(
                "Not enough Evaluators signed".to_string(),
            ));
        }
        if self.content.approved && !self.content.appr_required {
            return Ok(());
        }
        // Verify approvers signatures
        let appr_request = ApprovalRequest {
            event_request: self.content.event_request.clone(),
            sn: self.content.sn,
            gov_version: self.content.gov_version,
            patch: self.content.patch.clone(),
            state_hash: self.content.state_hash.clone(),
            hash_prev_event: self.content.hash_prev_event.clone(),
            gov_id,
        };
        let appr_response = ApprovalResponse {
            appr_req_hash: appr_request.hash_id()?,
            approved: self.content.approved,
        };
        let mut approvers = HashSet::new();
        for appr_signature in self.content.approvers.iter() {
            if !approvers.insert(appr_signature.signer.clone()) {
                return Err(SubjectError::RepeatedSignature(
                    "Repeated Signer in Approvers".to_string(),
                ));
            }
            appr_signature.verify(&appr_response)?;
        }
        if !approvers.is_subset(appr_sign_info.0) {
            return Err(SubjectError::SignersError(
                "Incorrect Approvers signed".to_string(),
            ));
        }
        let quorum_size_appr = if self.content.approved {
            appr_sign_info.1
        } else {
            appr_sign_info.2
        };
        if approvers.len() < quorum_size_appr as usize {
            return Err(SubjectError::SignersError(
                "Not enough Approvers signed".to_string(),
            ));
        }
        Ok(())
    }
}

/// A struct representing the metadata of a TAPLE event.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, BorshSerialize, BorshDeserialize)]
pub struct Metadata {
    /// The namespace of the event.
    pub namespace: String,
    /// The identifier of the subject of the event.
    pub subject_id: DigestIdentifier,
    /// The identifier of the governance contract.
    pub governance_id: DigestIdentifier,
    /// The version of the governance contract.
    pub governance_version: u64,
    /// The identifier of the schema used to validate the event.
    pub schema_id: String,
}