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