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