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
//! Contains all valid event requests

use borsh::{BorshDeserialize, BorshSerialize};
use serde::{Deserialize, Serialize};

use crate::{
    commons::errors::SubjectError,
    signature::{Signature, Signed},
    DigestIdentifier, KeyIdentifier, ValueWrapper,
};

use super::HashId;

/// An enum representing a TAPLE event request.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, BorshSerialize, BorshDeserialize)]
pub enum EventRequest {
    /// A request to create a new subject.
    Create(StartRequest),
    /// A request to add a fact to a subject.
    Fact(FactRequest),
    /// A request to transfer ownership of a subject.
    Transfer(TransferRequest),
    /// A request to mark a subject as end-of-life.
    EOL(EOLRequest),
}

/// A struct representing a request to create a new subject.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, BorshSerialize, BorshDeserialize)]
pub struct StartRequest {
    /// The identifier of the governance contract.
    pub governance_id: DigestIdentifier,
    /// The identifier of the schema used to validate the event.
    pub schema_id: String,
    /// The namespace of the subject.
    pub namespace: String,
    /// The name of the subject.
    pub name: String,
    /// The identifier of the public key of the subject owner.
    pub public_key: KeyIdentifier,
}

/// A struct representing a request to add a fact to a subject.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, BorshSerialize, BorshDeserialize)]
pub struct FactRequest {
    /// The identifier of the subject to which the fact will be added.
    pub subject_id: DigestIdentifier,
    /// The payload of the fact to be added.
    pub payload: ValueWrapper,
}

/// A struct representing a request to transfer ownership of a subject.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, BorshSerialize, BorshDeserialize)]
pub struct TransferRequest {
    /// The identifier of the subject to transfer ownership of.
    pub subject_id: DigestIdentifier,
    /// The identifier of the public key of the new owner.
    pub public_key: KeyIdentifier,
}

/// A struct representing a request to mark a subject as end-of-life.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, BorshSerialize, BorshDeserialize)]
pub struct EOLRequest {
    /// The identifier of the subject to mark as end-of-life.
    pub subject_id: DigestIdentifier,
}

impl EventRequest {
    pub fn requires_eval_appr(&self) -> bool {
        match self {
            EventRequest::Fact(_) => true,
            EventRequest::Create(_) | EventRequest::Transfer(_) | EventRequest::EOL(_) => false,
        }
    }
}

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

impl Signed<EventRequest> {
    pub fn new(request: EventRequest, signature: Signature) -> Self {
        Self {
            content: request,
            signature,
        }
    }

    pub fn verify(&self) -> Result<(), SubjectError> {
        self.signature.verify(&self.content)
    }
}

/// Indicates the current status of an event request.
#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, BorshSerialize, BorshDeserialize)]
pub enum RequestState {
    Finished,
    Error,
    Processing,
}

/// A struct representing a TAPLE request.
#[derive(Debug, Clone, Serialize, Deserialize, BorshSerialize, BorshDeserialize)]
pub struct TapleRequest {
    /// The identifier of the request.
    pub id: DigestIdentifier,
    /// The identifier of the subject associated with the request, if any.
    pub subject_id: Option<DigestIdentifier>,
    /// The sequence number of the request, if any.
    pub sn: Option<u64>,
    /// The event request associated with the request.
    pub event_request: Signed<EventRequest>,
    /// The state of the request.
    pub state: RequestState,
    /// The success status of the request, if any.
    pub success: Option<bool>,
}

impl TryFrom<Signed<EventRequest>> for TapleRequest {
    type Error = SubjectError;

    fn try_from(event_request: Signed<EventRequest>) -> Result<Self, Self::Error> {
        let id = DigestIdentifier::from_serializable_borsh(&event_request)
            .map_err(|_| SubjectError::CryptoError("Error generation request hash".to_owned()))?;
        let subject_id = match &event_request.content {
            crate::EventRequest::Create(_) => None,
            crate::EventRequest::Fact(fact_request) => Some(fact_request.subject_id.clone()),
            crate::EventRequest::Transfer(transfer_res) => Some(transfer_res.subject_id.clone()),
            crate::EventRequest::EOL(eol_request) => Some(eol_request.subject_id.clone()),
        };
        Ok(Self {
            id,
            subject_id,
            sn: None,
            event_request,
            state: RequestState::Processing,
            success: None,
        })
    }
}