1use std::{
8 collections::HashMap,
9 sync::{Arc, Mutex},
10};
11
12use linera_base::{data_types::Amount, ensure, identifiers::Account, 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 evm::inputs::{FAUCET_ADDRESS, FAUCET_BALANCE, ZERO_ADDRESS},
23 BaseRuntime, Batch, ContractRuntime, EvmExecutionError, ExecutionError, 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 caller: Address,
82 pub value: U256,
84 pub runtime: Arc<Mutex<Runtime>>,
86 pub changes: EvmState,
88 pub is_revm_instantiated: bool,
90 pub error: Arc<Mutex<Option<String>>>,
92}
93
94impl<Runtime> Clone for DatabaseRuntime<Runtime> {
95 fn clone(&self) -> Self {
96 Self {
97 storage_stats: self.storage_stats.clone(),
98 contract_address: self.contract_address,
99 caller: self.caller,
100 value: self.value,
101 runtime: self.runtime.clone(),
102 changes: self.changes.clone(),
103 is_revm_instantiated: self.is_revm_instantiated,
104 error: self.error.clone(),
105 }
106 }
107}
108
109#[repr(u8)]
110pub enum KeyCategory {
111 AccountInfo,
112 AccountState,
113 Storage,
114}
115
116impl<Runtime: BaseRuntime> DatabaseRuntime<Runtime> {
117 fn get_linera_key(key_prefix: &[u8], index: U256) -> Vec<u8> {
120 let mut key = key_prefix.to_vec();
121 key.extend(index.as_le_slice());
122 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 caller: Address::ZERO,
142 value: U256::ZERO,
143 runtime: Arc::new(Mutex::new(runtime)),
144 changes: HashMap::new(),
145 is_revm_instantiated: false,
146 error: Arc::new(Mutex::new(None)),
147 }
148 }
149
150 pub fn take_storage_stats(&self) -> StorageStats {
152 let mut storage_stats_read = self.storage_stats.lock().unwrap();
153 let storage_stats = storage_stats_read.clone();
154 *storage_stats_read = StorageStats::default();
155 storage_stats
156 }
157
158 pub fn insert_error(&self, exec_error: ExecutionError) {
160 let mut error = self.error.lock().unwrap();
161 *error = Some(format!("Runtime error {:?}", exec_error));
162 }
163
164 pub fn process_any_error(&self) -> Result<(), EvmExecutionError> {
166 let error = self.error.lock().unwrap();
167 if let Some(error) = error.clone() {
168 return Err(EvmExecutionError::RuntimeError(error.clone()));
169 }
170 Ok(())
171 }
172}
173
174impl DBErrorMarker for ExecutionError {}
175
176impl<Runtime> Database for DatabaseRuntime<Runtime>
177where
178 Runtime: BaseRuntime,
179{
180 type Error = ExecutionError;
181
182 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, ExecutionError> {
183 self.basic_ref(address)
184 }
185
186 fn code_by_hash(&mut self, _code_hash: B256) -> Result<Bytecode, ExecutionError> {
187 panic!("Functionality code_by_hash not implemented");
188 }
189
190 fn storage(&mut self, address: Address, index: U256) -> Result<U256, ExecutionError> {
191 self.storage_ref(address, index)
192 }
193
194 fn block_hash(&mut self, number: u64) -> Result<B256, ExecutionError> {
195 <Self as DatabaseRef>::block_hash_ref(self, number)
196 }
197}
198
199impl<Runtime> DatabaseCommit for DatabaseRuntime<Runtime>
200where
201 Runtime: BaseRuntime,
202{
203 fn commit(&mut self, changes: EvmState) {
204 self.changes = changes;
205 }
206}
207
208impl<Runtime> DatabaseRef for DatabaseRuntime<Runtime>
209where
210 Runtime: BaseRuntime,
211{
212 type Error = ExecutionError;
213
214 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, ExecutionError> {
216 if address == FAUCET_ADDRESS {
217 return Ok(Some(AccountInfo {
218 balance: FAUCET_BALANCE,
219 ..AccountInfo::default()
220 }));
221 }
222 if !self.changes.is_empty() {
223 let account = self.changes.get(&address);
229 return Ok(account.map(|account| account.info.clone()));
230 }
231 let mut runtime = self.runtime.lock().unwrap();
232 let account_owner = address.into();
233 let balance = runtime.read_owner_balance(account_owner)?;
236
237 let balance: U256 = balance.into();
238 let key_info = Self::get_address_key(KeyCategory::AccountInfo as u8, address);
239 let promise = runtime.read_value_bytes_new(key_info)?;
240 let result = runtime.read_value_bytes_wait(&promise)?;
241 let mut account_info = match result {
242 None => AccountInfo::default(),
243 Some(bytes) => bcs::from_bytes(&bytes)?,
244 };
245 let start_balance = if self.caller == address {
257 balance + self.value
258 } else if self.contract_address == address {
259 assert!(
260 balance >= self.value,
261 "We should have balance >= self.value"
262 );
263 balance - self.value
264 } else {
265 balance
266 };
267 account_info.balance = start_balance;
268 Ok(Some(account_info))
271 }
272
273 fn code_by_hash_ref(&self, _code_hash: B256) -> Result<Bytecode, ExecutionError> {
274 panic!("Functionality code_by_hash_ref not implemented");
275 }
276
277 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, ExecutionError> {
278 if !self.changes.is_empty() {
279 let account = self.changes.get(&address).unwrap();
280 return Ok(match account.storage.get(&index) {
281 None => U256::ZERO,
282 Some(slot) => slot.present_value(),
283 });
284 }
285 let key_prefix = Self::get_address_key(KeyCategory::Storage as u8, address);
286 let key = Self::get_linera_key(&key_prefix, index);
287 {
288 let mut storage_stats = self.storage_stats.lock().unwrap();
289 storage_stats.key_read += 1;
290 }
291 let result = {
292 let mut runtime = self.runtime.lock().unwrap();
293 let promise = runtime.read_value_bytes_new(key)?;
294 runtime.read_value_bytes_wait(&promise)
295 }?;
296 Ok(from_bytes_option::<U256>(&result)?.unwrap_or_default())
297 }
298
299 fn block_hash_ref(&self, number: u64) -> Result<B256, ExecutionError> {
300 Ok(keccak256(number.to_string().as_bytes()))
301 }
302}
303
304impl<Runtime> DatabaseRuntime<Runtime>
305where
306 Runtime: ContractRuntime,
307{
308 pub fn commit_changes(&mut self) -> Result<(), ExecutionError> {
310 let mut storage_stats = self.storage_stats.lock().unwrap();
311 let mut runtime = self.runtime.lock().unwrap();
312 let mut batch = Batch::new();
313 for (address, account) in &self.changes {
314 if address == &FAUCET_ADDRESS {
315 continue;
317 }
318 let owner = (*address).into();
319 let linera_balance: U256 = runtime.read_owner_balance(owner)?.into();
320 let revm_balance = account.info.balance;
321 ensure!(
322 linera_balance == revm_balance,
323 EvmExecutionError::IncoherentBalances(*address, linera_balance, revm_balance)
324 );
325 if !account.is_touched() {
326 continue;
327 }
328 let key_prefix = Self::get_address_key(KeyCategory::Storage as u8, *address);
329 let key_info = Self::get_address_key(KeyCategory::AccountInfo as u8, *address);
330 let key_state = Self::get_address_key(KeyCategory::AccountState as u8, *address);
331 if account.is_selfdestructed() {
332 batch.delete_key_prefix(key_prefix);
333 batch.put_key_value(key_info, &AccountInfo::default())?;
334 batch.put_key_value(key_state, &AccountState::NotExisting)?;
335 } else {
336 let is_newly_created = account.is_created();
337 batch.put_key_value(key_info, &account.info)?;
339 let account_state = if is_newly_created {
340 batch.delete_key_prefix(key_prefix.clone());
341 AccountState::StorageCleared
342 } else {
343 let promise = runtime.read_value_bytes_new(key_state.clone())?;
344 let result = runtime.read_value_bytes_wait(&promise)?;
345 let account_state =
346 from_bytes_option::<AccountState>(&result)?.unwrap_or_default();
347 if account_state.is_storage_cleared() {
348 AccountState::StorageCleared
349 } else {
350 AccountState::Touched
351 }
352 };
353 batch.put_key_value(key_state, &account_state)?;
354 for (index, value) in &account.storage {
355 if value.present_value() == value.original_value() {
356 storage_stats.key_no_operation += 1;
357 } else {
358 let key = Self::get_linera_key(&key_prefix, *index);
359 if value.original_value() == U256::ZERO {
360 batch.put_key_value(key, &value.present_value())?;
361 storage_stats.key_set += 1;
362 } else if value.present_value() == U256::ZERO {
363 batch.delete_key(key);
364 storage_stats.key_release += 1;
365 } else {
366 batch.put_key_value(key, &value.present_value())?;
367 storage_stats.key_reset += 1;
368 }
369 }
370 }
371 }
372 }
373 runtime.write_batch(batch)?;
374 self.changes.clear();
375 Ok(())
376 }
377}
378
379impl<Runtime> DatabaseRuntime<Runtime>
380where
381 Runtime: BaseRuntime,
382{
383 pub fn get_nonce(&self, address: &Address) -> Result<u64, ExecutionError> {
385 let account_info: Option<AccountInfo> = self.basic_ref(*address)?;
386 Ok(match account_info {
387 None => 0,
388 Some(account_info) => account_info.nonce,
389 })
390 }
391
392 pub fn get_deployed_bytecode(&self) -> Result<Vec<u8>, ExecutionError> {
393 let account_info = self.basic_ref(self.contract_address)?;
394 Ok(match account_info {
395 None => Vec::new(),
396 Some(account_info) => {
397 let bytecode = account_info
398 .code
399 .ok_or(EvmExecutionError::MissingBytecode)?;
400 bytecode.bytes_ref().to_vec()
401 }
402 })
403 }
404
405 pub fn set_contract_address(&mut self) -> Result<(), ExecutionError> {
408 let mut runtime = self.runtime.lock().unwrap();
409 let application_id = runtime.application_id()?;
410 self.contract_address = application_id.evm_address();
411 Ok(())
412 }
413
414 pub fn set_is_initialized(&mut self) -> Result<bool, ExecutionError> {
421 let mut runtime = self.runtime.lock().unwrap();
422 let evm_address = runtime.application_id()?.evm_address();
423 let key_info = Self::get_address_key(KeyCategory::AccountInfo as u8, evm_address);
424 let promise = runtime.contains_key_new(key_info)?;
425 let result = runtime.contains_key_wait(&promise)?;
426 self.is_revm_instantiated = result;
427 Ok(result)
428 }
429
430 pub fn get_block_env(&self) -> Result<BlockEnv, ExecutionError> {
431 let mut runtime = self.runtime.lock().unwrap();
432 let block_height_linera = runtime.block_height()?;
434 let block_height_evm = block_height_linera.0;
435 let beneficiary = address!("00000000000000000000000000000000000000bb");
437 let difficulty = U256::ZERO;
439 let gas_limit = u64::MAX;
442 let timestamp_linera = runtime.read_system_timestamp()?;
446 let timestamp_evm = timestamp_linera.micros() / 1_000_000;
447 let basefee = 0;
450 let chain_id = runtime.chain_id()?;
451 let entry = format!("{}{}", chain_id, block_height_linera);
452 let prevrandao = keccak256(entry.as_bytes());
454 let entry = BlobExcessGasAndPrice {
457 excess_blob_gas: 0,
458 blob_gasprice: 1,
459 };
460 let blob_excess_gas_and_price = Some(entry);
461 Ok(BlockEnv {
462 number: block_height_evm,
463 beneficiary,
464 difficulty,
465 gas_limit,
466 timestamp: timestamp_evm,
467 basefee,
468 prevrandao: Some(prevrandao),
469 blob_excess_gas_and_price,
470 })
471 }
472
473 pub fn constructor_argument(&self) -> Result<Vec<u8>, ExecutionError> {
474 let mut runtime = self.runtime.lock().unwrap();
475 let constructor_argument = runtime.application_parameters()?;
476 Ok(serde_json::from_slice::<Vec<u8>>(&constructor_argument)?)
477 }
478}
479
480impl<Runtime> DatabaseRuntime<Runtime>
481where
482 Runtime: ContractRuntime,
483{
484 pub fn get_contract_block_env(&self) -> Result<BlockEnv, ExecutionError> {
485 let mut block_env = self.get_block_env()?;
486 let mut runtime = self.runtime.lock().unwrap();
487 let gas_limit = runtime.maximum_fuel_per_block(VmRuntime::Evm)?;
489 block_env.gas_limit = gas_limit;
490 Ok(block_env)
491 }
492
493 pub fn deposit_funds(&self) -> Result<(), ExecutionError> {
494 if self.value != U256::ZERO {
495 if self.caller == ZERO_ADDRESS {
496 let error = EvmExecutionError::UnknownSigner;
497 return Err(error.into());
498 }
499 let source = self.caller.into();
500 let amount = Amount::try_from(self.value).map_err(EvmExecutionError::from)?;
501 let mut runtime = self.runtime.lock().expect("The lock should be possible");
502 let chain_id = runtime.chain_id()?;
503 let application_id = runtime.application_id()?;
504 let owner = application_id.into();
505 let destination = Account { chain_id, owner };
506 let authenticated_caller = runtime.authenticated_caller_id()?;
507 if authenticated_caller.is_none() {
508 runtime.transfer(source, destination, amount)?;
509 }
510 }
511 Ok(())
512 }
513}
514
515impl<Runtime> DatabaseRuntime<Runtime>
516where
517 Runtime: ServiceRuntime,
518{
519 pub fn get_service_block_env(&self) -> Result<BlockEnv, ExecutionError> {
520 let mut block_env = self.get_block_env()?;
521 block_env.gas_limit = EVM_SERVICE_GAS_LIMIT;
522 Ok(block_env)
523 }
524}