radix_engine/system/system_modules/transaction_runtime/
module.rs

1use crate::internal_prelude::*;
2use crate::system::module::*;
3use crate::system::system_callback::*;
4use radix_common::crypto::Hash;
5use radix_engine_interface::api::actor_api::EventFlags;
6use radix_engine_interface::api::ModuleId;
7
8#[derive(Debug, Clone)]
9pub struct Event {
10    pub type_identifier: EventTypeIdentifier,
11    pub payload: Vec<u8>,
12    pub flags: EventFlags,
13}
14
15/// Size of event flags when calculating event storage cost.
16pub const EVENT_FLAGS_LEN: usize = 4;
17
18impl Event {
19    #[allow(clippy::len_without_is_empty)]
20    pub fn len(&self) -> usize {
21        self.type_identifier.len() + self.payload.len() + EVENT_FLAGS_LEN
22    }
23}
24
25#[derive(Debug, Clone)]
26pub struct TransactionRuntimeModule {
27    pub network_definition: NetworkDefinition,
28    pub tx_hash: Hash,
29    pub next_id: u32,
30    pub logs: Vec<(Level, String)>,
31    pub events: Vec<Event>,
32    pub replacements: IndexMap<(NodeId, ModuleId), (NodeId, ModuleId)>,
33}
34
35impl TransactionRuntimeModule {
36    pub fn new(network_definition: NetworkDefinition, tx_hash: Hash) -> Self {
37        TransactionRuntimeModule {
38            network_definition,
39            tx_hash,
40            next_id: 0,
41            logs: Vec::new(),
42            events: Vec::new(),
43            replacements: index_map_new(),
44        }
45    }
46
47    pub fn generate_ruid(&mut self) -> [u8; 32] {
48        let mut bytes = [0u8; 36];
49        bytes[..32].copy_from_slice(self.tx_hash.as_slice());
50        bytes[32..].copy_from_slice(&self.next_id.to_le_bytes());
51
52        self.next_id += 1;
53
54        hash(bytes).0
55    }
56
57    pub fn add_log(&mut self, level: Level, message: String) {
58        self.logs.push((level, message))
59    }
60
61    pub fn add_event(&mut self, event: Event) {
62        self.events.push(event)
63    }
64
65    pub fn add_replacement(&mut self, old: (NodeId, ModuleId), new: (NodeId, ModuleId)) {
66        self.replacements.insert(old, new);
67    }
68
69    #[allow(clippy::type_complexity)]
70    pub fn finalize(
71        self,
72        is_success: bool,
73    ) -> (Vec<(EventTypeIdentifier, Vec<u8>)>, Vec<(Level, String)>) {
74        let mut results = Vec::new();
75
76        for Event {
77            mut type_identifier,
78            payload,
79            flags,
80        } in self.events.into_iter()
81        {
82            // Revert if failure
83            if !flags.contains(EventFlags::FORCE_WRITE) && !is_success {
84                continue;
85            }
86
87            // Apply replacements
88            if let EventTypeIdentifier(Emitter::Method(node_id, module_id), _) =
89                &mut type_identifier
90            {
91                if let Some((new_node_id, new_module_id)) =
92                    self.replacements.get(&(*node_id, *module_id))
93                {
94                    *node_id = *new_node_id;
95                    *module_id = *new_module_id;
96                }
97            };
98
99            // Add to results
100            results.push((type_identifier, payload))
101        }
102
103        (results, self.logs)
104    }
105}
106
107impl InitSystemModule for TransactionRuntimeModule {}
108impl ResolvableSystemModule for TransactionRuntimeModule {
109    #[inline]
110    fn resolve_from_system(system: &mut impl HasModules) -> &mut Self {
111        &mut system.modules_mut().transaction_runtime
112    }
113}
114impl PrivilegedSystemModule for TransactionRuntimeModule {}
115impl<ModuleApi: SystemModuleApiFor<Self>> SystemModule<ModuleApi> for TransactionRuntimeModule {}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn test_ruid_gen() {
123        let mut id = TransactionRuntimeModule {
124            network_definition: NetworkDefinition::simulator(),
125            tx_hash: Hash::from_str(
126                "71f26aab5eec6679f67c71211aba9a3486cc8d24194d339385ee91ee5ca7b30d",
127            )
128            .unwrap(),
129            next_id: 5,
130            logs: Vec::new(),
131            events: Vec::new(),
132            replacements: index_map_new(),
133        };
134        assert_eq!(
135            NonFungibleLocalId::ruid(id.generate_ruid()).to_string(),
136            "{7b003d8e0b2c9e3a-516cf99882de64a1-f1cd6742ce3299e0-357f54f0333d25d0}"
137        );
138
139        let mut id = TransactionRuntimeModule {
140            network_definition: NetworkDefinition::simulator(),
141            tx_hash: Hash([0u8; 32]),
142            next_id: 5,
143            logs: Vec::new(),
144            events: Vec::new(),
145            replacements: index_map_new(),
146        };
147        assert_eq!(
148            NonFungibleLocalId::ruid(id.generate_ruid()).to_string(),
149            "{69f38caee99e9468-866032d1a68b4d2e-7931bb74aede4d0f-8043d3a87e9f2da3}"
150        );
151
152        let mut id = TransactionRuntimeModule {
153            network_definition: NetworkDefinition::simulator(),
154            tx_hash: Hash([255u8; 32]),
155            next_id: 5,
156            logs: Vec::new(),
157            events: Vec::new(),
158            replacements: index_map_new(),
159        };
160        assert_eq!(
161            NonFungibleLocalId::ruid(id.generate_ruid()).to_string(),
162            "{04660ebc8e2a2b36-44a6553bd6a17a3a-ef14ce1fae4cb5bc-000811f979007003}"
163        );
164    }
165}