linera_execution/evm/
revm.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Code specific to the usage of the [Revm](https://bluealloy.github.io/revm/) runtime.
5
6use core::ops::Range;
7use std::{collections::BTreeSet, convert::TryFrom};
8
9#[cfg(with_metrics)]
10use linera_base::prometheus_util::MeasureLatency as _;
11use linera_base::{
12    crypto::CryptoHash,
13    data_types::{Bytecode, Resources, SendMessageRequest, StreamUpdate},
14    ensure,
15    identifiers::{ApplicationId, ChainId, StreamName},
16    vm::{EvmQuery, VmRuntime},
17};
18use revm::{primitives::Bytes, InspectCommitEvm, InspectEvm, Inspector};
19use revm_context::{
20    result::{ExecutionResult, Output, SuccessReason},
21    BlockEnv, Cfg, ContextTr, Evm, Journal, LocalContextTr, TxEnv,
22};
23use revm_database::WrapDatabaseRef;
24use revm_handler::{
25    instructions::EthInstructions, EthPrecompiles, MainnetContext, PrecompileProvider,
26};
27use revm_interpreter::{
28    CallInput, CallInputs, CallOutcome, CreateInputs, CreateOutcome, CreateScheme, Gas, InputsImpl,
29    InstructionResult, InterpreterResult,
30};
31use revm_primitives::{address, hardfork::SpecId, Address, Log, TxKind};
32use revm_state::EvmState;
33use serde::{Deserialize, Serialize};
34
35use crate::{
36    evm::database::{DatabaseRuntime, StorageStats, EVM_SERVICE_GAS_LIMIT},
37    BaseRuntime, ContractRuntime, ContractSyncRuntimeHandle, EvmExecutionError, EvmRuntime,
38    ExecutionError, ServiceRuntime, ServiceSyncRuntimeHandle, UserContract, UserContractInstance,
39    UserContractModule, UserService, UserServiceInstance, UserServiceModule,
40};
41
42/// This is the selector of the `execute_message` that should be called
43/// only from a submitted message
44const EXECUTE_MESSAGE_SELECTOR: &[u8] = &[173, 125, 234, 205];
45
46/// This is the selector of the `process_streams` that should be called
47/// only from a submitted message
48const PROCESS_STREAMS_SELECTOR: &[u8] = &[227, 9, 189, 153];
49
50/// This is the selector of the `instantiate` that should be called
51/// only when creating a new instance of a shared contract
52const INSTANTIATE_SELECTOR: &[u8] = &[156, 163, 60, 158];
53
54fn forbid_execute_operation_origin(vec: &[u8]) -> Result<(), EvmExecutionError> {
55    if vec == EXECUTE_MESSAGE_SELECTOR {
56        return Err(EvmExecutionError::IllegalOperationCall(
57            "function execute_message".to_string(),
58        ));
59    }
60    if vec == PROCESS_STREAMS_SELECTOR {
61        return Err(EvmExecutionError::IllegalOperationCall(
62            "function process_streams".to_string(),
63        ));
64    }
65    if vec == INSTANTIATE_SELECTOR {
66        return Err(EvmExecutionError::IllegalOperationCall(
67            "function instantiate".to_string(),
68        ));
69    }
70    Ok(())
71}
72
73fn ensure_message_length(actual_length: usize, min_length: usize) -> Result<(), EvmExecutionError> {
74    ensure!(
75        actual_length >= min_length,
76        EvmExecutionError::OperationIsTooShort
77    );
78    Ok(())
79}
80
81fn ensure_selector_presence(
82    module: &[u8],
83    selector: &[u8],
84    fct_name: &str,
85) -> Result<(), EvmExecutionError> {
86    if !has_selector(module, selector) {
87        return Err(EvmExecutionError::MissingFunction(fct_name.to_string()));
88    }
89    Ok(())
90}
91
92/// The selector when calling for `InterpreterResult`. This is a fictional
93/// selector that does not correspond to a real function.
94const INTERPRETER_RESULT_SELECTOR: &[u8] = &[1, 2, 3, 4];
95
96#[cfg(test)]
97mod tests {
98    use revm_primitives::keccak256;
99
100    use crate::evm::revm::{
101        EXECUTE_MESSAGE_SELECTOR, INSTANTIATE_SELECTOR, PROCESS_STREAMS_SELECTOR,
102    };
103
104    // The function keccak256 is not const so we cannot build the execute_message
105    // selector directly.
106    #[test]
107    fn check_execute_message_selector() {
108        let selector = &keccak256("execute_message(bytes)".as_bytes())[..4];
109        assert_eq!(selector, EXECUTE_MESSAGE_SELECTOR);
110    }
111
112    #[test]
113    fn check_process_streams_selector() {
114        use alloy_sol_types::{sol, SolCall};
115        sol! {
116            struct InternalCryptoHash {
117                bytes32 value;
118            }
119
120            struct InternalApplicationId {
121                InternalCryptoHash application_description_hash;
122            }
123
124            struct InternalGenericApplicationId {
125                uint8 choice;
126                InternalApplicationId user;
127            }
128
129            struct InternalStreamName {
130                bytes stream_name;
131            }
132
133            struct InternalStreamId {
134                InternalGenericApplicationId application_id;
135                InternalStreamName stream_name;
136            }
137
138            struct InternalChainId {
139                InternalCryptoHash value;
140            }
141
142            struct InternalStreamUpdate {
143                InternalChainId chain_id;
144                InternalStreamId stream_id;
145                uint32 previous_index;
146                uint32 next_index;
147            }
148
149            function process_streams(InternalStreamUpdate[] internal_streams);
150        }
151        assert_eq!(
152            process_streamsCall::SIGNATURE,
153            "process_streams((((bytes32)),((uint8,((bytes32))),(bytes)),uint32,uint32)[])"
154        );
155        assert_eq!(process_streamsCall::SELECTOR, PROCESS_STREAMS_SELECTOR);
156    }
157
158    #[test]
159    fn check_instantiate_selector() {
160        let selector = &keccak256("instantiate(bytes)".as_bytes())[..4];
161        assert_eq!(selector, INSTANTIATE_SELECTOR);
162    }
163}
164
165fn has_selector(module: &[u8], selector: &[u8]) -> bool {
166    let push4 = 0x63; // An EVM instruction
167    let mut vec = vec![push4];
168    vec.extend(selector);
169    module.windows(5).any(|window| window == vec)
170}
171
172#[cfg(with_metrics)]
173mod metrics {
174    use std::sync::LazyLock;
175
176    use linera_base::prometheus_util::{exponential_bucket_latencies, register_histogram_vec};
177    use prometheus::HistogramVec;
178
179    pub static CONTRACT_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
180        register_histogram_vec(
181            "evm_contract_instantiation_latency",
182            "EVM contract instantiation latency",
183            &[],
184            exponential_bucket_latencies(1.0),
185        )
186    });
187
188    pub static SERVICE_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
189        register_histogram_vec(
190            "evm_service_instantiation_latency",
191            "EVM service instantiation latency",
192            &[],
193            exponential_bucket_latencies(1.0),
194        )
195    });
196}
197
198fn get_revm_instantiation_bytes(value: Vec<u8>) -> Vec<u8> {
199    use alloy_primitives::Bytes;
200    use alloy_sol_types::{sol, SolCall};
201    sol! {
202        function instantiate(bytes value);
203    }
204    let bytes = Bytes::from(value);
205    let argument = instantiateCall { value: bytes };
206    argument.abi_encode()
207}
208
209fn get_revm_execute_message_bytes(value: Vec<u8>) -> Vec<u8> {
210    use alloy_primitives::Bytes;
211    use alloy_sol_types::{sol, SolCall};
212    sol! {
213        function execute_message(bytes value);
214    }
215    let value = Bytes::from(value);
216    let argument = execute_messageCall { value };
217    argument.abi_encode()
218}
219
220fn get_revm_process_streams_bytes(streams: Vec<StreamUpdate>) -> Vec<u8> {
221    // See TODO(#3966) for a better support of the input.
222    use alloy_primitives::{Bytes, B256};
223    use alloy_sol_types::{sol, SolCall};
224    use linera_base::identifiers::{GenericApplicationId, StreamId};
225    sol! {
226        struct InternalCryptoHash {
227            bytes32 value;
228        }
229
230        struct InternalApplicationId {
231            InternalCryptoHash application_description_hash;
232        }
233
234        struct InternalGenericApplicationId {
235            uint8 choice;
236            InternalApplicationId user;
237        }
238
239        struct InternalStreamName {
240            bytes stream_name;
241        }
242
243        struct InternalStreamId {
244            InternalGenericApplicationId application_id;
245            InternalStreamName stream_name;
246        }
247
248        struct InternalChainId {
249            InternalCryptoHash value;
250        }
251
252        struct InternalStreamUpdate {
253            InternalChainId chain_id;
254            InternalStreamId stream_id;
255            uint32 previous_index;
256            uint32 next_index;
257        }
258
259        function process_streams(InternalStreamUpdate[] internal_streams);
260    }
261
262    fn crypto_hash_to_internal_crypto_hash(hash: CryptoHash) -> InternalCryptoHash {
263        let hash: [u64; 4] = <[u64; 4]>::from(hash);
264        let hash: [u8; 32] = linera_base::crypto::u64_array_to_be_bytes(hash);
265        let value: B256 = hash.into();
266        InternalCryptoHash { value }
267    }
268
269    fn chain_id_to_internal_chain_id(chain_id: ChainId) -> InternalChainId {
270        let value = crypto_hash_to_internal_crypto_hash(chain_id.0);
271        InternalChainId { value }
272    }
273
274    fn application_id_to_internal_application_id(
275        application_id: ApplicationId,
276    ) -> InternalApplicationId {
277        let application_description_hash =
278            crypto_hash_to_internal_crypto_hash(application_id.application_description_hash);
279        InternalApplicationId {
280            application_description_hash,
281        }
282    }
283
284    fn stream_name_to_internal_stream_name(stream_name: StreamName) -> InternalStreamName {
285        let stream_name = Bytes::from(stream_name.0);
286        InternalStreamName { stream_name }
287    }
288
289    fn generic_application_id_to_internal_generic_application_id(
290        generic_application_id: GenericApplicationId,
291    ) -> InternalGenericApplicationId {
292        match generic_application_id {
293            GenericApplicationId::System => {
294                let application_description_hash = InternalCryptoHash { value: B256::ZERO };
295                InternalGenericApplicationId {
296                    choice: 0,
297                    user: InternalApplicationId {
298                        application_description_hash,
299                    },
300                }
301            }
302            GenericApplicationId::User(application_id) => InternalGenericApplicationId {
303                choice: 1,
304                user: application_id_to_internal_application_id(application_id),
305            },
306        }
307    }
308
309    fn stream_id_to_internal_stream_id(stream_id: StreamId) -> InternalStreamId {
310        let application_id =
311            generic_application_id_to_internal_generic_application_id(stream_id.application_id);
312        let stream_name = stream_name_to_internal_stream_name(stream_id.stream_name);
313        InternalStreamId {
314            application_id,
315            stream_name,
316        }
317    }
318
319    fn stream_update_to_internal_stream_update(
320        stream_update: StreamUpdate,
321    ) -> InternalStreamUpdate {
322        let chain_id = chain_id_to_internal_chain_id(stream_update.chain_id);
323        let stream_id = stream_id_to_internal_stream_id(stream_update.stream_id);
324        InternalStreamUpdate {
325            chain_id,
326            stream_id,
327            previous_index: stream_update.previous_index,
328            next_index: stream_update.next_index,
329        }
330    }
331
332    let internal_streams = streams
333        .into_iter()
334        .map(stream_update_to_internal_stream_update)
335        .collect::<Vec<_>>();
336
337    let fct_call = process_streamsCall { internal_streams };
338    fct_call.abi_encode()
339}
340
341#[derive(Clone)]
342pub enum EvmContractModule {
343    #[cfg(with_revm)]
344    Revm { module: Vec<u8> },
345}
346
347impl EvmContractModule {
348    /// Creates a new [`EvmContractModule`] using the EVM module with the provided `contract_bytecode`.
349    pub async fn new(
350        contract_bytecode: Bytecode,
351        runtime: EvmRuntime,
352    ) -> Result<Self, EvmExecutionError> {
353        match runtime {
354            #[cfg(with_revm)]
355            EvmRuntime::Revm => Self::from_revm(contract_bytecode).await,
356        }
357    }
358
359    /// Creates a new [`EvmContractModule`] using the EVM module in `contract_bytecode_file`.
360    #[cfg(with_fs)]
361    pub async fn from_file(
362        contract_bytecode_file: impl AsRef<std::path::Path>,
363        runtime: EvmRuntime,
364    ) -> Result<Self, EvmExecutionError> {
365        Self::new(
366            Bytecode::load_from_file(contract_bytecode_file)
367                .await
368                .map_err(anyhow::Error::from)
369                .map_err(EvmExecutionError::LoadContractModule)?,
370            runtime,
371        )
372        .await
373    }
374
375    /// Creates a new [`EvmContractModule`] using Revm with the provided bytecode files.
376    pub async fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
377        let module = contract_bytecode.bytes;
378        Ok(EvmContractModule::Revm { module })
379    }
380}
381
382impl UserContractModule for EvmContractModule {
383    fn instantiate(
384        &self,
385        runtime: ContractSyncRuntimeHandle,
386    ) -> Result<UserContractInstance, ExecutionError> {
387        #[cfg(with_metrics)]
388        let _instantiation_latency = metrics::CONTRACT_INSTANTIATION_LATENCY.measure_latency();
389
390        let instance: UserContractInstance = match self {
391            #[cfg(with_revm)]
392            EvmContractModule::Revm { module } => {
393                Box::new(RevmContractInstance::prepare(module.to_vec(), runtime))
394            }
395        };
396
397        Ok(instance)
398    }
399}
400
401/// A user service in a compiled EVM module.
402#[derive(Clone)]
403pub enum EvmServiceModule {
404    #[cfg(with_revm)]
405    Revm { module: Vec<u8> },
406}
407
408impl EvmServiceModule {
409    /// Creates a new [`EvmServiceModule`] using the EVM module with the provided bytecode.
410    pub async fn new(
411        service_bytecode: Bytecode,
412        runtime: EvmRuntime,
413    ) -> Result<Self, EvmExecutionError> {
414        match runtime {
415            #[cfg(with_revm)]
416            EvmRuntime::Revm => Self::from_revm(service_bytecode).await,
417        }
418    }
419
420    /// Creates a new [`EvmServiceModule`] using the EVM module in `service_bytecode_file`.
421    #[cfg(with_fs)]
422    pub async fn from_file(
423        service_bytecode_file: impl AsRef<std::path::Path>,
424        runtime: EvmRuntime,
425    ) -> Result<Self, EvmExecutionError> {
426        Self::new(
427            Bytecode::load_from_file(service_bytecode_file)
428                .await
429                .map_err(anyhow::Error::from)
430                .map_err(EvmExecutionError::LoadServiceModule)?,
431            runtime,
432        )
433        .await
434    }
435
436    /// Creates a new [`EvmServiceModule`] using Revm with the provided bytecode files.
437    pub async fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
438        let module = contract_bytecode.bytes;
439        Ok(EvmServiceModule::Revm { module })
440    }
441}
442
443impl UserServiceModule for EvmServiceModule {
444    fn instantiate(
445        &self,
446        runtime: ServiceSyncRuntimeHandle,
447    ) -> Result<UserServiceInstance, ExecutionError> {
448        #[cfg(with_metrics)]
449        let _instantiation_latency = metrics::SERVICE_INSTANTIATION_LATENCY.measure_latency();
450
451        let instance: UserServiceInstance = match self {
452            #[cfg(with_revm)]
453            EvmServiceModule::Revm { module } => {
454                Box::new(RevmServiceInstance::prepare(module.to_vec(), runtime))
455            }
456        };
457
458        Ok(instance)
459    }
460}
461
462type Ctx<'a, Runtime> = MainnetContext<WrapDatabaseRef<&'a mut DatabaseRuntime<Runtime>>>;
463
464// This is the precompile address that contains the Linera specific
465// functionalities accessed from the EVM.
466const PRECOMPILE_ADDRESS: Address = address!("000000000000000000000000000000000000000b");
467
468// This is the zero address of the contract
469const ZERO_ADDRESS: Address = address!("0000000000000000000000000000000000000000");
470
471fn address_to_user_application_id(address: Address) -> ApplicationId {
472    let mut vec = vec![0_u8; 32];
473    vec[..20].copy_from_slice(address.as_ref());
474    ApplicationId::new(CryptoHash::try_from(&vec as &[u8]).unwrap())
475}
476
477/// Some functionalities from the BaseRuntime
478#[derive(Debug, Serialize, Deserialize)]
479enum BaseRuntimePrecompile {
480    /// Calling `chain_id` of `BaseRuntime`
481    ChainId,
482    /// Calling `application_creator_chain_id` of `BaseRuntime`
483    ApplicationCreatorChainId,
484    /// Calling `chain_ownership` of `BaseRuntime`
485    ChainOwnership,
486    /// Calling `read_data_blob` of `BaseRuntime`
487    ReadDataBlob { hash: CryptoHash },
488    /// Calling `assert_data_blob_exists` of `BaseRuntime`
489    AssertDataBlobExists { hash: CryptoHash },
490}
491
492/// Some functionalities from the ContractRuntime not in BaseRuntime
493#[derive(Debug, Serialize, Deserialize)]
494enum ContractRuntimePrecompile {
495    /// Calling `try_call_application` of `ContractRuntime`
496    TryCallApplication {
497        target: ApplicationId,
498        argument: Vec<u8>,
499    },
500    /// Calling `validation_round` of `ContractRuntime`
501    ValidationRound,
502    /// Calling `send_message` of `ContractRuntime`
503    SendMessage {
504        destination: ChainId,
505        message: Vec<u8>,
506    },
507    /// Calling `message_id` of `ContractRuntime`
508    MessageId,
509    /// Calling `message_is_bouncing` of `ContractRuntime`
510    MessageIsBouncing,
511    /// Calling `emit` of `ContractRuntime`
512    Emit {
513        stream_name: StreamName,
514        value: Vec<u8>,
515    },
516    /// Calling `read_event` of `ContractRuntime`
517    ReadEvent {
518        chain_id: ChainId,
519        stream_name: StreamName,
520        index: u32,
521    },
522    /// Calling `subscribe_to_events` of `ContractRuntime`
523    SubscribeToEvents {
524        chain_id: ChainId,
525        application_id: ApplicationId,
526        stream_name: StreamName,
527    },
528    /// Calling `unsubscribe_from_events` of `ContractRuntime`
529    UnsubscribeFromEvents {
530        chain_id: ChainId,
531        application_id: ApplicationId,
532        stream_name: StreamName,
533    },
534}
535
536/// Some functionalities from the ServiceRuntime not in BaseRuntime
537#[derive(Debug, Serialize, Deserialize)]
538enum ServiceRuntimePrecompile {
539    /// Calling `try_query_application` of `ServiceRuntime`
540    TryQueryApplication {
541        target: ApplicationId,
542        argument: Vec<u8>,
543    },
544}
545
546/// Key prefixes used to transmit precompiles.
547#[derive(Debug, Serialize, Deserialize)]
548enum RuntimePrecompile {
549    Base(BaseRuntimePrecompile),
550    Contract(ContractRuntimePrecompile),
551    Service(ServiceRuntimePrecompile),
552}
553
554fn get_precompile_output(
555    output: Vec<u8>,
556    gas_limit: u64,
557) -> Result<Option<InterpreterResult>, String> {
558    // The gas usage is set to `gas_limit` and no spending is being done on it.
559    // This means that for REVM, it looks like the precompile call costs nothing.
560    // This is because the costs of the EVM precompile calls is accounted for
561    // separately in Linera.
562    let output = Bytes::from(output);
563    let result = InstructionResult::default();
564    let gas = Gas::new(gas_limit);
565    Ok(Some(InterpreterResult {
566        result,
567        output,
568        gas,
569    }))
570}
571
572fn get_precompile_argument<Ctx: ContextTr>(context: &mut Ctx, input: &CallInput) -> Vec<u8> {
573    let mut argument = Vec::new();
574    get_argument(context, &mut argument, input);
575    argument
576}
577
578fn base_runtime_call<Runtime: BaseRuntime>(
579    request: BaseRuntimePrecompile,
580    context: &mut Ctx<'_, Runtime>,
581) -> Result<Vec<u8>, ExecutionError> {
582    let mut runtime = context
583        .db()
584        .0
585        .runtime
586        .lock()
587        .expect("The lock should be possible");
588    match request {
589        BaseRuntimePrecompile::ChainId => {
590            let chain_id = runtime.chain_id()?;
591            Ok(bcs::to_bytes(&chain_id)?)
592        }
593        BaseRuntimePrecompile::ApplicationCreatorChainId => {
594            let chain_id = runtime.application_creator_chain_id()?;
595            Ok(bcs::to_bytes(&chain_id)?)
596        }
597        BaseRuntimePrecompile::ChainOwnership => {
598            let chain_ownership = runtime.chain_ownership()?;
599            Ok(bcs::to_bytes(&chain_ownership)?)
600        }
601        BaseRuntimePrecompile::ReadDataBlob { hash } => runtime.read_data_blob(&hash),
602        BaseRuntimePrecompile::AssertDataBlobExists { hash } => {
603            runtime.assert_data_blob_exists(&hash)?;
604            Ok(Vec::new())
605        }
606    }
607}
608
609fn precompile_addresses() -> BTreeSet<Address> {
610    let mut addresses = BTreeSet::new();
611    for address in EthPrecompiles::default().warm_addresses() {
612        addresses.insert(address);
613    }
614    addresses.insert(PRECOMPILE_ADDRESS);
615    addresses
616}
617
618#[derive(Debug, Default)]
619struct ContractPrecompile {
620    inner: EthPrecompiles,
621}
622
623impl<'a, Runtime: ContractRuntime> PrecompileProvider<Ctx<'a, Runtime>> for ContractPrecompile {
624    type Output = InterpreterResult;
625
626    fn set_spec(&mut self, spec: <<Ctx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec) -> bool {
627        <EthPrecompiles as PrecompileProvider<Ctx<'a, Runtime>>>::set_spec(&mut self.inner, spec)
628    }
629
630    fn run(
631        &mut self,
632        context: &mut Ctx<'a, Runtime>,
633        address: &Address,
634        inputs: &InputsImpl,
635        is_static: bool,
636        gas_limit: u64,
637    ) -> Result<Option<InterpreterResult>, String> {
638        if address == &PRECOMPILE_ADDRESS {
639            let input = get_precompile_argument(context, &inputs.input);
640            let output = Self::call_or_fail(&input, context)
641                .map_err(|error| format!("ContractPrecompile error: {error}"))?;
642            return get_precompile_output(output, gas_limit);
643        }
644        self.inner
645            .run(context, address, inputs, is_static, gas_limit)
646    }
647
648    fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
649        let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
650        addresses.push(PRECOMPILE_ADDRESS);
651        Box::new(addresses.into_iter())
652    }
653
654    fn contains(&self, address: &Address) -> bool {
655        address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
656    }
657}
658
659impl<'a> ContractPrecompile {
660    fn contract_runtime_call<Runtime: ContractRuntime>(
661        request: ContractRuntimePrecompile,
662        context: &mut Ctx<'a, Runtime>,
663    ) -> Result<Vec<u8>, ExecutionError> {
664        let mut runtime = context
665            .db()
666            .0
667            .runtime
668            .lock()
669            .expect("The lock should be possible");
670        match request {
671            ContractRuntimePrecompile::TryCallApplication { target, argument } => {
672                let authenticated = true;
673                runtime.try_call_application(authenticated, target, argument)
674            }
675            ContractRuntimePrecompile::ValidationRound => {
676                let value = runtime.validation_round()?;
677                Ok(bcs::to_bytes(&value)?)
678            }
679            ContractRuntimePrecompile::SendMessage {
680                destination,
681                message,
682            } => {
683                let authenticated = true;
684                let is_tracked = true;
685                let grant = Resources::default();
686                let send_message_request = SendMessageRequest {
687                    destination,
688                    authenticated,
689                    is_tracked,
690                    grant,
691                    message,
692                };
693                runtime.send_message(send_message_request)?;
694                Ok(vec![])
695            }
696            ContractRuntimePrecompile::MessageId => {
697                let message_id = runtime.message_id()?;
698                Ok(bcs::to_bytes(&message_id)?)
699            }
700            ContractRuntimePrecompile::MessageIsBouncing => {
701                let result = runtime.message_is_bouncing()?;
702                Ok(bcs::to_bytes(&result)?)
703            }
704            ContractRuntimePrecompile::Emit { stream_name, value } => {
705                let result = runtime.emit(stream_name, value)?;
706                Ok(bcs::to_bytes(&result)?)
707            }
708            ContractRuntimePrecompile::ReadEvent {
709                chain_id,
710                stream_name,
711                index,
712            } => runtime.read_event(chain_id, stream_name, index),
713            ContractRuntimePrecompile::SubscribeToEvents {
714                chain_id,
715                application_id,
716                stream_name,
717            } => {
718                runtime.subscribe_to_events(chain_id, application_id, stream_name)?;
719                Ok(vec![])
720            }
721            ContractRuntimePrecompile::UnsubscribeFromEvents {
722                chain_id,
723                application_id,
724                stream_name,
725            } => {
726                runtime.unsubscribe_from_events(chain_id, application_id, stream_name)?;
727                Ok(vec![])
728            }
729        }
730    }
731
732    fn call_or_fail<Runtime: ContractRuntime>(
733        input: &[u8],
734        context: &mut Ctx<'a, Runtime>,
735    ) -> Result<Vec<u8>, ExecutionError> {
736        match bcs::from_bytes(input)? {
737            RuntimePrecompile::Base(base_tag) => base_runtime_call(base_tag, context),
738            RuntimePrecompile::Contract(contract_tag) => {
739                Self::contract_runtime_call(contract_tag, context)
740            }
741            RuntimePrecompile::Service(_) => Err(EvmExecutionError::PrecompileError(
742                "Service tags are not available in GeneralContractCall".to_string(),
743            )
744            .into()),
745        }
746    }
747}
748
749#[derive(Debug, Default)]
750struct ServicePrecompile {
751    inner: EthPrecompiles,
752}
753
754impl<'a> ServicePrecompile {
755    fn service_runtime_call<Runtime: ServiceRuntime>(
756        request: ServiceRuntimePrecompile,
757        context: &mut Ctx<'a, Runtime>,
758    ) -> Result<Vec<u8>, ExecutionError> {
759        let mut runtime = context
760            .db()
761            .0
762            .runtime
763            .lock()
764            .expect("The lock should be possible");
765        match request {
766            ServiceRuntimePrecompile::TryQueryApplication { target, argument } => {
767                runtime.try_query_application(target, argument)
768            }
769        }
770    }
771
772    fn call_or_fail<Runtime: ServiceRuntime>(
773        input: &[u8],
774        context: &mut Ctx<'a, Runtime>,
775    ) -> Result<Vec<u8>, ExecutionError> {
776        match bcs::from_bytes(input)? {
777            RuntimePrecompile::Base(base_tag) => base_runtime_call(base_tag, context),
778            RuntimePrecompile::Contract(_) => Err(EvmExecutionError::PrecompileError(
779                "Contract calls are not available in GeneralServiceCall".to_string(),
780            )
781            .into()),
782            RuntimePrecompile::Service(service_tag) => {
783                Self::service_runtime_call(service_tag, context)
784            }
785        }
786    }
787}
788
789impl<'a, Runtime: ServiceRuntime> PrecompileProvider<Ctx<'a, Runtime>> for ServicePrecompile {
790    type Output = InterpreterResult;
791
792    fn set_spec(&mut self, spec: <<Ctx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec) -> bool {
793        <EthPrecompiles as PrecompileProvider<Ctx<'a, Runtime>>>::set_spec(&mut self.inner, spec)
794    }
795
796    fn run(
797        &mut self,
798        context: &mut Ctx<'a, Runtime>,
799        address: &Address,
800        inputs: &InputsImpl,
801        is_static: bool,
802        gas_limit: u64,
803    ) -> Result<Option<InterpreterResult>, String> {
804        if address == &PRECOMPILE_ADDRESS {
805            let input = get_precompile_argument(context, &inputs.input);
806            let output = Self::call_or_fail(&input, context)
807                .map_err(|error| format!("ServicePrecompile error: {error}"))?;
808            return get_precompile_output(output, gas_limit);
809        }
810        self.inner
811            .run(context, address, inputs, is_static, gas_limit)
812    }
813
814    fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
815        let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
816        addresses.push(PRECOMPILE_ADDRESS);
817        Box::new(addresses.into_iter())
818    }
819
820    fn contains(&self, address: &Address) -> bool {
821        address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
822    }
823}
824
825fn map_result_call_outcome(
826    result: Result<Option<CallOutcome>, ExecutionError>,
827) -> Option<CallOutcome> {
828    match result {
829        Err(_error) => {
830            // An alternative way would be to return None, which would induce
831            // Revm to call the smart contract in its database, where it is
832            // non-existent.
833            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
851fn get_interpreter_result(
852    result: &[u8],
853    inputs: &mut CallInputs,
854) -> Result<InterpreterResult, ExecutionError> {
855    let mut result = bcs::from_bytes::<InterpreterResult>(result)?;
856    // This effectively means that no cost is incurred by the call to another contract.
857    // This is fine since the costs are incurred by the other contract itself.
858    result.gas = Gas::new(inputs.gas_limit);
859    Ok(result)
860}
861
862struct CallInterceptorContract<Runtime> {
863    db: DatabaseRuntime<Runtime>,
864    // This is the contract address of the contract being created.
865    contract_address: Address,
866    precompile_addresses: BTreeSet<Address>,
867}
868
869impl<Runtime> Clone for CallInterceptorContract<Runtime> {
870    fn clone(&self) -> Self {
871        Self {
872            db: self.db.clone(),
873            contract_address: self.contract_address,
874            precompile_addresses: self.precompile_addresses.clone(),
875        }
876    }
877}
878
879fn get_argument<Ctx: ContextTr>(context: &mut Ctx, argument: &mut Vec<u8>, input: &CallInput) {
880    match input {
881        CallInput::Bytes(bytes) => {
882            argument.extend(bytes.to_vec());
883        }
884        CallInput::SharedBuffer(range) => {
885            if let Some(slice) = context.local().shared_memory_buffer_slice(range.clone()) {
886                argument.extend(&*slice);
887            }
888        }
889    };
890}
891
892fn get_call_argument<Ctx: ContextTr>(context: &mut Ctx, input: &CallInput) -> Vec<u8> {
893    let mut argument: Vec<u8> = INTERPRETER_RESULT_SELECTOR.to_vec();
894    get_argument(context, &mut argument, input);
895    argument
896}
897
898impl<'a, Runtime: ContractRuntime> Inspector<Ctx<'a, Runtime>>
899    for CallInterceptorContract<Runtime>
900{
901    fn create(
902        &mut self,
903        _context: &mut Ctx<'a, Runtime>,
904        inputs: &mut CreateInputs,
905    ) -> Option<CreateOutcome> {
906        inputs.scheme = CreateScheme::Custom {
907            address: self.contract_address,
908        };
909        None
910    }
911
912    fn call(
913        &mut self,
914        context: &mut Ctx<'a, Runtime>,
915        inputs: &mut CallInputs,
916    ) -> Option<CallOutcome> {
917        let result = self.call_or_fail(context, inputs);
918        map_result_call_outcome(result)
919    }
920}
921
922impl<Runtime: ContractRuntime> CallInterceptorContract<Runtime> {
923    fn call_or_fail(
924        &mut self,
925        context: &mut Ctx<'_, Runtime>,
926        inputs: &mut CallInputs,
927    ) -> Result<Option<CallOutcome>, ExecutionError> {
928        // Every call to a contract passes by this function.
929        // Three kinds:
930        // --- Call to the PRECOMPILE smart contract.
931        // --- Call to the EVM smart contract itself
932        // --- Call to other EVM smart contract
933        if self.precompile_addresses.contains(&inputs.target_address)
934            || inputs.target_address == self.contract_address
935        {
936            // Precompile calls are handled by the precompile code.
937            // The EVM smart contract is being called
938            return Ok(None);
939        }
940        // Other smart contracts calls are handled by the runtime
941        let target = address_to_user_application_id(inputs.target_address);
942        let argument = get_call_argument(context, &inputs.input);
943        let authenticated = true;
944        let result = {
945            let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
946            runtime.try_call_application(authenticated, target, argument)?
947        };
948        let call_outcome = CallOutcome {
949            result: get_interpreter_result(&result, inputs)?,
950            memory_offset: inputs.return_memory_offset.clone(),
951        };
952        Ok(Some(call_outcome))
953    }
954}
955
956struct CallInterceptorService<Runtime> {
957    db: DatabaseRuntime<Runtime>,
958    // This is the contract address of the contract being created.
959    contract_address: Address,
960    precompile_addresses: BTreeSet<Address>,
961}
962
963impl<Runtime> Clone for CallInterceptorService<Runtime> {
964    fn clone(&self) -> Self {
965        Self {
966            db: self.db.clone(),
967            contract_address: self.contract_address,
968            precompile_addresses: self.precompile_addresses.clone(),
969        }
970    }
971}
972
973impl<'a, Runtime: ServiceRuntime> Inspector<Ctx<'a, Runtime>> for CallInterceptorService<Runtime> {
974    fn create(
975        &mut self,
976        _context: &mut Ctx<'a, Runtime>,
977        inputs: &mut CreateInputs,
978    ) -> Option<CreateOutcome> {
979        inputs.scheme = CreateScheme::Custom {
980            address: self.contract_address,
981        };
982        None
983    }
984
985    fn call(
986        &mut self,
987        context: &mut Ctx<'a, Runtime>,
988        inputs: &mut CallInputs,
989    ) -> Option<CallOutcome> {
990        let result = self.call_or_fail(context, inputs);
991        map_result_call_outcome(result)
992    }
993}
994
995impl<Runtime: ServiceRuntime> CallInterceptorService<Runtime> {
996    fn call_or_fail(
997        &mut self,
998        context: &mut Ctx<'_, Runtime>,
999        inputs: &mut CallInputs,
1000    ) -> Result<Option<CallOutcome>, ExecutionError> {
1001        // Every call to a contract passes by this function.
1002        // Three kinds:
1003        // --- Call to the PRECOMPILE smart contract.
1004        // --- Call to the EVM smart contract itself
1005        // --- Call to other EVM smart contract
1006        if self.precompile_addresses.contains(&inputs.target_address)
1007            || inputs.target_address == self.contract_address
1008        {
1009            // Precompile calls are handled by the precompile code.
1010            // The EVM smart contract is being called
1011            return Ok(None);
1012        }
1013        // Other smart contracts calls are handled by the runtime
1014        let target = address_to_user_application_id(inputs.target_address);
1015        let argument = get_call_argument(context, &inputs.input);
1016        let result = {
1017            let evm_query = EvmQuery::Query(argument);
1018            let evm_query = serde_json::to_vec(&evm_query)?;
1019            let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1020            runtime.try_query_application(target, evm_query)?
1021        };
1022        let call_outcome = CallOutcome {
1023            result: get_interpreter_result(&result, inputs)?,
1024            memory_offset: inputs.return_memory_offset.clone(),
1025        };
1026        Ok(Some(call_outcome))
1027    }
1028}
1029
1030pub struct RevmContractInstance<Runtime> {
1031    module: Vec<u8>,
1032    db: DatabaseRuntime<Runtime>,
1033}
1034
1035enum EvmTxKind {
1036    Create,
1037    Call,
1038}
1039
1040#[derive(Debug)]
1041struct ExecutionResultSuccess {
1042    reason: SuccessReason,
1043    gas_final: u64,
1044    logs: Vec<Log>,
1045    output: Output,
1046}
1047
1048impl ExecutionResultSuccess {
1049    fn interpreter_result_and_logs(self) -> Result<(u64, Vec<u8>, Vec<Log>), ExecutionError> {
1050        let result: InstructionResult = self.reason.into();
1051        let Output::Call(output) = self.output else {
1052            unreachable!("The output should have been created from a EvmTxKind::Call");
1053        };
1054        let gas = Gas::new(0);
1055        let result = InterpreterResult {
1056            result,
1057            output,
1058            gas,
1059        };
1060        let result = bcs::to_bytes(&result)?;
1061        Ok((self.gas_final, result, self.logs))
1062    }
1063
1064    fn output_and_logs(self) -> (u64, Vec<u8>, Vec<Log>) {
1065        let Output::Call(output) = self.output else {
1066            unreachable!("The output should have been created from a EvmTxKind::Call");
1067        };
1068        let output = output.as_ref().to_vec();
1069        (self.gas_final, output, self.logs)
1070    }
1071
1072    // Checks that the contract has been correctly instantiated
1073    fn check_contract_initialization(&self, expected_address: Address) -> Result<(), String> {
1074        // Checks that the output is the expected one.
1075        let Output::Create(_, contract_address) = self.output else {
1076            return Err("Input should be ExmTxKind::Create".to_string());
1077        };
1078        // Checks that the contract address exists.
1079        let contract_address = contract_address.ok_or("Deployment failed")?;
1080        // Checks that the created contract address is the one of the `ApplicationId`.
1081        if contract_address == expected_address {
1082            Ok(())
1083        } else {
1084            Err("Contract address is not the same as ApplicationId".to_string())
1085        }
1086    }
1087}
1088
1089impl<Runtime> UserContract for RevmContractInstance<Runtime>
1090where
1091    Runtime: ContractRuntime,
1092{
1093    fn instantiate(&mut self, argument: Vec<u8>) -> Result<(), ExecutionError> {
1094        self.db.set_contract_address()?;
1095        self.initialize_contract()?;
1096        if has_selector(&self.module, INSTANTIATE_SELECTOR) {
1097            let instantiation_argument = serde_json::from_slice::<Vec<u8>>(&argument)?;
1098            let argument = get_revm_instantiation_bytes(instantiation_argument);
1099            let result = self.transact_commit(EvmTxKind::Call, argument)?;
1100            self.write_logs(result.logs, "instantiate")?;
1101        }
1102        Ok(())
1103    }
1104
1105    fn execute_operation(&mut self, operation: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1106        self.db.set_contract_address()?;
1107        ensure_message_length(operation.len(), 4)?;
1108        let (gas_final, output, logs) = if &operation[..4] == INTERPRETER_RESULT_SELECTOR {
1109            ensure_message_length(operation.len(), 8)?;
1110            forbid_execute_operation_origin(&operation[4..8])?;
1111            let result = self.init_transact_commit(operation[4..].to_vec())?;
1112            result.interpreter_result_and_logs()?
1113        } else {
1114            ensure_message_length(operation.len(), 4)?;
1115            forbid_execute_operation_origin(&operation[..4])?;
1116            let result = self.init_transact_commit(operation)?;
1117            result.output_and_logs()
1118        };
1119        self.consume_fuel(gas_final)?;
1120        self.write_logs(logs, "operation")?;
1121        Ok(output)
1122    }
1123
1124    fn execute_message(&mut self, message: Vec<u8>) -> Result<(), ExecutionError> {
1125        self.db.set_contract_address()?;
1126        ensure_selector_presence(
1127            &self.module,
1128            EXECUTE_MESSAGE_SELECTOR,
1129            "function execute_message(bytes)",
1130        )?;
1131        let operation = get_revm_execute_message_bytes(message);
1132        self.execute_no_return_operation(operation, "message")
1133    }
1134
1135    fn process_streams(&mut self, streams: Vec<StreamUpdate>) -> Result<(), ExecutionError> {
1136        self.db.set_contract_address()?;
1137        let operation = get_revm_process_streams_bytes(streams);
1138        ensure_selector_presence(
1139            &self.module,
1140            PROCESS_STREAMS_SELECTOR,
1141            "function process_streams(LineraTypes.StreamUpdate[] memory streams)",
1142        )?;
1143        self.execute_no_return_operation(operation, "process_streams")
1144    }
1145
1146    fn finalize(&mut self) -> Result<(), ExecutionError> {
1147        Ok(())
1148    }
1149}
1150
1151fn process_execution_result(
1152    storage_stats: StorageStats,
1153    result: ExecutionResult,
1154) -> Result<ExecutionResultSuccess, EvmExecutionError> {
1155    match result {
1156        ExecutionResult::Success {
1157            reason,
1158            gas_used,
1159            gas_refunded,
1160            logs,
1161            output,
1162        } => {
1163            let mut gas_final = gas_used;
1164            gas_final -= storage_stats.storage_costs();
1165            assert_eq!(gas_refunded, storage_stats.storage_refund());
1166            if !matches!(reason, SuccessReason::Return) {
1167                Err(EvmExecutionError::NoReturnInterpreter {
1168                    reason,
1169                    gas_used,
1170                    gas_refunded,
1171                    logs,
1172                    output,
1173                })
1174            } else {
1175                Ok(ExecutionResultSuccess {
1176                    reason,
1177                    gas_final,
1178                    logs,
1179                    output,
1180                })
1181            }
1182        }
1183        ExecutionResult::Revert { gas_used, output } => {
1184            Err(EvmExecutionError::Revert { gas_used, output })
1185        }
1186        ExecutionResult::Halt { gas_used, reason } => {
1187            Err(EvmExecutionError::Halt { gas_used, reason })
1188        }
1189    }
1190}
1191
1192impl<Runtime> RevmContractInstance<Runtime>
1193where
1194    Runtime: ContractRuntime,
1195{
1196    pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1197        let db = DatabaseRuntime::new(runtime);
1198        Self { module, db }
1199    }
1200
1201    fn execute_no_return_operation(
1202        &mut self,
1203        operation: Vec<u8>,
1204        origin: &str,
1205    ) -> Result<(), ExecutionError> {
1206        let result = self.init_transact_commit(operation)?;
1207        let (gas_final, output, logs) = result.output_and_logs();
1208        self.consume_fuel(gas_final)?;
1209        self.write_logs(logs, origin)?;
1210        assert_eq!(output.len(), 0);
1211        Ok(())
1212    }
1213
1214    /// Executes the transaction. If needed initializes the contract.
1215    fn init_transact_commit(
1216        &mut self,
1217        vec: Vec<u8>,
1218    ) -> Result<ExecutionResultSuccess, ExecutionError> {
1219        // An application can be instantiated in Linera sense, but not in EVM sense,
1220        // that is the contract entries corresponding to the deployed contract may
1221        // be missing.
1222        if !self.db.is_initialized()? {
1223            self.initialize_contract()?;
1224        }
1225        self.transact_commit(EvmTxKind::Call, vec)
1226    }
1227
1228    /// Initializes the contract.
1229    fn initialize_contract(&mut self) -> Result<(), ExecutionError> {
1230        let mut vec_init = self.module.clone();
1231        let constructor_argument = self.db.constructor_argument()?;
1232        vec_init.extend_from_slice(&constructor_argument);
1233        let result = self.transact_commit(EvmTxKind::Create, vec_init)?;
1234        result
1235            .check_contract_initialization(self.db.contract_address)
1236            .map_err(EvmExecutionError::IncorrectContractCreation)?;
1237        self.write_logs(result.logs, "deploy")
1238    }
1239
1240    fn transact_commit(
1241        &mut self,
1242        ch: EvmTxKind,
1243        input: Vec<u8>,
1244    ) -> Result<ExecutionResultSuccess, ExecutionError> {
1245        let data = Bytes::from(input);
1246        let kind = match ch {
1247            EvmTxKind::Create => TxKind::Create,
1248            EvmTxKind::Call => TxKind::Call(self.db.contract_address),
1249        };
1250        let inspector = CallInterceptorContract {
1251            db: self.db.clone(),
1252            contract_address: self.db.contract_address,
1253            precompile_addresses: precompile_addresses(),
1254        };
1255        let block_env = self.db.get_contract_block_env()?;
1256        let gas_limit = {
1257            let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1258            runtime.remaining_fuel(VmRuntime::Evm)?
1259        };
1260        let nonce = self.db.get_nonce(&ZERO_ADDRESS)?;
1261        let result = {
1262            let ctx: revm_context::Context<
1263                BlockEnv,
1264                _,
1265                _,
1266                _,
1267                Journal<WrapDatabaseRef<&mut DatabaseRuntime<Runtime>>>,
1268                (),
1269            > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1270                WrapDatabaseRef(&mut self.db),
1271                SpecId::PRAGUE,
1272            )
1273            .with_block(block_env);
1274            let instructions = EthInstructions::new_mainnet();
1275            let mut evm = Evm::new_with_inspector(
1276                ctx,
1277                inspector.clone(),
1278                instructions,
1279                ContractPrecompile::default(),
1280            );
1281            evm.inspect_commit(
1282                TxEnv {
1283                    kind,
1284                    data,
1285                    nonce,
1286                    gas_limit,
1287                    ..TxEnv::default()
1288                },
1289                inspector,
1290            )
1291            .map_err(|error| {
1292                let error = format!("{:?}", error);
1293                EvmExecutionError::TransactCommitError(error)
1294            })
1295        }?;
1296        let storage_stats = self.db.take_storage_stats();
1297        self.db.commit_changes()?;
1298        Ok(process_execution_result(storage_stats, result)?)
1299    }
1300
1301    fn consume_fuel(&mut self, gas_final: u64) -> Result<(), ExecutionError> {
1302        let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1303        runtime.consume_fuel(gas_final, VmRuntime::Evm)
1304    }
1305
1306    fn write_logs(&mut self, logs: Vec<Log>, origin: &str) -> Result<(), ExecutionError> {
1307        // TODO(#3758): Extracting Ethereum events from the Linera events.
1308        if !logs.is_empty() {
1309            let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1310            let block_height = runtime.block_height()?;
1311            let stream_name = bcs::to_bytes("ethereum_event")?;
1312            let stream_name = StreamName(stream_name);
1313            for log in &logs {
1314                let value = bcs::to_bytes(&(origin, block_height.0, log))?;
1315                runtime.emit(stream_name.clone(), value)?;
1316            }
1317        }
1318        Ok(())
1319    }
1320}
1321
1322pub struct RevmServiceInstance<Runtime> {
1323    module: Vec<u8>,
1324    db: DatabaseRuntime<Runtime>,
1325}
1326
1327impl<Runtime> RevmServiceInstance<Runtime>
1328where
1329    Runtime: ServiceRuntime,
1330{
1331    pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1332        let db = DatabaseRuntime::new(runtime);
1333        Self { module, db }
1334    }
1335}
1336
1337impl<Runtime> UserService for RevmServiceInstance<Runtime>
1338where
1339    Runtime: ServiceRuntime,
1340{
1341    fn handle_query(&mut self, argument: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1342        self.db.set_contract_address()?;
1343        let evm_query = serde_json::from_slice(&argument)?;
1344        let query = match evm_query {
1345            EvmQuery::Query(vec) => vec,
1346            EvmQuery::Mutation(operation) => {
1347                let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1348                runtime.schedule_operation(operation)?;
1349                return Ok(Vec::new());
1350            }
1351        };
1352
1353        ensure_message_length(query.len(), 4)?;
1354        // We drop the logs since the "eth_call" execution does not return any log.
1355        // Also, for handle_query, we do not have associated costs.
1356        // More generally, there is gas costs associated to service operation.
1357        let answer = if &query[..4] == INTERPRETER_RESULT_SELECTOR {
1358            let result = self.init_transact(query[4..].to_vec())?;
1359            let (_gas_final, answer, _logs) = result.interpreter_result_and_logs()?;
1360            answer
1361        } else {
1362            let result = self.init_transact(query)?;
1363            let (_gas_final, output, _logs) = result.output_and_logs();
1364            serde_json::to_vec(&output)?
1365        };
1366        Ok(answer)
1367    }
1368}
1369
1370impl<Runtime> RevmServiceInstance<Runtime>
1371where
1372    Runtime: ServiceRuntime,
1373{
1374    fn init_transact(&mut self, vec: Vec<u8>) -> Result<ExecutionResultSuccess, ExecutionError> {
1375        // In case of a shared application, we need to instantiate it first
1376        // However, since in ServiceRuntime, we cannot modify the storage,
1377        // therefore the compiled contract is saved in the changes.
1378        if !self.db.is_initialized()? {
1379            let changes = {
1380                let mut vec_init = self.module.clone();
1381                let constructor_argument = self.db.constructor_argument()?;
1382                vec_init.extend_from_slice(&constructor_argument);
1383                let (result, changes) = self.transact(TxKind::Create, vec_init)?;
1384                result
1385                    .check_contract_initialization(self.db.contract_address)
1386                    .map_err(EvmExecutionError::IncorrectContractCreation)?;
1387                changes
1388            };
1389            self.db.changes = changes;
1390        }
1391        ensure_message_length(vec.len(), 4)?;
1392        forbid_execute_operation_origin(&vec[..4])?;
1393        let kind = TxKind::Call(self.db.contract_address);
1394        let (execution_result, _) = self.transact(kind, vec)?;
1395        Ok(execution_result)
1396    }
1397
1398    fn transact(
1399        &mut self,
1400        kind: TxKind,
1401        input: Vec<u8>,
1402    ) -> Result<(ExecutionResultSuccess, EvmState), ExecutionError> {
1403        let data = Bytes::from(input);
1404
1405        let block_env = self.db.get_service_block_env()?;
1406        let inspector = CallInterceptorService {
1407            db: self.db.clone(),
1408            contract_address: self.db.contract_address,
1409            precompile_addresses: precompile_addresses(),
1410        };
1411        let nonce = self.db.get_nonce(&ZERO_ADDRESS)?;
1412        let result_state = {
1413            let ctx: revm_context::Context<
1414                BlockEnv,
1415                _,
1416                _,
1417                _,
1418                Journal<WrapDatabaseRef<&mut DatabaseRuntime<Runtime>>>,
1419                (),
1420            > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1421                WrapDatabaseRef(&mut self.db),
1422                SpecId::PRAGUE,
1423            )
1424            .with_block(block_env);
1425            let instructions = EthInstructions::new_mainnet();
1426            let mut evm = Evm::new_with_inspector(
1427                ctx,
1428                inspector.clone(),
1429                instructions,
1430                ServicePrecompile::default(),
1431            );
1432            evm.inspect(
1433                TxEnv {
1434                    kind,
1435                    data,
1436                    nonce,
1437                    gas_limit: EVM_SERVICE_GAS_LIMIT,
1438                    ..TxEnv::default()
1439                },
1440                inspector,
1441            )
1442            .map_err(|error| {
1443                let error = format!("{:?}", error);
1444                EvmExecutionError::TransactCommitError(error)
1445            })
1446        }?;
1447        let storage_stats = self.db.take_storage_stats();
1448        Ok((
1449            process_execution_result(storage_stats, result_state.result)?,
1450            result_state.state,
1451        ))
1452    }
1453}