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