1use std::{
8 collections::HashMap,
9 mem,
10 ops::DerefMut,
11 sync::{Arc, Mutex},
12};
13
14use linera_base::{
15 data_types::Amount,
16 ensure,
17 identifiers::{self, ApplicationId, ModuleId},
18 vm::{EvmInstantiation, EvmQuery, VmRuntime},
19};
20use linera_views::common::from_bytes_option;
21use revm::{primitives::keccak256, Database, DatabaseCommit, DatabaseRef};
22use revm_context::BlockEnv;
23use revm_context_interface::block::BlobExcessGasAndPrice;
24use revm_database::DBErrorMarker;
25use revm_primitives::{address, Address, B256, KECCAK_EMPTY, U256};
26use revm_state::{AccountInfo, Bytecode, EvmState};
27
28use crate::{
29 evm::{
30 inputs::{FAUCET_ADDRESS, FAUCET_BALANCE, ZERO_ADDRESS},
31 revm::{
32 address_to_user_application_id, ALREADY_CREATED_CONTRACT_SELECTOR,
33 COMMIT_CONTRACT_CHANGES_SELECTOR, GET_ACCOUNT_INFO_SELECTOR,
34 GET_CONTRACT_STORAGE_SELECTOR, JSON_EMPTY_VECTOR,
35 },
36 },
37 BaseRuntime, Batch, ContractRuntime, EvmExecutionError, ExecutionError, ServiceRuntime,
38};
39
40pub const EVM_SERVICE_GAS_LIMIT: u64 = 20_000_000;
45
46impl DBErrorMarker for ExecutionError {}
47
48pub(crate) struct InnerDatabase<Runtime> {
66 pub contract_address: Address,
71
72 pub caller: Address,
78
79 pub value: U256,
83
84 pub runtime: Arc<Mutex<Runtime>>,
89
90 pub changes: EvmState,
96
97 pub is_revm_instantiated: bool,
102
103 pub error: Arc<Mutex<Option<String>>>,
109}
110
111impl<Runtime> Clone for InnerDatabase<Runtime> {
112 fn clone(&self) -> Self {
113 Self {
114 contract_address: self.contract_address,
115 caller: self.caller,
116 value: self.value,
117 runtime: self.runtime.clone(),
118 changes: self.changes.clone(),
119 is_revm_instantiated: self.is_revm_instantiated,
120 error: self.error.clone(),
121 }
122 }
123}
124
125fn get_storage_key(index: U256) -> Vec<u8> {
128 let mut key = vec![KeyCategory::Storage as u8];
129 key.extend(index.as_le_slice());
130 key
131}
132
133fn get_category_key(category: KeyCategory) -> Vec<u8> {
135 vec![category as u8]
136}
137
138impl<Runtime> InnerDatabase<Runtime>
139where
140 Runtime: BaseRuntime,
141{
142 pub fn new(runtime: Runtime) -> Self {
149 Self {
150 contract_address: Address::ZERO,
151 caller: Address::ZERO,
152 value: U256::ZERO,
153 runtime: Arc::new(Mutex::new(runtime)),
154 changes: HashMap::new(),
155 is_revm_instantiated: false,
156 error: Arc::new(Mutex::new(None)),
157 }
158 }
159
160 pub fn lock_runtime(&self) -> std::sync::MutexGuard<'_, Runtime> {
172 self.runtime.lock().unwrap()
173 }
174
175 pub fn insert_error(&self, exec_error: ExecutionError) {
180 let mut error = self.error.lock().unwrap();
181 *error = Some(format!("Runtime error {:?}", exec_error));
182 }
183
184 pub fn process_any_error(&self) -> Result<(), EvmExecutionError> {
193 let error = self.error.lock().unwrap();
194 if let Some(error) = error.clone() {
195 return Err(EvmExecutionError::RuntimeError(error.clone()));
196 }
197 Ok(())
198 }
199
200 fn read_basic_ref(
226 &self,
227 f: fn(&Self, Address) -> Result<Option<AccountInfo>, ExecutionError>,
228 address: Address,
229 is_newly_created: bool,
230 ) -> Result<Option<AccountInfo>, ExecutionError> {
231 if address == FAUCET_ADDRESS {
232 return Ok(Some(AccountInfo {
233 balance: FAUCET_BALANCE,
234 ..AccountInfo::default()
235 }));
236 }
237 let mut account_info = self
238 .account_info_from_storage(f, address)?
239 .unwrap_or_default();
240 if !is_newly_created {
241 account_info.balance = self.get_start_balance(address)?;
243 }
244 Ok(Some(account_info))
247 }
248
249 fn account_info_from_local_storage(&self) -> Result<Option<AccountInfo>, ExecutionError> {
251 let mut runtime = self.runtime.lock().unwrap();
252 let key_info = get_category_key(KeyCategory::AccountInfo);
253 let promise = runtime.read_value_bytes_new(key_info)?;
254 let result = runtime.read_value_bytes_wait(&promise)?;
255 Ok(from_bytes_option::<AccountInfo>(&result)?)
256 }
257
258 fn account_info_from_inner_database(
267 &self,
268 address: Address,
269 ) -> Result<Option<AccountInfo>, ExecutionError> {
270 if !self.changes.is_empty() {
271 let account = self.changes.get(&address);
277 return Ok(account.map(|account| account.info.clone()));
278 }
279 if address == self.contract_address {
280 self.account_info_from_local_storage()
282 } else {
283 Ok(None)
285 }
286 }
287
288 fn account_info_from_storage(
290 &self,
291 f: fn(&Self, Address) -> Result<Option<AccountInfo>, ExecutionError>,
292 address: Address,
293 ) -> Result<Option<AccountInfo>, ExecutionError> {
294 let account_info = self.account_info_from_inner_database(address)?;
295 if let Some(account_info) = account_info {
296 return Ok(Some(account_info));
298 }
299 if self.has_empty_storage(address)? {
300 Ok(None)
302 } else {
303 f(self, address)
305 }
306 }
307
308 fn has_empty_storage(&self, address: Address) -> Result<bool, ExecutionError> {
312 let application_id = address_to_user_application_id(address);
313 let mut runtime = self.runtime.lock().unwrap();
314 runtime.has_empty_storage(application_id)
315 }
316
317 fn get_start_balance(&self, address: Address) -> Result<U256, ExecutionError> {
336 let mut runtime = self.runtime.lock().unwrap();
337 let account_owner = address.into();
338 let balance = runtime.read_owner_balance(account_owner)?;
339 let balance: U256 = balance.into();
340
341 Ok(if self.caller == address {
342 balance + self.value
344 } else if self.contract_address == address {
345 assert!(
347 balance >= self.value,
348 "Contract balance should be >= transferred value"
349 );
350 balance - self.value
351 } else {
352 balance
354 })
355 }
356
357 pub fn get_account_info(&self) -> Result<AccountInfo, ExecutionError> {
358 let address = self.contract_address;
359 let account_info = self.account_info_from_inner_database(address)?;
360 let mut account_info = account_info.ok_or(EvmExecutionError::MissingAccountInfo)?;
361 account_info.balance = self.get_start_balance(address)?;
362 Ok(account_info)
363 }
364
365 fn read_storage(
370 &self,
371 f: fn(&Self, Address, U256) -> Result<U256, ExecutionError>,
372 address: Address,
373 index: U256,
374 ) -> Result<U256, ExecutionError> {
375 if !self.changes.is_empty() {
376 let account = self.changes.get(&address).unwrap();
379 return Ok(match account.storage.get(&index) {
380 None => U256::ZERO,
381 Some(slot) => slot.present_value(),
382 });
383 }
384 if address == self.contract_address {
385 return self.read_from_local_storage(index);
388 }
389 f(self, address, index)
391 }
392
393 pub fn read_from_local_storage(&self, index: U256) -> Result<U256, ExecutionError> {
395 let key = get_storage_key(index);
396 let mut runtime = self.runtime.lock().unwrap();
397 let promise = runtime.read_value_bytes_new(key)?;
398 let result = runtime.read_value_bytes_wait(&promise)?;
399 Ok(from_bytes_option::<U256>(&result)?.unwrap_or_default())
400 }
401
402 pub fn set_contract_address(&mut self) -> Result<(), ExecutionError> {
412 let mut runtime = self.runtime.lock().unwrap();
413 let application_id = runtime.application_id()?;
414 self.contract_address = application_id.evm_address();
415 Ok(())
416 }
417
418 pub fn set_is_initialized(&mut self) -> Result<bool, ExecutionError> {
438 let mut runtime = self.runtime.lock().unwrap();
439 let key_info = get_category_key(KeyCategory::AccountInfo);
440 let promise = runtime.contains_key_new(key_info)?;
441 let result = runtime.contains_key_wait(&promise)?;
442 self.is_revm_instantiated = result;
443 Ok(result)
444 }
445
446 pub fn get_block_env(&self) -> Result<BlockEnv, ExecutionError> {
447 let mut runtime = self.runtime.lock().unwrap();
448 let block_height_linera = runtime.block_height()?;
450 let block_height_evm = block_height_linera.0;
451 let beneficiary = address!("00000000000000000000000000000000000000bb");
453 let difficulty = U256::ZERO;
455 let gas_limit = u64::MAX;
458 let timestamp_linera = runtime.read_system_timestamp()?;
462 let timestamp_evm = timestamp_linera.micros() / 1_000_000;
463 let basefee = 0;
466 let chain_id = runtime.chain_id()?;
467 let entry = format!("{}{}", chain_id, block_height_linera);
468 let prevrandao = keccak256(entry.as_bytes());
470 let entry = BlobExcessGasAndPrice {
473 excess_blob_gas: 0,
474 blob_gasprice: 1,
475 };
476 let blob_excess_gas_and_price = Some(entry);
477 Ok(BlockEnv {
478 number: block_height_evm,
479 beneficiary,
480 difficulty,
481 gas_limit,
482 timestamp: timestamp_evm,
483 basefee,
484 prevrandao: Some(prevrandao),
485 blob_excess_gas_and_price,
486 })
487 }
488
489 pub fn constructor_argument(&self) -> Result<Vec<u8>, ExecutionError> {
490 let mut runtime = self.runtime.lock().unwrap();
491 let constructor_argument = runtime.application_parameters()?;
492 Ok(serde_json::from_slice::<Vec<u8>>(&constructor_argument)?)
493 }
494}
495
496impl<Runtime> InnerDatabase<Runtime>
497where
498 Runtime: ContractRuntime,
499{
500 fn get_contract_account_info(
502 &self,
503 address: Address,
504 ) -> Result<Option<AccountInfo>, ExecutionError> {
505 let application_id = address_to_user_application_id(address);
506 let argument = GET_ACCOUNT_INFO_SELECTOR.to_vec();
507 let mut runtime = self.runtime.lock().unwrap();
508 let account_info = runtime.try_call_application(false, application_id, argument)?;
509 let account_info = bcs::from_bytes(&account_info)?;
510 Ok(Some(account_info))
511 }
512
513 fn get_contract_storage_value(
515 &self,
516 address: Address,
517 index: U256,
518 ) -> Result<U256, ExecutionError> {
519 let application_id = address_to_user_application_id(address);
520 let mut argument = GET_CONTRACT_STORAGE_SELECTOR.to_vec();
521 argument.extend(bcs::to_bytes(&index)?);
522 let mut runtime = self.runtime.lock().unwrap();
523 let value = runtime.try_call_application(false, application_id, argument)?;
524 let value = bcs::from_bytes(&value)?;
525 Ok(value)
526 }
527
528 pub fn deposit_funds(&self) -> Result<(), ExecutionError> {
529 if self.value != U256::ZERO {
530 if self.caller == ZERO_ADDRESS {
531 let error = EvmExecutionError::UnknownSigner;
532 return Err(error.into());
533 }
534 let source = self.caller.into();
535 let amount = Amount::try_from(self.value).map_err(EvmExecutionError::from)?;
536 let mut runtime = self.runtime.lock().expect("The lock should be possible");
537 let chain_id = runtime.chain_id()?;
538 let application_id = runtime.application_id()?;
539 let owner = application_id.into();
540 let destination = identifiers::Account { chain_id, owner };
541 let authenticated_caller = runtime.authenticated_caller_id()?;
542 if authenticated_caller.is_none() {
543 runtime.transfer(source, destination, amount)?;
544 }
545 }
546 Ok(())
547 }
548}
549
550impl<Runtime> InnerDatabase<Runtime>
551where
552 Runtime: ServiceRuntime,
553{
554 fn get_service_account_info(
556 &self,
557 address: Address,
558 ) -> Result<Option<AccountInfo>, ExecutionError> {
559 let application_id = address_to_user_application_id(address);
560 let argument = serde_json::to_vec(&EvmQuery::AccountInfo)?;
561 let mut runtime = self.runtime.lock().expect("The lock should be possible");
562 let account_info = runtime.try_query_application(application_id, argument)?;
563 let account_info = serde_json::from_slice::<AccountInfo>(&account_info)?;
564 Ok(Some(account_info))
565 }
566
567 fn get_service_storage_value(
569 &self,
570 address: Address,
571 index: U256,
572 ) -> Result<U256, ExecutionError> {
573 let application_id = address_to_user_application_id(address);
574 let argument = serde_json::to_vec(&EvmQuery::Storage(index))?;
575 let mut runtime = self.runtime.lock().expect("The lock should be possible");
576 let value = runtime.try_query_application(application_id, argument)?;
577 let value = serde_json::from_slice::<U256>(&value)?;
578 Ok(value)
579 }
580}
581
582impl<Runtime> ContractDatabase<Runtime>
583where
584 Runtime: ContractRuntime,
585{
586 pub fn new(runtime: Runtime) -> Self {
587 Self {
588 inner: InnerDatabase::new(runtime),
589 modules: Arc::new(Mutex::new(HashMap::new())),
590 }
591 }
592
593 pub fn lock_runtime(&self) -> std::sync::MutexGuard<'_, Runtime> {
594 self.inner.lock_runtime()
595 }
596
597 fn check_balance(
601 &mut self,
602 address: Address,
603 revm_balance: U256,
604 ) -> Result<(), ExecutionError> {
605 let mut runtime = self.inner.runtime.lock().unwrap();
606 let owner = address.into();
607 let linera_balance: U256 = runtime.read_owner_balance(owner)?.into();
608 ensure!(
609 linera_balance == revm_balance,
610 EvmExecutionError::IncoherentBalances(address, linera_balance, revm_balance)
611 );
612 Ok(())
613 }
614
615 pub fn commit_contract_changes(
617 &mut self,
618 account: &revm_state::Account,
619 ) -> Result<(), ExecutionError> {
620 let mut runtime = self.inner.runtime.lock().unwrap();
621 let mut batch = Batch::new();
622 let key_prefix = get_category_key(KeyCategory::Storage);
623 let key_info = get_category_key(KeyCategory::AccountInfo);
624 if account.is_selfdestructed() {
625 batch.delete_key_prefix(key_prefix);
626 batch.put_key_value(key_info, &AccountInfo::default())?;
627 } else {
628 batch.put_key_value(key_info, &account.info)?;
629 for (index, value) in &account.storage {
630 if value.present_value() != value.original_value() {
631 let key = get_storage_key(*index);
632 if value.present_value() == U256::ZERO {
633 batch.delete_key(key);
634 } else {
635 batch.put_key_value(key, &value.present_value())?;
636 }
637 }
638 }
639 }
640 runtime.write_batch(batch)?;
641 Ok(())
642 }
643
644 fn is_account_writable(&self, address: &Address, account: &revm_state::Account) -> bool {
647 if *address == FAUCET_ADDRESS {
648 return false;
650 }
651 if !account.is_touched() {
652 return false;
654 }
655 let code_hash = account.info.code_hash;
656 let code_empty = code_hash == KECCAK_EMPTY || code_hash.is_zero();
660 !code_empty
661 }
662
663 fn is_account_checkable(&self, address: &Address) -> bool {
665 if *address == FAUCET_ADDRESS {
666 return false;
668 }
669 true
670 }
671
672 fn create_new_contract(
679 &mut self,
680 address: Address,
681 account: revm_state::Account,
682 module_id: ModuleId,
683 ) -> Result<(), ExecutionError> {
684 let application_id = address_to_user_application_id(address);
685 let mut argument = ALREADY_CREATED_CONTRACT_SELECTOR.to_vec();
686 argument.extend(bcs::to_bytes(&account)?);
687 let evm_instantiation = EvmInstantiation {
688 value: U256::ZERO,
689 argument,
690 };
691 let argument = serde_json::to_vec(&evm_instantiation)?;
692 let parameters = JSON_EMPTY_VECTOR.to_vec(); let required_application_ids = Vec::new();
694 let mut runtime = self.inner.runtime.lock().unwrap();
695 let created_application_id = runtime.create_application(
696 module_id,
697 parameters,
698 argument,
699 required_application_ids,
700 )?;
701 ensure!(
702 application_id == created_application_id,
703 EvmExecutionError::IncorrectApplicationId
704 );
705 Ok(())
706 }
707
708 fn commit_remote_contract(
711 &mut self,
712 address: Address,
713 account: revm_state::Account,
714 ) -> Result<(), ExecutionError> {
715 let application_id = address_to_user_application_id(address);
716 let mut argument = COMMIT_CONTRACT_CHANGES_SELECTOR.to_vec();
717 argument.extend(bcs::to_bytes(&account)?);
718 let mut runtime = self.inner.runtime.lock().unwrap();
719 runtime.try_call_application(false, application_id, argument)?;
720 Ok(())
721 }
722
723 pub fn commit_changes(&mut self) -> Result<(), ExecutionError> {
733 let changes = mem::take(&mut self.inner.changes);
734 let mut balances = Vec::new();
735 let modules = mem::take(self.modules.lock().unwrap().deref_mut());
736 let mut contracts_to_create = vec![None; modules.len()];
737 for (address, account) in changes {
738 if self.is_account_checkable(&address) {
739 let revm_balance = account.info.balance;
740 balances.push((address, revm_balance));
741 }
742 if self.is_account_writable(&address, &account) {
743 if address == self.inner.contract_address {
744 self.commit_contract_changes(&account)?;
745 } else {
746 let application_id = address_to_user_application_id(address);
747 if let Some((module_id, index)) = modules.get(&application_id) {
748 contracts_to_create[*index as usize] = Some((address, account, *module_id));
749 } else {
750 self.commit_remote_contract(address, account)?;
751 }
752 }
753 }
754 }
755 for entry in contracts_to_create {
756 let (address, account, module_id) =
757 entry.expect("An entry since all have been matched above");
758 self.create_new_contract(address, account, module_id)?;
759 }
760 for (address, revm_balance) in balances {
761 self.check_balance(address, revm_balance)?;
762 }
763 Ok(())
764 }
765}
766
767#[repr(u8)]
772pub enum KeyCategory {
773 AccountInfo,
775 Storage,
777}
778
779pub(crate) struct ContractDatabase<Runtime> {
781 pub inner: InnerDatabase<Runtime>,
782 pub modules: Arc<Mutex<HashMap<ApplicationId, (ModuleId, u32)>>>,
783}
784
785impl<Runtime> Clone for ContractDatabase<Runtime> {
786 fn clone(&self) -> Self {
787 Self {
788 inner: self.inner.clone(),
789 modules: self.modules.clone(),
790 }
791 }
792}
793
794impl<Runtime> DatabaseRef for ContractDatabase<Runtime>
795where
796 Runtime: ContractRuntime,
797{
798 type Error = ExecutionError;
799
800 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, ExecutionError> {
803 let is_newly_created = {
804 let modules = self.modules.lock().unwrap();
805 let application_id = address_to_user_application_id(address);
806 modules.contains_key(&application_id)
807 };
808 self.inner.read_basic_ref(
809 InnerDatabase::<Runtime>::get_contract_account_info,
810 address,
811 is_newly_created,
812 )
813 }
814
815 fn code_by_hash_ref(&self, _code_hash: B256) -> Result<Bytecode, ExecutionError> {
822 panic!("Returned AccountInfo should have code: Some(...) and so code_by_hash_ref should never be called");
823 }
824
825 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, ExecutionError> {
827 self.inner.read_storage(
828 InnerDatabase::<Runtime>::get_contract_storage_value,
829 address,
830 index,
831 )
832 }
833
834 fn block_hash_ref(&self, number: u64) -> Result<B256, ExecutionError> {
835 Ok(keccak256(number.to_string().as_bytes()))
836 }
837}
838
839impl<Runtime> Database for ContractDatabase<Runtime>
840where
841 Runtime: ContractRuntime,
842{
843 type Error = ExecutionError;
844
845 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, ExecutionError> {
846 self.basic_ref(address)
847 }
848
849 fn code_by_hash(&mut self, _code_hash: B256) -> Result<Bytecode, ExecutionError> {
850 panic!("Returned AccountInfo should have code: Some(...) and so code_by_hash should never be called");
851 }
852
853 fn storage(&mut self, address: Address, index: U256) -> Result<U256, ExecutionError> {
854 self.storage_ref(address, index)
855 }
856
857 fn block_hash(&mut self, number: u64) -> Result<B256, ExecutionError> {
858 <Self as DatabaseRef>::block_hash_ref(self, number)
859 }
860}
861
862impl<Runtime> DatabaseCommit for ContractDatabase<Runtime>
863where
864 Runtime: ContractRuntime,
865{
866 fn commit(&mut self, changes: EvmState) {
867 self.inner.changes = changes;
868 }
869}
870
871impl<Runtime> ContractDatabase<Runtime>
872where
873 Runtime: ContractRuntime,
874{
875 pub fn get_block_env(&self) -> Result<BlockEnv, ExecutionError> {
876 let mut block_env = self.inner.get_block_env()?;
877 let mut runtime = self.inner.runtime.lock().unwrap();
878 let gas_limit = runtime.maximum_fuel_per_block(VmRuntime::Evm)?;
880 block_env.gas_limit = gas_limit;
881 Ok(block_env)
882 }
883
884 pub fn get_nonce(&self, address: &Address) -> Result<u64, ExecutionError> {
886 let account_info = self.basic_ref(*address)?;
887 Ok(match account_info {
888 None => 0,
889 Some(account_info) => account_info.nonce,
890 })
891 }
892}
893
894pub(crate) struct ServiceDatabase<Runtime> {
897 pub inner: InnerDatabase<Runtime>,
898}
899
900impl<Runtime> Clone for ServiceDatabase<Runtime> {
901 fn clone(&self) -> Self {
902 Self {
903 inner: self.inner.clone(),
904 }
905 }
906}
907
908impl<Runtime> DatabaseRef for ServiceDatabase<Runtime>
909where
910 Runtime: ServiceRuntime,
911{
912 type Error = ExecutionError;
913
914 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, ExecutionError> {
917 let is_newly_created = false; self.inner.read_basic_ref(
919 InnerDatabase::<Runtime>::get_service_account_info,
920 address,
921 is_newly_created,
922 )
923 }
924
925 fn code_by_hash_ref(&self, _code_hash: B256) -> Result<Bytecode, ExecutionError> {
932 panic!("Returned AccountInfo should have code: Some(...) and so code_by_hash_ref should never be called");
933 }
934
935 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, ExecutionError> {
936 self.inner.read_storage(
937 InnerDatabase::<Runtime>::get_service_storage_value,
938 address,
939 index,
940 )
941 }
942
943 fn block_hash_ref(&self, number: u64) -> Result<B256, ExecutionError> {
944 Ok(keccak256(number.to_string().as_bytes()))
945 }
946}
947
948impl<Runtime> Database for ServiceDatabase<Runtime>
949where
950 Runtime: ServiceRuntime,
951{
952 type Error = ExecutionError;
953
954 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, ExecutionError> {
955 self.basic_ref(address)
956 }
957
958 fn code_by_hash(&mut self, _code_hash: B256) -> Result<Bytecode, ExecutionError> {
959 panic!("Returned AccountInfo should have code: Some(...) and so code_by_hash should never be called");
960 }
961
962 fn storage(&mut self, address: Address, index: U256) -> Result<U256, ExecutionError> {
963 self.storage_ref(address, index)
964 }
965
966 fn block_hash(&mut self, number: u64) -> Result<B256, ExecutionError> {
967 <Self as DatabaseRef>::block_hash_ref(self, number)
968 }
969}
970
971impl<Runtime> DatabaseCommit for ServiceDatabase<Runtime>
972where
973 Runtime: ServiceRuntime,
974{
975 fn commit(&mut self, changes: EvmState) {
976 self.inner.changes = changes;
977 }
978}
979
980impl<Runtime> ServiceDatabase<Runtime>
981where
982 Runtime: ServiceRuntime,
983{
984 pub fn new(runtime: Runtime) -> Self {
985 Self {
986 inner: InnerDatabase::new(runtime),
987 }
988 }
989
990 pub fn lock_runtime(&self) -> std::sync::MutexGuard<'_, Runtime> {
991 self.inner.lock_runtime()
992 }
993
994 pub fn get_block_env(&self) -> Result<BlockEnv, ExecutionError> {
995 let mut block_env = self.inner.get_block_env()?;
996 block_env.gas_limit = EVM_SERVICE_GAS_LIMIT;
997 Ok(block_env)
998 }
999
1000 pub fn get_nonce(&self, address: &Address) -> Result<u64, ExecutionError> {
1002 let account_info = self.basic_ref(*address)?;
1003 Ok(match account_info {
1004 None => 0,
1005 Some(account_info) => account_info.nonce,
1006 })
1007 }
1008}