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::{ApplicationId, BaseRuntime, Batch, ContractRuntime, ExecutionError, ServiceRuntime};
22
23pub const EVM_SERVICE_GAS_LIMIT: u64 = 20_000_000;
28
29const SLOAD_COST: u64 = 2100;
31
32const SSTORE_COST_SET: u64 = 20000;
34
35const SSTORE_COST_NO_OPERATION: u64 = 100;
37
38const SSTORE_COST_RESET: u64 = 2900;
40
41const SSTORE_REFUND_RELEASE: u64 = 4800;
43
44#[derive(Clone, Default)]
47pub(crate) struct StorageStats {
48 key_no_operation: u64,
49 key_reset: u64,
50 key_set: u64,
51 key_release: u64,
52 key_read: u64,
53}
54
55impl StorageStats {
56 pub fn storage_costs(&self) -> u64 {
57 let mut storage_costs = 0;
58 storage_costs += self.key_no_operation * SSTORE_COST_NO_OPERATION;
59 storage_costs += self.key_reset * SSTORE_COST_RESET;
60 storage_costs += self.key_set * SSTORE_COST_SET;
61 storage_costs += self.key_read * SLOAD_COST;
62 storage_costs
63 }
64
65 pub fn storage_refund(&self) -> u64 {
66 self.key_release * SSTORE_REFUND_RELEASE
67 }
68}
69
70pub(crate) struct DatabaseRuntime<Runtime> {
72 storage_stats: Arc<Mutex<StorageStats>>,
74 pub contract_address: Address,
77 pub runtime: Arc<Mutex<Runtime>>,
79 pub changes: EvmState,
81}
82
83impl<Runtime> Clone for DatabaseRuntime<Runtime> {
84 fn clone(&self) -> Self {
85 Self {
86 storage_stats: self.storage_stats.clone(),
87 contract_address: self.contract_address,
88 runtime: self.runtime.clone(),
89 changes: self.changes.clone(),
90 }
91 }
92}
93
94#[repr(u8)]
95enum KeyTag {
96 NullAddress,
98 ContractAddress,
100}
101
102#[repr(u8)]
103pub enum KeyCategory {
104 AccountInfo,
105 AccountState,
106 Storage,
107}
108
109fn application_id_to_address(application_id: ApplicationId) -> Address {
110 let application_id: [u64; 4] = <[u64; 4]>::from(application_id.application_description_hash);
111 let application_id: [u8; 32] = linera_base::crypto::u64_array_to_be_bytes(application_id);
112 Address::from_slice(&application_id[0..20])
113}
114
115impl<Runtime: BaseRuntime> DatabaseRuntime<Runtime> {
116 fn get_linera_key(val: u8, index: U256) -> Result<Vec<u8>, ExecutionError> {
119 let mut key = vec![val, KeyCategory::Storage as u8];
120 bcs::serialize_into(&mut key, &index)?;
121 Ok(key)
122 }
123
124 fn get_contract_address_key(&self, address: &Address) -> Option<u8> {
126 if address == &Address::ZERO {
127 return Some(KeyTag::NullAddress as u8);
128 }
129 if address == &self.contract_address {
130 return Some(KeyTag::ContractAddress as u8);
131 }
132 None
133 }
134
135 pub fn new(runtime: Runtime) -> Self {
137 let storage_stats = StorageStats::default();
138 Self {
142 storage_stats: Arc::new(Mutex::new(storage_stats)),
143 contract_address: Address::ZERO,
144 runtime: Arc::new(Mutex::new(runtime)),
145 changes: HashMap::new(),
146 }
147 }
148
149 pub fn take_storage_stats(&self) -> StorageStats {
151 let mut storage_stats_read = self
152 .storage_stats
153 .lock()
154 .expect("The lock should be possible");
155 let storage_stats = storage_stats_read.clone();
156 *storage_stats_read = StorageStats::default();
157 storage_stats
158 }
159}
160
161impl DBErrorMarker for ExecutionError {}
162
163impl<Runtime> Database for DatabaseRuntime<Runtime>
164where
165 Runtime: BaseRuntime,
166{
167 type Error = ExecutionError;
168
169 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, ExecutionError> {
170 self.basic_ref(address)
171 }
172
173 fn code_by_hash(&mut self, _code_hash: B256) -> Result<Bytecode, ExecutionError> {
174 panic!("Functionality code_by_hash not implemented");
175 }
176
177 fn storage(&mut self, address: Address, index: U256) -> Result<U256, ExecutionError> {
178 self.storage_ref(address, index)
179 }
180
181 fn block_hash(&mut self, number: u64) -> Result<B256, ExecutionError> {
182 <Self as DatabaseRef>::block_hash_ref(self, number)
183 }
184}
185
186impl<Runtime> DatabaseCommit for DatabaseRuntime<Runtime>
187where
188 Runtime: BaseRuntime,
189{
190 fn commit(&mut self, changes: EvmState) {
191 self.changes = changes;
192 }
193}
194
195impl<Runtime> DatabaseRef for DatabaseRuntime<Runtime>
196where
197 Runtime: BaseRuntime,
198{
199 type Error = ExecutionError;
200
201 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, ExecutionError> {
202 if !self.changes.is_empty() {
203 let account = self.changes.get(&address).unwrap();
204 return Ok(Some(account.info.clone()));
205 }
206 let mut runtime = self.runtime.lock().expect("The lock should be possible");
207 let val = self.get_contract_address_key(&address);
208 let Some(val) = val else {
209 return Ok(Some(AccountInfo::default()));
210 };
211 let key_info = vec![val, KeyCategory::AccountInfo as u8];
212 let promise = runtime.read_value_bytes_new(key_info)?;
213 let result = runtime.read_value_bytes_wait(&promise)?;
214 let account_info = from_bytes_option::<AccountInfo>(&result)?;
215 Ok(account_info)
216 }
217
218 fn code_by_hash_ref(&self, _code_hash: B256) -> Result<Bytecode, ExecutionError> {
219 panic!("Functionality code_by_hash_ref not implemented");
220 }
221
222 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, ExecutionError> {
223 if !self.changes.is_empty() {
224 let account = self.changes.get(&address).unwrap();
225 return Ok(match account.storage.get(&index) {
226 None => U256::ZERO,
227 Some(slot) => slot.present_value(),
228 });
229 }
230 let val = self.get_contract_address_key(&address);
231 let Some(val) = val else {
232 panic!("There is no storage associated to externally owned account");
233 };
234 let key = Self::get_linera_key(val, index)?;
235 {
236 let mut storage_stats = self
237 .storage_stats
238 .lock()
239 .expect("The lock should be possible");
240 storage_stats.key_read += 1;
241 }
242 let result = {
243 let mut runtime = self.runtime.lock().expect("The lock should be possible");
244 let promise = runtime.read_value_bytes_new(key)?;
245 runtime.read_value_bytes_wait(&promise)
246 }?;
247 Ok(from_bytes_option::<U256>(&result)?.unwrap_or_default())
248 }
249
250 fn block_hash_ref(&self, number: u64) -> Result<B256, ExecutionError> {
251 Ok(keccak256(number.to_string().as_bytes()))
252 }
253}
254
255impl<Runtime> DatabaseRuntime<Runtime>
256where
257 Runtime: ContractRuntime,
258{
259 pub fn commit_changes(&mut self) -> Result<(), ExecutionError> {
261 let mut storage_stats = self
262 .storage_stats
263 .lock()
264 .expect("The lock should be possible");
265 let mut runtime = self.runtime.lock().expect("The lock should be possible");
266 let mut batch = Batch::new();
267 let mut list_new_balances = Vec::new();
268 for (address, account) in &self.changes {
269 if !account.is_touched() {
270 continue;
271 }
272 let val = self.get_contract_address_key(address);
273 if let Some(val) = val {
274 let key_prefix = vec![val, KeyCategory::Storage as u8];
275 let key_info = vec![val, KeyCategory::AccountInfo as u8];
276 let key_state = vec![val, KeyCategory::AccountState as u8];
277 if account.is_selfdestructed() {
278 batch.delete_key_prefix(key_prefix);
279 batch.put_key_value(key_info, &AccountInfo::default())?;
280 batch.put_key_value(key_state, &AccountState::NotExisting)?;
281 } else {
282 let is_newly_created = account.is_created();
283 batch.put_key_value(key_info, &account.info)?;
284
285 let account_state = if is_newly_created {
286 batch.delete_key_prefix(key_prefix);
287 AccountState::StorageCleared
288 } else {
289 let promise = runtime.read_value_bytes_new(key_state.clone())?;
290 let result = runtime.read_value_bytes_wait(&promise)?;
291 let account_state =
292 from_bytes_option::<AccountState>(&result)?.unwrap_or_default();
293 if account_state.is_storage_cleared() {
294 AccountState::StorageCleared
295 } else {
296 AccountState::Touched
297 }
298 };
299 batch.put_key_value(key_state, &account_state)?;
300 for (index, value) in &account.storage {
301 if value.present_value() == value.original_value() {
302 storage_stats.key_no_operation += 1;
303 } else {
304 let key = Self::get_linera_key(val, *index)?;
305 if value.original_value() == U256::ZERO {
306 batch.put_key_value(key, &value.present_value())?;
307 storage_stats.key_set += 1;
308 } else if value.present_value() == U256::ZERO {
309 batch.delete_key(key);
310 storage_stats.key_release += 1;
311 } else {
312 batch.put_key_value(key, &value.present_value())?;
313 storage_stats.key_reset += 1;
314 }
315 }
316 }
317 }
318 } else {
319 if !account.storage.is_empty() {
320 panic!("For user account, storage must be empty");
321 }
322 if account.info.balance != U256::ZERO {
326 let new_balance = (address, account.info.balance);
327 list_new_balances.push(new_balance);
328 }
329 }
330 }
331 runtime.write_batch(batch)?;
332 if !list_new_balances.is_empty() {
333 panic!("The conversion Ethereum address / Linera address is not yet implemented");
334 }
335 self.changes.clear();
336 Ok(())
337 }
338}
339
340impl<Runtime> DatabaseRuntime<Runtime>
341where
342 Runtime: BaseRuntime,
343{
344 pub fn get_nonce(&self, address: &Address) -> Result<u64, ExecutionError> {
346 let account_info = self.basic_ref(*address)?;
347 Ok(match account_info {
348 None => 0,
349 Some(account_info) => account_info.nonce,
350 })
351 }
352
353 pub fn set_contract_address(&mut self) -> Result<(), ExecutionError> {
356 let mut runtime = self.runtime.lock().expect("The lock should be possible");
357 let application_id = runtime.application_id()?;
358 self.contract_address = application_id_to_address(application_id);
359 Ok(())
360 }
361
362 pub fn is_initialized(&self) -> Result<bool, ExecutionError> {
365 let mut keys = Vec::new();
366 for key_tag in [KeyTag::NullAddress, KeyTag::ContractAddress] {
367 let key = vec![key_tag as u8, KeyCategory::AccountInfo as u8];
368 keys.push(key);
369 }
370 let mut runtime = self.runtime.lock().expect("The lock should be possible");
371 let promise = runtime.contains_keys_new(keys)?;
372 let result = runtime.contains_keys_wait(&promise)?;
373 Ok(result[0] && result[1])
374 }
375
376 pub fn get_block_env(&self) -> Result<BlockEnv, ExecutionError> {
377 let mut runtime = self.runtime.lock().expect("The lock should be possible");
378 let block_height_linera = runtime.block_height()?;
380 let block_height_evm = block_height_linera.0;
381 let beneficiary = address!("00000000000000000000000000000000000000bb");
383 let difficulty = U256::ZERO;
385 let gas_limit = u64::MAX;
388 let timestamp_linera = runtime.read_system_timestamp()?;
392 let timestamp_evm = timestamp_linera.micros() / 1_000_000;
393 let basefee = 0;
396 let chain_id = runtime.chain_id()?;
397 let entry = format!("{}{}", chain_id, block_height_linera);
398 let prevrandao = keccak256(entry.as_bytes());
400 let entry = BlobExcessGasAndPrice {
403 excess_blob_gas: 0,
404 blob_gasprice: 1,
405 };
406 let blob_excess_gas_and_price = Some(entry);
407 Ok(BlockEnv {
408 number: block_height_evm,
409 beneficiary,
410 difficulty,
411 gas_limit,
412 timestamp: timestamp_evm,
413 basefee,
414 prevrandao: Some(prevrandao),
415 blob_excess_gas_and_price,
416 })
417 }
418
419 pub fn constructor_argument(&self) -> Result<Vec<u8>, ExecutionError> {
420 let mut runtime = self.runtime.lock().expect("The lock should be possible");
421 let constructor_argument = runtime.application_parameters()?;
422 Ok(serde_json::from_slice::<Vec<u8>>(&constructor_argument)?)
423 }
424}
425
426impl<Runtime> DatabaseRuntime<Runtime>
427where
428 Runtime: ContractRuntime,
429{
430 pub fn get_contract_block_env(&self) -> Result<BlockEnv, ExecutionError> {
431 let mut block_env = self.get_block_env()?;
432 let mut runtime = self.runtime.lock().expect("The lock should be possible");
433 let gas_limit = runtime.maximum_fuel_per_block(VmRuntime::Evm)?;
435 block_env.gas_limit = gas_limit;
436 Ok(block_env)
437 }
438}
439
440impl<Runtime> DatabaseRuntime<Runtime>
441where
442 Runtime: ServiceRuntime,
443{
444 pub fn get_service_block_env(&self) -> Result<BlockEnv, ExecutionError> {
445 let mut block_env = self.get_block_env()?;
446 block_env.gas_limit = EVM_SERVICE_GAS_LIMIT;
447 Ok(block_env)
448 }
449}