oasis_core_runtime/transaction/
dispatcher.rs

1//! Runtime transaction batch dispatcher.
2use std::sync::{atomic::AtomicBool, Arc};
3
4use super::{context::Context, tags::Tags, types::TxnBatch};
5use crate::{
6    common::crypto::hash::Hash,
7    consensus::roothash,
8    types::{CheckTxResult, Error as RuntimeError},
9};
10
11/// Runtime transaction dispatcher trait.
12///
13/// It defines the interface used by the runtime call dispatcher
14/// to process transactions.
15pub trait Dispatcher: Send + Sync {
16    /// Whether dispatch is supported by this dispatcher.
17    fn is_supported(&self) -> bool {
18        true
19    }
20
21    /// Execute the transactions in the given batch.
22    ///
23    /// # Consensus Layer State Integrity
24    ///
25    /// Before this method is invoked, consensus layer state integrity verification is performed.
26    fn execute_batch(
27        &self,
28        ctx: Context,
29        batch: &TxnBatch,
30        in_msgs: &[roothash::IncomingMessage],
31    ) -> Result<ExecuteBatchResult, RuntimeError>;
32
33    /// Schedule and execute transactions in the given batch.
34    ///
35    /// The passed batch is an initial batch. In case the runtime needs additional items it should
36    /// request them from the host.
37    ///
38    /// # Consensus Layer State Integrity
39    ///
40    /// Before this method is invoked, consensus layer state integrity verification is performed.
41    fn schedule_and_execute_batch(
42        &self,
43        _ctx: Context,
44        _initial_batch: &mut TxnBatch,
45        _in_msgs: &[roothash::IncomingMessage],
46    ) -> Result<ExecuteBatchResult, RuntimeError> {
47        Err(RuntimeError::new(
48            "rhp/dispatcher",
49            3,
50            "scheduling not supported",
51        ))
52    }
53
54    /// Check the transactions in the given batch for validity.
55    ///
56    /// # Consensus Layer State Integrity
57    ///
58    /// No consensus layer state integrity verification is performed for queries by default. The
59    /// runtime dispatcher implementation should perform integrity verification if needed on a
60    /// query-by-query basis.
61    fn check_batch(
62        &self,
63        ctx: Context,
64        batch: &TxnBatch,
65    ) -> Result<Vec<CheckTxResult>, RuntimeError>;
66
67    /// Invoke the finalizer (if any).
68    fn finalize(&self, _new_storage_root: Hash) {
69        // Default implementation does nothing.
70    }
71
72    /// Configure abort batch flag.
73    fn set_abort_batch_flag(&mut self, _abort_batch: Arc<AtomicBool>) {
74        // Default implementation does nothing.
75    }
76
77    /// Process a query.
78    ///
79    /// # Consensus Layer State Integrity
80    ///
81    /// No consensus layer state integrity verification is performed for queries by default. The
82    /// runtime dispatcher implementation should perform integrity verification if needed on a
83    /// query-by-query basis.
84    fn query(&self, _ctx: Context, _method: &str, _args: Vec<u8>) -> Result<Vec<u8>, RuntimeError> {
85        // Default implementation returns an error.
86        Err(RuntimeError::new(
87            "rhp/dispatcher",
88            2,
89            "query not supported",
90        ))
91    }
92}
93
94impl<T: Dispatcher + ?Sized> Dispatcher for Box<T> {
95    fn is_supported(&self) -> bool {
96        T::is_supported(&**self)
97    }
98
99    fn execute_batch(
100        &self,
101        ctx: Context,
102        batch: &TxnBatch,
103        in_msgs: &[roothash::IncomingMessage],
104    ) -> Result<ExecuteBatchResult, RuntimeError> {
105        T::execute_batch(&**self, ctx, batch, in_msgs)
106    }
107
108    fn schedule_and_execute_batch(
109        &self,
110        ctx: Context,
111        initial_batch: &mut TxnBatch,
112        in_msgs: &[roothash::IncomingMessage],
113    ) -> Result<ExecuteBatchResult, RuntimeError> {
114        T::schedule_and_execute_batch(&**self, ctx, initial_batch, in_msgs)
115    }
116
117    fn check_batch(
118        &self,
119        ctx: Context,
120        batch: &TxnBatch,
121    ) -> Result<Vec<CheckTxResult>, RuntimeError> {
122        T::check_batch(&**self, ctx, batch)
123    }
124
125    fn finalize(&self, new_storage_root: Hash) {
126        T::finalize(&**self, new_storage_root)
127    }
128
129    fn set_abort_batch_flag(&mut self, abort_batch: Arc<AtomicBool>) {
130        T::set_abort_batch_flag(&mut **self, abort_batch)
131    }
132
133    fn query(&self, ctx: Context, method: &str, args: Vec<u8>) -> Result<Vec<u8>, RuntimeError> {
134        T::query(&**self, ctx, method, args)
135    }
136}
137
138impl<T: Dispatcher + ?Sized> Dispatcher for Arc<T> {
139    fn is_supported(&self) -> bool {
140        T::is_supported(&**self)
141    }
142
143    fn execute_batch(
144        &self,
145        ctx: Context,
146        batch: &TxnBatch,
147        in_msgs: &[roothash::IncomingMessage],
148    ) -> Result<ExecuteBatchResult, RuntimeError> {
149        T::execute_batch(&**self, ctx, batch, in_msgs)
150    }
151
152    fn schedule_and_execute_batch(
153        &self,
154        ctx: Context,
155        initial_batch: &mut TxnBatch,
156        in_msgs: &[roothash::IncomingMessage],
157    ) -> Result<ExecuteBatchResult, RuntimeError> {
158        T::schedule_and_execute_batch(&**self, ctx, initial_batch, in_msgs)
159    }
160
161    fn check_batch(
162        &self,
163        ctx: Context,
164        batch: &TxnBatch,
165    ) -> Result<Vec<CheckTxResult>, RuntimeError> {
166        T::check_batch(&**self, ctx, batch)
167    }
168
169    fn finalize(&self, new_storage_root: Hash) {
170        T::finalize(&**self, new_storage_root)
171    }
172
173    fn set_abort_batch_flag(&mut self, _abort_batch: Arc<AtomicBool>) {
174        unimplemented!()
175    }
176
177    fn query(&self, ctx: Context, method: &str, args: Vec<u8>) -> Result<Vec<u8>, RuntimeError> {
178        T::query(&**self, ctx, method, args)
179    }
180}
181
182/// Result of processing an ExecuteTx.
183pub struct ExecuteTxResult {
184    /// Transaction output.
185    pub output: Vec<u8>,
186    /// Emitted tags.
187    pub tags: Tags,
188}
189
190/// Result of processing a batch of ExecuteTx.
191pub struct ExecuteBatchResult {
192    /// Per-transaction execution results.
193    pub results: Vec<ExecuteTxResult>,
194    /// Emitted runtime messages.
195    pub messages: Vec<roothash::Message>,
196    /// Number of processed incoming messages.
197    pub in_msgs_count: usize,
198    /// Block emitted tags (not emitted by a specific transaction).
199    pub block_tags: Tags,
200    /// Hashes of transactions to reject.
201    ///
202    /// Note that these are only taken into account in schedule execution mode.
203    pub tx_reject_hashes: Vec<Hash>,
204}
205
206/// No-op dispatcher.
207///
208/// This is mainly used by the runtime dispatcher as a fallback in case
209/// the runtime's initializer doesn't produce its own dispatcher object.
210#[derive(Default)]
211pub struct NoopDispatcher;
212
213impl Dispatcher for NoopDispatcher {
214    fn is_supported(&self) -> bool {
215        false
216    }
217
218    fn execute_batch(
219        &self,
220        _ctx: Context,
221        _batch: &TxnBatch,
222        in_msgs: &[roothash::IncomingMessage],
223    ) -> Result<ExecuteBatchResult, RuntimeError> {
224        Ok(ExecuteBatchResult {
225            results: Vec::new(),
226            messages: Vec::new(),
227            block_tags: Tags::new(),
228            in_msgs_count: in_msgs.len(),
229            tx_reject_hashes: Vec::new(),
230        })
231    }
232
233    fn schedule_and_execute_batch(
234        &self,
235        _ctx: Context,
236        _initial_batch: &mut TxnBatch,
237        in_msgs: &[roothash::IncomingMessage],
238    ) -> Result<ExecuteBatchResult, RuntimeError> {
239        Ok(ExecuteBatchResult {
240            results: Vec::new(),
241            messages: Vec::new(),
242            block_tags: Tags::new(),
243            in_msgs_count: in_msgs.len(),
244            tx_reject_hashes: Vec::new(),
245        })
246    }
247
248    fn check_batch(
249        &self,
250        _ctx: Context,
251        _batch: &TxnBatch,
252    ) -> Result<Vec<CheckTxResult>, RuntimeError> {
253        Ok(Vec::new())
254    }
255}