1use super::{
2 ExecutableTransaction,
3 InitialBalances,
4 Interpreter,
5 Memory,
6 RuntimeBalances,
7};
8use crate::{
9 checked_transaction::{
10 IntoChecked,
11 Ready,
12 },
13 consts::*,
14 context::Context,
15 error::{
16 Bug,
17 BugVariant,
18 InterpreterError,
19 },
20 interpreter::CheckedMetadata,
21 prelude::RuntimeError,
22 storage::InterpreterStorage,
23};
24use fuel_asm::RegId;
25use fuel_tx::{
26 Input,
27 Output,
28 field::{
29 Owner,
30 Script,
31 ScriptGasLimit,
32 },
33};
34use fuel_types::{
35 Address,
36 Word,
37};
38
39impl<M, S, Tx, Ecal, V> Interpreter<M, S, Tx, Ecal, V>
40where
41 M: Memory,
42 Tx: ExecutableTransaction,
43 S: InterpreterStorage,
44{
45 fn init_inner(
47 &mut self,
48 mut tx: Tx,
49 initial_balances: InitialBalances,
50 runtime_balances: RuntimeBalances,
51 gas_limit: Word,
52 ) -> Result<(), RuntimeError<S::DataError>> {
53 tx.prepare_sign();
54 self.tx = tx;
55 self.input_contracts = self
56 .tx
57 .inputs()
58 .iter()
59 .filter_map(|i| match i {
60 Input::Contract(contract) => Some(contract.contract_id),
61 _ => None,
62 })
63 .collect();
64
65 let mut owner: Option<(usize, Address)> = None;
66
67 if let Some(owner_index) = self.tx.owner() {
69 let owner_index = u32::try_from(owner_index).map_err(|_| {
72 RuntimeError::Bug(Bug::new(BugVariant::TransactionOwnerIndexOutOfBounds))
73 })? as usize;
74
75 if owner_index >= self.tx.inputs().len() {
76 return Err(Bug::new(BugVariant::TransactionOwnerIndexOutOfBounds).into());
77 }
78
79 let input = &self.tx.inputs()[owner_index];
80 if let Some(input_owner) = input.input_owner() {
81 owner = Some((owner_index, *input_owner));
82 } else {
83 return Err(Bug::new(BugVariant::TransactionOwnerInputHasNoOwner {
84 index: owner_index,
85 })
86 .into());
87 }
88 } else {
89 for (idx, input) in self.tx.inputs().iter().enumerate() {
91 if let Some(input_owner) = input.input_owner() {
92 match owner {
93 None => {
94 owner = Some((idx, *input_owner));
95 }
96 Some((_, cached_owner)) => {
97 if *input_owner != cached_owner {
98 owner = None;
99 break;
100 }
101 }
102 }
103 }
104 }
105 }
106
107 let owner = owner.and_then(|(idx, _)| {
108 let tx_offset = self.tx_offset() as Word;
109 let owner_offset = self
110 .tx
111 .inputs()
112 .get(idx)
113 .map(Input::repr)
114 .and_then(|r| r.owner_offset())
115 .and_then(|ofs| {
116 self.tx.inputs_offset_at(idx).map(|o| o.saturating_add(ofs))
117 })?;
118
119 let owner_ptr = tx_offset.saturating_add(owner_offset as Word);
120
121 Some(owner_ptr)
122 });
123
124 self.owner_ptr = owner;
125
126 self.input_contracts_index_to_output_index = self
127 .tx
128 .outputs()
129 .iter()
130 .enumerate()
131 .filter_map(|(output_idx, o)| match o {
132 Output::Contract(fuel_tx::output::contract::Contract {
133 input_index,
134 ..
135 }) => Some((
136 *input_index,
137 u16::try_from(output_idx)
138 .expect("The maximum number of outputs is `u16::MAX`"),
139 )),
140 _ => None,
141 })
142 .collect();
143
144 self.initial_balances = initial_balances.clone();
145
146 self.frames.clear();
147 self.receipts.clear();
148 self.memory_mut().reset();
149
150 self.registers.iter_mut().for_each(|r| *r = 0);
152
153 self.registers[RegId::ONE] = 1;
154
155 self.registers[RegId::HP] = VM_MAX_RAM;
157
158 macro_rules! push_stack {
160 ($v:expr) => {{
161 let data = $v;
162 let old_ssp = self.registers[RegId::SSP];
163 let new_ssp = old_ssp
164 .checked_add(data.len() as Word)
165 .expect("VM initialization data must fit into the stack");
166 self.memory_mut().grow_stack(new_ssp)?;
167 self.registers[RegId::SSP] = new_ssp;
168 self.memory_mut()
169 .write_noownerchecks(old_ssp, data.len())
170 .expect("VM initialization data must fit into the stack")
171 .copy_from_slice(data);
172 }};
173 }
174
175 push_stack!(&*self.transaction().id(&self.chain_id()));
176
177 let base_asset_id = self.interpreter_params.base_asset_id;
178 push_stack!(&*base_asset_id);
179
180 runtime_balances.to_vm(self);
181
182 let tx_size = self.transaction().size() as Word;
183 self.set_gas(gas_limit);
184
185 push_stack!(&tx_size.to_be_bytes());
186
187 let tx_bytes = self.tx.to_bytes();
188 push_stack!(tx_bytes.as_slice());
189
190 self.registers[RegId::SP] = self.registers[RegId::SSP];
191
192 Ok(())
193 }
194}
195
196impl<M, S, Tx, Ecal, V> Interpreter<M, S, Tx, Ecal, V>
197where
198 M: Memory,
199 Tx: ExecutableTransaction,
200 S: InterpreterStorage,
201{
202 pub fn init_predicate(
204 &mut self,
205 context: Context,
206 tx: Tx,
207 gas_limit: Word,
208 ) -> Result<(), InterpreterError<S::DataError>> {
209 self.context = context;
210 let initial_balances: InitialBalances = Default::default();
211 let runtime_balances = initial_balances.clone().try_into()?;
212
213 let range = self
214 .context
215 .predicate()
216 .expect("The context is not predicate")
217 .program()
218 .words();
219
220 self.init_inner(tx, initial_balances, runtime_balances, gas_limit)?;
221 self.registers[RegId::PC] = range.start as fuel_asm::Word;
222 self.registers[RegId::IS] = range.start as fuel_asm::Word;
223
224 Ok(())
225 }
226}
227
228impl<M, S, Tx, Ecal, V> Interpreter<M, S, Tx, Ecal, V>
229where
230 M: Memory,
231 S: InterpreterStorage,
232 <S as InterpreterStorage>::DataError: From<S::DataError>,
233 Tx: ExecutableTransaction,
234 <Tx as IntoChecked>::Metadata: CheckedMetadata,
235{
236 pub fn init_script(
241 &mut self,
242 ready_tx: Ready<Tx>,
243 ) -> Result<(), InterpreterError<S::DataError>> {
244 let block_height = self.storage.block_height().map_err(RuntimeError::Storage)?;
245
246 self.context = Context::Script { block_height };
247
248 let (_, checked) = ready_tx.decompose();
249 let (tx, metadata): (Tx, Tx::Metadata) = checked.into();
250
251 let gas_limit = tx
252 .as_script()
253 .map(|script| *script.script_gas_limit())
254 .unwrap_or_default();
255
256 let initial_balances = metadata.balances();
257 let runtime_balances = initial_balances.try_into()?;
258 self.init_inner(tx, metadata.balances(), runtime_balances, gas_limit)?;
259
260 if let Some(script) = self.transaction().as_script() {
261 let offset = self.tx_offset().saturating_add(script.script_offset()) as Word;
262
263 debug_assert!(offset < VM_MAX_RAM);
264
265 self.registers[RegId::PC] = offset;
266 self.registers[RegId::IS] = offset;
267 }
268
269 Ok(())
270 }
271}