1use std::{
8 collections::HashMap,
9 sync::{Arc, Mutex},
10};
11
12use linera_base::vm::VmRuntime;
13use linera_views::common::from_bytes_option;
14use revm::{primitives::keccak256, Database, DatabaseCommit, DatabaseRef};
15use revm_context::BlockEnv;
16use revm_context_interface::block::BlobExcessGasAndPrice;
17use revm_database::{AccountState, DBErrorMarker};
18use revm_primitives::{address, Address, B256, U256};
19use revm_state::{AccountInfo, Bytecode, EvmState};
20
21use crate::{
22 ApplicationId, BaseRuntime, Batch, ContractRuntime, EvmExecutionError, ExecutionError,
23 ServiceRuntime,
24};
25
26pub const EVM_SERVICE_GAS_LIMIT: u64 = 20_000_000;
31
32const SLOAD_COST: u64 = 2100;
34
35const SSTORE_COST_SET: u64 = 20000;
37
38const SSTORE_COST_NO_OPERATION: u64 = 100;
40
41const SSTORE_COST_RESET: u64 = 2900;
43
44const SSTORE_REFUND_RELEASE: u64 = 4800;
46
47#[derive(Clone, Default)]
50pub(crate) struct StorageStats {
51 key_no_operation: u64,
52 key_reset: u64,
53 key_set: u64,
54 key_release: u64,
55 key_read: u64,
56}
57
58impl StorageStats {
59 pub fn storage_costs(&self) -> u64 {
60 let mut storage_costs = 0;
61 storage_costs += self.key_no_operation * SSTORE_COST_NO_OPERATION;
62 storage_costs += self.key_reset * SSTORE_COST_RESET;
63 storage_costs += self.key_set * SSTORE_COST_SET;
64 storage_costs += self.key_read * SLOAD_COST;
65 storage_costs
66 }
67
68 pub fn storage_refund(&self) -> u64 {
69 self.key_release * SSTORE_REFUND_RELEASE
70 }
71}
72
73pub(crate) struct DatabaseRuntime<Runtime> {
75 storage_stats: Arc<Mutex<StorageStats>>,
77 pub contract_address: Address,
80 pub runtime: Arc<Mutex<Runtime>>,
82 pub changes: EvmState,
84 pub is_revm_instantiated: bool,
86 pub error: Arc<Mutex<Option<String>>>,
88}
89
90impl<Runtime> Clone for DatabaseRuntime<Runtime> {
91 fn clone(&self) -> Self {
92 Self {
93 storage_stats: self.storage_stats.clone(),
94 contract_address: self.contract_address,
95 runtime: self.runtime.clone(),
96 changes: self.changes.clone(),
97 is_revm_instantiated: self.is_revm_instantiated,
98 error: self.error.clone(),
99 }
100 }
101}
102
103#[repr(u8)]
104pub enum KeyCategory {
105 AccountInfo,
106 AccountState,
107 Storage,
108}
109
110fn application_id_to_address(application_id: ApplicationId) -> Address {
111 let application_id: [u64; 4] = <[u64; 4]>::from(application_id.application_description_hash);
112 let application_id: [u8; 32] = linera_base::crypto::u64_array_to_be_bytes(application_id);
113 Address::from_slice(&application_id[0..20])
114}
115
116impl<Runtime: BaseRuntime> DatabaseRuntime<Runtime> {
117 fn get_linera_key(key_prefix: &[u8], index: U256) -> Result<Vec<u8>, ExecutionError> {
120 let mut key = key_prefix.to_vec();
121 bcs::serialize_into(&mut key, &index)?;
122 Ok(key)
123 }
124
125 fn get_address_key(prefix: u8, address: Address) -> Vec<u8> {
127 let mut key = vec![prefix];
128 key.extend(address);
129 key
130 }
131
132 pub fn new(runtime: Runtime) -> Self {
134 let storage_stats = StorageStats::default();
135 Self {
139 storage_stats: Arc::new(Mutex::new(storage_stats)),
140 contract_address: Address::ZERO,
141 runtime: Arc::new(Mutex::new(runtime)),
142 changes: HashMap::new(),
143 is_revm_instantiated: false,
144 error: Arc::new(Mutex::new(None)),
145 }
146 }
147
148 pub fn take_storage_stats(&self) -> StorageStats {
150 let mut storage_stats_read = self.storage_stats.lock().unwrap();
151 let storage_stats = storage_stats_read.clone();
152 *storage_stats_read = StorageStats::default();
153 storage_stats
154 }
155
156 pub fn insert_error(&self, exec_error: ExecutionError) {
158 let mut error = self.error.lock().unwrap();
159 *error = Some(format!("Runtime error {:?}", exec_error));
160 }
161
162 pub fn process_any_error(&self) -> Result<(), EvmExecutionError> {
164 let error = self.error.lock().unwrap();
165 if let Some(error) = error.clone() {
166 return Err(EvmExecutionError::RuntimeError(error.clone()));
167 }
168 Ok(())
169 }
170}
171
172impl DBErrorMarker for ExecutionError {}
173
174impl<Runtime> Database for DatabaseRuntime<Runtime>
175where
176 Runtime: BaseRuntime,
177{
178 type Error = ExecutionError;
179
180 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, ExecutionError> {
181 self.basic_ref(address)
182 }
183
184 fn code_by_hash(&mut self, _code_hash: B256) -> Result<Bytecode, ExecutionError> {
185 panic!("Functionality code_by_hash not implemented");
186 }
187
188 fn storage(&mut self, address: Address, index: U256) -> Result<U256, ExecutionError> {
189 self.storage_ref(address, index)
190 }
191
192 fn block_hash(&mut self, number: u64) -> Result<B256, ExecutionError> {
193 <Self as DatabaseRef>::block_hash_ref(self, number)
194 }
195}
196
197impl<Runtime> DatabaseCommit for DatabaseRuntime<Runtime>
198where
199 Runtime: BaseRuntime,
200{
201 fn commit(&mut self, changes: EvmState) {
202 self.changes = changes;
203 }
204}
205
206impl<Runtime> DatabaseRef for DatabaseRuntime<Runtime>
207where
208 Runtime: BaseRuntime,
209{
210 type Error = ExecutionError;
211
212 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, ExecutionError> {
213 if !self.changes.is_empty() {
214 let account = self.changes.get(&address).unwrap();
215 return Ok(Some(account.info.clone()));
216 }
217 let mut runtime = self.runtime.lock().unwrap();
218 let key_info = Self::get_address_key(KeyCategory::AccountInfo as u8, address);
219 let promise = runtime.read_value_bytes_new(key_info)?;
220 let result = runtime.read_value_bytes_wait(&promise)?;
221 let account_info = from_bytes_option::<AccountInfo>(&result)?;
222 Ok(account_info)
223 }
224
225 fn code_by_hash_ref(&self, _code_hash: B256) -> Result<Bytecode, ExecutionError> {
226 panic!("Functionality code_by_hash_ref not implemented");
227 }
228
229 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, ExecutionError> {
230 if !self.changes.is_empty() {
231 let account = self.changes.get(&address).unwrap();
232 return Ok(match account.storage.get(&index) {
233 None => U256::ZERO,
234 Some(slot) => slot.present_value(),
235 });
236 }
237 let key_prefix = Self::get_address_key(KeyCategory::Storage as u8, address);
238 let key = Self::get_linera_key(&key_prefix, index)?;
239 {
240 let mut storage_stats = self.storage_stats.lock().unwrap();
241 storage_stats.key_read += 1;
242 }
243 let result = {
244 let mut runtime = self.runtime.lock().unwrap();
245 let promise = runtime.read_value_bytes_new(key)?;
246 runtime.read_value_bytes_wait(&promise)
247 }?;
248 Ok(from_bytes_option::<U256>(&result)?.unwrap_or_default())
249 }
250
251 fn block_hash_ref(&self, number: u64) -> Result<B256, ExecutionError> {
252 Ok(keccak256(number.to_string().as_bytes()))
253 }
254}
255
256impl<Runtime> DatabaseRuntime<Runtime>
257where
258 Runtime: ContractRuntime,
259{
260 pub fn commit_changes(&mut self) -> Result<(), ExecutionError> {
262 let mut storage_stats = self.storage_stats.lock().unwrap();
263 let mut runtime = self.runtime.lock().unwrap();
264 let mut batch = Batch::new();
265 for (address, account) in &self.changes {
266 if !account.is_touched() {
267 continue;
268 }
269 let key_prefix = Self::get_address_key(KeyCategory::Storage as u8, *address);
270 let key_info = Self::get_address_key(KeyCategory::AccountInfo as u8, *address);
271 let key_state = Self::get_address_key(KeyCategory::AccountState as u8, *address);
272 if account.is_selfdestructed() {
273 batch.delete_key_prefix(key_prefix);
274 batch.put_key_value(key_info, &AccountInfo::default())?;
275 batch.put_key_value(key_state, &AccountState::NotExisting)?;
276 } else {
277 let is_newly_created = account.is_created();
278 batch.put_key_value(key_info, &account.info)?;
279 let account_state = if is_newly_created {
280 batch.delete_key_prefix(key_prefix.clone());
281 AccountState::StorageCleared
282 } else {
283 let promise = runtime.read_value_bytes_new(key_state.clone())?;
284 let result = runtime.read_value_bytes_wait(&promise)?;
285 let account_state =
286 from_bytes_option::<AccountState>(&result)?.unwrap_or_default();
287 if account_state.is_storage_cleared() {
288 AccountState::StorageCleared
289 } else {
290 AccountState::Touched
291 }
292 };
293 batch.put_key_value(key_state, &account_state)?;
294 for (index, value) in &account.storage {
295 if value.present_value() == value.original_value() {
296 storage_stats.key_no_operation += 1;
297 } else {
298 let key = Self::get_linera_key(&key_prefix, *index)?;
299 if value.original_value() == U256::ZERO {
300 batch.put_key_value(key, &value.present_value())?;
301 storage_stats.key_set += 1;
302 } else if value.present_value() == U256::ZERO {
303 batch.delete_key(key);
304 storage_stats.key_release += 1;
305 } else {
306 batch.put_key_value(key, &value.present_value())?;
307 storage_stats.key_reset += 1;
308 }
309 }
310 }
311 }
312 }
313 runtime.write_batch(batch)?;
314 self.changes.clear();
315 Ok(())
316 }
317}
318
319impl<Runtime> DatabaseRuntime<Runtime>
320where
321 Runtime: BaseRuntime,
322{
323 pub fn get_nonce(&self, address: &Address) -> Result<u64, ExecutionError> {
325 let account_info: Option<AccountInfo> = self.basic_ref(*address)?;
326 Ok(match account_info {
327 None => 0,
328 Some(account_info) => account_info.nonce,
329 })
330 }
331
332 pub fn get_deployed_bytecode(&self) -> Result<Vec<u8>, ExecutionError> {
333 let account_info = self.basic_ref(self.contract_address)?;
334 Ok(match account_info {
335 None => Vec::new(),
336 Some(account_info) => {
337 let bytecode = account_info
338 .code
339 .ok_or(EvmExecutionError::MissingBytecode)?;
340 bytecode.bytes_ref().to_vec()
341 }
342 })
343 }
344
345 pub fn set_contract_address(&mut self) -> Result<(), ExecutionError> {
348 let mut runtime = self.runtime.lock().unwrap();
349 let application_id = runtime.application_id()?;
350 self.contract_address = application_id_to_address(application_id);
351 Ok(())
352 }
353
354 pub fn set_is_initialized(&mut self) -> Result<bool, ExecutionError> {
361 let mut runtime = self.runtime.lock().unwrap();
362 let evm_address = runtime.application_id()?.evm_address();
363 let key_info = Self::get_address_key(KeyCategory::AccountInfo as u8, evm_address);
364 let promise = runtime.contains_key_new(key_info)?;
365 let result = runtime.contains_key_wait(&promise)?;
366 self.is_revm_instantiated = result;
367 Ok(result)
368 }
369
370 pub fn get_block_env(&self) -> Result<BlockEnv, ExecutionError> {
371 let mut runtime = self.runtime.lock().unwrap();
372 let block_height_linera = runtime.block_height()?;
374 let block_height_evm = block_height_linera.0;
375 let beneficiary = address!("00000000000000000000000000000000000000bb");
377 let difficulty = U256::ZERO;
379 let gas_limit = u64::MAX;
382 let timestamp_linera = runtime.read_system_timestamp()?;
386 let timestamp_evm = timestamp_linera.micros() / 1_000_000;
387 let basefee = 0;
390 let chain_id = runtime.chain_id()?;
391 let entry = format!("{}{}", chain_id, block_height_linera);
392 let prevrandao = keccak256(entry.as_bytes());
394 let entry = BlobExcessGasAndPrice {
397 excess_blob_gas: 0,
398 blob_gasprice: 1,
399 };
400 let blob_excess_gas_and_price = Some(entry);
401 Ok(BlockEnv {
402 number: block_height_evm,
403 beneficiary,
404 difficulty,
405 gas_limit,
406 timestamp: timestamp_evm,
407 basefee,
408 prevrandao: Some(prevrandao),
409 blob_excess_gas_and_price,
410 })
411 }
412
413 pub fn constructor_argument(&self) -> Result<Vec<u8>, ExecutionError> {
414 let mut runtime = self.runtime.lock().unwrap();
415 let constructor_argument = runtime.application_parameters()?;
416 Ok(serde_json::from_slice::<Vec<u8>>(&constructor_argument)?)
417 }
418}
419
420impl<Runtime> DatabaseRuntime<Runtime>
421where
422 Runtime: ContractRuntime,
423{
424 pub fn get_contract_block_env(&self) -> Result<BlockEnv, ExecutionError> {
425 let mut block_env = self.get_block_env()?;
426 let mut runtime = self.runtime.lock().unwrap();
427 let gas_limit = runtime.maximum_fuel_per_block(VmRuntime::Evm)?;
429 block_env.gas_limit = gas_limit;
430 Ok(block_env)
431 }
432}
433
434impl<Runtime> DatabaseRuntime<Runtime>
435where
436 Runtime: ServiceRuntime,
437{
438 pub fn get_service_block_env(&self) -> Result<BlockEnv, ExecutionError> {
439 let mut block_env = self.get_block_env()?;
440 block_env.gas_limit = EVM_SERVICE_GAS_LIMIT;
441 Ok(block_env)
442 }
443}