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::{AccountOwner, 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 used when no address can be obtained from `authenticated_signer`
469// and `authenticated_caller_id`. This scenario does not occur if an Address20 user calls or
470// if an EVM contract calls another EVM contract.
471const ZERO_ADDRESS: Address = address!("0000000000000000000000000000000000000000");
472
473// This is the address being used for service calls.
474const SERVICE_ADDRESS: Address = address!("0000000000000000000000000000000000002000");
475
476fn address_to_user_application_id(address: Address) -> ApplicationId {
477    let mut vec = vec![0_u8; 32];
478    vec[..20].copy_from_slice(address.as_ref());
479    ApplicationId::new(CryptoHash::try_from(&vec as &[u8]).unwrap())
480}
481
482/// Some functionalities from the BaseRuntime
483#[derive(Debug, Serialize, Deserialize)]
484enum BaseRuntimePrecompile {
485    /// Calling `chain_id` of `BaseRuntime`
486    ChainId,
487    /// Calling `application_creator_chain_id` of `BaseRuntime`
488    ApplicationCreatorChainId,
489    /// Calling `chain_ownership` of `BaseRuntime`
490    ChainOwnership,
491    /// Calling `read_data_blob` of `BaseRuntime`
492    ReadDataBlob { hash: CryptoHash },
493    /// Calling `assert_data_blob_exists` of `BaseRuntime`
494    AssertDataBlobExists { hash: CryptoHash },
495}
496
497/// Some functionalities from the ContractRuntime not in BaseRuntime
498#[derive(Debug, Serialize, Deserialize)]
499enum ContractRuntimePrecompile {
500    /// Calling `try_call_application` of `ContractRuntime`
501    TryCallApplication {
502        target: ApplicationId,
503        argument: Vec<u8>,
504    },
505    /// Calling `validation_round` of `ContractRuntime`
506    ValidationRound,
507    /// Calling `send_message` of `ContractRuntime`
508    SendMessage {
509        destination: ChainId,
510        message: Vec<u8>,
511    },
512    /// Calling `message_id` of `ContractRuntime`
513    MessageId,
514    /// Calling `message_is_bouncing` of `ContractRuntime`
515    MessageIsBouncing,
516    /// Calling `emit` of `ContractRuntime`
517    Emit {
518        stream_name: StreamName,
519        value: Vec<u8>,
520    },
521    /// Calling `read_event` of `ContractRuntime`
522    ReadEvent {
523        chain_id: ChainId,
524        stream_name: StreamName,
525        index: u32,
526    },
527    /// Calling `subscribe_to_events` of `ContractRuntime`
528    SubscribeToEvents {
529        chain_id: ChainId,
530        application_id: ApplicationId,
531        stream_name: StreamName,
532    },
533    /// Calling `unsubscribe_from_events` of `ContractRuntime`
534    UnsubscribeFromEvents {
535        chain_id: ChainId,
536        application_id: ApplicationId,
537        stream_name: StreamName,
538    },
539}
540
541/// Some functionalities from the ServiceRuntime not in BaseRuntime
542#[derive(Debug, Serialize, Deserialize)]
543enum ServiceRuntimePrecompile {
544    /// Calling `try_query_application` of `ServiceRuntime`
545    TryQueryApplication {
546        target: ApplicationId,
547        argument: Vec<u8>,
548    },
549}
550
551/// Key prefixes used to transmit precompiles.
552#[derive(Debug, Serialize, Deserialize)]
553enum RuntimePrecompile {
554    Base(BaseRuntimePrecompile),
555    Contract(ContractRuntimePrecompile),
556    Service(ServiceRuntimePrecompile),
557}
558
559fn get_precompile_output(
560    output: Vec<u8>,
561    gas_limit: u64,
562) -> Result<Option<InterpreterResult>, String> {
563    // The gas usage is set to `gas_limit` and no spending is being done on it.
564    // This means that for REVM, it looks like the precompile call costs nothing.
565    // This is because the costs of the EVM precompile calls is accounted for
566    // separately in Linera.
567    let output = Bytes::from(output);
568    let result = InstructionResult::default();
569    let gas = Gas::new(gas_limit);
570    Ok(Some(InterpreterResult {
571        result,
572        output,
573        gas,
574    }))
575}
576
577fn get_precompile_argument<Ctx: ContextTr>(context: &mut Ctx, input: &CallInput) -> Vec<u8> {
578    let mut argument = Vec::new();
579    get_argument(context, &mut argument, input);
580    argument
581}
582
583fn base_runtime_call<Runtime: BaseRuntime>(
584    request: BaseRuntimePrecompile,
585    context: &mut Ctx<'_, Runtime>,
586) -> Result<Vec<u8>, ExecutionError> {
587    let mut runtime = context
588        .db()
589        .0
590        .runtime
591        .lock()
592        .expect("The lock should be possible");
593    match request {
594        BaseRuntimePrecompile::ChainId => {
595            let chain_id = runtime.chain_id()?;
596            Ok(bcs::to_bytes(&chain_id)?)
597        }
598        BaseRuntimePrecompile::ApplicationCreatorChainId => {
599            let chain_id = runtime.application_creator_chain_id()?;
600            Ok(bcs::to_bytes(&chain_id)?)
601        }
602        BaseRuntimePrecompile::ChainOwnership => {
603            let chain_ownership = runtime.chain_ownership()?;
604            Ok(bcs::to_bytes(&chain_ownership)?)
605        }
606        BaseRuntimePrecompile::ReadDataBlob { hash } => runtime.read_data_blob(&hash),
607        BaseRuntimePrecompile::AssertDataBlobExists { hash } => {
608            runtime.assert_data_blob_exists(&hash)?;
609            Ok(Vec::new())
610        }
611    }
612}
613
614fn precompile_addresses() -> BTreeSet<Address> {
615    let mut addresses = BTreeSet::new();
616    for address in EthPrecompiles::default().warm_addresses() {
617        addresses.insert(address);
618    }
619    addresses.insert(PRECOMPILE_ADDRESS);
620    addresses
621}
622
623#[derive(Debug, Default)]
624struct ContractPrecompile {
625    inner: EthPrecompiles,
626}
627
628impl<'a, Runtime: ContractRuntime> PrecompileProvider<Ctx<'a, Runtime>> for ContractPrecompile {
629    type Output = InterpreterResult;
630
631    fn set_spec(&mut self, spec: <<Ctx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec) -> bool {
632        <EthPrecompiles as PrecompileProvider<Ctx<'a, Runtime>>>::set_spec(&mut self.inner, spec)
633    }
634
635    fn run(
636        &mut self,
637        context: &mut Ctx<'a, Runtime>,
638        address: &Address,
639        inputs: &InputsImpl,
640        is_static: bool,
641        gas_limit: u64,
642    ) -> Result<Option<InterpreterResult>, String> {
643        if address == &PRECOMPILE_ADDRESS {
644            let input = get_precompile_argument(context, &inputs.input);
645            let output = Self::call_or_fail(&input, context)
646                .map_err(|error| format!("ContractPrecompile error: {error}"))?;
647            return get_precompile_output(output, gas_limit);
648        }
649        self.inner
650            .run(context, address, inputs, is_static, gas_limit)
651    }
652
653    fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
654        let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
655        addresses.push(PRECOMPILE_ADDRESS);
656        Box::new(addresses.into_iter())
657    }
658
659    fn contains(&self, address: &Address) -> bool {
660        address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
661    }
662}
663
664impl<'a> ContractPrecompile {
665    fn contract_runtime_call<Runtime: ContractRuntime>(
666        request: ContractRuntimePrecompile,
667        context: &mut Ctx<'a, Runtime>,
668    ) -> Result<Vec<u8>, ExecutionError> {
669        let mut runtime = context
670            .db()
671            .0
672            .runtime
673            .lock()
674            .expect("The lock should be possible");
675        match request {
676            ContractRuntimePrecompile::TryCallApplication { target, argument } => {
677                let authenticated = true;
678                runtime.try_call_application(authenticated, target, argument)
679            }
680            ContractRuntimePrecompile::ValidationRound => {
681                let value = runtime.validation_round()?;
682                Ok(bcs::to_bytes(&value)?)
683            }
684            ContractRuntimePrecompile::SendMessage {
685                destination,
686                message,
687            } => {
688                let authenticated = true;
689                let is_tracked = true;
690                let grant = Resources::default();
691                let send_message_request = SendMessageRequest {
692                    destination,
693                    authenticated,
694                    is_tracked,
695                    grant,
696                    message,
697                };
698                runtime.send_message(send_message_request)?;
699                Ok(vec![])
700            }
701            ContractRuntimePrecompile::MessageId => {
702                let message_id = runtime.message_id()?;
703                Ok(bcs::to_bytes(&message_id)?)
704            }
705            ContractRuntimePrecompile::MessageIsBouncing => {
706                let result = runtime.message_is_bouncing()?;
707                Ok(bcs::to_bytes(&result)?)
708            }
709            ContractRuntimePrecompile::Emit { stream_name, value } => {
710                let result = runtime.emit(stream_name, value)?;
711                Ok(bcs::to_bytes(&result)?)
712            }
713            ContractRuntimePrecompile::ReadEvent {
714                chain_id,
715                stream_name,
716                index,
717            } => runtime.read_event(chain_id, stream_name, index),
718            ContractRuntimePrecompile::SubscribeToEvents {
719                chain_id,
720                application_id,
721                stream_name,
722            } => {
723                runtime.subscribe_to_events(chain_id, application_id, stream_name)?;
724                Ok(vec![])
725            }
726            ContractRuntimePrecompile::UnsubscribeFromEvents {
727                chain_id,
728                application_id,
729                stream_name,
730            } => {
731                runtime.unsubscribe_from_events(chain_id, application_id, stream_name)?;
732                Ok(vec![])
733            }
734        }
735    }
736
737    fn call_or_fail<Runtime: ContractRuntime>(
738        input: &[u8],
739        context: &mut Ctx<'a, Runtime>,
740    ) -> Result<Vec<u8>, ExecutionError> {
741        match bcs::from_bytes(input)? {
742            RuntimePrecompile::Base(base_tag) => base_runtime_call(base_tag, context),
743            RuntimePrecompile::Contract(contract_tag) => {
744                Self::contract_runtime_call(contract_tag, context)
745            }
746            RuntimePrecompile::Service(_) => Err(EvmExecutionError::PrecompileError(
747                "Service tags are not available in GeneralContractCall".to_string(),
748            )
749            .into()),
750        }
751    }
752}
753
754#[derive(Debug, Default)]
755struct ServicePrecompile {
756    inner: EthPrecompiles,
757}
758
759impl<'a> ServicePrecompile {
760    fn service_runtime_call<Runtime: ServiceRuntime>(
761        request: ServiceRuntimePrecompile,
762        context: &mut Ctx<'a, Runtime>,
763    ) -> Result<Vec<u8>, ExecutionError> {
764        let mut runtime = context
765            .db()
766            .0
767            .runtime
768            .lock()
769            .expect("The lock should be possible");
770        match request {
771            ServiceRuntimePrecompile::TryQueryApplication { target, argument } => {
772                runtime.try_query_application(target, argument)
773            }
774        }
775    }
776
777    fn call_or_fail<Runtime: ServiceRuntime>(
778        input: &[u8],
779        context: &mut Ctx<'a, Runtime>,
780    ) -> Result<Vec<u8>, ExecutionError> {
781        match bcs::from_bytes(input)? {
782            RuntimePrecompile::Base(base_tag) => base_runtime_call(base_tag, context),
783            RuntimePrecompile::Contract(_) => Err(EvmExecutionError::PrecompileError(
784                "Contract calls are not available in GeneralServiceCall".to_string(),
785            )
786            .into()),
787            RuntimePrecompile::Service(service_tag) => {
788                Self::service_runtime_call(service_tag, context)
789            }
790        }
791    }
792}
793
794impl<'a, Runtime: ServiceRuntime> PrecompileProvider<Ctx<'a, Runtime>> for ServicePrecompile {
795    type Output = InterpreterResult;
796
797    fn set_spec(&mut self, spec: <<Ctx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec) -> bool {
798        <EthPrecompiles as PrecompileProvider<Ctx<'a, Runtime>>>::set_spec(&mut self.inner, spec)
799    }
800
801    fn run(
802        &mut self,
803        context: &mut Ctx<'a, Runtime>,
804        address: &Address,
805        inputs: &InputsImpl,
806        is_static: bool,
807        gas_limit: u64,
808    ) -> Result<Option<InterpreterResult>, String> {
809        if address == &PRECOMPILE_ADDRESS {
810            let input = get_precompile_argument(context, &inputs.input);
811            let output = Self::call_or_fail(&input, context)
812                .map_err(|error| format!("ServicePrecompile error: {error}"))?;
813            return get_precompile_output(output, gas_limit);
814        }
815        self.inner
816            .run(context, address, inputs, is_static, gas_limit)
817    }
818
819    fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
820        let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
821        addresses.push(PRECOMPILE_ADDRESS);
822        Box::new(addresses.into_iter())
823    }
824
825    fn contains(&self, address: &Address) -> bool {
826        address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
827    }
828}
829
830fn map_result_call_outcome(
831    result: Result<Option<CallOutcome>, ExecutionError>,
832) -> Option<CallOutcome> {
833    match result {
834        Err(_error) => {
835            // An alternative way would be to return None, which would induce
836            // Revm to call the smart contract in its database, where it is
837            // non-existent.
838            let result = InstructionResult::Revert;
839            let output = Bytes::default();
840            let gas = Gas::default();
841            let result = InterpreterResult {
842                result,
843                output,
844                gas,
845            };
846            let memory_offset = Range::default();
847            Some(CallOutcome {
848                result,
849                memory_offset,
850            })
851        }
852        Ok(result) => result,
853    }
854}
855
856fn get_interpreter_result(
857    result: &[u8],
858    inputs: &mut CallInputs,
859) -> Result<InterpreterResult, ExecutionError> {
860    let mut result = bcs::from_bytes::<InterpreterResult>(result)?;
861    // This effectively means that no cost is incurred by the call to another contract.
862    // This is fine since the costs are incurred by the other contract itself.
863    result.gas = Gas::new(inputs.gas_limit);
864    Ok(result)
865}
866
867struct CallInterceptorContract<Runtime> {
868    db: DatabaseRuntime<Runtime>,
869    // This is the contract address of the contract being created.
870    contract_address: Address,
871    precompile_addresses: BTreeSet<Address>,
872}
873
874impl<Runtime> Clone for CallInterceptorContract<Runtime> {
875    fn clone(&self) -> Self {
876        Self {
877            db: self.db.clone(),
878            contract_address: self.contract_address,
879            precompile_addresses: self.precompile_addresses.clone(),
880        }
881    }
882}
883
884fn get_argument<Ctx: ContextTr>(context: &mut Ctx, argument: &mut Vec<u8>, input: &CallInput) {
885    match input {
886        CallInput::Bytes(bytes) => {
887            argument.extend(bytes.to_vec());
888        }
889        CallInput::SharedBuffer(range) => {
890            if let Some(slice) = context.local().shared_memory_buffer_slice(range.clone()) {
891                argument.extend(&*slice);
892            }
893        }
894    };
895}
896
897fn get_call_argument<Ctx: ContextTr>(context: &mut Ctx, inputs: &CallInputs) -> Vec<u8> {
898    let mut argument = INTERPRETER_RESULT_SELECTOR.to_vec();
899    get_argument(context, &mut argument, &inputs.input);
900    argument
901}
902
903impl<'a, Runtime: ContractRuntime> Inspector<Ctx<'a, Runtime>>
904    for CallInterceptorContract<Runtime>
905{
906    fn create(
907        &mut self,
908        _context: &mut Ctx<'a, Runtime>,
909        inputs: &mut CreateInputs,
910    ) -> Option<CreateOutcome> {
911        inputs.scheme = CreateScheme::Custom {
912            address: self.contract_address,
913        };
914        None
915    }
916
917    fn call(
918        &mut self,
919        context: &mut Ctx<'a, Runtime>,
920        inputs: &mut CallInputs,
921    ) -> Option<CallOutcome> {
922        let result = self.call_or_fail(context, inputs);
923        map_result_call_outcome(result)
924    }
925}
926
927impl<Runtime: ContractRuntime> CallInterceptorContract<Runtime> {
928    fn call_or_fail(
929        &mut self,
930        context: &mut Ctx<'_, Runtime>,
931        inputs: &mut CallInputs,
932    ) -> Result<Option<CallOutcome>, ExecutionError> {
933        // Every call to a contract passes by this function.
934        // Three kinds:
935        // --- Call to the PRECOMPILE smart contract.
936        // --- Call to the EVM smart contract itself
937        // --- Call to other EVM smart contract
938        if self.precompile_addresses.contains(&inputs.target_address)
939            || inputs.target_address == self.contract_address
940        {
941            // Precompile calls are handled by the precompile code.
942            // The EVM smart contract is being called
943            return Ok(None);
944        }
945        // Other smart contracts calls are handled by the runtime
946        let target = address_to_user_application_id(inputs.target_address);
947        let argument = get_call_argument(context, inputs);
948        let authenticated = true;
949        let result = {
950            let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
951            runtime.try_call_application(authenticated, target, argument)?
952        };
953        let call_outcome = CallOutcome {
954            result: get_interpreter_result(&result, inputs)?,
955            memory_offset: inputs.return_memory_offset.clone(),
956        };
957        Ok(Some(call_outcome))
958    }
959}
960
961struct CallInterceptorService<Runtime> {
962    db: DatabaseRuntime<Runtime>,
963    // This is the contract address of the contract being created.
964    contract_address: Address,
965    precompile_addresses: BTreeSet<Address>,
966}
967
968impl<Runtime> Clone for CallInterceptorService<Runtime> {
969    fn clone(&self) -> Self {
970        Self {
971            db: self.db.clone(),
972            contract_address: self.contract_address,
973            precompile_addresses: self.precompile_addresses.clone(),
974        }
975    }
976}
977
978impl<'a, Runtime: ServiceRuntime> Inspector<Ctx<'a, Runtime>> for CallInterceptorService<Runtime> {
979    fn create(
980        &mut self,
981        _context: &mut Ctx<'a, Runtime>,
982        inputs: &mut CreateInputs,
983    ) -> Option<CreateOutcome> {
984        inputs.scheme = CreateScheme::Custom {
985            address: self.contract_address,
986        };
987        None
988    }
989
990    fn call(
991        &mut self,
992        context: &mut Ctx<'a, Runtime>,
993        inputs: &mut CallInputs,
994    ) -> Option<CallOutcome> {
995        let result = self.call_or_fail(context, inputs);
996        map_result_call_outcome(result)
997    }
998}
999
1000impl<Runtime: ServiceRuntime> CallInterceptorService<Runtime> {
1001    fn call_or_fail(
1002        &mut self,
1003        context: &mut Ctx<'_, Runtime>,
1004        inputs: &mut CallInputs,
1005    ) -> Result<Option<CallOutcome>, ExecutionError> {
1006        // Every call to a contract passes by this function.
1007        // Three kinds:
1008        // --- Call to the PRECOMPILE smart contract.
1009        // --- Call to the EVM smart contract itself
1010        // --- Call to other EVM smart contract
1011        if self.precompile_addresses.contains(&inputs.target_address)
1012            || inputs.target_address == self.contract_address
1013        {
1014            // Precompile calls are handled by the precompile code.
1015            // The EVM smart contract is being called
1016            return Ok(None);
1017        }
1018        // Other smart contracts calls are handled by the runtime
1019        let target = address_to_user_application_id(inputs.target_address);
1020        let argument = get_call_argument(context, inputs);
1021        let result = {
1022            let evm_query = EvmQuery::Query(argument);
1023            let evm_query = serde_json::to_vec(&evm_query)?;
1024            let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1025            runtime.try_query_application(target, evm_query)?
1026        };
1027        let call_outcome = CallOutcome {
1028            result: get_interpreter_result(&result, inputs)?,
1029            memory_offset: inputs.return_memory_offset.clone(),
1030        };
1031        Ok(Some(call_outcome))
1032    }
1033}
1034
1035pub struct RevmContractInstance<Runtime> {
1036    module: Vec<u8>,
1037    db: DatabaseRuntime<Runtime>,
1038}
1039
1040enum EvmTxKind {
1041    Create,
1042    Call,
1043}
1044
1045#[derive(Debug)]
1046struct ExecutionResultSuccess {
1047    reason: SuccessReason,
1048    gas_final: u64,
1049    logs: Vec<Log>,
1050    output: Output,
1051}
1052
1053impl ExecutionResultSuccess {
1054    fn interpreter_result_and_logs(self) -> Result<(u64, Vec<u8>, Vec<Log>), ExecutionError> {
1055        let result: InstructionResult = self.reason.into();
1056        let Output::Call(output) = self.output else {
1057            unreachable!("The output should have been created from a EvmTxKind::Call");
1058        };
1059        let gas = Gas::new(0);
1060        let result = InterpreterResult {
1061            result,
1062            output,
1063            gas,
1064        };
1065        let result = bcs::to_bytes(&result)?;
1066        Ok((self.gas_final, result, self.logs))
1067    }
1068
1069    fn output_and_logs(self) -> (u64, Vec<u8>, Vec<Log>) {
1070        let Output::Call(output) = self.output else {
1071            unreachable!("The output should have been created from a EvmTxKind::Call");
1072        };
1073        let output = output.as_ref().to_vec();
1074        (self.gas_final, output, self.logs)
1075    }
1076
1077    // Checks that the contract has been correctly instantiated
1078    fn check_contract_initialization(&self, expected_address: Address) -> Result<(), String> {
1079        // Checks that the output is the expected one.
1080        let Output::Create(_, contract_address) = self.output else {
1081            return Err("Input should be ExmTxKind::Create".to_string());
1082        };
1083        // Checks that the contract address exists.
1084        let contract_address = contract_address.ok_or("Deployment failed")?;
1085        // Checks that the created contract address is the one of the `ApplicationId`.
1086        if contract_address == expected_address {
1087            Ok(())
1088        } else {
1089            Err("Contract address is not the same as ApplicationId".to_string())
1090        }
1091    }
1092}
1093
1094impl<Runtime> UserContract for RevmContractInstance<Runtime>
1095where
1096    Runtime: ContractRuntime,
1097{
1098    fn instantiate(&mut self, argument: Vec<u8>) -> Result<(), ExecutionError> {
1099        self.db.set_contract_address()?;
1100        let caller = self.get_msg_address()?;
1101        self.initialize_contract(caller)?;
1102        if has_selector(&self.module, INSTANTIATE_SELECTOR) {
1103            let instantiation_argument = serde_json::from_slice::<Vec<u8>>(&argument)?;
1104            let argument = get_revm_instantiation_bytes(instantiation_argument);
1105            let result = self.transact_commit(EvmTxKind::Call, argument, caller)?;
1106            self.write_logs(result.logs, "instantiate")?;
1107        }
1108        Ok(())
1109    }
1110
1111    fn execute_operation(&mut self, operation: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1112        self.db.set_contract_address()?;
1113        ensure_message_length(operation.len(), 4)?;
1114        let caller = self.get_msg_address()?;
1115        let (gas_final, output, logs) = if &operation[..4] == INTERPRETER_RESULT_SELECTOR {
1116            ensure_message_length(operation.len(), 8)?;
1117            forbid_execute_operation_origin(&operation[4..8])?;
1118            let result = self.init_transact_commit(operation[4..].to_vec(), caller)?;
1119            result.interpreter_result_and_logs()?
1120        } else {
1121            ensure_message_length(operation.len(), 4)?;
1122            forbid_execute_operation_origin(&operation[..4])?;
1123            let result = self.init_transact_commit(operation, caller)?;
1124            result.output_and_logs()
1125        };
1126        self.consume_fuel(gas_final)?;
1127        self.write_logs(logs, "operation")?;
1128        Ok(output)
1129    }
1130
1131    fn execute_message(&mut self, message: Vec<u8>) -> Result<(), ExecutionError> {
1132        self.db.set_contract_address()?;
1133        ensure_selector_presence(
1134            &self.module,
1135            EXECUTE_MESSAGE_SELECTOR,
1136            "function execute_message(bytes)",
1137        )?;
1138        let operation = get_revm_execute_message_bytes(message);
1139        let caller = self.get_msg_address()?;
1140        self.execute_no_return_operation(operation, "message", caller)
1141    }
1142
1143    fn process_streams(&mut self, streams: Vec<StreamUpdate>) -> Result<(), ExecutionError> {
1144        self.db.set_contract_address()?;
1145        let operation = get_revm_process_streams_bytes(streams);
1146        ensure_selector_presence(
1147            &self.module,
1148            PROCESS_STREAMS_SELECTOR,
1149            "function process_streams(LineraTypes.StreamUpdate[] memory streams)",
1150        )?;
1151        // For process_streams, authenticated_signer and authenticated_called_id are None.
1152        let caller = Address::ZERO;
1153        self.execute_no_return_operation(operation, "process_streams", caller)
1154    }
1155
1156    fn finalize(&mut self) -> Result<(), ExecutionError> {
1157        Ok(())
1158    }
1159}
1160
1161fn process_execution_result(
1162    storage_stats: StorageStats,
1163    result: ExecutionResult,
1164) -> Result<ExecutionResultSuccess, EvmExecutionError> {
1165    match result {
1166        ExecutionResult::Success {
1167            reason,
1168            gas_used,
1169            gas_refunded,
1170            logs,
1171            output,
1172        } => {
1173            let mut gas_final = gas_used;
1174            gas_final -= storage_stats.storage_costs();
1175            assert_eq!(gas_refunded, storage_stats.storage_refund());
1176            if !matches!(reason, SuccessReason::Return) {
1177                Err(EvmExecutionError::NoReturnInterpreter {
1178                    reason,
1179                    gas_used,
1180                    gas_refunded,
1181                    logs,
1182                    output,
1183                })
1184            } else {
1185                Ok(ExecutionResultSuccess {
1186                    reason,
1187                    gas_final,
1188                    logs,
1189                    output,
1190                })
1191            }
1192        }
1193        ExecutionResult::Revert { gas_used, output } => {
1194            Err(EvmExecutionError::Revert { gas_used, output })
1195        }
1196        ExecutionResult::Halt { gas_used, reason } => {
1197            Err(EvmExecutionError::Halt { gas_used, reason })
1198        }
1199    }
1200}
1201
1202impl<Runtime> RevmContractInstance<Runtime>
1203where
1204    Runtime: ContractRuntime,
1205{
1206    pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1207        let db = DatabaseRuntime::new(runtime);
1208        Self { module, db }
1209    }
1210
1211    fn execute_no_return_operation(
1212        &mut self,
1213        operation: Vec<u8>,
1214        origin: &str,
1215        caller: Address,
1216    ) -> Result<(), ExecutionError> {
1217        let result = self.init_transact_commit(operation, caller)?;
1218        let (gas_final, output, logs) = result.output_and_logs();
1219        self.consume_fuel(gas_final)?;
1220        self.write_logs(logs, origin)?;
1221        assert_eq!(output.len(), 0);
1222        Ok(())
1223    }
1224
1225    /// Executes the transaction. If needed initializes the contract.
1226    fn init_transact_commit(
1227        &mut self,
1228        vec: Vec<u8>,
1229        caller: Address,
1230    ) -> Result<ExecutionResultSuccess, ExecutionError> {
1231        // An application can be instantiated in Linera sense, but not in EVM sense,
1232        // that is the contract entries corresponding to the deployed contract may
1233        // be missing.
1234        if !self.db.is_initialized()? {
1235            self.initialize_contract(caller)?;
1236        }
1237        self.transact_commit(EvmTxKind::Call, vec, caller)
1238    }
1239
1240    /// Initializes the contract.
1241    fn initialize_contract(&mut self, caller: Address) -> Result<(), ExecutionError> {
1242        let mut vec_init = self.module.clone();
1243        let constructor_argument = self.db.constructor_argument()?;
1244        vec_init.extend_from_slice(&constructor_argument);
1245        let result = self.transact_commit(EvmTxKind::Create, vec_init, caller)?;
1246        result
1247            .check_contract_initialization(self.db.contract_address)
1248            .map_err(EvmExecutionError::IncorrectContractCreation)?;
1249        self.write_logs(result.logs, "deploy")
1250    }
1251
1252    /// Computes the address used in the `msg.sender` variable.
1253    /// It is computed in the following way:
1254    /// * If a Wasm contract calls an EVM contract then it is `Address::ZERO`.
1255    /// * If an EVM contract calls an EVM contract it is the address of the contract.
1256    /// * If a user having an `AccountOwner::Address32` address calls an EVM contract
1257    ///   then it is `Address::ZERO`.
1258    /// * If a user having an `AccountOwner::Address20` address calls an EVM contract
1259    ///   then it is this address.
1260    ///
1261    /// By doing this we ensure that EVM smart contracts works in the same way as
1262    /// on the EVM and that users and contracts outside of that realm can still
1263    /// call EVM smart contracts.
1264    fn get_msg_address(&self) -> Result<Address, ExecutionError> {
1265        let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1266        let application_id = runtime.authenticated_caller_id()?;
1267        if let Some(application_id) = application_id {
1268            return Ok(if application_id.is_evm() {
1269                application_id.evm_address()
1270            } else {
1271                Address::ZERO
1272            });
1273        };
1274        let account_owner = runtime.authenticated_signer()?;
1275        if let Some(AccountOwner::Address20(address)) = account_owner {
1276            return Ok(Address::from(address));
1277        };
1278        Ok(ZERO_ADDRESS)
1279    }
1280
1281    fn transact_commit(
1282        &mut self,
1283        ch: EvmTxKind,
1284        input: Vec<u8>,
1285        caller: Address,
1286    ) -> Result<ExecutionResultSuccess, ExecutionError> {
1287        let data = Bytes::from(input);
1288        let kind = match ch {
1289            EvmTxKind::Create => TxKind::Create,
1290            EvmTxKind::Call => TxKind::Call(self.db.contract_address),
1291        };
1292        let inspector = CallInterceptorContract {
1293            db: self.db.clone(),
1294            contract_address: self.db.contract_address,
1295            precompile_addresses: precompile_addresses(),
1296        };
1297        let block_env = self.db.get_contract_block_env()?;
1298        let gas_limit = {
1299            let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1300            runtime.remaining_fuel(VmRuntime::Evm)?
1301        };
1302        let nonce = self.db.get_nonce(&caller)?;
1303        let result = {
1304            let ctx: revm_context::Context<
1305                BlockEnv,
1306                _,
1307                _,
1308                _,
1309                Journal<WrapDatabaseRef<&mut DatabaseRuntime<Runtime>>>,
1310                (),
1311            > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1312                WrapDatabaseRef(&mut self.db),
1313                SpecId::PRAGUE,
1314            )
1315            .with_block(block_env);
1316            let instructions = EthInstructions::new_mainnet();
1317            let mut evm = Evm::new_with_inspector(
1318                ctx,
1319                inspector.clone(),
1320                instructions,
1321                ContractPrecompile::default(),
1322            );
1323            evm.inspect_commit(
1324                TxEnv {
1325                    kind,
1326                    data,
1327                    nonce,
1328                    gas_limit,
1329                    caller,
1330                    ..TxEnv::default()
1331                },
1332                inspector,
1333            )
1334            .map_err(|error| {
1335                let error = format!("{:?}", error);
1336                EvmExecutionError::TransactCommitError(error)
1337            })
1338        }?;
1339        let storage_stats = self.db.take_storage_stats();
1340        self.db.commit_changes()?;
1341        Ok(process_execution_result(storage_stats, result)?)
1342    }
1343
1344    fn consume_fuel(&mut self, gas_final: u64) -> Result<(), ExecutionError> {
1345        let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1346        runtime.consume_fuel(gas_final, VmRuntime::Evm)
1347    }
1348
1349    fn write_logs(&mut self, logs: Vec<Log>, origin: &str) -> Result<(), ExecutionError> {
1350        // TODO(#3758): Extracting Ethereum events from the Linera events.
1351        if !logs.is_empty() {
1352            let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1353            let block_height = runtime.block_height()?;
1354            let stream_name = bcs::to_bytes("ethereum_event")?;
1355            let stream_name = StreamName(stream_name);
1356            for log in &logs {
1357                let value = bcs::to_bytes(&(origin, block_height.0, log))?;
1358                runtime.emit(stream_name.clone(), value)?;
1359            }
1360        }
1361        Ok(())
1362    }
1363}
1364
1365pub struct RevmServiceInstance<Runtime> {
1366    module: Vec<u8>,
1367    db: DatabaseRuntime<Runtime>,
1368}
1369
1370impl<Runtime> RevmServiceInstance<Runtime>
1371where
1372    Runtime: ServiceRuntime,
1373{
1374    pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1375        let db = DatabaseRuntime::new(runtime);
1376        Self { module, db }
1377    }
1378}
1379
1380impl<Runtime> UserService for RevmServiceInstance<Runtime>
1381where
1382    Runtime: ServiceRuntime,
1383{
1384    fn handle_query(&mut self, argument: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1385        self.db.set_contract_address()?;
1386        let evm_query = serde_json::from_slice(&argument)?;
1387        let query = match evm_query {
1388            EvmQuery::Query(vec) => vec,
1389            EvmQuery::Mutation(operation) => {
1390                let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1391                runtime.schedule_operation(operation)?;
1392                return Ok(Vec::new());
1393            }
1394        };
1395
1396        ensure_message_length(query.len(), 4)?;
1397        // We drop the logs since the "eth_call" execution does not return any log.
1398        // Also, for handle_query, we do not have associated costs.
1399        // More generally, there is gas costs associated to service operation.
1400        let answer = if &query[..4] == INTERPRETER_RESULT_SELECTOR {
1401            let result = self.init_transact(query[4..].to_vec())?;
1402            let (_gas_final, answer, _logs) = result.interpreter_result_and_logs()?;
1403            answer
1404        } else {
1405            let result = self.init_transact(query)?;
1406            let (_gas_final, output, _logs) = result.output_and_logs();
1407            serde_json::to_vec(&output)?
1408        };
1409        Ok(answer)
1410    }
1411}
1412
1413impl<Runtime> RevmServiceInstance<Runtime>
1414where
1415    Runtime: ServiceRuntime,
1416{
1417    fn init_transact(&mut self, vec: Vec<u8>) -> Result<ExecutionResultSuccess, ExecutionError> {
1418        // In case of a shared application, we need to instantiate it first
1419        // However, since in ServiceRuntime, we cannot modify the storage,
1420        // therefore the compiled contract is saved in the changes.
1421        if !self.db.is_initialized()? {
1422            let changes = {
1423                let mut vec_init = self.module.clone();
1424                let constructor_argument = self.db.constructor_argument()?;
1425                vec_init.extend_from_slice(&constructor_argument);
1426                let (result, changes) = self.transact(TxKind::Create, vec_init)?;
1427                result
1428                    .check_contract_initialization(self.db.contract_address)
1429                    .map_err(EvmExecutionError::IncorrectContractCreation)?;
1430                changes
1431            };
1432            self.db.changes = changes;
1433        }
1434        ensure_message_length(vec.len(), 4)?;
1435        forbid_execute_operation_origin(&vec[..4])?;
1436        let kind = TxKind::Call(self.db.contract_address);
1437        let (execution_result, _) = self.transact(kind, vec)?;
1438        Ok(execution_result)
1439    }
1440
1441    fn transact(
1442        &mut self,
1443        kind: TxKind,
1444        input: Vec<u8>,
1445    ) -> Result<(ExecutionResultSuccess, EvmState), ExecutionError> {
1446        let data = Bytes::from(input);
1447        let block_env = self.db.get_service_block_env()?;
1448        let inspector = CallInterceptorService {
1449            db: self.db.clone(),
1450            contract_address: self.db.contract_address,
1451            precompile_addresses: precompile_addresses(),
1452        };
1453        let caller = SERVICE_ADDRESS;
1454        let nonce = self.db.get_nonce(&caller)?;
1455        let result_state = {
1456            let ctx: revm_context::Context<
1457                BlockEnv,
1458                _,
1459                _,
1460                _,
1461                Journal<WrapDatabaseRef<&mut DatabaseRuntime<Runtime>>>,
1462                (),
1463            > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1464                WrapDatabaseRef(&mut self.db),
1465                SpecId::PRAGUE,
1466            )
1467            .with_block(block_env);
1468            let instructions = EthInstructions::new_mainnet();
1469            let mut evm = Evm::new_with_inspector(
1470                ctx,
1471                inspector.clone(),
1472                instructions,
1473                ServicePrecompile::default(),
1474            );
1475            evm.inspect(
1476                TxEnv {
1477                    kind,
1478                    data,
1479                    nonce,
1480                    caller,
1481                    gas_limit: EVM_SERVICE_GAS_LIMIT,
1482                    ..TxEnv::default()
1483                },
1484                inspector,
1485            )
1486            .map_err(|error| {
1487                let error = format!("{:?}", error);
1488                EvmExecutionError::TransactCommitError(error)
1489            })
1490        }?;
1491        let storage_stats = self.db.take_storage_stats();
1492        Ok((
1493            process_execution_result(storage_stats, result_state.result)?,
1494            result_state.state,
1495        ))
1496    }
1497}