1use core::ops::Range;
33use std::{
34 collections::BTreeSet,
35 convert::TryFrom,
36 ops::DerefMut,
37 sync::{Arc, Mutex},
38};
39
40#[cfg(with_metrics)]
41use linera_base::prometheus_util::MeasureLatency as _;
42use linera_base::{
43 crypto::CryptoHash,
44 data_types::{
45 Amount, ApplicationDescription, ArithmeticError, Bytecode, Resources, SendMessageRequest,
46 StreamUpdate,
47 },
48 ensure,
49 identifiers::{self, Account, AccountOwner, ApplicationId, ChainId, ModuleId, StreamName},
50 vm::{EvmInstantiation, EvmOperation, EvmQuery, VmRuntime},
51};
52use revm::{primitives::Bytes, InspectCommitEvm, InspectEvm, Inspector};
53use revm_context::{
54 result::{ExecutionResult, Output},
55 BlockEnv, Cfg, ContextTr, Evm, Journal, JournalTr, LocalContextTr as _, TxEnv,
56};
57use revm_database::WrapDatabaseRef;
58use revm_handler::{
59 instructions::EthInstructions, EthPrecompiles, MainnetContext, PrecompileProvider,
60};
61use revm_interpreter::{
62 CallInput, CallInputs, CallOutcome, CallValue, CreateInputs, CreateOutcome, CreateScheme, Gas,
63 InputsImpl, InstructionResult, InterpreterResult,
64};
65use revm_primitives::{hardfork::SpecId, Address, Log, TxKind, U256};
66use revm_state::EvmState;
67use serde::{Deserialize, Serialize};
68
69use crate::{
70 evm::{
71 data_types::AmountU256,
72 database::{ContractDatabase, InnerDatabase, ServiceDatabase, EVM_SERVICE_GAS_LIMIT},
73 inputs::{
74 ensure_message_length, ensure_selector_presence, forbid_execute_operation_origin,
75 get_revm_execute_message_bytes, get_revm_instantiation_bytes,
76 get_revm_process_streams_bytes, has_selector, EXECUTE_MESSAGE_SELECTOR, FAUCET_ADDRESS,
77 INSTANTIATE_SELECTOR, PRECOMPILE_ADDRESS, PROCESS_STREAMS_SELECTOR, SERVICE_ADDRESS,
78 ZERO_ADDRESS,
79 },
80 },
81 BaseRuntime, ContractRuntime, ContractSyncRuntimeHandle, DataBlobHash, EvmExecutionError,
82 EvmRuntime, ExecutionError, ServiceRuntime, ServiceSyncRuntimeHandle, UserContract,
83 UserContractInstance, UserContractModule, UserService, UserServiceInstance, UserServiceModule,
84};
85
86pub const GET_ACCOUNT_INFO_SELECTOR: &[u8] = &[21, 34, 55, 89];
92
93pub const GET_CONTRACT_STORAGE_SELECTOR: &[u8] = &[5, 14, 42, 132];
99
100pub const COMMIT_CONTRACT_CHANGES_SELECTOR: &[u8] = &[5, 15, 52, 203];
106
107pub const ALREADY_CREATED_CONTRACT_SELECTOR: &[u8] = &[23, 47, 106, 235];
113
114pub const JSON_EMPTY_VECTOR: &[u8] = &[91, 93];
118
119#[cfg(with_metrics)]
120mod metrics {
121 use std::sync::LazyLock;
122
123 use linera_base::prometheus_util::{exponential_bucket_latencies, register_histogram_vec};
124 use prometheus::HistogramVec;
125
126 pub static CONTRACT_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
127 register_histogram_vec(
128 "evm_contract_instantiation_latency",
129 "EVM contract instantiation latency",
130 &[],
131 exponential_bucket_latencies(100.0),
132 )
133 });
134
135 pub static SERVICE_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
136 register_histogram_vec(
137 "evm_service_instantiation_latency",
138 "EVM service instantiation latency",
139 &[],
140 exponential_bucket_latencies(100.0),
141 )
142 });
143}
144
145#[derive(Clone)]
146pub enum EvmContractModule {
147 #[cfg(with_revm)]
148 Revm { module: Vec<u8> },
149}
150
151impl EvmContractModule {
152 pub fn new(
154 contract_bytecode: Bytecode,
155 runtime: EvmRuntime,
156 ) -> Result<Self, EvmExecutionError> {
157 match runtime {
158 #[cfg(with_revm)]
159 EvmRuntime::Revm => Self::from_revm(contract_bytecode),
160 }
161 }
162
163 #[cfg(with_fs)]
165 pub async fn from_file(
166 contract_bytecode_file: impl AsRef<std::path::Path>,
167 runtime: EvmRuntime,
168 ) -> Result<Self, EvmExecutionError> {
169 Self::new(
170 Bytecode::load_from_file(contract_bytecode_file)
171 .await
172 .map_err(anyhow::Error::from)
173 .map_err(EvmExecutionError::LoadContractModule)?,
174 runtime,
175 )
176 }
177
178 pub fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
180 let module = contract_bytecode.bytes;
181 Ok(EvmContractModule::Revm { module })
182 }
183}
184
185impl UserContractModule for EvmContractModule {
186 fn instantiate(
187 &self,
188 runtime: ContractSyncRuntimeHandle,
189 ) -> Result<UserContractInstance, ExecutionError> {
190 #[cfg(with_metrics)]
191 let _instantiation_latency = metrics::CONTRACT_INSTANTIATION_LATENCY.measure_latency();
192
193 let instance: UserContractInstance = match self {
194 #[cfg(with_revm)]
195 EvmContractModule::Revm { module } => {
196 Box::new(RevmContractInstance::prepare(module.to_vec(), runtime))
197 }
198 };
199
200 Ok(instance)
201 }
202}
203
204#[derive(Clone)]
206pub enum EvmServiceModule {
207 #[cfg(with_revm)]
208 Revm { module: Vec<u8> },
209}
210
211impl EvmServiceModule {
212 pub fn new(service_bytecode: Bytecode, runtime: EvmRuntime) -> Result<Self, EvmExecutionError> {
214 match runtime {
215 #[cfg(with_revm)]
216 EvmRuntime::Revm => Self::from_revm(service_bytecode),
217 }
218 }
219
220 #[cfg(with_fs)]
222 pub async fn from_file(
223 service_bytecode_file: impl AsRef<std::path::Path>,
224 runtime: EvmRuntime,
225 ) -> Result<Self, EvmExecutionError> {
226 Self::new(
227 Bytecode::load_from_file(service_bytecode_file)
228 .await
229 .map_err(anyhow::Error::from)
230 .map_err(EvmExecutionError::LoadServiceModule)?,
231 runtime,
232 )
233 }
234
235 pub fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
237 let module = contract_bytecode.bytes;
238 Ok(EvmServiceModule::Revm { module })
239 }
240}
241
242impl UserServiceModule for EvmServiceModule {
243 fn instantiate(
244 &self,
245 runtime: ServiceSyncRuntimeHandle,
246 ) -> Result<UserServiceInstance, ExecutionError> {
247 #[cfg(with_metrics)]
248 let _instantiation_latency = metrics::SERVICE_INSTANTIATION_LATENCY.measure_latency();
249
250 let instance: UserServiceInstance = match self {
251 #[cfg(with_revm)]
252 EvmServiceModule::Revm { module } => {
253 Box::new(RevmServiceInstance::prepare(module.to_vec(), runtime))
254 }
255 };
256
257 Ok(instance)
258 }
259}
260
261type ContractCtx<'a, Runtime> = MainnetContext<WrapDatabaseRef<&'a mut ContractDatabase<Runtime>>>;
262
263type ServiceCtx<'a, Runtime> = MainnetContext<WrapDatabaseRef<&'a mut ServiceDatabase<Runtime>>>;
264
265pub fn address_to_user_application_id(address: Address) -> ApplicationId {
266 let mut vec = vec![0_u8; 32];
267 vec[..20].copy_from_slice(address.as_ref());
268 ApplicationId::new(CryptoHash::try_from(&vec as &[u8]).unwrap())
269}
270
271#[derive(Debug, Serialize, Deserialize)]
273enum BaseRuntimePrecompile {
274 ChainId,
276 BlockHeight,
278 ApplicationCreatorChainId,
280 ReadSystemTimestamp,
282 ReadChainBalance,
284 ReadOwnerBalance(AccountOwner),
286 ReadOwnerBalances,
288 ReadBalanceOwners,
290 ChainOwnership,
292 ReadDataBlob(DataBlobHash),
294 AssertDataBlobExists(DataBlobHash),
296}
297
298#[derive(Debug, Serialize, Deserialize)]
300enum ContractRuntimePrecompile {
301 AuthenticatedOwner,
303 MessageOriginChainId,
305 MessageIsBouncing,
307 AuthenticatedCallerId,
309 SendMessage {
311 destination: ChainId,
312 message: Vec<u8>,
313 },
314 TryCallApplication {
316 target: ApplicationId,
317 argument: Vec<u8>,
318 },
319 Emit {
321 stream_name: StreamName,
322 value: Vec<u8>,
323 },
324 ReadEvent {
326 chain_id: ChainId,
327 stream_name: StreamName,
328 index: u32,
329 },
330 SubscribeToEvents {
332 chain_id: ChainId,
333 application_id: ApplicationId,
334 stream_name: StreamName,
335 },
336 UnsubscribeFromEvents {
338 chain_id: ChainId,
339 application_id: ApplicationId,
340 stream_name: StreamName,
341 },
342 QueryService {
344 application_id: ApplicationId,
345 query: Vec<u8>,
346 },
347 ValidationRound,
349 Transfer {
351 account: Account,
352 amount: AmountU256,
353 },
354 MessageOriginTimestamp,
356}
357
358#[derive(Debug, Serialize, Deserialize)]
360enum ServiceRuntimePrecompile {
361 TryQueryApplication {
363 target: ApplicationId,
364 argument: Vec<u8>,
365 },
366}
367
368#[derive(Debug, Serialize, Deserialize)]
370enum RuntimePrecompile {
371 Base(BaseRuntimePrecompile),
372 Contract(ContractRuntimePrecompile),
373 Service(ServiceRuntimePrecompile),
374}
375
376fn get_precompile_output(output: Vec<u8>, gas_limit: u64) -> InterpreterResult {
394 let output = Bytes::from(output);
395 let result = InstructionResult::default();
396 let gas = Gas::new(gas_limit);
397 InterpreterResult {
398 result,
399 output,
400 gas,
401 }
402}
403
404fn get_argument<Ctx: ContextTr>(context: &mut Ctx, input: &CallInput) -> Vec<u8> {
405 match input {
406 CallInput::Bytes(bytes) => bytes.to_vec(),
407 CallInput::SharedBuffer(range) => {
408 match context.local().shared_memory_buffer_slice(range.clone()) {
409 None => Vec::new(),
410 Some(slice) => slice.to_vec(),
411 }
412 }
413 }
414}
415
416fn get_precompile_argument<Ctx: ContextTr>(context: &mut Ctx, inputs: &InputsImpl) -> Vec<u8> {
417 get_argument(context, &inputs.input)
418}
419
420fn base_runtime_call<Runtime: BaseRuntime>(
421 request: &BaseRuntimePrecompile,
422 runtime: &mut Runtime,
423) -> Result<Vec<u8>, ExecutionError> {
424 match request {
425 BaseRuntimePrecompile::ChainId => {
426 let chain_id = runtime.chain_id()?;
427 Ok(bcs::to_bytes(&chain_id)?)
428 }
429 BaseRuntimePrecompile::BlockHeight => {
430 let block_height = runtime.block_height()?;
431 Ok(bcs::to_bytes(&block_height)?)
432 }
433 BaseRuntimePrecompile::ApplicationCreatorChainId => {
434 let chain_id = runtime.application_creator_chain_id()?;
435 Ok(bcs::to_bytes(&chain_id)?)
436 }
437 BaseRuntimePrecompile::ReadSystemTimestamp => {
438 let timestamp = runtime.read_system_timestamp()?;
439 Ok(bcs::to_bytes(×tamp)?)
440 }
441 BaseRuntimePrecompile::ReadChainBalance => {
442 let balance: linera_base::data_types::Amount = runtime.read_chain_balance()?;
443 let balance: AmountU256 = balance.into();
444 Ok(bcs::to_bytes(&balance)?)
445 }
446 BaseRuntimePrecompile::ReadOwnerBalance(account_owner) => {
447 let balance = runtime.read_owner_balance(*account_owner)?;
448 let balance = Into::<U256>::into(balance);
449 Ok(bcs::to_bytes(&balance)?)
450 }
451 BaseRuntimePrecompile::ReadOwnerBalances => {
452 let owner_balances = runtime.read_owner_balances()?;
453 let owner_balances = owner_balances
454 .into_iter()
455 .map(|(account_owner, balance)| (account_owner, balance.into()))
456 .collect::<Vec<(AccountOwner, AmountU256)>>();
457 Ok(bcs::to_bytes(&owner_balances)?)
458 }
459 BaseRuntimePrecompile::ReadBalanceOwners => {
460 let owners = runtime.read_balance_owners()?;
461 Ok(bcs::to_bytes(&owners)?)
462 }
463 BaseRuntimePrecompile::ChainOwnership => {
464 let chain_ownership = runtime.chain_ownership()?;
465 Ok(bcs::to_bytes(&chain_ownership)?)
466 }
467 BaseRuntimePrecompile::ReadDataBlob(hash) => runtime.read_data_blob(*hash),
468 BaseRuntimePrecompile::AssertDataBlobExists(hash) => {
469 runtime.assert_data_blob_exists(*hash)?;
470 Ok(Vec::new())
471 }
472 }
473}
474
475fn precompile_addresses() -> BTreeSet<Address> {
476 let mut addresses = BTreeSet::new();
477 for address in EthPrecompiles::default().warm_addresses() {
478 addresses.insert(address);
479 }
480 addresses.insert(PRECOMPILE_ADDRESS);
481 addresses
482}
483
484#[derive(Debug, Default)]
485struct ContractPrecompile {
486 inner: EthPrecompiles,
487}
488
489impl<'a, Runtime: ContractRuntime> PrecompileProvider<ContractCtx<'a, Runtime>>
490 for ContractPrecompile
491{
492 type Output = InterpreterResult;
493
494 fn set_spec(
495 &mut self,
496 spec: <<ContractCtx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec,
497 ) -> bool {
498 <EthPrecompiles as PrecompileProvider<ContractCtx<'a, Runtime>>>::set_spec(
499 &mut self.inner,
500 spec,
501 )
502 }
503
504 fn run(
505 &mut self,
506 context: &mut ContractCtx<'a, Runtime>,
507 address: &Address,
508 inputs: &InputsImpl,
509 is_static: bool,
510 gas_limit: u64,
511 ) -> Result<Option<InterpreterResult>, String> {
512 if address == &PRECOMPILE_ADDRESS {
513 let output = Self::call_or_fail(inputs, context)
514 .map_err(|error| format!("ContractPrecompile error: {error}"))?;
515 return Ok(Some(get_precompile_output(output, gas_limit)));
516 }
517 self.inner
518 .run(context, address, inputs, is_static, gas_limit)
519 }
520
521 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
522 let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
523 addresses.push(PRECOMPILE_ADDRESS);
524 Box::new(addresses.into_iter())
525 }
526
527 fn contains(&self, address: &Address) -> bool {
528 address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
529 }
530}
531
532fn get_evm_destination<Runtime: ContractRuntime>(
533 context: &mut ContractCtx<'_, Runtime>,
534 account: Account,
535) -> Result<Option<Address>, ExecutionError> {
536 let mut runtime = context.db().0.lock_runtime();
537 if runtime.chain_id()? != account.chain_id {
538 return Ok(None);
539 }
540 Ok(account.owner.to_evm_address())
541}
542
543fn revm_transfer<Runtime: ContractRuntime>(
545 context: &mut ContractCtx<'_, Runtime>,
546 source: Address,
547 destination: Address,
548 value: U256,
549) -> Result<(), ExecutionError> {
550 if let Some(error) = context.journal().transfer(source, destination, value)? {
551 let error = format!("{error:?}");
552 let error = EvmExecutionError::TransactError(error);
553 return Err(error.into());
554 }
555 Ok(())
556}
557
558impl<'a> ContractPrecompile {
559 fn contract_runtime_call<Runtime: ContractRuntime>(
560 request: ContractRuntimePrecompile,
561 context: &mut ContractCtx<'a, Runtime>,
562 ) -> Result<Vec<u8>, ExecutionError> {
563 match request {
564 ContractRuntimePrecompile::AuthenticatedOwner => {
565 let mut runtime = context.db().0.lock_runtime();
566 let account_owner = runtime.authenticated_owner()?;
567 Ok(bcs::to_bytes(&account_owner)?)
568 }
569
570 ContractRuntimePrecompile::MessageOriginChainId => {
571 let mut runtime = context.db().0.lock_runtime();
572 let origin_chain_id = runtime.message_origin_chain_id()?;
573 Ok(bcs::to_bytes(&origin_chain_id)?)
574 }
575
576 ContractRuntimePrecompile::MessageIsBouncing => {
577 let mut runtime = context.db().0.lock_runtime();
578 let result = runtime.message_is_bouncing()?;
579 Ok(bcs::to_bytes(&result)?)
580 }
581 ContractRuntimePrecompile::MessageOriginTimestamp => {
582 let mut runtime = context.db().0.lock_runtime();
583 let result = runtime.message_origin_timestamp()?;
584 Ok(bcs::to_bytes(&result)?)
585 }
586 ContractRuntimePrecompile::AuthenticatedCallerId => {
587 let mut runtime = context.db().0.lock_runtime();
588 let application_id = runtime.authenticated_caller_id()?;
589 Ok(bcs::to_bytes(&application_id)?)
590 }
591 ContractRuntimePrecompile::SendMessage {
592 destination,
593 message,
594 } => {
595 let authenticated = true;
596 let is_tracked = true;
597 let grant = Resources::default();
598 let send_message_request = SendMessageRequest {
599 destination,
600 authenticated,
601 is_tracked,
602 grant,
603 message,
604 };
605 let mut runtime = context.db().0.lock_runtime();
606 runtime.send_message(send_message_request)?;
607 Ok(vec![])
608 }
609 ContractRuntimePrecompile::TryCallApplication { target, argument } => {
610 let authenticated = true;
611 let mut runtime = context.db().0.lock_runtime();
612 ensure!(
613 target != runtime.application_id()?,
614 EvmExecutionError::NoSelfCall
615 );
616 runtime.try_call_application(authenticated, target, argument)
617 }
618 ContractRuntimePrecompile::Emit { stream_name, value } => {
619 let mut runtime = context.db().0.lock_runtime();
620 let result = runtime.emit(stream_name, value)?;
621 Ok(bcs::to_bytes(&result)?)
622 }
623 ContractRuntimePrecompile::ReadEvent {
624 chain_id,
625 stream_name,
626 index,
627 } => {
628 let mut runtime = context.db().0.lock_runtime();
629 runtime.read_event(chain_id, stream_name, index)
630 }
631 ContractRuntimePrecompile::SubscribeToEvents {
632 chain_id,
633 application_id,
634 stream_name,
635 } => {
636 let mut runtime = context.db().0.lock_runtime();
637 runtime.subscribe_to_events(chain_id, application_id, stream_name)?;
638 Ok(vec![])
639 }
640 ContractRuntimePrecompile::UnsubscribeFromEvents {
641 chain_id,
642 application_id,
643 stream_name,
644 } => {
645 let mut runtime = context.db().0.lock_runtime();
646 runtime.unsubscribe_from_events(chain_id, application_id, stream_name)?;
647 Ok(vec![])
648 }
649 ContractRuntimePrecompile::QueryService {
650 application_id,
651 query,
652 } => {
653 let mut runtime = context.db().0.lock_runtime();
654 ensure!(
655 application_id != runtime.application_id()?,
656 EvmExecutionError::NoSelfCall
657 );
658 runtime.query_service(application_id, query)
659 }
660 ContractRuntimePrecompile::ValidationRound => {
661 let mut runtime = context.db().0.lock_runtime();
662 let value = runtime.validation_round()?;
663 Ok(bcs::to_bytes(&value)?)
664 }
665 ContractRuntimePrecompile::Transfer { account, amount } => {
666 if amount.0 != U256::ZERO {
667 let destination = {
668 let destination = get_evm_destination(context, account)?;
669 destination.unwrap_or(FAUCET_ADDRESS)
670 };
671 let application_id = {
672 let mut runtime = context.db().0.lock_runtime();
673 let application_id = runtime.application_id()?;
674 let source = application_id.into();
675 let value = Amount::try_from(amount.0).map_err(EvmExecutionError::from)?;
676 runtime.transfer(source, account, value)?;
677 application_id
678 };
679 let source: Address = application_id.evm_address();
680 revm_transfer(context, source, destination, amount.0)?;
681 }
682 Ok(vec![])
683 }
684 }
685 }
686
687 fn call_or_fail<Runtime: ContractRuntime>(
688 inputs: &InputsImpl,
689 context: &mut ContractCtx<'a, Runtime>,
690 ) -> Result<Vec<u8>, ExecutionError> {
691 let input = get_precompile_argument(context, inputs);
692 match bcs::from_bytes(&input)? {
693 RuntimePrecompile::Base(base_tag) => {
694 let mut runtime = context.db().0.lock_runtime();
695 base_runtime_call(&base_tag, runtime.deref_mut())
696 }
697 RuntimePrecompile::Contract(contract_tag) => {
698 Self::contract_runtime_call(contract_tag, context)
699 }
700 RuntimePrecompile::Service(_) => Err(EvmExecutionError::PrecompileError(
701 "Service tags are not available in GeneralContractCall".to_string(),
702 )
703 .into()),
704 }
705 }
706}
707
708#[derive(Debug, Default)]
709struct ServicePrecompile {
710 inner: EthPrecompiles,
711}
712
713impl<'a> ServicePrecompile {
714 fn service_runtime_call<Runtime: ServiceRuntime>(
715 request: ServiceRuntimePrecompile,
716 context: &mut ServiceCtx<'a, Runtime>,
717 ) -> Result<Vec<u8>, ExecutionError> {
718 let mut runtime = context.db().0.lock_runtime();
719 match request {
720 ServiceRuntimePrecompile::TryQueryApplication { target, argument } => {
721 ensure!(
722 target != runtime.application_id()?,
723 EvmExecutionError::NoSelfCall
724 );
725 runtime.try_query_application(target, argument)
726 }
727 }
728 }
729
730 fn call_or_fail<Runtime: ServiceRuntime>(
731 inputs: &InputsImpl,
732 context: &mut ServiceCtx<'a, Runtime>,
733 ) -> Result<Vec<u8>, ExecutionError> {
734 let input = get_precompile_argument(context, inputs);
735 match bcs::from_bytes(&input)? {
736 RuntimePrecompile::Base(base_tag) => {
737 let mut runtime = context.db().0.lock_runtime();
738 base_runtime_call(&base_tag, runtime.deref_mut())
739 }
740 RuntimePrecompile::Contract(_) => Err(EvmExecutionError::PrecompileError(
741 "Contract calls are not available in GeneralServiceCall".to_string(),
742 )
743 .into()),
744 RuntimePrecompile::Service(service_tag) => {
745 Self::service_runtime_call(service_tag, context)
746 }
747 }
748 }
749}
750
751impl<'a, Runtime: ServiceRuntime> PrecompileProvider<ServiceCtx<'a, Runtime>>
752 for ServicePrecompile
753{
754 type Output = InterpreterResult;
755
756 fn set_spec(
757 &mut self,
758 spec: <<ServiceCtx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec,
759 ) -> bool {
760 <EthPrecompiles as PrecompileProvider<ServiceCtx<'a, Runtime>>>::set_spec(
761 &mut self.inner,
762 spec,
763 )
764 }
765
766 fn run(
767 &mut self,
768 context: &mut ServiceCtx<'a, Runtime>,
769 address: &Address,
770 inputs: &InputsImpl,
771 is_static: bool,
772 gas_limit: u64,
773 ) -> Result<Option<InterpreterResult>, String> {
774 if address == &PRECOMPILE_ADDRESS {
775 let output = Self::call_or_fail(inputs, context)
776 .map_err(|error| format!("ServicePrecompile error: {error}"))?;
777 return Ok(Some(get_precompile_output(output, gas_limit)));
778 }
779 self.inner
780 .run(context, address, inputs, is_static, gas_limit)
781 }
782
783 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
784 let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
785 addresses.push(PRECOMPILE_ADDRESS);
786 Box::new(addresses.into_iter())
787 }
788
789 fn contains(&self, address: &Address) -> bool {
790 address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
791 }
792}
793
794fn map_result_create_outcome<Runtime: BaseRuntime>(
795 database: &InnerDatabase<Runtime>,
796 result: Result<Option<CreateOutcome>, ExecutionError>,
797) -> Option<CreateOutcome> {
798 match result {
799 Err(error) => {
800 database.insert_error(&error);
801 let result = InstructionResult::Revert;
803 let output = Bytes::default();
804 let gas = Gas::default();
805 let result = InterpreterResult {
806 result,
807 output,
808 gas,
809 };
810 Some(CreateOutcome {
811 result,
812 address: None,
813 })
814 }
815 Ok(result) => result,
816 }
817}
818
819fn map_result_call_outcome<Runtime: BaseRuntime>(
820 database: &InnerDatabase<Runtime>,
821 result: Result<Option<CallOutcome>, ExecutionError>,
822) -> Option<CallOutcome> {
823 match result {
824 Err(error) => {
825 database.insert_error(&error);
826 let result = InstructionResult::Revert;
828 let output = Bytes::default();
829 let gas = Gas::default();
830 let result = InterpreterResult {
831 result,
832 output,
833 gas,
834 };
835 let memory_offset = Range::default();
836 Some(CallOutcome {
837 result,
838 memory_offset,
839 })
840 }
841 Ok(result) => result,
842 }
843}
844
845struct CallInterceptorContract<Runtime> {
846 db: ContractDatabase<Runtime>,
847 contract_address: Address,
849 precompile_addresses: BTreeSet<Address>,
850 error: Arc<Mutex<Option<U256>>>,
851}
852
853impl<Runtime> Clone for CallInterceptorContract<Runtime> {
854 fn clone(&self) -> Self {
855 Self {
856 db: self.db.clone(),
857 contract_address: self.contract_address,
858 precompile_addresses: self.precompile_addresses.clone(),
859 error: self.error.clone(),
860 }
861 }
862}
863
864impl<'a, Runtime: ContractRuntime> Inspector<ContractCtx<'a, Runtime>>
865 for CallInterceptorContract<Runtime>
866{
867 fn create(
868 &mut self,
869 context: &mut ContractCtx<'a, Runtime>,
870 inputs: &mut CreateInputs,
871 ) -> Option<CreateOutcome> {
872 let result = self.create_or_fail(context, inputs);
873 map_result_create_outcome(&self.db.inner, result)
874 }
875
876 fn call(
877 &mut self,
878 context: &mut ContractCtx<'a, Runtime>,
879 inputs: &mut CallInputs,
880 ) -> Option<CallOutcome> {
881 let result = self.call_or_fail(context, inputs);
882 map_result_call_outcome(&self.db.inner, result)
883 }
884}
885
886impl<Runtime: ContractRuntime> CallInterceptorContract<Runtime> {
887 fn get_expected_application_id(
902 context: &mut ContractCtx<'_, Runtime>,
903 module_id: ModuleId,
904 num_apps: u32,
905 ) -> Result<ApplicationId, ExecutionError> {
906 let mut runtime = context.db().0.lock_runtime();
907 let chain_id = runtime.chain_id()?;
908 let block_height = runtime.block_height()?;
909 let application_index = runtime.peek_application_index()? + num_apps;
910 let parameters = JSON_EMPTY_VECTOR.to_vec(); let required_application_ids = Vec::new();
912 let application_description = ApplicationDescription {
913 module_id,
914 creator_chain_id: chain_id,
915 block_height,
916 application_index,
917 parameters: parameters.clone(),
918 required_application_ids,
919 };
920 Ok(ApplicationId::from(&application_description))
921 }
922
923 fn publish_create_inputs(
926 context: &mut ContractCtx<'_, Runtime>,
927 inputs: &CreateInputs,
928 ) -> Result<ModuleId, ExecutionError> {
929 let contract = linera_base::data_types::Bytecode::new(inputs.init_code.to_vec());
930 let service = linera_base::data_types::Bytecode::new(vec![]);
931 let mut runtime = context.db().0.lock_runtime();
932 runtime.publish_module(contract, service, VmRuntime::Evm, None)
933 }
934
935 fn create_or_fail(
1028 &mut self,
1029 context: &mut ContractCtx<'_, Runtime>,
1030 inputs: &mut CreateInputs,
1031 ) -> Result<Option<CreateOutcome>, ExecutionError> {
1032 if !self.db.inner.is_revm_instantiated {
1033 self.db.inner.is_revm_instantiated = true;
1034 inputs.scheme = CreateScheme::Custom {
1035 address: self.contract_address,
1036 };
1037 return Ok(None);
1038 }
1039 let module_id = Self::publish_create_inputs(context, inputs)?;
1040 let mut map = self.db.modules.lock().unwrap();
1041 let num_apps = u32::try_from(map.len()).map_err(|_| ArithmeticError::Overflow)?;
1042 let expected_application_id =
1043 Self::get_expected_application_id(context, module_id, num_apps)?;
1044 map.insert(expected_application_id, (module_id, num_apps));
1045 let address = expected_application_id.evm_address();
1046 if inputs.value != U256::ZERO {
1047 let value = Amount::try_from(inputs.value).map_err(EvmExecutionError::from)?;
1048 let mut runtime = context.db().0.lock_runtime();
1049 let application_id = runtime.application_id()?;
1050 let source = application_id.into();
1051 let chain_id = runtime.chain_id()?;
1052 let account = identifiers::Account {
1053 chain_id,
1054 owner: expected_application_id.into(),
1055 };
1056 runtime.transfer(source, account, value)?;
1057 }
1058 inputs.scheme = CreateScheme::Custom { address };
1059 Ok(None)
1060 }
1061
1062 fn call_or_fail(
1082 &self,
1083 _context: &mut ContractCtx<'_, Runtime>,
1084 inputs: &CallInputs,
1085 ) -> Result<Option<CallOutcome>, ExecutionError> {
1086 let is_precompile = self.precompile_addresses.contains(&inputs.target_address);
1087 let is_first_call = inputs.target_address == self.contract_address;
1088 if is_precompile {
1089 if let CallValue::Transfer(value) = inputs.value {
1090 ensure!(
1091 value == U256::ZERO,
1092 EvmExecutionError::NonZeroTransferPrecompile
1093 );
1094 }
1095 }
1096 if is_precompile || is_first_call {
1097 return Ok(None);
1099 }
1100 if let CallValue::Transfer(value) = inputs.value {
1102 if value != U256::ZERO {
1103 let source: AccountOwner = inputs.caller.into();
1104 let owner: AccountOwner = inputs.bytecode_address.into();
1105 let mut runtime = self.db.lock_runtime();
1106 let amount = Amount::try_from(value).map_err(EvmExecutionError::from)?;
1107 let chain_id = runtime.chain_id()?;
1108 let destination = Account { chain_id, owner };
1109 runtime.transfer(source, destination, amount)?;
1110 }
1111 }
1112 Ok(None)
1114 }
1115}
1116
1117struct CallInterceptorService<Runtime> {
1118 db: ServiceDatabase<Runtime>,
1119 contract_address: Address,
1121 precompile_addresses: BTreeSet<Address>,
1122}
1123
1124impl<Runtime> Clone for CallInterceptorService<Runtime> {
1125 fn clone(&self) -> Self {
1126 Self {
1127 db: self.db.clone(),
1128 contract_address: self.contract_address,
1129 precompile_addresses: self.precompile_addresses.clone(),
1130 }
1131 }
1132}
1133
1134impl<'a, Runtime: ServiceRuntime> Inspector<ServiceCtx<'a, Runtime>>
1135 for CallInterceptorService<Runtime>
1136{
1137 fn create(
1139 &mut self,
1140 context: &mut ServiceCtx<'a, Runtime>,
1141 inputs: &mut CreateInputs,
1142 ) -> Option<CreateOutcome> {
1143 let result = self.create_or_fail(context, inputs);
1144 map_result_create_outcome(&self.db.inner, result)
1145 }
1146}
1147
1148impl<Runtime: ServiceRuntime> CallInterceptorService<Runtime> {
1149 fn create_or_fail(
1170 &mut self,
1171 _context: &ServiceCtx<'_, Runtime>,
1172 inputs: &mut CreateInputs,
1173 ) -> Result<Option<CreateOutcome>, ExecutionError> {
1174 if !self.db.inner.is_revm_instantiated {
1175 self.db.inner.is_revm_instantiated = true;
1176 inputs.scheme = CreateScheme::Custom {
1177 address: self.contract_address,
1178 };
1179 Ok(None)
1180 } else {
1181 Err(EvmExecutionError::NoContractCreationInService.into())
1182 }
1183 }
1184}
1185
1186pub struct RevmContractInstance<Runtime> {
1187 module: Vec<u8>,
1188 db: ContractDatabase<Runtime>,
1189}
1190
1191#[derive(Debug)]
1193enum EvmTxKind {
1194 Create,
1196 Call,
1198}
1199
1200#[derive(Debug)]
1202struct ExecutionResultSuccess {
1203 gas_final: u64,
1205 logs: Vec<Log>,
1207 output: Output,
1209}
1210
1211impl ExecutionResultSuccess {
1212 fn output_and_logs(self) -> (u64, Vec<u8>, Vec<Log>) {
1213 let Output::Call(output) = self.output else {
1214 unreachable!("The output should have been created from a EvmTxKind::Call");
1215 };
1216 let output = output.as_ref().to_vec();
1217 (self.gas_final, output, self.logs)
1218 }
1219
1220 fn check_contract_initialization(&self, expected_address: Address) -> Result<(), String> {
1222 let Output::Create(_, contract_address) = self.output else {
1224 return Err("Input should be ExmTxKind::Create".to_string());
1225 };
1226 let contract_address = contract_address.ok_or("Deployment failed")?;
1228 if contract_address == expected_address {
1230 Ok(())
1231 } else {
1232 Err("Contract address is not the same as ApplicationId".to_string())
1233 }
1234 }
1235}
1236
1237impl<Runtime> UserContract for RevmContractInstance<Runtime>
1238where
1239 Runtime: ContractRuntime,
1240{
1241 fn instantiate(&mut self, argument: Vec<u8>) -> Result<(), ExecutionError> {
1242 self.db.inner.set_contract_address()?;
1243 let caller = self.get_msg_address()?;
1244 let instantiation_argument = serde_json::from_slice::<EvmInstantiation>(&argument)?;
1245 if let Some(remainder) = instantiation_argument
1248 .argument
1249 .as_slice()
1250 .strip_prefix(ALREADY_CREATED_CONTRACT_SELECTOR)
1251 {
1252 let account = bcs::from_bytes::<revm_state::Account>(remainder)?;
1253 return self.db.commit_contract_changes(&account);
1254 }
1255 self.initialize_contract(instantiation_argument.value, caller)?;
1256 if has_selector(&self.module, INSTANTIATE_SELECTOR) {
1257 let argument = get_revm_instantiation_bytes(instantiation_argument.argument);
1258 let result = self.transact_commit(&EvmTxKind::Call, argument, U256::ZERO, caller)?;
1259 self.write_logs(&result.logs, "instantiate")?;
1260 }
1261 Ok(())
1262 }
1263
1264 fn execute_operation(&mut self, operation: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1277 self.db.inner.set_contract_address()?;
1278 ensure_message_length(operation.len(), 4)?;
1279 if operation == GET_ACCOUNT_INFO_SELECTOR {
1280 let account_info = self.db.inner.get_account_info()?;
1281 return Ok(bcs::to_bytes(&account_info)?);
1282 }
1283 if let Some(remainder) = operation
1284 .as_slice()
1285 .strip_prefix(GET_CONTRACT_STORAGE_SELECTOR)
1286 {
1287 let index = bcs::from_bytes(remainder)?;
1288 let value = self.db.inner.read_from_local_storage(index)?;
1289 return Ok(bcs::to_bytes(&value)?);
1290 }
1291 if let Some(remainder) = operation
1292 .as_slice()
1293 .strip_prefix(COMMIT_CONTRACT_CHANGES_SELECTOR)
1294 {
1295 let account = bcs::from_bytes::<revm_state::Account>(remainder)?;
1296 self.db.commit_contract_changes(&account)?;
1297 return Ok(Vec::new());
1298 }
1299 let caller = self.get_msg_address()?;
1300 forbid_execute_operation_origin(&operation[..4])?;
1301 let evm_call = bcs::from_bytes::<EvmOperation>(&operation)?;
1302 let result = self.init_transact_commit(evm_call.argument, evm_call.value, caller)?;
1303 let (gas_final, output, logs) = result.output_and_logs();
1304 self.consume_fuel(gas_final)?;
1305 self.write_logs(&logs, "operation")?;
1306 Ok(output)
1307 }
1308
1309 fn execute_message(&mut self, message: Vec<u8>) -> Result<(), ExecutionError> {
1310 self.db.inner.set_contract_address()?;
1311 ensure_selector_presence(
1312 &self.module,
1313 EXECUTE_MESSAGE_SELECTOR,
1314 "function execute_message(bytes)",
1315 )?;
1316 let operation = get_revm_execute_message_bytes(message);
1317 let caller = self.get_msg_address()?;
1318 let value = U256::ZERO;
1319 self.execute_no_return_operation(operation, "message", value, caller)
1320 }
1321
1322 fn process_streams(&mut self, streams: Vec<StreamUpdate>) -> Result<(), ExecutionError> {
1323 self.db.inner.set_contract_address()?;
1324 let operation = get_revm_process_streams_bytes(streams);
1325 ensure_selector_presence(
1326 &self.module,
1327 PROCESS_STREAMS_SELECTOR,
1328 "function process_streams(Linera.StreamUpdate[] memory streams)",
1329 )?;
1330 let caller = Address::ZERO;
1332 let value = U256::ZERO;
1333 self.execute_no_return_operation(operation, "process_streams", value, caller)
1334 }
1335
1336 fn finalize(&mut self) -> Result<(), ExecutionError> {
1337 Ok(())
1338 }
1339}
1340
1341fn process_execution_result(
1342 result: ExecutionResult,
1343) -> Result<ExecutionResultSuccess, EvmExecutionError> {
1344 match result {
1345 ExecutionResult::Success {
1346 gas_used,
1347 gas_refunded,
1348 logs,
1349 output,
1350 ..
1351 } => {
1352 let max_refund = gas_used / 5;
1357 let actual_refund = gas_refunded.min(max_refund);
1358 let gas_final = gas_used - actual_refund;
1359 Ok(ExecutionResultSuccess {
1360 gas_final,
1361 logs,
1362 output,
1363 })
1364 }
1365 ExecutionResult::Revert { gas_used, output } => {
1366 Err(EvmExecutionError::Revert { gas_used, output })
1367 }
1368 ExecutionResult::Halt { gas_used, reason } => {
1369 Err(EvmExecutionError::Halt { gas_used, reason })
1370 }
1371 }
1372}
1373
1374impl<Runtime> RevmContractInstance<Runtime>
1375where
1376 Runtime: ContractRuntime,
1377{
1378 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1379 let db = ContractDatabase::new(runtime);
1380 Self { module, db }
1381 }
1382
1383 fn execute_no_return_operation(
1384 &mut self,
1385 operation: Vec<u8>,
1386 origin: &str,
1387 value: U256,
1388 caller: Address,
1389 ) -> Result<(), ExecutionError> {
1390 let result = self.init_transact_commit(operation, value, caller)?;
1391 let (gas_final, output, logs) = result.output_and_logs();
1392 self.consume_fuel(gas_final)?;
1393 self.write_logs(&logs, origin)?;
1394 assert_eq!(output.len(), 0);
1395 Ok(())
1396 }
1397
1398 fn init_transact_commit(
1400 &mut self,
1401 vec: Vec<u8>,
1402 value: U256,
1403 caller: Address,
1404 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1405 if !self.db.inner.set_is_initialized()? {
1409 self.initialize_contract(U256::ZERO, caller)?;
1410 }
1411 self.transact_commit(&EvmTxKind::Call, vec, value, caller)
1412 }
1413
1414 fn initialize_contract(&mut self, value: U256, caller: Address) -> Result<(), ExecutionError> {
1416 let mut vec_init = self.module.clone();
1417 let constructor_argument = self.db.inner.constructor_argument()?;
1418 vec_init.extend_from_slice(&constructor_argument);
1419 let result = self.transact_commit(&EvmTxKind::Create, vec_init, value, caller)?;
1420 result
1421 .check_contract_initialization(self.db.inner.contract_address)
1422 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1423 self.write_logs(&result.logs, "deploy")
1424 }
1425
1426 fn get_msg_address(&self) -> Result<Address, ExecutionError> {
1439 let mut runtime = self.db.lock_runtime();
1440 let application_id = runtime.authenticated_caller_id()?;
1441 if let Some(application_id) = application_id {
1442 return Ok(if application_id.is_evm() {
1443 application_id.evm_address()
1444 } else {
1445 Address::ZERO
1446 });
1447 };
1448 let account_owner = runtime.authenticated_owner()?;
1449 if let Some(AccountOwner::Address20(address)) = account_owner {
1450 return Ok(Address::from(address));
1451 };
1452 Ok(ZERO_ADDRESS)
1453 }
1454
1455 fn transact_commit(
1456 &mut self,
1457 tx_kind: &EvmTxKind,
1458 input: Vec<u8>,
1459 value: U256,
1460 caller: Address,
1461 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1462 let contract_address = self.db.inner.contract_address;
1463 self.db.inner.caller = caller;
1464 self.db.inner.value = value;
1465 self.db.inner.deposit_funds()?;
1466 let data = Bytes::from(input);
1467 let kind = match tx_kind {
1468 EvmTxKind::Create => TxKind::Create,
1469 EvmTxKind::Call => TxKind::Call(contract_address),
1470 };
1471 let inspector = CallInterceptorContract {
1472 db: self.db.clone(),
1473 contract_address,
1474 precompile_addresses: precompile_addresses(),
1475 error: Arc::new(Mutex::new(None)),
1476 };
1477 let block_env = self.db.get_block_env()?;
1478 let (max_size_evm_contract, gas_limit) = {
1479 let mut runtime = self.db.lock_runtime();
1480 let gas_limit = runtime.remaining_fuel(VmRuntime::Evm)?;
1481 let max_size_evm_contract =
1482 usize::try_from(runtime.maximum_blob_size()?).unwrap_or(usize::MAX);
1483 (max_size_evm_contract, gas_limit)
1484 };
1485 let nonce = self.db.get_nonce(&caller)?;
1486 let result = {
1487 let mut ctx: revm_context::Context<
1488 BlockEnv,
1489 _,
1490 _,
1491 _,
1492 Journal<WrapDatabaseRef<&mut ContractDatabase<Runtime>>>,
1493 (),
1494 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1495 WrapDatabaseRef(&mut self.db),
1496 SpecId::PRAGUE,
1497 )
1498 .with_block(block_env);
1499 ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1500 let instructions = EthInstructions::new_mainnet();
1501 let mut evm = Evm::new_with_inspector(
1502 ctx,
1503 inspector.clone(),
1504 instructions,
1505 ContractPrecompile::default(),
1506 );
1507 evm.inspect_commit(
1508 TxEnv {
1509 kind,
1510 data,
1511 nonce,
1512 gas_limit,
1513 caller,
1514 value,
1515 ..TxEnv::default()
1516 },
1517 inspector.clone(),
1518 )
1519 .map_err(|error| {
1520 let error = format!("{error:?}");
1521 EvmExecutionError::TransactCommitError(error)
1522 })
1523 }?;
1524 self.db.inner.process_any_error()?;
1525 self.db.commit_changes()?;
1526 Ok(process_execution_result(result)?)
1527 }
1528
1529 fn consume_fuel(&self, gas_final: u64) -> Result<(), ExecutionError> {
1530 let mut runtime = self.db.lock_runtime();
1531 runtime.consume_fuel(gas_final, VmRuntime::Evm)
1532 }
1533
1534 fn write_logs(&self, logs: &[Log], origin: &str) -> Result<(), ExecutionError> {
1535 if !logs.is_empty() {
1537 let mut runtime = self.db.lock_runtime();
1538 let block_height = runtime.block_height()?;
1539 let stream_name = bcs::to_bytes("ethereum_event")?;
1540 let stream_name = StreamName(stream_name);
1541 for log in logs {
1542 let value = bcs::to_bytes(&(origin, block_height.0, log))?;
1543 runtime.emit(stream_name.clone(), value)?;
1544 }
1545 }
1546 Ok(())
1547 }
1548}
1549
1550pub struct RevmServiceInstance<Runtime> {
1551 module: Vec<u8>,
1552 db: ServiceDatabase<Runtime>,
1553}
1554
1555impl<Runtime> RevmServiceInstance<Runtime>
1556where
1557 Runtime: ServiceRuntime,
1558{
1559 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1560 let db = ServiceDatabase::new(runtime);
1561 Self { module, db }
1562 }
1563}
1564
1565impl<Runtime> UserService for RevmServiceInstance<Runtime>
1566where
1567 Runtime: ServiceRuntime,
1568{
1569 fn handle_query(&mut self, argument: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1570 self.db.inner.set_contract_address()?;
1571 let evm_query = serde_json::from_slice(&argument)?;
1572 let query = match evm_query {
1573 EvmQuery::AccountInfo => {
1574 let account_info = self.db.inner.get_account_info()?;
1575 return Ok(serde_json::to_vec(&account_info)?);
1576 }
1577 EvmQuery::Storage(index) => {
1578 let value = self.db.inner.read_from_local_storage(index)?;
1579 return Ok(serde_json::to_vec(&value)?);
1580 }
1581 EvmQuery::Query(vec) => vec,
1582 EvmQuery::Operation(operation) => {
1583 let mut runtime = self.db.lock_runtime();
1584 runtime.schedule_operation(operation)?;
1585 return Ok(Vec::new());
1586 }
1587 EvmQuery::Operations(operations) => {
1588 let mut runtime = self.db.lock_runtime();
1589 for operation in operations {
1590 runtime.schedule_operation(operation)?;
1591 }
1592 return Ok(Vec::new());
1593 }
1594 };
1595
1596 ensure_message_length(query.len(), 4)?;
1597 let result = self.init_transact(query)?;
1601 let (_gas_final, output, _logs) = result.output_and_logs();
1602 let answer = serde_json::to_vec(&output)?;
1603 Ok(answer)
1604 }
1605}
1606
1607impl<Runtime> RevmServiceInstance<Runtime>
1608where
1609 Runtime: ServiceRuntime,
1610{
1611 fn init_transact(&mut self, vec: Vec<u8>) -> Result<ExecutionResultSuccess, ExecutionError> {
1612 let contract_address = self.db.inner.contract_address;
1616 if !self.db.inner.set_is_initialized()? {
1617 let changes = {
1618 let mut vec_init = self.module.clone();
1619 let constructor_argument = self.db.inner.constructor_argument()?;
1620 vec_init.extend_from_slice(&constructor_argument);
1621 let (result, changes) = self.transact(TxKind::Create, vec_init)?;
1622 result
1623 .check_contract_initialization(contract_address)
1624 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1625 changes
1626 };
1627 self.db.inner.changes = changes;
1628 }
1629 ensure_message_length(vec.len(), 4)?;
1630 forbid_execute_operation_origin(&vec[..4])?;
1631 let kind = TxKind::Call(contract_address);
1632 let (execution_result, _) = self.transact(kind, vec)?;
1633 Ok(execution_result)
1634 }
1635
1636 fn transact(
1637 &mut self,
1638 kind: TxKind,
1639 input: Vec<u8>,
1640 ) -> Result<(ExecutionResultSuccess, EvmState), ExecutionError> {
1641 let contract_address = self.db.inner.contract_address;
1642 let caller = SERVICE_ADDRESS;
1643 let value = U256::ZERO;
1644 self.db.inner.caller = caller;
1645 self.db.inner.value = value;
1646 let data = Bytes::from(input);
1647 let block_env = self.db.get_block_env()?;
1648 let inspector = CallInterceptorService {
1649 db: self.db.clone(),
1650 contract_address,
1651 precompile_addresses: precompile_addresses(),
1652 };
1653 let max_size_evm_contract = {
1654 let mut runtime = self.db.lock_runtime();
1655 usize::try_from(runtime.maximum_blob_size()?).unwrap_or(usize::MAX)
1656 };
1657 let nonce = self.db.get_nonce(&caller)?;
1658 let result_state = {
1659 let mut ctx: revm_context::Context<
1660 BlockEnv,
1661 _,
1662 _,
1663 _,
1664 Journal<WrapDatabaseRef<&mut ServiceDatabase<Runtime>>>,
1665 (),
1666 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1667 WrapDatabaseRef(&mut self.db),
1668 SpecId::PRAGUE,
1669 )
1670 .with_block(block_env);
1671 ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1672 let instructions = EthInstructions::new_mainnet();
1673 let mut evm = Evm::new_with_inspector(
1674 ctx,
1675 inspector.clone(),
1676 instructions,
1677 ServicePrecompile::default(),
1678 );
1679 evm.inspect(
1680 TxEnv {
1681 kind,
1682 data,
1683 nonce,
1684 value,
1685 caller,
1686 gas_limit: EVM_SERVICE_GAS_LIMIT,
1687 ..TxEnv::default()
1688 },
1689 inspector,
1690 )
1691 .map_err(|error| {
1692 let error = format!("{error:?}");
1693 EvmExecutionError::TransactCommitError(error)
1694 })
1695 }?;
1696 self.db.inner.process_any_error()?;
1697 let result = process_execution_result(result_state.result)?;
1698 Ok((result, result_state.state))
1699 }
1700}