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, Bytecode, Resources, SendMessageRequest, StreamUpdate,
46 },
47 ensure,
48 identifiers::{self, Account, AccountOwner, ApplicationId, ChainId, ModuleId, StreamName},
49 vm::{EvmInstantiation, EvmOperation, EvmQuery, VmRuntime},
50};
51use revm::{primitives::Bytes, InspectCommitEvm, InspectEvm, Inspector};
52use revm_context::{
53 result::{ExecutionResult, Output, SuccessReason},
54 BlockEnv, Cfg, ContextTr, Evm, Journal, JournalTr, LocalContextTr as _, TxEnv,
55};
56use revm_database::WrapDatabaseRef;
57use revm_handler::{
58 instructions::EthInstructions, EthPrecompiles, MainnetContext, PrecompileProvider,
59};
60use revm_interpreter::{
61 CallInput, CallInputs, CallOutcome, CallValue, CreateInputs, CreateOutcome, CreateScheme, Gas,
62 InputsImpl, InstructionResult, InterpreterResult,
63};
64use revm_primitives::{hardfork::SpecId, Address, Log, TxKind, U256};
65use revm_state::EvmState;
66use serde::{Deserialize, Serialize};
67
68use crate::{
69 evm::{
70 data_types::AmountU256,
71 database::{ContractDatabase, InnerDatabase, ServiceDatabase, EVM_SERVICE_GAS_LIMIT},
72 inputs::{
73 ensure_message_length, ensure_selector_presence, forbid_execute_operation_origin,
74 get_revm_execute_message_bytes, get_revm_instantiation_bytes,
75 get_revm_process_streams_bytes, has_selector, EXECUTE_MESSAGE_SELECTOR, FAUCET_ADDRESS,
76 INSTANTIATE_SELECTOR, PRECOMPILE_ADDRESS, PROCESS_STREAMS_SELECTOR, SERVICE_ADDRESS,
77 ZERO_ADDRESS,
78 },
79 },
80 BaseRuntime, ContractRuntime, ContractSyncRuntimeHandle, DataBlobHash, EvmExecutionError,
81 EvmRuntime, ExecutionError, ServiceRuntime, ServiceSyncRuntimeHandle, UserContract,
82 UserContractInstance, UserContractModule, UserService, UserServiceInstance, UserServiceModule,
83};
84
85pub const GET_ACCOUNT_INFO_SELECTOR: &[u8] = &[21, 34, 55, 89];
91
92pub const GET_CONTRACT_STORAGE_SELECTOR: &[u8] = &[5, 14, 42, 132];
98
99pub const COMMIT_CONTRACT_CHANGES_SELECTOR: &[u8] = &[5, 15, 52, 203];
105
106pub const ALREADY_CREATED_CONTRACT_SELECTOR: &[u8] = &[23, 47, 106, 235];
112
113pub const JSON_EMPTY_VECTOR: &[u8] = &[91, 93];
117
118#[cfg(with_metrics)]
119mod metrics {
120 use std::sync::LazyLock;
121
122 use linera_base::prometheus_util::{exponential_bucket_latencies, register_histogram_vec};
123 use prometheus::HistogramVec;
124
125 pub static CONTRACT_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
126 register_histogram_vec(
127 "evm_contract_instantiation_latency",
128 "EVM contract instantiation latency",
129 &[],
130 exponential_bucket_latencies(1.0),
131 )
132 });
133
134 pub static SERVICE_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
135 register_histogram_vec(
136 "evm_service_instantiation_latency",
137 "EVM service instantiation latency",
138 &[],
139 exponential_bucket_latencies(1.0),
140 )
141 });
142}
143
144#[derive(Clone)]
145pub enum EvmContractModule {
146 #[cfg(with_revm)]
147 Revm { module: Vec<u8> },
148}
149
150impl EvmContractModule {
151 pub fn new(
153 contract_bytecode: Bytecode,
154 runtime: EvmRuntime,
155 ) -> Result<Self, EvmExecutionError> {
156 match runtime {
157 #[cfg(with_revm)]
158 EvmRuntime::Revm => Self::from_revm(contract_bytecode),
159 }
160 }
161
162 #[cfg(with_fs)]
164 pub async fn from_file(
165 contract_bytecode_file: impl AsRef<std::path::Path>,
166 runtime: EvmRuntime,
167 ) -> Result<Self, EvmExecutionError> {
168 Self::new(
169 Bytecode::load_from_file(contract_bytecode_file)
170 .await
171 .map_err(anyhow::Error::from)
172 .map_err(EvmExecutionError::LoadContractModule)?,
173 runtime,
174 )
175 }
176
177 pub fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
179 let module = contract_bytecode.bytes;
180 Ok(EvmContractModule::Revm { module })
181 }
182}
183
184impl UserContractModule for EvmContractModule {
185 fn instantiate(
186 &self,
187 runtime: ContractSyncRuntimeHandle,
188 ) -> Result<UserContractInstance, ExecutionError> {
189 #[cfg(with_metrics)]
190 let _instantiation_latency = metrics::CONTRACT_INSTANTIATION_LATENCY.measure_latency();
191
192 let instance: UserContractInstance = match self {
193 #[cfg(with_revm)]
194 EvmContractModule::Revm { module } => {
195 Box::new(RevmContractInstance::prepare(module.to_vec(), runtime))
196 }
197 };
198
199 Ok(instance)
200 }
201}
202
203#[derive(Clone)]
205pub enum EvmServiceModule {
206 #[cfg(with_revm)]
207 Revm { module: Vec<u8> },
208}
209
210impl EvmServiceModule {
211 pub fn new(service_bytecode: Bytecode, runtime: EvmRuntime) -> Result<Self, EvmExecutionError> {
213 match runtime {
214 #[cfg(with_revm)]
215 EvmRuntime::Revm => Self::from_revm(service_bytecode),
216 }
217 }
218
219 #[cfg(with_fs)]
221 pub async fn from_file(
222 service_bytecode_file: impl AsRef<std::path::Path>,
223 runtime: EvmRuntime,
224 ) -> Result<Self, EvmExecutionError> {
225 Self::new(
226 Bytecode::load_from_file(service_bytecode_file)
227 .await
228 .map_err(anyhow::Error::from)
229 .map_err(EvmExecutionError::LoadServiceModule)?,
230 runtime,
231 )
232 }
233
234 pub fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
236 let module = contract_bytecode.bytes;
237 Ok(EvmServiceModule::Revm { module })
238 }
239}
240
241impl UserServiceModule for EvmServiceModule {
242 fn instantiate(
243 &self,
244 runtime: ServiceSyncRuntimeHandle,
245 ) -> Result<UserServiceInstance, ExecutionError> {
246 #[cfg(with_metrics)]
247 let _instantiation_latency = metrics::SERVICE_INSTANTIATION_LATENCY.measure_latency();
248
249 let instance: UserServiceInstance = match self {
250 #[cfg(with_revm)]
251 EvmServiceModule::Revm { module } => {
252 Box::new(RevmServiceInstance::prepare(module.to_vec(), runtime))
253 }
254 };
255
256 Ok(instance)
257 }
258}
259
260type ContractCtx<'a, Runtime> = MainnetContext<WrapDatabaseRef<&'a mut ContractDatabase<Runtime>>>;
261
262type ServiceCtx<'a, Runtime> = MainnetContext<WrapDatabaseRef<&'a mut ServiceDatabase<Runtime>>>;
263
264pub fn address_to_user_application_id(address: Address) -> ApplicationId {
265 let mut vec = vec![0_u8; 32];
266 vec[..20].copy_from_slice(address.as_ref());
267 ApplicationId::new(CryptoHash::try_from(&vec as &[u8]).unwrap())
268}
269
270#[derive(Debug, Serialize, Deserialize)]
272enum BaseRuntimePrecompile {
273 ChainId,
275 BlockHeight,
277 ApplicationCreatorChainId,
279 ReadSystemTimestamp,
281 ReadChainBalance,
283 ReadOwnerBalance(AccountOwner),
285 ReadOwnerBalances,
287 ReadBalanceOwners,
289 ChainOwnership,
291 ReadDataBlob(DataBlobHash),
293 AssertDataBlobExists(DataBlobHash),
295}
296
297#[derive(Debug, Serialize, Deserialize)]
299enum ContractRuntimePrecompile {
300 AuthenticatedOwner,
302 MessageOriginChainId,
304 MessageIsBouncing,
306 AuthenticatedCallerId,
308 SendMessage {
310 destination: ChainId,
311 message: Vec<u8>,
312 },
313 TryCallApplication {
315 target: ApplicationId,
316 argument: Vec<u8>,
317 },
318 Emit {
320 stream_name: StreamName,
321 value: Vec<u8>,
322 },
323 ReadEvent {
325 chain_id: ChainId,
326 stream_name: StreamName,
327 index: u32,
328 },
329 SubscribeToEvents {
331 chain_id: ChainId,
332 application_id: ApplicationId,
333 stream_name: StreamName,
334 },
335 UnsubscribeFromEvents {
337 chain_id: ChainId,
338 application_id: ApplicationId,
339 stream_name: StreamName,
340 },
341 QueryService {
343 application_id: ApplicationId,
344 query: Vec<u8>,
345 },
346 ValidationRound,
348 Transfer {
350 account: Account,
351 amount: AmountU256,
352 },
353}
354
355#[derive(Debug, Serialize, Deserialize)]
357enum ServiceRuntimePrecompile {
358 TryQueryApplication {
360 target: ApplicationId,
361 argument: Vec<u8>,
362 },
363}
364
365#[derive(Debug, Serialize, Deserialize)]
367enum RuntimePrecompile {
368 Base(BaseRuntimePrecompile),
369 Contract(ContractRuntimePrecompile),
370 Service(ServiceRuntimePrecompile),
371}
372
373fn get_precompile_output(output: Vec<u8>, gas_limit: u64) -> InterpreterResult {
391 let output = Bytes::from(output);
392 let result = InstructionResult::default();
393 let gas = Gas::new(gas_limit);
394 InterpreterResult {
395 result,
396 output,
397 gas,
398 }
399}
400
401fn get_argument<Ctx: ContextTr>(context: &mut Ctx, input: &CallInput) -> Vec<u8> {
402 match input {
403 CallInput::Bytes(bytes) => bytes.to_vec(),
404 CallInput::SharedBuffer(range) => {
405 match context.local().shared_memory_buffer_slice(range.clone()) {
406 None => Vec::new(),
407 Some(slice) => slice.to_vec(),
408 }
409 }
410 }
411}
412
413fn get_precompile_argument<Ctx: ContextTr>(
414 context: &mut Ctx,
415 inputs: &InputsImpl,
416) -> Result<Vec<u8>, ExecutionError> {
417 Ok(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::AuthenticatedCallerId => {
582 let mut runtime = context.db().0.lock_runtime();
583 let application_id = runtime.authenticated_caller_id()?;
584 Ok(bcs::to_bytes(&application_id)?)
585 }
586 ContractRuntimePrecompile::SendMessage {
587 destination,
588 message,
589 } => {
590 let authenticated = true;
591 let is_tracked = true;
592 let grant = Resources::default();
593 let send_message_request = SendMessageRequest {
594 destination,
595 authenticated,
596 is_tracked,
597 grant,
598 message,
599 };
600 let mut runtime = context.db().0.lock_runtime();
601 runtime.send_message(send_message_request)?;
602 Ok(vec![])
603 }
604 ContractRuntimePrecompile::TryCallApplication { target, argument } => {
605 let authenticated = true;
606 let mut runtime = context.db().0.lock_runtime();
607 ensure!(
608 target != runtime.application_id()?,
609 EvmExecutionError::NoSelfCall
610 );
611 runtime.try_call_application(authenticated, target, argument)
612 }
613 ContractRuntimePrecompile::Emit { stream_name, value } => {
614 let mut runtime = context.db().0.lock_runtime();
615 let result = runtime.emit(stream_name, value)?;
616 Ok(bcs::to_bytes(&result)?)
617 }
618 ContractRuntimePrecompile::ReadEvent {
619 chain_id,
620 stream_name,
621 index,
622 } => {
623 let mut runtime = context.db().0.lock_runtime();
624 runtime.read_event(chain_id, stream_name, index)
625 }
626 ContractRuntimePrecompile::SubscribeToEvents {
627 chain_id,
628 application_id,
629 stream_name,
630 } => {
631 let mut runtime = context.db().0.lock_runtime();
632 runtime.subscribe_to_events(chain_id, application_id, stream_name)?;
633 Ok(vec![])
634 }
635 ContractRuntimePrecompile::UnsubscribeFromEvents {
636 chain_id,
637 application_id,
638 stream_name,
639 } => {
640 let mut runtime = context.db().0.lock_runtime();
641 runtime.unsubscribe_from_events(chain_id, application_id, stream_name)?;
642 Ok(vec![])
643 }
644 ContractRuntimePrecompile::QueryService {
645 application_id,
646 query,
647 } => {
648 let mut runtime = context.db().0.lock_runtime();
649 ensure!(
650 application_id != runtime.application_id()?,
651 EvmExecutionError::NoSelfCall
652 );
653 runtime.query_service(application_id, query)
654 }
655 ContractRuntimePrecompile::ValidationRound => {
656 let mut runtime = context.db().0.lock_runtime();
657 let value = runtime.validation_round()?;
658 Ok(bcs::to_bytes(&value)?)
659 }
660 ContractRuntimePrecompile::Transfer { account, amount } => {
661 if amount.0 != U256::ZERO {
662 let destination = {
663 let destination = get_evm_destination(context, account)?;
664 destination.unwrap_or(FAUCET_ADDRESS)
665 };
666 let application_id = {
667 let mut runtime = context.db().0.lock_runtime();
668 let application_id = runtime.application_id()?;
669 let source = application_id.into();
670 let value = Amount::try_from(amount.0).map_err(EvmExecutionError::from)?;
671 runtime.transfer(source, account, value)?;
672 application_id
673 };
674 let source: Address = application_id.evm_address();
675 revm_transfer(context, source, destination, amount.0)?;
676 }
677 Ok(vec![])
678 }
679 }
680 }
681
682 fn call_or_fail<Runtime: ContractRuntime>(
683 inputs: &InputsImpl,
684 context: &mut ContractCtx<'a, Runtime>,
685 ) -> Result<Vec<u8>, ExecutionError> {
686 let input = get_precompile_argument(context, inputs)?;
687 match bcs::from_bytes(&input)? {
688 RuntimePrecompile::Base(base_tag) => {
689 let mut runtime = context.db().0.lock_runtime();
690 base_runtime_call(base_tag, runtime.deref_mut())
691 }
692 RuntimePrecompile::Contract(contract_tag) => {
693 Self::contract_runtime_call(contract_tag, context)
694 }
695 RuntimePrecompile::Service(_) => Err(EvmExecutionError::PrecompileError(
696 "Service tags are not available in GeneralContractCall".to_string(),
697 )
698 .into()),
699 }
700 }
701}
702
703#[derive(Debug, Default)]
704struct ServicePrecompile {
705 inner: EthPrecompiles,
706}
707
708impl<'a> ServicePrecompile {
709 fn service_runtime_call<Runtime: ServiceRuntime>(
710 request: ServiceRuntimePrecompile,
711 context: &mut ServiceCtx<'a, Runtime>,
712 ) -> Result<Vec<u8>, ExecutionError> {
713 let mut runtime = context.db().0.lock_runtime();
714 match request {
715 ServiceRuntimePrecompile::TryQueryApplication { target, argument } => {
716 ensure!(
717 target != runtime.application_id()?,
718 EvmExecutionError::NoSelfCall
719 );
720 runtime.try_query_application(target, argument)
721 }
722 }
723 }
724
725 fn call_or_fail<Runtime: ServiceRuntime>(
726 inputs: &InputsImpl,
727 context: &mut ServiceCtx<'a, Runtime>,
728 ) -> Result<Vec<u8>, ExecutionError> {
729 let input = get_precompile_argument(context, inputs)?;
730 match bcs::from_bytes(&input)? {
731 RuntimePrecompile::Base(base_tag) => {
732 let mut runtime = context.db().0.lock_runtime();
733 base_runtime_call(base_tag, runtime.deref_mut())
734 }
735 RuntimePrecompile::Contract(_) => Err(EvmExecutionError::PrecompileError(
736 "Contract calls are not available in GeneralServiceCall".to_string(),
737 )
738 .into()),
739 RuntimePrecompile::Service(service_tag) => {
740 Self::service_runtime_call(service_tag, context)
741 }
742 }
743 }
744}
745
746impl<'a, Runtime: ServiceRuntime> PrecompileProvider<ServiceCtx<'a, Runtime>>
747 for ServicePrecompile
748{
749 type Output = InterpreterResult;
750
751 fn set_spec(
752 &mut self,
753 spec: <<ServiceCtx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec,
754 ) -> bool {
755 <EthPrecompiles as PrecompileProvider<ServiceCtx<'a, Runtime>>>::set_spec(
756 &mut self.inner,
757 spec,
758 )
759 }
760
761 fn run(
762 &mut self,
763 context: &mut ServiceCtx<'a, Runtime>,
764 address: &Address,
765 inputs: &InputsImpl,
766 is_static: bool,
767 gas_limit: u64,
768 ) -> Result<Option<InterpreterResult>, String> {
769 if address == &PRECOMPILE_ADDRESS {
770 let output = Self::call_or_fail(inputs, context)
771 .map_err(|error| format!("ServicePrecompile error: {error}"))?;
772 return Ok(Some(get_precompile_output(output, gas_limit)));
773 }
774 self.inner
775 .run(context, address, inputs, is_static, gas_limit)
776 }
777
778 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
779 let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
780 addresses.push(PRECOMPILE_ADDRESS);
781 Box::new(addresses.into_iter())
782 }
783
784 fn contains(&self, address: &Address) -> bool {
785 address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
786 }
787}
788
789fn map_result_create_outcome<Runtime: BaseRuntime>(
790 database: &InnerDatabase<Runtime>,
791 result: Result<Option<CreateOutcome>, ExecutionError>,
792) -> Option<CreateOutcome> {
793 match result {
794 Err(error) => {
795 database.insert_error(error);
796 let result = InstructionResult::Revert;
798 let output = Bytes::default();
799 let gas = Gas::default();
800 let result = InterpreterResult {
801 result,
802 output,
803 gas,
804 };
805 Some(CreateOutcome {
806 result,
807 address: None,
808 })
809 }
810 Ok(result) => result,
811 }
812}
813
814fn map_result_call_outcome<Runtime: BaseRuntime>(
815 database: &InnerDatabase<Runtime>,
816 result: Result<Option<CallOutcome>, ExecutionError>,
817) -> Option<CallOutcome> {
818 match result {
819 Err(error) => {
820 database.insert_error(error);
821 let result = InstructionResult::Revert;
823 let output = Bytes::default();
824 let gas = Gas::default();
825 let result = InterpreterResult {
826 result,
827 output,
828 gas,
829 };
830 let memory_offset = Range::default();
831 Some(CallOutcome {
832 result,
833 memory_offset,
834 })
835 }
836 Ok(result) => result,
837 }
838}
839
840struct CallInterceptorContract<Runtime> {
841 db: ContractDatabase<Runtime>,
842 contract_address: Address,
844 precompile_addresses: BTreeSet<Address>,
845 error: Arc<Mutex<Option<U256>>>,
846}
847
848impl<Runtime> Clone for CallInterceptorContract<Runtime> {
849 fn clone(&self) -> Self {
850 Self {
851 db: self.db.clone(),
852 contract_address: self.contract_address,
853 precompile_addresses: self.precompile_addresses.clone(),
854 error: self.error.clone(),
855 }
856 }
857}
858
859impl<'a, Runtime: ContractRuntime> Inspector<ContractCtx<'a, Runtime>>
860 for CallInterceptorContract<Runtime>
861{
862 fn create(
863 &mut self,
864 context: &mut ContractCtx<'a, Runtime>,
865 inputs: &mut CreateInputs,
866 ) -> Option<CreateOutcome> {
867 let result = self.create_or_fail(context, inputs);
868 map_result_create_outcome(&self.db.inner, result)
869 }
870
871 fn call(
872 &mut self,
873 context: &mut ContractCtx<'a, Runtime>,
874 inputs: &mut CallInputs,
875 ) -> Option<CallOutcome> {
876 let result = self.call_or_fail(context, inputs);
877 map_result_call_outcome(&self.db.inner, result)
878 }
879}
880
881impl<Runtime: ContractRuntime> CallInterceptorContract<Runtime> {
882 fn get_expected_application_id(
897 context: &mut ContractCtx<'_, Runtime>,
898 module_id: ModuleId,
899 num_apps: u32,
900 ) -> Result<ApplicationId, ExecutionError> {
901 let mut runtime = context.db().0.lock_runtime();
902 let chain_id = runtime.chain_id()?;
903 let block_height = runtime.block_height()?;
904 let application_index = runtime.peek_application_index()? + num_apps;
905 let parameters = JSON_EMPTY_VECTOR.to_vec(); let required_application_ids = Vec::new();
907 let application_description = ApplicationDescription {
908 module_id,
909 creator_chain_id: chain_id,
910 block_height,
911 application_index,
912 parameters: parameters.clone(),
913 required_application_ids,
914 };
915 Ok(ApplicationId::from(&application_description))
916 }
917
918 fn publish_create_inputs(
921 context: &mut ContractCtx<'_, Runtime>,
922 inputs: &mut CreateInputs,
923 ) -> Result<ModuleId, ExecutionError> {
924 let contract = linera_base::data_types::Bytecode::new(inputs.init_code.to_vec());
925 let service = linera_base::data_types::Bytecode::new(vec![]);
926 let mut runtime = context.db().0.lock_runtime();
927 runtime.publish_module(contract, service, VmRuntime::Evm)
928 }
929
930 fn create_or_fail(
1023 &mut self,
1024 context: &mut ContractCtx<'_, Runtime>,
1025 inputs: &mut CreateInputs,
1026 ) -> Result<Option<CreateOutcome>, ExecutionError> {
1027 if !self.db.inner.is_revm_instantiated {
1028 self.db.inner.is_revm_instantiated = true;
1029 inputs.scheme = CreateScheme::Custom {
1030 address: self.contract_address,
1031 };
1032 return Ok(None);
1033 }
1034 let module_id = Self::publish_create_inputs(context, inputs)?;
1035 let mut map = self.db.modules.lock().unwrap();
1036 let num_apps = map.len() as u32;
1037 let expected_application_id =
1038 Self::get_expected_application_id(context, module_id, num_apps)?;
1039 map.insert(expected_application_id, (module_id, num_apps));
1040 let address = expected_application_id.evm_address();
1041 if inputs.value != U256::ZERO {
1042 let value = Amount::try_from(inputs.value).map_err(EvmExecutionError::from)?;
1043 let mut runtime = context.db().0.lock_runtime();
1044 let application_id = runtime.application_id()?;
1045 let source = application_id.into();
1046 let chain_id = runtime.chain_id()?;
1047 let account = identifiers::Account {
1048 chain_id,
1049 owner: expected_application_id.into(),
1050 };
1051 runtime.transfer(source, account, value)?;
1052 }
1053 inputs.scheme = CreateScheme::Custom { address };
1054 Ok(None)
1055 }
1056
1057 fn call_or_fail(
1077 &mut self,
1078 _context: &mut ContractCtx<'_, Runtime>,
1079 inputs: &mut CallInputs,
1080 ) -> Result<Option<CallOutcome>, ExecutionError> {
1081 let is_precompile = self.precompile_addresses.contains(&inputs.target_address);
1082 let is_first_call = inputs.target_address == self.contract_address;
1083 if is_precompile {
1084 if let CallValue::Transfer(value) = inputs.value {
1085 ensure!(
1086 value == U256::ZERO,
1087 EvmExecutionError::NonZeroTransferPrecompile
1088 );
1089 }
1090 }
1091 if is_precompile || is_first_call {
1092 return Ok(None);
1094 }
1095 if let CallValue::Transfer(value) = inputs.value {
1097 if value != U256::ZERO {
1098 let source: AccountOwner = inputs.caller.into();
1099 let owner: AccountOwner = inputs.bytecode_address.into();
1100 let mut runtime = self.db.lock_runtime();
1101 let amount = Amount::try_from(value).map_err(EvmExecutionError::from)?;
1102 let chain_id = runtime.chain_id()?;
1103 let destination = Account { chain_id, owner };
1104 runtime.transfer(source, destination, amount)?;
1105 }
1106 }
1107 Ok(None)
1109 }
1110}
1111
1112struct CallInterceptorService<Runtime> {
1113 db: ServiceDatabase<Runtime>,
1114 contract_address: Address,
1116 precompile_addresses: BTreeSet<Address>,
1117}
1118
1119impl<Runtime> Clone for CallInterceptorService<Runtime> {
1120 fn clone(&self) -> Self {
1121 Self {
1122 db: self.db.clone(),
1123 contract_address: self.contract_address,
1124 precompile_addresses: self.precompile_addresses.clone(),
1125 }
1126 }
1127}
1128
1129impl<'a, Runtime: ServiceRuntime> Inspector<ServiceCtx<'a, Runtime>>
1130 for CallInterceptorService<Runtime>
1131{
1132 fn create(
1134 &mut self,
1135 context: &mut ServiceCtx<'a, Runtime>,
1136 inputs: &mut CreateInputs,
1137 ) -> Option<CreateOutcome> {
1138 let result = self.create_or_fail(context, inputs);
1139 map_result_create_outcome(&self.db.inner, result)
1140 }
1141}
1142
1143impl<Runtime: ServiceRuntime> CallInterceptorService<Runtime> {
1144 fn create_or_fail(
1165 &mut self,
1166 _context: &mut ServiceCtx<'_, Runtime>,
1167 inputs: &mut CreateInputs,
1168 ) -> Result<Option<CreateOutcome>, ExecutionError> {
1169 if !self.db.inner.is_revm_instantiated {
1170 self.db.inner.is_revm_instantiated = true;
1171 inputs.scheme = CreateScheme::Custom {
1172 address: self.contract_address,
1173 };
1174 Ok(None)
1175 } else {
1176 Err(EvmExecutionError::NoContractCreationInService.into())
1177 }
1178 }
1179}
1180
1181pub struct RevmContractInstance<Runtime> {
1182 module: Vec<u8>,
1183 db: ContractDatabase<Runtime>,
1184}
1185
1186#[derive(Debug)]
1188enum EvmTxKind {
1189 Create,
1191 Call,
1193}
1194
1195#[derive(Debug)]
1197struct ExecutionResultSuccess {
1198 gas_final: u64,
1200 logs: Vec<Log>,
1202 output: Output,
1204}
1205
1206impl ExecutionResultSuccess {
1207 fn output_and_logs(self) -> (u64, Vec<u8>, Vec<Log>) {
1208 let Output::Call(output) = self.output else {
1209 unreachable!("The output should have been created from a EvmTxKind::Call");
1210 };
1211 let output = output.as_ref().to_vec();
1212 (self.gas_final, output, self.logs)
1213 }
1214
1215 fn check_contract_initialization(&self, expected_address: Address) -> Result<(), String> {
1217 let Output::Create(_, contract_address) = self.output else {
1219 return Err("Input should be ExmTxKind::Create".to_string());
1220 };
1221 let contract_address = contract_address.ok_or("Deployment failed")?;
1223 if contract_address == expected_address {
1225 Ok(())
1226 } else {
1227 Err("Contract address is not the same as ApplicationId".to_string())
1228 }
1229 }
1230}
1231
1232impl<Runtime> UserContract for RevmContractInstance<Runtime>
1233where
1234 Runtime: ContractRuntime,
1235{
1236 fn instantiate(&mut self, argument: Vec<u8>) -> Result<(), ExecutionError> {
1237 self.db.inner.set_contract_address()?;
1238 let caller = self.get_msg_address()?;
1239 let instantiation_argument = serde_json::from_slice::<EvmInstantiation>(&argument)?;
1240 if let Some(remainder) = instantiation_argument
1243 .argument
1244 .as_slice()
1245 .strip_prefix(ALREADY_CREATED_CONTRACT_SELECTOR)
1246 {
1247 let account = bcs::from_bytes::<revm_state::Account>(remainder)?;
1248 return self.db.commit_contract_changes(&account);
1249 }
1250 self.initialize_contract(instantiation_argument.value, caller)?;
1251 if has_selector(&self.module, INSTANTIATE_SELECTOR) {
1252 let argument = get_revm_instantiation_bytes(instantiation_argument.argument);
1253 let result = self.transact_commit(EvmTxKind::Call, argument, U256::ZERO, caller)?;
1254 self.write_logs(result.logs, "instantiate")?;
1255 }
1256 Ok(())
1257 }
1258
1259 fn execute_operation(&mut self, operation: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1272 self.db.inner.set_contract_address()?;
1273 ensure_message_length(operation.len(), 4)?;
1274 if operation == GET_ACCOUNT_INFO_SELECTOR {
1275 let account_info = self.db.inner.get_account_info()?;
1276 return Ok(bcs::to_bytes(&account_info)?);
1277 }
1278 if let Some(remainder) = operation
1279 .as_slice()
1280 .strip_prefix(GET_CONTRACT_STORAGE_SELECTOR)
1281 {
1282 let index = bcs::from_bytes(remainder)?;
1283 let value = self.db.inner.read_from_local_storage(index)?;
1284 return Ok(bcs::to_bytes(&value)?);
1285 }
1286 if let Some(remainder) = operation
1287 .as_slice()
1288 .strip_prefix(COMMIT_CONTRACT_CHANGES_SELECTOR)
1289 {
1290 let account = bcs::from_bytes::<revm_state::Account>(remainder)?;
1291 self.db.commit_contract_changes(&account)?;
1292 return Ok(Vec::new());
1293 }
1294 let caller = self.get_msg_address()?;
1295 forbid_execute_operation_origin(&operation[..4])?;
1296 let evm_call = bcs::from_bytes::<EvmOperation>(&operation)?;
1297 let result = self.init_transact_commit(evm_call.argument, evm_call.value, caller)?;
1298 let (gas_final, output, logs) = result.output_and_logs();
1299 self.consume_fuel(gas_final)?;
1300 self.write_logs(logs, "operation")?;
1301 Ok(output)
1302 }
1303
1304 fn execute_message(&mut self, message: Vec<u8>) -> Result<(), ExecutionError> {
1305 self.db.inner.set_contract_address()?;
1306 ensure_selector_presence(
1307 &self.module,
1308 EXECUTE_MESSAGE_SELECTOR,
1309 "function execute_message(bytes)",
1310 )?;
1311 let operation = get_revm_execute_message_bytes(message);
1312 let caller = self.get_msg_address()?;
1313 let value = U256::ZERO;
1314 self.execute_no_return_operation(operation, "message", value, caller)
1315 }
1316
1317 fn process_streams(&mut self, streams: Vec<StreamUpdate>) -> Result<(), ExecutionError> {
1318 self.db.inner.set_contract_address()?;
1319 let operation = get_revm_process_streams_bytes(streams);
1320 ensure_selector_presence(
1321 &self.module,
1322 PROCESS_STREAMS_SELECTOR,
1323 "function process_streams(Linera.StreamUpdate[] memory streams)",
1324 )?;
1325 let caller = Address::ZERO;
1327 let value = U256::ZERO;
1328 self.execute_no_return_operation(operation, "process_streams", value, caller)
1329 }
1330
1331 fn finalize(&mut self) -> Result<(), ExecutionError> {
1332 Ok(())
1333 }
1334}
1335
1336fn process_execution_result(
1337 result: ExecutionResult,
1338) -> Result<ExecutionResultSuccess, EvmExecutionError> {
1339 match result {
1340 ExecutionResult::Success {
1341 reason,
1342 gas_used,
1343 gas_refunded,
1344 logs,
1345 output,
1346 } => {
1347 let max_refund = gas_used / 5;
1349 let actual_refund = gas_refunded.min(max_refund);
1350 let gas_final = gas_used - actual_refund;
1351 if !matches!(reason, SuccessReason::Return) {
1352 Err(EvmExecutionError::NoReturnInterpreter {
1353 reason,
1354 gas_used,
1355 gas_refunded,
1356 logs,
1357 output,
1358 })
1359 } else {
1360 Ok(ExecutionResultSuccess {
1361 gas_final,
1362 logs,
1363 output,
1364 })
1365 }
1366 }
1367 ExecutionResult::Revert { gas_used, output } => {
1368 Err(EvmExecutionError::Revert { gas_used, output })
1369 }
1370 ExecutionResult::Halt { gas_used, reason } => {
1371 Err(EvmExecutionError::Halt { gas_used, reason })
1372 }
1373 }
1374}
1375
1376impl<Runtime> RevmContractInstance<Runtime>
1377where
1378 Runtime: ContractRuntime,
1379{
1380 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1381 let db = ContractDatabase::new(runtime);
1382 Self { module, db }
1383 }
1384
1385 fn execute_no_return_operation(
1386 &mut self,
1387 operation: Vec<u8>,
1388 origin: &str,
1389 value: U256,
1390 caller: Address,
1391 ) -> Result<(), ExecutionError> {
1392 let result = self.init_transact_commit(operation, value, caller)?;
1393 let (gas_final, output, logs) = result.output_and_logs();
1394 self.consume_fuel(gas_final)?;
1395 self.write_logs(logs, origin)?;
1396 assert_eq!(output.len(), 0);
1397 Ok(())
1398 }
1399
1400 fn init_transact_commit(
1402 &mut self,
1403 vec: Vec<u8>,
1404 value: U256,
1405 caller: Address,
1406 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1407 if !self.db.inner.set_is_initialized()? {
1411 self.initialize_contract(U256::ZERO, caller)?;
1412 }
1413 self.transact_commit(EvmTxKind::Call, vec, value, caller)
1414 }
1415
1416 fn initialize_contract(&mut self, value: U256, caller: Address) -> Result<(), ExecutionError> {
1418 let mut vec_init = self.module.clone();
1419 let constructor_argument = self.db.inner.constructor_argument()?;
1420 vec_init.extend_from_slice(&constructor_argument);
1421 let result = self.transact_commit(EvmTxKind::Create, vec_init, value, caller)?;
1422 result
1423 .check_contract_initialization(self.db.inner.contract_address)
1424 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1425 self.write_logs(result.logs, "deploy")
1426 }
1427
1428 fn get_msg_address(&self) -> Result<Address, ExecutionError> {
1441 let mut runtime = self.db.lock_runtime();
1442 let application_id = runtime.authenticated_caller_id()?;
1443 if let Some(application_id) = application_id {
1444 return Ok(if application_id.is_evm() {
1445 application_id.evm_address()
1446 } else {
1447 Address::ZERO
1448 });
1449 };
1450 let account_owner = runtime.authenticated_owner()?;
1451 if let Some(AccountOwner::Address20(address)) = account_owner {
1452 return Ok(Address::from(address));
1453 };
1454 Ok(ZERO_ADDRESS)
1455 }
1456
1457 fn transact_commit(
1458 &mut self,
1459 tx_kind: EvmTxKind,
1460 input: Vec<u8>,
1461 value: U256,
1462 caller: Address,
1463 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1464 let contract_address = self.db.inner.contract_address;
1465 self.db.inner.caller = caller;
1466 self.db.inner.value = value;
1467 self.db.inner.deposit_funds()?;
1468 let data = Bytes::from(input);
1469 let kind = match tx_kind {
1470 EvmTxKind::Create => TxKind::Create,
1471 EvmTxKind::Call => TxKind::Call(contract_address),
1472 };
1473 let inspector = CallInterceptorContract {
1474 db: self.db.clone(),
1475 contract_address,
1476 precompile_addresses: precompile_addresses(),
1477 error: Arc::new(Mutex::new(None)),
1478 };
1479 let block_env = self.db.get_block_env()?;
1480 let (max_size_evm_contract, gas_limit) = {
1481 let mut runtime = self.db.lock_runtime();
1482 let gas_limit = runtime.remaining_fuel(VmRuntime::Evm)?;
1483 let max_size_evm_contract = runtime.maximum_blob_size()? as usize;
1484 (max_size_evm_contract, gas_limit)
1485 };
1486 let nonce = self.db.get_nonce(&caller)?;
1487 let result = {
1488 let mut ctx: revm_context::Context<
1489 BlockEnv,
1490 _,
1491 _,
1492 _,
1493 Journal<WrapDatabaseRef<&mut ContractDatabase<Runtime>>>,
1494 (),
1495 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1496 WrapDatabaseRef(&mut self.db),
1497 SpecId::PRAGUE,
1498 )
1499 .with_block(block_env);
1500 ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1501 let instructions = EthInstructions::new_mainnet();
1502 let mut evm = Evm::new_with_inspector(
1503 ctx,
1504 inspector.clone(),
1505 instructions,
1506 ContractPrecompile::default(),
1507 );
1508 evm.inspect_commit(
1509 TxEnv {
1510 kind,
1511 data,
1512 nonce,
1513 gas_limit,
1514 caller,
1515 value,
1516 ..TxEnv::default()
1517 },
1518 inspector.clone(),
1519 )
1520 .map_err(|error| {
1521 let error = format!("{:?}", error);
1522 EvmExecutionError::TransactCommitError(error)
1523 })
1524 }?;
1525 self.db.inner.process_any_error()?;
1526 self.db.commit_changes()?;
1527 Ok(process_execution_result(result)?)
1528 }
1529
1530 fn consume_fuel(&mut self, gas_final: u64) -> Result<(), ExecutionError> {
1531 let mut runtime = self.db.lock_runtime();
1532 runtime.consume_fuel(gas_final, VmRuntime::Evm)
1533 }
1534
1535 fn write_logs(&mut self, logs: Vec<Log>, origin: &str) -> Result<(), ExecutionError> {
1536 if !logs.is_empty() {
1538 let mut runtime = self.db.lock_runtime();
1539 let block_height = runtime.block_height()?;
1540 let stream_name = bcs::to_bytes("ethereum_event")?;
1541 let stream_name = StreamName(stream_name);
1542 for log in &logs {
1543 let value = bcs::to_bytes(&(origin, block_height.0, log))?;
1544 runtime.emit(stream_name.clone(), value)?;
1545 }
1546 }
1547 Ok(())
1548 }
1549}
1550
1551pub struct RevmServiceInstance<Runtime> {
1552 module: Vec<u8>,
1553 db: ServiceDatabase<Runtime>,
1554}
1555
1556impl<Runtime> RevmServiceInstance<Runtime>
1557where
1558 Runtime: ServiceRuntime,
1559{
1560 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1561 let db = ServiceDatabase::new(runtime);
1562 Self { module, db }
1563 }
1564}
1565
1566impl<Runtime> UserService for RevmServiceInstance<Runtime>
1567where
1568 Runtime: ServiceRuntime,
1569{
1570 fn handle_query(&mut self, argument: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1571 self.db.inner.set_contract_address()?;
1572 let evm_query = serde_json::from_slice(&argument)?;
1573 let query = match evm_query {
1574 EvmQuery::AccountInfo => {
1575 let account_info = self.db.inner.get_account_info()?;
1576 return Ok(serde_json::to_vec(&account_info)?);
1577 }
1578 EvmQuery::Storage(index) => {
1579 let value = self.db.inner.read_from_local_storage(index)?;
1580 return Ok(serde_json::to_vec(&value)?);
1581 }
1582 EvmQuery::Query(vec) => vec,
1583 EvmQuery::Operation(operation) => {
1584 let mut runtime = self.db.lock_runtime();
1585 runtime.schedule_operation(operation)?;
1586 return Ok(Vec::new());
1587 }
1588 EvmQuery::Operations(operations) => {
1589 let mut runtime = self.db.lock_runtime();
1590 for operation in operations {
1591 runtime.schedule_operation(operation)?;
1592 }
1593 return Ok(Vec::new());
1594 }
1595 };
1596
1597 ensure_message_length(query.len(), 4)?;
1598 let result = self.init_transact(query)?;
1602 let (_gas_final, output, _logs) = result.output_and_logs();
1603 let answer = serde_json::to_vec(&output)?;
1604 Ok(answer)
1605 }
1606}
1607
1608impl<Runtime> RevmServiceInstance<Runtime>
1609where
1610 Runtime: ServiceRuntime,
1611{
1612 fn init_transact(&mut self, vec: Vec<u8>) -> Result<ExecutionResultSuccess, ExecutionError> {
1613 let contract_address = self.db.inner.contract_address;
1617 if !self.db.inner.set_is_initialized()? {
1618 let changes = {
1619 let mut vec_init = self.module.clone();
1620 let constructor_argument = self.db.inner.constructor_argument()?;
1621 vec_init.extend_from_slice(&constructor_argument);
1622 let (result, changes) = self.transact(TxKind::Create, vec_init)?;
1623 result
1624 .check_contract_initialization(contract_address)
1625 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1626 changes
1627 };
1628 self.db.inner.changes = changes;
1629 }
1630 ensure_message_length(vec.len(), 4)?;
1631 forbid_execute_operation_origin(&vec[..4])?;
1632 let kind = TxKind::Call(contract_address);
1633 let (execution_result, _) = self.transact(kind, vec)?;
1634 Ok(execution_result)
1635 }
1636
1637 fn transact(
1638 &mut self,
1639 kind: TxKind,
1640 input: Vec<u8>,
1641 ) -> Result<(ExecutionResultSuccess, EvmState), ExecutionError> {
1642 let contract_address = self.db.inner.contract_address;
1643 let caller = SERVICE_ADDRESS;
1644 let value = U256::ZERO;
1645 self.db.inner.caller = caller;
1646 self.db.inner.value = value;
1647 let data = Bytes::from(input);
1648 let block_env = self.db.get_block_env()?;
1649 let inspector = CallInterceptorService {
1650 db: self.db.clone(),
1651 contract_address,
1652 precompile_addresses: precompile_addresses(),
1653 };
1654 let max_size_evm_contract = {
1655 let mut runtime = self.db.lock_runtime();
1656 runtime.maximum_blob_size()? as usize
1657 };
1658 let nonce = self.db.get_nonce(&caller)?;
1659 let result_state = {
1660 let mut ctx: revm_context::Context<
1661 BlockEnv,
1662 _,
1663 _,
1664 _,
1665 Journal<WrapDatabaseRef<&mut ServiceDatabase<Runtime>>>,
1666 (),
1667 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1668 WrapDatabaseRef(&mut self.db),
1669 SpecId::PRAGUE,
1670 )
1671 .with_block(block_env);
1672 ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1673 let instructions = EthInstructions::new_mainnet();
1674 let mut evm = Evm::new_with_inspector(
1675 ctx,
1676 inspector.clone(),
1677 instructions,
1678 ServicePrecompile::default(),
1679 );
1680 evm.inspect(
1681 TxEnv {
1682 kind,
1683 data,
1684 nonce,
1685 value,
1686 caller,
1687 gas_limit: EVM_SERVICE_GAS_LIMIT,
1688 ..TxEnv::default()
1689 },
1690 inspector,
1691 )
1692 .map_err(|error| {
1693 let error = format!("{:?}", error);
1694 EvmExecutionError::TransactCommitError(error)
1695 })
1696 }?;
1697 self.db.inner.process_any_error()?;
1698 let result = process_execution_result(result_state.result)?;
1699 Ok((result, result_state.state))
1700 }
1701}