Skip to main content

dpp/document/
document_event.rs

1use crate::data_contract::accessors::v0::DataContractV0Getters;
2use crate::data_contract::document_type::DocumentTypeRef;
3use crate::data_contract::DataContract;
4use crate::document::{Document, DocumentV0};
5use crate::fee::Credits;
6use crate::prelude::IdentityNonce;
7use crate::ProtocolError;
8use platform_value::Identifier;
9use std::collections::BTreeMap;
10
11use crate::block::block_info::BlockInfo;
12
13/// A document event that is recorded in the document history system contract
14/// for document types that opted in via the `keepsTransferHistory`,
15/// `keepsPurchaseHistory` and `keepsPricingHistory` configuration flags.
16#[derive(Debug, PartialEq, Eq, Clone)]
17pub enum DocumentEvent {
18    /// The document was transferred to another identity without a trade.
19    /// The history document is owned by the sender.
20    Transfer {
21        /// The identity the document was transferred to
22        to_identity_id: Identifier,
23    },
24    /// The document was bought at its asking price.
25    /// The history document is owned by the buyer.
26    Purchase {
27        /// The identity that sold the document
28        seller_id: Identifier,
29        /// The price paid in credits
30        price: Credits,
31    },
32    /// The document's asking price was updated by its owner.
33    /// The history document is owned by the seller.
34    PriceUpdate {
35        /// The new asking price in credits
36        price: Credits,
37    },
38}
39
40impl DocumentEvent {
41    /// The name of the document type in the document history contract that
42    /// records this event.
43    pub fn associated_document_type_name(&self) -> &'static str {
44        match self {
45            DocumentEvent::Transfer { .. } => "transfer",
46            DocumentEvent::Purchase { .. } => "purchase",
47            DocumentEvent::PriceUpdate { .. } => "priceUpdate",
48        }
49    }
50
51    /// The document type in the document history contract that records this
52    /// event.
53    pub fn associated_document_type<'a>(
54        &self,
55        document_history_contract: &'a DataContract,
56    ) -> Result<DocumentTypeRef<'a>, ProtocolError> {
57        Ok(document_history_contract
58            .document_type_for_name(self.associated_document_type_name())?)
59    }
60
61    /// Builds the history document recording this event.
62    ///
63    /// The id is deterministically derived from the source document, the
64    /// acting identity and its contract nonce, so every validator produces
65    /// the same history document for the same state transition.
66    #[allow(clippy::too_many_arguments)]
67    pub fn build_historical_document_owned(
68        self,
69        source_data_contract_id: Identifier,
70        source_document_type_name: &str,
71        source_document_id: Identifier,
72        owner_id: Identifier,
73        owner_nonce: IdentityNonce,
74        block_info: &BlockInfo,
75    ) -> Document {
76        let document_id = Document::generate_document_id_v0(
77            &source_document_id,
78            &owner_id,
79            format!("history_{}", self.associated_document_type_name()).as_str(),
80            owner_nonce.to_be_bytes().as_slice(),
81        );
82
83        let mut properties = BTreeMap::from([
84            ("dataContractId".to_string(), source_data_contract_id.into()),
85            (
86                "documentTypeName".to_string(),
87                source_document_type_name.into(),
88            ),
89            ("documentId".to_string(), source_document_id.into()),
90        ]);
91
92        match self {
93            DocumentEvent::Transfer { to_identity_id } => {
94                properties.insert("toIdentityId".to_string(), to_identity_id.into());
95            }
96            DocumentEvent::Purchase { seller_id, price } => {
97                properties.insert("sellerId".to_string(), seller_id.into());
98                properties.insert("price".to_string(), price.into());
99            }
100            DocumentEvent::PriceUpdate { price } => {
101                properties.insert("price".to_string(), price.into());
102            }
103        }
104
105        DocumentV0 {
106            contract_version: None,
107            id: document_id,
108            owner_id,
109            properties,
110            revision: None,
111            created_at: Some(block_info.time_ms),
112            updated_at: None,
113            transferred_at: None,
114            created_at_block_height: Some(block_info.height),
115            updated_at_block_height: None,
116            transferred_at_block_height: None,
117            created_at_core_block_height: None,
118            updated_at_core_block_height: None,
119            transferred_at_core_block_height: None,
120            creator_id: None,
121        }
122        .into()
123    }
124}