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>(context: &mut Ctx, inputs: &InputsImpl) -> Vec<u8> {
414 get_argument(context, &inputs.input)
415}
416
417fn base_runtime_call<Runtime: BaseRuntime>(
418 request: &BaseRuntimePrecompile,
419 runtime: &mut Runtime,
420) -> Result<Vec<u8>, ExecutionError> {
421 match request {
422 BaseRuntimePrecompile::ChainId => {
423 let chain_id = runtime.chain_id()?;
424 Ok(bcs::to_bytes(&chain_id)?)
425 }
426 BaseRuntimePrecompile::BlockHeight => {
427 let block_height = runtime.block_height()?;
428 Ok(bcs::to_bytes(&block_height)?)
429 }
430 BaseRuntimePrecompile::ApplicationCreatorChainId => {
431 let chain_id = runtime.application_creator_chain_id()?;
432 Ok(bcs::to_bytes(&chain_id)?)
433 }
434 BaseRuntimePrecompile::ReadSystemTimestamp => {
435 let timestamp = runtime.read_system_timestamp()?;
436 Ok(bcs::to_bytes(×tamp)?)
437 }
438 BaseRuntimePrecompile::ReadChainBalance => {
439 let balance: linera_base::data_types::Amount = runtime.read_chain_balance()?;
440 let balance: AmountU256 = balance.into();
441 Ok(bcs::to_bytes(&balance)?)
442 }
443 BaseRuntimePrecompile::ReadOwnerBalance(account_owner) => {
444 let balance = runtime.read_owner_balance(*account_owner)?;
445 let balance = Into::<U256>::into(balance);
446 Ok(bcs::to_bytes(&balance)?)
447 }
448 BaseRuntimePrecompile::ReadOwnerBalances => {
449 let owner_balances = runtime.read_owner_balances()?;
450 let owner_balances = owner_balances
451 .into_iter()
452 .map(|(account_owner, balance)| (account_owner, balance.into()))
453 .collect::<Vec<(AccountOwner, AmountU256)>>();
454 Ok(bcs::to_bytes(&owner_balances)?)
455 }
456 BaseRuntimePrecompile::ReadBalanceOwners => {
457 let owners = runtime.read_balance_owners()?;
458 Ok(bcs::to_bytes(&owners)?)
459 }
460 BaseRuntimePrecompile::ChainOwnership => {
461 let chain_ownership = runtime.chain_ownership()?;
462 Ok(bcs::to_bytes(&chain_ownership)?)
463 }
464 BaseRuntimePrecompile::ReadDataBlob(hash) => runtime.read_data_blob(*hash),
465 BaseRuntimePrecompile::AssertDataBlobExists(hash) => {
466 runtime.assert_data_blob_exists(*hash)?;
467 Ok(Vec::new())
468 }
469 }
470}
471
472fn precompile_addresses() -> BTreeSet<Address> {
473 let mut addresses = BTreeSet::new();
474 for address in EthPrecompiles::default().warm_addresses() {
475 addresses.insert(address);
476 }
477 addresses.insert(PRECOMPILE_ADDRESS);
478 addresses
479}
480
481#[derive(Debug, Default)]
482struct ContractPrecompile {
483 inner: EthPrecompiles,
484}
485
486impl<'a, Runtime: ContractRuntime> PrecompileProvider<ContractCtx<'a, Runtime>>
487 for ContractPrecompile
488{
489 type Output = InterpreterResult;
490
491 fn set_spec(
492 &mut self,
493 spec: <<ContractCtx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec,
494 ) -> bool {
495 <EthPrecompiles as PrecompileProvider<ContractCtx<'a, Runtime>>>::set_spec(
496 &mut self.inner,
497 spec,
498 )
499 }
500
501 fn run(
502 &mut self,
503 context: &mut ContractCtx<'a, Runtime>,
504 address: &Address,
505 inputs: &InputsImpl,
506 is_static: bool,
507 gas_limit: u64,
508 ) -> Result<Option<InterpreterResult>, String> {
509 if address == &PRECOMPILE_ADDRESS {
510 let output = Self::call_or_fail(inputs, context)
511 .map_err(|error| format!("ContractPrecompile error: {error}"))?;
512 return Ok(Some(get_precompile_output(output, gas_limit)));
513 }
514 self.inner
515 .run(context, address, inputs, is_static, gas_limit)
516 }
517
518 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
519 let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
520 addresses.push(PRECOMPILE_ADDRESS);
521 Box::new(addresses.into_iter())
522 }
523
524 fn contains(&self, address: &Address) -> bool {
525 address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
526 }
527}
528
529fn get_evm_destination<Runtime: ContractRuntime>(
530 context: &mut ContractCtx<'_, Runtime>,
531 account: Account,
532) -> Result<Option<Address>, ExecutionError> {
533 let mut runtime = context.db().0.lock_runtime();
534 if runtime.chain_id()? != account.chain_id {
535 return Ok(None);
536 }
537 Ok(account.owner.to_evm_address())
538}
539
540fn revm_transfer<Runtime: ContractRuntime>(
542 context: &mut ContractCtx<'_, Runtime>,
543 source: Address,
544 destination: Address,
545 value: U256,
546) -> Result<(), ExecutionError> {
547 if let Some(error) = context.journal().transfer(source, destination, value)? {
548 let error = format!("{error:?}");
549 let error = EvmExecutionError::TransactError(error);
550 return Err(error.into());
551 }
552 Ok(())
553}
554
555impl<'a> ContractPrecompile {
556 fn contract_runtime_call<Runtime: ContractRuntime>(
557 request: ContractRuntimePrecompile,
558 context: &mut ContractCtx<'a, Runtime>,
559 ) -> Result<Vec<u8>, ExecutionError> {
560 match request {
561 ContractRuntimePrecompile::AuthenticatedOwner => {
562 let mut runtime = context.db().0.lock_runtime();
563 let account_owner = runtime.authenticated_owner()?;
564 Ok(bcs::to_bytes(&account_owner)?)
565 }
566
567 ContractRuntimePrecompile::MessageOriginChainId => {
568 let mut runtime = context.db().0.lock_runtime();
569 let origin_chain_id = runtime.message_origin_chain_id()?;
570 Ok(bcs::to_bytes(&origin_chain_id)?)
571 }
572
573 ContractRuntimePrecompile::MessageIsBouncing => {
574 let mut runtime = context.db().0.lock_runtime();
575 let result = runtime.message_is_bouncing()?;
576 Ok(bcs::to_bytes(&result)?)
577 }
578 ContractRuntimePrecompile::AuthenticatedCallerId => {
579 let mut runtime = context.db().0.lock_runtime();
580 let application_id = runtime.authenticated_caller_id()?;
581 Ok(bcs::to_bytes(&application_id)?)
582 }
583 ContractRuntimePrecompile::SendMessage {
584 destination,
585 message,
586 } => {
587 let authenticated = true;
588 let is_tracked = true;
589 let grant = Resources::default();
590 let send_message_request = SendMessageRequest {
591 destination,
592 authenticated,
593 is_tracked,
594 grant,
595 message,
596 };
597 let mut runtime = context.db().0.lock_runtime();
598 runtime.send_message(send_message_request)?;
599 Ok(vec![])
600 }
601 ContractRuntimePrecompile::TryCallApplication { target, argument } => {
602 let authenticated = true;
603 let mut runtime = context.db().0.lock_runtime();
604 ensure!(
605 target != runtime.application_id()?,
606 EvmExecutionError::NoSelfCall
607 );
608 runtime.try_call_application(authenticated, target, argument)
609 }
610 ContractRuntimePrecompile::Emit { stream_name, value } => {
611 let mut runtime = context.db().0.lock_runtime();
612 let result = runtime.emit(stream_name, value)?;
613 Ok(bcs::to_bytes(&result)?)
614 }
615 ContractRuntimePrecompile::ReadEvent {
616 chain_id,
617 stream_name,
618 index,
619 } => {
620 let mut runtime = context.db().0.lock_runtime();
621 runtime.read_event(chain_id, stream_name, index)
622 }
623 ContractRuntimePrecompile::SubscribeToEvents {
624 chain_id,
625 application_id,
626 stream_name,
627 } => {
628 let mut runtime = context.db().0.lock_runtime();
629 runtime.subscribe_to_events(chain_id, application_id, stream_name)?;
630 Ok(vec![])
631 }
632 ContractRuntimePrecompile::UnsubscribeFromEvents {
633 chain_id,
634 application_id,
635 stream_name,
636 } => {
637 let mut runtime = context.db().0.lock_runtime();
638 runtime.unsubscribe_from_events(chain_id, application_id, stream_name)?;
639 Ok(vec![])
640 }
641 ContractRuntimePrecompile::QueryService {
642 application_id,
643 query,
644 } => {
645 let mut runtime = context.db().0.lock_runtime();
646 ensure!(
647 application_id != runtime.application_id()?,
648 EvmExecutionError::NoSelfCall
649 );
650 runtime.query_service(application_id, query)
651 }
652 ContractRuntimePrecompile::ValidationRound => {
653 let mut runtime = context.db().0.lock_runtime();
654 let value = runtime.validation_round()?;
655 Ok(bcs::to_bytes(&value)?)
656 }
657 ContractRuntimePrecompile::Transfer { account, amount } => {
658 if amount.0 != U256::ZERO {
659 let destination = {
660 let destination = get_evm_destination(context, account)?;
661 destination.unwrap_or(FAUCET_ADDRESS)
662 };
663 let application_id = {
664 let mut runtime = context.db().0.lock_runtime();
665 let application_id = runtime.application_id()?;
666 let source = application_id.into();
667 let value = Amount::try_from(amount.0).map_err(EvmExecutionError::from)?;
668 runtime.transfer(source, account, value)?;
669 application_id
670 };
671 let source: Address = application_id.evm_address();
672 revm_transfer(context, source, destination, amount.0)?;
673 }
674 Ok(vec![])
675 }
676 }
677 }
678
679 fn call_or_fail<Runtime: ContractRuntime>(
680 inputs: &InputsImpl,
681 context: &mut ContractCtx<'a, Runtime>,
682 ) -> Result<Vec<u8>, ExecutionError> {
683 let input = get_precompile_argument(context, inputs);
684 match bcs::from_bytes(&input)? {
685 RuntimePrecompile::Base(base_tag) => {
686 let mut runtime = context.db().0.lock_runtime();
687 base_runtime_call(&base_tag, runtime.deref_mut())
688 }
689 RuntimePrecompile::Contract(contract_tag) => {
690 Self::contract_runtime_call(contract_tag, context)
691 }
692 RuntimePrecompile::Service(_) => Err(EvmExecutionError::PrecompileError(
693 "Service tags are not available in GeneralContractCall".to_string(),
694 )
695 .into()),
696 }
697 }
698}
699
700#[derive(Debug, Default)]
701struct ServicePrecompile {
702 inner: EthPrecompiles,
703}
704
705impl<'a> ServicePrecompile {
706 fn service_runtime_call<Runtime: ServiceRuntime>(
707 request: ServiceRuntimePrecompile,
708 context: &mut ServiceCtx<'a, Runtime>,
709 ) -> Result<Vec<u8>, ExecutionError> {
710 let mut runtime = context.db().0.lock_runtime();
711 match request {
712 ServiceRuntimePrecompile::TryQueryApplication { target, argument } => {
713 ensure!(
714 target != runtime.application_id()?,
715 EvmExecutionError::NoSelfCall
716 );
717 runtime.try_query_application(target, argument)
718 }
719 }
720 }
721
722 fn call_or_fail<Runtime: ServiceRuntime>(
723 inputs: &InputsImpl,
724 context: &mut ServiceCtx<'a, Runtime>,
725 ) -> Result<Vec<u8>, ExecutionError> {
726 let input = get_precompile_argument(context, inputs);
727 match bcs::from_bytes(&input)? {
728 RuntimePrecompile::Base(base_tag) => {
729 let mut runtime = context.db().0.lock_runtime();
730 base_runtime_call(&base_tag, runtime.deref_mut())
731 }
732 RuntimePrecompile::Contract(_) => Err(EvmExecutionError::PrecompileError(
733 "Contract calls are not available in GeneralServiceCall".to_string(),
734 )
735 .into()),
736 RuntimePrecompile::Service(service_tag) => {
737 Self::service_runtime_call(service_tag, context)
738 }
739 }
740 }
741}
742
743impl<'a, Runtime: ServiceRuntime> PrecompileProvider<ServiceCtx<'a, Runtime>>
744 for ServicePrecompile
745{
746 type Output = InterpreterResult;
747
748 fn set_spec(
749 &mut self,
750 spec: <<ServiceCtx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec,
751 ) -> bool {
752 <EthPrecompiles as PrecompileProvider<ServiceCtx<'a, Runtime>>>::set_spec(
753 &mut self.inner,
754 spec,
755 )
756 }
757
758 fn run(
759 &mut self,
760 context: &mut ServiceCtx<'a, Runtime>,
761 address: &Address,
762 inputs: &InputsImpl,
763 is_static: bool,
764 gas_limit: u64,
765 ) -> Result<Option<InterpreterResult>, String> {
766 if address == &PRECOMPILE_ADDRESS {
767 let output = Self::call_or_fail(inputs, context)
768 .map_err(|error| format!("ServicePrecompile error: {error}"))?;
769 return Ok(Some(get_precompile_output(output, gas_limit)));
770 }
771 self.inner
772 .run(context, address, inputs, is_static, gas_limit)
773 }
774
775 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
776 let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
777 addresses.push(PRECOMPILE_ADDRESS);
778 Box::new(addresses.into_iter())
779 }
780
781 fn contains(&self, address: &Address) -> bool {
782 address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
783 }
784}
785
786fn map_result_create_outcome<Runtime: BaseRuntime>(
787 database: &InnerDatabase<Runtime>,
788 result: Result<Option<CreateOutcome>, ExecutionError>,
789) -> Option<CreateOutcome> {
790 match result {
791 Err(error) => {
792 database.insert_error(&error);
793 let result = InstructionResult::Revert;
795 let output = Bytes::default();
796 let gas = Gas::default();
797 let result = InterpreterResult {
798 result,
799 output,
800 gas,
801 };
802 Some(CreateOutcome {
803 result,
804 address: None,
805 })
806 }
807 Ok(result) => result,
808 }
809}
810
811fn map_result_call_outcome<Runtime: BaseRuntime>(
812 database: &InnerDatabase<Runtime>,
813 result: Result<Option<CallOutcome>, ExecutionError>,
814) -> Option<CallOutcome> {
815 match result {
816 Err(error) => {
817 database.insert_error(&error);
818 let result = InstructionResult::Revert;
820 let output = Bytes::default();
821 let gas = Gas::default();
822 let result = InterpreterResult {
823 result,
824 output,
825 gas,
826 };
827 let memory_offset = Range::default();
828 Some(CallOutcome {
829 result,
830 memory_offset,
831 })
832 }
833 Ok(result) => result,
834 }
835}
836
837struct CallInterceptorContract<Runtime> {
838 db: ContractDatabase<Runtime>,
839 contract_address: Address,
841 precompile_addresses: BTreeSet<Address>,
842 error: Arc<Mutex<Option<U256>>>,
843}
844
845impl<Runtime> Clone for CallInterceptorContract<Runtime> {
846 fn clone(&self) -> Self {
847 Self {
848 db: self.db.clone(),
849 contract_address: self.contract_address,
850 precompile_addresses: self.precompile_addresses.clone(),
851 error: self.error.clone(),
852 }
853 }
854}
855
856impl<'a, Runtime: ContractRuntime> Inspector<ContractCtx<'a, Runtime>>
857 for CallInterceptorContract<Runtime>
858{
859 fn create(
860 &mut self,
861 context: &mut ContractCtx<'a, Runtime>,
862 inputs: &mut CreateInputs,
863 ) -> Option<CreateOutcome> {
864 let result = self.create_or_fail(context, inputs);
865 map_result_create_outcome(&self.db.inner, result)
866 }
867
868 fn call(
869 &mut self,
870 context: &mut ContractCtx<'a, Runtime>,
871 inputs: &mut CallInputs,
872 ) -> Option<CallOutcome> {
873 let result = self.call_or_fail(context, inputs);
874 map_result_call_outcome(&self.db.inner, result)
875 }
876}
877
878impl<Runtime: ContractRuntime> CallInterceptorContract<Runtime> {
879 fn get_expected_application_id(
894 context: &mut ContractCtx<'_, Runtime>,
895 module_id: ModuleId,
896 num_apps: u32,
897 ) -> Result<ApplicationId, ExecutionError> {
898 let mut runtime = context.db().0.lock_runtime();
899 let chain_id = runtime.chain_id()?;
900 let block_height = runtime.block_height()?;
901 let application_index = runtime.peek_application_index()? + num_apps;
902 let parameters = JSON_EMPTY_VECTOR.to_vec(); let required_application_ids = Vec::new();
904 let application_description = ApplicationDescription {
905 module_id,
906 creator_chain_id: chain_id,
907 block_height,
908 application_index,
909 parameters: parameters.clone(),
910 required_application_ids,
911 };
912 Ok(ApplicationId::from(&application_description))
913 }
914
915 fn publish_create_inputs(
918 context: &mut ContractCtx<'_, Runtime>,
919 inputs: &CreateInputs,
920 ) -> Result<ModuleId, ExecutionError> {
921 let contract = linera_base::data_types::Bytecode::new(inputs.init_code.to_vec());
922 let service = linera_base::data_types::Bytecode::new(vec![]);
923 let mut runtime = context.db().0.lock_runtime();
924 runtime.publish_module(contract, service, VmRuntime::Evm)
925 }
926
927 fn create_or_fail(
1020 &mut self,
1021 context: &mut ContractCtx<'_, Runtime>,
1022 inputs: &mut CreateInputs,
1023 ) -> Result<Option<CreateOutcome>, ExecutionError> {
1024 if !self.db.inner.is_revm_instantiated {
1025 self.db.inner.is_revm_instantiated = true;
1026 inputs.scheme = CreateScheme::Custom {
1027 address: self.contract_address,
1028 };
1029 return Ok(None);
1030 }
1031 let module_id = Self::publish_create_inputs(context, inputs)?;
1032 let mut map = self.db.modules.lock().unwrap();
1033 let num_apps = map.len() as u32;
1034 let expected_application_id =
1035 Self::get_expected_application_id(context, module_id, num_apps)?;
1036 map.insert(expected_application_id, (module_id, num_apps));
1037 let address = expected_application_id.evm_address();
1038 if inputs.value != U256::ZERO {
1039 let value = Amount::try_from(inputs.value).map_err(EvmExecutionError::from)?;
1040 let mut runtime = context.db().0.lock_runtime();
1041 let application_id = runtime.application_id()?;
1042 let source = application_id.into();
1043 let chain_id = runtime.chain_id()?;
1044 let account = identifiers::Account {
1045 chain_id,
1046 owner: expected_application_id.into(),
1047 };
1048 runtime.transfer(source, account, value)?;
1049 }
1050 inputs.scheme = CreateScheme::Custom { address };
1051 Ok(None)
1052 }
1053
1054 fn call_or_fail(
1074 &self,
1075 _context: &mut ContractCtx<'_, Runtime>,
1076 inputs: &CallInputs,
1077 ) -> Result<Option<CallOutcome>, ExecutionError> {
1078 let is_precompile = self.precompile_addresses.contains(&inputs.target_address);
1079 let is_first_call = inputs.target_address == self.contract_address;
1080 if is_precompile {
1081 if let CallValue::Transfer(value) = inputs.value {
1082 ensure!(
1083 value == U256::ZERO,
1084 EvmExecutionError::NonZeroTransferPrecompile
1085 );
1086 }
1087 }
1088 if is_precompile || is_first_call {
1089 return Ok(None);
1091 }
1092 if let CallValue::Transfer(value) = inputs.value {
1094 if value != U256::ZERO {
1095 let source: AccountOwner = inputs.caller.into();
1096 let owner: AccountOwner = inputs.bytecode_address.into();
1097 let mut runtime = self.db.lock_runtime();
1098 let amount = Amount::try_from(value).map_err(EvmExecutionError::from)?;
1099 let chain_id = runtime.chain_id()?;
1100 let destination = Account { chain_id, owner };
1101 runtime.transfer(source, destination, amount)?;
1102 }
1103 }
1104 Ok(None)
1106 }
1107}
1108
1109struct CallInterceptorService<Runtime> {
1110 db: ServiceDatabase<Runtime>,
1111 contract_address: Address,
1113 precompile_addresses: BTreeSet<Address>,
1114}
1115
1116impl<Runtime> Clone for CallInterceptorService<Runtime> {
1117 fn clone(&self) -> Self {
1118 Self {
1119 db: self.db.clone(),
1120 contract_address: self.contract_address,
1121 precompile_addresses: self.precompile_addresses.clone(),
1122 }
1123 }
1124}
1125
1126impl<'a, Runtime: ServiceRuntime> Inspector<ServiceCtx<'a, Runtime>>
1127 for CallInterceptorService<Runtime>
1128{
1129 fn create(
1131 &mut self,
1132 context: &mut ServiceCtx<'a, Runtime>,
1133 inputs: &mut CreateInputs,
1134 ) -> Option<CreateOutcome> {
1135 let result = self.create_or_fail(context, inputs);
1136 map_result_create_outcome(&self.db.inner, result)
1137 }
1138}
1139
1140impl<Runtime: ServiceRuntime> CallInterceptorService<Runtime> {
1141 fn create_or_fail(
1162 &mut self,
1163 _context: &ServiceCtx<'_, Runtime>,
1164 inputs: &mut CreateInputs,
1165 ) -> Result<Option<CreateOutcome>, ExecutionError> {
1166 if !self.db.inner.is_revm_instantiated {
1167 self.db.inner.is_revm_instantiated = true;
1168 inputs.scheme = CreateScheme::Custom {
1169 address: self.contract_address,
1170 };
1171 Ok(None)
1172 } else {
1173 Err(EvmExecutionError::NoContractCreationInService.into())
1174 }
1175 }
1176}
1177
1178pub struct RevmContractInstance<Runtime> {
1179 module: Vec<u8>,
1180 db: ContractDatabase<Runtime>,
1181}
1182
1183#[derive(Debug)]
1185enum EvmTxKind {
1186 Create,
1188 Call,
1190}
1191
1192#[derive(Debug)]
1194struct ExecutionResultSuccess {
1195 gas_final: u64,
1197 logs: Vec<Log>,
1199 output: Output,
1201}
1202
1203impl ExecutionResultSuccess {
1204 fn output_and_logs(self) -> (u64, Vec<u8>, Vec<Log>) {
1205 let Output::Call(output) = self.output else {
1206 unreachable!("The output should have been created from a EvmTxKind::Call");
1207 };
1208 let output = output.as_ref().to_vec();
1209 (self.gas_final, output, self.logs)
1210 }
1211
1212 fn check_contract_initialization(&self, expected_address: Address) -> Result<(), String> {
1214 let Output::Create(_, contract_address) = self.output else {
1216 return Err("Input should be ExmTxKind::Create".to_string());
1217 };
1218 let contract_address = contract_address.ok_or("Deployment failed")?;
1220 if contract_address == expected_address {
1222 Ok(())
1223 } else {
1224 Err("Contract address is not the same as ApplicationId".to_string())
1225 }
1226 }
1227}
1228
1229impl<Runtime> UserContract for RevmContractInstance<Runtime>
1230where
1231 Runtime: ContractRuntime,
1232{
1233 fn instantiate(&mut self, argument: Vec<u8>) -> Result<(), ExecutionError> {
1234 self.db.inner.set_contract_address()?;
1235 let caller = self.get_msg_address()?;
1236 let instantiation_argument = serde_json::from_slice::<EvmInstantiation>(&argument)?;
1237 if let Some(remainder) = instantiation_argument
1240 .argument
1241 .as_slice()
1242 .strip_prefix(ALREADY_CREATED_CONTRACT_SELECTOR)
1243 {
1244 let account = bcs::from_bytes::<revm_state::Account>(remainder)?;
1245 return self.db.commit_contract_changes(&account);
1246 }
1247 self.initialize_contract(instantiation_argument.value, caller)?;
1248 if has_selector(&self.module, INSTANTIATE_SELECTOR) {
1249 let argument = get_revm_instantiation_bytes(instantiation_argument.argument);
1250 let result = self.transact_commit(&EvmTxKind::Call, argument, U256::ZERO, caller)?;
1251 self.write_logs(&result.logs, "instantiate")?;
1252 }
1253 Ok(())
1254 }
1255
1256 fn execute_operation(&mut self, operation: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1269 self.db.inner.set_contract_address()?;
1270 ensure_message_length(operation.len(), 4)?;
1271 if operation == GET_ACCOUNT_INFO_SELECTOR {
1272 let account_info = self.db.inner.get_account_info()?;
1273 return Ok(bcs::to_bytes(&account_info)?);
1274 }
1275 if let Some(remainder) = operation
1276 .as_slice()
1277 .strip_prefix(GET_CONTRACT_STORAGE_SELECTOR)
1278 {
1279 let index = bcs::from_bytes(remainder)?;
1280 let value = self.db.inner.read_from_local_storage(index)?;
1281 return Ok(bcs::to_bytes(&value)?);
1282 }
1283 if let Some(remainder) = operation
1284 .as_slice()
1285 .strip_prefix(COMMIT_CONTRACT_CHANGES_SELECTOR)
1286 {
1287 let account = bcs::from_bytes::<revm_state::Account>(remainder)?;
1288 self.db.commit_contract_changes(&account)?;
1289 return Ok(Vec::new());
1290 }
1291 let caller = self.get_msg_address()?;
1292 forbid_execute_operation_origin(&operation[..4])?;
1293 let evm_call = bcs::from_bytes::<EvmOperation>(&operation)?;
1294 let result = self.init_transact_commit(evm_call.argument, evm_call.value, caller)?;
1295 let (gas_final, output, logs) = result.output_and_logs();
1296 self.consume_fuel(gas_final)?;
1297 self.write_logs(&logs, "operation")?;
1298 Ok(output)
1299 }
1300
1301 fn execute_message(&mut self, message: Vec<u8>) -> Result<(), ExecutionError> {
1302 self.db.inner.set_contract_address()?;
1303 ensure_selector_presence(
1304 &self.module,
1305 EXECUTE_MESSAGE_SELECTOR,
1306 "function execute_message(bytes)",
1307 )?;
1308 let operation = get_revm_execute_message_bytes(message);
1309 let caller = self.get_msg_address()?;
1310 let value = U256::ZERO;
1311 self.execute_no_return_operation(operation, "message", value, caller)
1312 }
1313
1314 fn process_streams(&mut self, streams: Vec<StreamUpdate>) -> Result<(), ExecutionError> {
1315 self.db.inner.set_contract_address()?;
1316 let operation = get_revm_process_streams_bytes(streams);
1317 ensure_selector_presence(
1318 &self.module,
1319 PROCESS_STREAMS_SELECTOR,
1320 "function process_streams(Linera.StreamUpdate[] memory streams)",
1321 )?;
1322 let caller = Address::ZERO;
1324 let value = U256::ZERO;
1325 self.execute_no_return_operation(operation, "process_streams", value, caller)
1326 }
1327
1328 fn finalize(&mut self) -> Result<(), ExecutionError> {
1329 Ok(())
1330 }
1331}
1332
1333fn process_execution_result(
1334 result: ExecutionResult,
1335) -> Result<ExecutionResultSuccess, EvmExecutionError> {
1336 match result {
1337 ExecutionResult::Success {
1338 reason,
1339 gas_used,
1340 gas_refunded,
1341 logs,
1342 output,
1343 } => {
1344 let max_refund = gas_used / 5;
1346 let actual_refund = gas_refunded.min(max_refund);
1347 let gas_final = gas_used - actual_refund;
1348 if !matches!(reason, SuccessReason::Return) {
1349 Err(EvmExecutionError::NoReturnInterpreter {
1350 reason,
1351 gas_used,
1352 gas_refunded,
1353 logs,
1354 output,
1355 })
1356 } else {
1357 Ok(ExecutionResultSuccess {
1358 gas_final,
1359 logs,
1360 output,
1361 })
1362 }
1363 }
1364 ExecutionResult::Revert { gas_used, output } => {
1365 Err(EvmExecutionError::Revert { gas_used, output })
1366 }
1367 ExecutionResult::Halt { gas_used, reason } => {
1368 Err(EvmExecutionError::Halt { gas_used, reason })
1369 }
1370 }
1371}
1372
1373impl<Runtime> RevmContractInstance<Runtime>
1374where
1375 Runtime: ContractRuntime,
1376{
1377 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1378 let db = ContractDatabase::new(runtime);
1379 Self { module, db }
1380 }
1381
1382 fn execute_no_return_operation(
1383 &mut self,
1384 operation: Vec<u8>,
1385 origin: &str,
1386 value: U256,
1387 caller: Address,
1388 ) -> Result<(), ExecutionError> {
1389 let result = self.init_transact_commit(operation, value, caller)?;
1390 let (gas_final, output, logs) = result.output_and_logs();
1391 self.consume_fuel(gas_final)?;
1392 self.write_logs(&logs, origin)?;
1393 assert_eq!(output.len(), 0);
1394 Ok(())
1395 }
1396
1397 fn init_transact_commit(
1399 &mut self,
1400 vec: Vec<u8>,
1401 value: U256,
1402 caller: Address,
1403 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1404 if !self.db.inner.set_is_initialized()? {
1408 self.initialize_contract(U256::ZERO, caller)?;
1409 }
1410 self.transact_commit(&EvmTxKind::Call, vec, value, caller)
1411 }
1412
1413 fn initialize_contract(&mut self, value: U256, caller: Address) -> Result<(), ExecutionError> {
1415 let mut vec_init = self.module.clone();
1416 let constructor_argument = self.db.inner.constructor_argument()?;
1417 vec_init.extend_from_slice(&constructor_argument);
1418 let result = self.transact_commit(&EvmTxKind::Create, vec_init, value, caller)?;
1419 result
1420 .check_contract_initialization(self.db.inner.contract_address)
1421 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1422 self.write_logs(&result.logs, "deploy")
1423 }
1424
1425 fn get_msg_address(&self) -> Result<Address, ExecutionError> {
1438 let mut runtime = self.db.lock_runtime();
1439 let application_id = runtime.authenticated_caller_id()?;
1440 if let Some(application_id) = application_id {
1441 return Ok(if application_id.is_evm() {
1442 application_id.evm_address()
1443 } else {
1444 Address::ZERO
1445 });
1446 };
1447 let account_owner = runtime.authenticated_owner()?;
1448 if let Some(AccountOwner::Address20(address)) = account_owner {
1449 return Ok(Address::from(address));
1450 };
1451 Ok(ZERO_ADDRESS)
1452 }
1453
1454 fn transact_commit(
1455 &mut self,
1456 tx_kind: &EvmTxKind,
1457 input: Vec<u8>,
1458 value: U256,
1459 caller: Address,
1460 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1461 let contract_address = self.db.inner.contract_address;
1462 self.db.inner.caller = caller;
1463 self.db.inner.value = value;
1464 self.db.inner.deposit_funds()?;
1465 let data = Bytes::from(input);
1466 let kind = match tx_kind {
1467 EvmTxKind::Create => TxKind::Create,
1468 EvmTxKind::Call => TxKind::Call(contract_address),
1469 };
1470 let inspector = CallInterceptorContract {
1471 db: self.db.clone(),
1472 contract_address,
1473 precompile_addresses: precompile_addresses(),
1474 error: Arc::new(Mutex::new(None)),
1475 };
1476 let block_env = self.db.get_block_env()?;
1477 let (max_size_evm_contract, gas_limit) = {
1478 let mut runtime = self.db.lock_runtime();
1479 let gas_limit = runtime.remaining_fuel(VmRuntime::Evm)?;
1480 let max_size_evm_contract = runtime.maximum_blob_size()? as usize;
1481 (max_size_evm_contract, gas_limit)
1482 };
1483 let nonce = self.db.get_nonce(&caller)?;
1484 let result = {
1485 let mut ctx: revm_context::Context<
1486 BlockEnv,
1487 _,
1488 _,
1489 _,
1490 Journal<WrapDatabaseRef<&mut ContractDatabase<Runtime>>>,
1491 (),
1492 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1493 WrapDatabaseRef(&mut self.db),
1494 SpecId::PRAGUE,
1495 )
1496 .with_block(block_env);
1497 ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1498 let instructions = EthInstructions::new_mainnet();
1499 let mut evm = Evm::new_with_inspector(
1500 ctx,
1501 inspector.clone(),
1502 instructions,
1503 ContractPrecompile::default(),
1504 );
1505 evm.inspect_commit(
1506 TxEnv {
1507 kind,
1508 data,
1509 nonce,
1510 gas_limit,
1511 caller,
1512 value,
1513 ..TxEnv::default()
1514 },
1515 inspector.clone(),
1516 )
1517 .map_err(|error| {
1518 let error = format!("{:?}", error);
1519 EvmExecutionError::TransactCommitError(error)
1520 })
1521 }?;
1522 self.db.inner.process_any_error()?;
1523 self.db.commit_changes()?;
1524 Ok(process_execution_result(result)?)
1525 }
1526
1527 fn consume_fuel(&self, gas_final: u64) -> Result<(), ExecutionError> {
1528 let mut runtime = self.db.lock_runtime();
1529 runtime.consume_fuel(gas_final, VmRuntime::Evm)
1530 }
1531
1532 fn write_logs(&self, logs: &[Log], origin: &str) -> Result<(), ExecutionError> {
1533 if !logs.is_empty() {
1535 let mut runtime = self.db.lock_runtime();
1536 let block_height = runtime.block_height()?;
1537 let stream_name = bcs::to_bytes("ethereum_event")?;
1538 let stream_name = StreamName(stream_name);
1539 for log in logs {
1540 let value = bcs::to_bytes(&(origin, block_height.0, log))?;
1541 runtime.emit(stream_name.clone(), value)?;
1542 }
1543 }
1544 Ok(())
1545 }
1546}
1547
1548pub struct RevmServiceInstance<Runtime> {
1549 module: Vec<u8>,
1550 db: ServiceDatabase<Runtime>,
1551}
1552
1553impl<Runtime> RevmServiceInstance<Runtime>
1554where
1555 Runtime: ServiceRuntime,
1556{
1557 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1558 let db = ServiceDatabase::new(runtime);
1559 Self { module, db }
1560 }
1561}
1562
1563impl<Runtime> UserService for RevmServiceInstance<Runtime>
1564where
1565 Runtime: ServiceRuntime,
1566{
1567 fn handle_query(&mut self, argument: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1568 self.db.inner.set_contract_address()?;
1569 let evm_query = serde_json::from_slice(&argument)?;
1570 let query = match evm_query {
1571 EvmQuery::AccountInfo => {
1572 let account_info = self.db.inner.get_account_info()?;
1573 return Ok(serde_json::to_vec(&account_info)?);
1574 }
1575 EvmQuery::Storage(index) => {
1576 let value = self.db.inner.read_from_local_storage(index)?;
1577 return Ok(serde_json::to_vec(&value)?);
1578 }
1579 EvmQuery::Query(vec) => vec,
1580 EvmQuery::Operation(operation) => {
1581 let mut runtime = self.db.lock_runtime();
1582 runtime.schedule_operation(operation)?;
1583 return Ok(Vec::new());
1584 }
1585 EvmQuery::Operations(operations) => {
1586 let mut runtime = self.db.lock_runtime();
1587 for operation in operations {
1588 runtime.schedule_operation(operation)?;
1589 }
1590 return Ok(Vec::new());
1591 }
1592 };
1593
1594 ensure_message_length(query.len(), 4)?;
1595 let result = self.init_transact(query)?;
1599 let (_gas_final, output, _logs) = result.output_and_logs();
1600 let answer = serde_json::to_vec(&output)?;
1601 Ok(answer)
1602 }
1603}
1604
1605impl<Runtime> RevmServiceInstance<Runtime>
1606where
1607 Runtime: ServiceRuntime,
1608{
1609 fn init_transact(&mut self, vec: Vec<u8>) -> Result<ExecutionResultSuccess, ExecutionError> {
1610 let contract_address = self.db.inner.contract_address;
1614 if !self.db.inner.set_is_initialized()? {
1615 let changes = {
1616 let mut vec_init = self.module.clone();
1617 let constructor_argument = self.db.inner.constructor_argument()?;
1618 vec_init.extend_from_slice(&constructor_argument);
1619 let (result, changes) = self.transact(TxKind::Create, vec_init)?;
1620 result
1621 .check_contract_initialization(contract_address)
1622 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1623 changes
1624 };
1625 self.db.inner.changes = changes;
1626 }
1627 ensure_message_length(vec.len(), 4)?;
1628 forbid_execute_operation_origin(&vec[..4])?;
1629 let kind = TxKind::Call(contract_address);
1630 let (execution_result, _) = self.transact(kind, vec)?;
1631 Ok(execution_result)
1632 }
1633
1634 fn transact(
1635 &mut self,
1636 kind: TxKind,
1637 input: Vec<u8>,
1638 ) -> Result<(ExecutionResultSuccess, EvmState), ExecutionError> {
1639 let contract_address = self.db.inner.contract_address;
1640 let caller = SERVICE_ADDRESS;
1641 let value = U256::ZERO;
1642 self.db.inner.caller = caller;
1643 self.db.inner.value = value;
1644 let data = Bytes::from(input);
1645 let block_env = self.db.get_block_env()?;
1646 let inspector = CallInterceptorService {
1647 db: self.db.clone(),
1648 contract_address,
1649 precompile_addresses: precompile_addresses(),
1650 };
1651 let max_size_evm_contract = {
1652 let mut runtime = self.db.lock_runtime();
1653 runtime.maximum_blob_size()? as usize
1654 };
1655 let nonce = self.db.get_nonce(&caller)?;
1656 let result_state = {
1657 let mut ctx: revm_context::Context<
1658 BlockEnv,
1659 _,
1660 _,
1661 _,
1662 Journal<WrapDatabaseRef<&mut ServiceDatabase<Runtime>>>,
1663 (),
1664 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1665 WrapDatabaseRef(&mut self.db),
1666 SpecId::PRAGUE,
1667 )
1668 .with_block(block_env);
1669 ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1670 let instructions = EthInstructions::new_mainnet();
1671 let mut evm = Evm::new_with_inspector(
1672 ctx,
1673 inspector.clone(),
1674 instructions,
1675 ServicePrecompile::default(),
1676 );
1677 evm.inspect(
1678 TxEnv {
1679 kind,
1680 data,
1681 nonce,
1682 value,
1683 caller,
1684 gas_limit: EVM_SERVICE_GAS_LIMIT,
1685 ..TxEnv::default()
1686 },
1687 inspector,
1688 )
1689 .map_err(|error| {
1690 let error = format!("{:?}", error);
1691 EvmExecutionError::TransactCommitError(error)
1692 })
1693 }?;
1694 self.db.inner.process_any_error()?;
1695 let result = process_execution_result(result_state.result)?;
1696 Ok((result, result_state.state))
1697 }
1698}