linera_execution/evm/
revm.rs

1// Copyright (c) Zefchain Labs, Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Integration of the [Revm](https://bluealloy.github.io/revm/) EVM runtime with Linera.
5//!
6//! This module provides the glue between Linera's blockchain infrastructure and the
7//! Revm EVM interpreter, enabling Ethereum smart contracts to run on Linera chains.
8//!
9//! # Architecture
10//!
11//! The integration consists of several key components:
12//!
13//! - **Database Trait Implementations**: Adapts Linera's storage layer to Revm's
14//!   `Database` and `DatabaseRef` traits (see `database.rs`).
15//!
16//! - **Inspector Pattern**: Intercepts EVM operations like contract creation and calls
17//!   to bridge between Revm's execution model and Linera's runtime requirements.
18//!
19//! - **Precompiles**: Extends standard Ethereum precompiles with Linera-specific
20//!   functionality accessible from EVM contracts.
21//!
22//! - **Contract/Service Modules**: Provides both contract (mutable) and service
23//!   (read-only query) execution modes for EVM bytecode.
24//!
25//! # Cross-Contract Communication
26//!
27//! EVM contracts running on Linera can interact with each other using fictional
28//! selectors (see `GET_ACCOUNT_INFO_SELECTOR`, etc.) that don't correspond to real
29//! EVM functions but enable internal protocol operations like querying state from
30//! other contracts or committing changes across contract boundaries.
31
32use core::ops::Range;
33use std::{
34    collections::BTreeSet,
35    convert::TryFrom,
36    ops::DerefMut,
37    sync::{Arc, Mutex},
38};
39
40#[cfg(with_metrics)]
41use linera_base::prometheus_util::MeasureLatency as _;
42use linera_base::{
43    crypto::CryptoHash,
44    data_types::{
45        Amount, ApplicationDescription, Bytecode, Resources, SendMessageRequest, StreamUpdate,
46    },
47    ensure,
48    identifiers::{self, Account, AccountOwner, ApplicationId, ChainId, ModuleId, StreamName},
49    vm::{EvmInstantiation, EvmOperation, EvmQuery, VmRuntime},
50};
51use revm::{primitives::Bytes, InspectCommitEvm, InspectEvm, Inspector};
52use revm_context::{
53    result::{ExecutionResult, Output, SuccessReason},
54    BlockEnv, Cfg, ContextTr, Evm, Journal, JournalTr, LocalContextTr as _, TxEnv,
55};
56use revm_database::WrapDatabaseRef;
57use revm_handler::{
58    instructions::EthInstructions, EthPrecompiles, MainnetContext, PrecompileProvider,
59};
60use revm_interpreter::{
61    CallInput, CallInputs, CallOutcome, CallValue, CreateInputs, CreateOutcome, CreateScheme, Gas,
62    InputsImpl, InstructionResult, InterpreterResult,
63};
64use revm_primitives::{hardfork::SpecId, Address, Log, TxKind, U256};
65use revm_state::EvmState;
66use serde::{Deserialize, Serialize};
67
68use crate::{
69    evm::{
70        data_types::AmountU256,
71        database::{ContractDatabase, InnerDatabase, ServiceDatabase, EVM_SERVICE_GAS_LIMIT},
72        inputs::{
73            ensure_message_length, ensure_selector_presence, forbid_execute_operation_origin,
74            get_revm_execute_message_bytes, get_revm_instantiation_bytes,
75            get_revm_process_streams_bytes, has_selector, EXECUTE_MESSAGE_SELECTOR, FAUCET_ADDRESS,
76            INSTANTIATE_SELECTOR, PRECOMPILE_ADDRESS, PROCESS_STREAMS_SELECTOR, SERVICE_ADDRESS,
77            ZERO_ADDRESS,
78        },
79    },
80    BaseRuntime, ContractRuntime, ContractSyncRuntimeHandle, DataBlobHash, EvmExecutionError,
81    EvmRuntime, ExecutionError, ServiceRuntime, ServiceSyncRuntimeHandle, UserContract,
82    UserContractInstance, UserContractModule, UserService, UserServiceInstance, UserServiceModule,
83};
84
85/// Fictional selector for internal cross-contract calls to retrieve account information.
86///
87/// This selector is used when one EVM contract needs to query the `AccountInfo`
88/// of another EVM contract. It does not correspond to any real EVM function,
89/// but is instead an internal protocol for inter-contract communication within Linera.
90pub const GET_ACCOUNT_INFO_SELECTOR: &[u8] = &[21, 34, 55, 89];
91
92/// Fictional selector for internal cross-contract calls to retrieve storage values.
93///
94/// This selector is used when one EVM contract needs to read a specific storage
95/// slot from another EVM contract. It does not correspond to any real EVM function,
96/// but is instead an internal protocol for inter-contract communication within Linera.
97pub const GET_CONTRACT_STORAGE_SELECTOR: &[u8] = &[5, 14, 42, 132];
98
99/// Fictional selector for internal cross-contract calls to commit state changes.
100///
101/// This selector is used to propagate state changes from Revm to the storage layer
102/// of a remote contract. It does not correspond to any real EVM function,
103/// but is instead an internal protocol for state synchronization within Linera.
104pub const COMMIT_CONTRACT_CHANGES_SELECTOR: &[u8] = &[5, 15, 52, 203];
105
106/// Fictional selector for creating a contract from a pre-populated account.
107///
108/// This selector is used when instantiating a contract that was already created
109/// and populated by Revm during execution. It bypasses the normal constructor flow
110/// since the account data is already complete. This does not correspond to any real EVM function.
111pub const ALREADY_CREATED_CONTRACT_SELECTOR: &[u8] = &[23, 47, 106, 235];
112
113/// The JSON serialization of an empty vector: `[]`.
114///
115/// Used as a placeholder for constructor parameters when no arguments are needed.
116pub const JSON_EMPTY_VECTOR: &[u8] = &[91, 93];
117
118#[cfg(with_metrics)]
119mod metrics {
120    use std::sync::LazyLock;
121
122    use linera_base::prometheus_util::{exponential_bucket_latencies, register_histogram_vec};
123    use prometheus::HistogramVec;
124
125    pub static CONTRACT_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
126        register_histogram_vec(
127            "evm_contract_instantiation_latency",
128            "EVM contract instantiation latency",
129            &[],
130            exponential_bucket_latencies(1.0),
131        )
132    });
133
134    pub static SERVICE_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
135        register_histogram_vec(
136            "evm_service_instantiation_latency",
137            "EVM service instantiation latency",
138            &[],
139            exponential_bucket_latencies(1.0),
140        )
141    });
142}
143
144#[derive(Clone)]
145pub enum EvmContractModule {
146    #[cfg(with_revm)]
147    Revm { module: Vec<u8> },
148}
149
150impl EvmContractModule {
151    /// Creates a new [`EvmContractModule`] using the EVM module with the provided `contract_bytecode`.
152    pub fn new(
153        contract_bytecode: Bytecode,
154        runtime: EvmRuntime,
155    ) -> Result<Self, EvmExecutionError> {
156        match runtime {
157            #[cfg(with_revm)]
158            EvmRuntime::Revm => Self::from_revm(contract_bytecode),
159        }
160    }
161
162    /// Creates a new [`EvmContractModule`] using the EVM module in `contract_bytecode_file`.
163    #[cfg(with_fs)]
164    pub async fn from_file(
165        contract_bytecode_file: impl AsRef<std::path::Path>,
166        runtime: EvmRuntime,
167    ) -> Result<Self, EvmExecutionError> {
168        Self::new(
169            Bytecode::load_from_file(contract_bytecode_file)
170                .await
171                .map_err(anyhow::Error::from)
172                .map_err(EvmExecutionError::LoadContractModule)?,
173            runtime,
174        )
175    }
176
177    /// Creates a new [`EvmContractModule`] using Revm with the provided bytecode files.
178    pub fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
179        let module = contract_bytecode.bytes;
180        Ok(EvmContractModule::Revm { module })
181    }
182}
183
184impl UserContractModule for EvmContractModule {
185    fn instantiate(
186        &self,
187        runtime: ContractSyncRuntimeHandle,
188    ) -> Result<UserContractInstance, ExecutionError> {
189        #[cfg(with_metrics)]
190        let _instantiation_latency = metrics::CONTRACT_INSTANTIATION_LATENCY.measure_latency();
191
192        let instance: UserContractInstance = match self {
193            #[cfg(with_revm)]
194            EvmContractModule::Revm { module } => {
195                Box::new(RevmContractInstance::prepare(module.to_vec(), runtime))
196            }
197        };
198
199        Ok(instance)
200    }
201}
202
203/// A user service in a compiled EVM module.
204#[derive(Clone)]
205pub enum EvmServiceModule {
206    #[cfg(with_revm)]
207    Revm { module: Vec<u8> },
208}
209
210impl EvmServiceModule {
211    /// Creates a new [`EvmServiceModule`] using the EVM module with the provided bytecode.
212    pub fn new(service_bytecode: Bytecode, runtime: EvmRuntime) -> Result<Self, EvmExecutionError> {
213        match runtime {
214            #[cfg(with_revm)]
215            EvmRuntime::Revm => Self::from_revm(service_bytecode),
216        }
217    }
218
219    /// Creates a new [`EvmServiceModule`] using the EVM module in `service_bytecode_file`.
220    #[cfg(with_fs)]
221    pub async fn from_file(
222        service_bytecode_file: impl AsRef<std::path::Path>,
223        runtime: EvmRuntime,
224    ) -> Result<Self, EvmExecutionError> {
225        Self::new(
226            Bytecode::load_from_file(service_bytecode_file)
227                .await
228                .map_err(anyhow::Error::from)
229                .map_err(EvmExecutionError::LoadServiceModule)?,
230            runtime,
231        )
232    }
233
234    /// Creates a new [`EvmServiceModule`] using Revm with the provided bytecode files.
235    pub fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
236        let module = contract_bytecode.bytes;
237        Ok(EvmServiceModule::Revm { module })
238    }
239}
240
241impl UserServiceModule for EvmServiceModule {
242    fn instantiate(
243        &self,
244        runtime: ServiceSyncRuntimeHandle,
245    ) -> Result<UserServiceInstance, ExecutionError> {
246        #[cfg(with_metrics)]
247        let _instantiation_latency = metrics::SERVICE_INSTANTIATION_LATENCY.measure_latency();
248
249        let instance: UserServiceInstance = match self {
250            #[cfg(with_revm)]
251            EvmServiceModule::Revm { module } => {
252                Box::new(RevmServiceInstance::prepare(module.to_vec(), runtime))
253            }
254        };
255
256        Ok(instance)
257    }
258}
259
260type ContractCtx<'a, Runtime> = MainnetContext<WrapDatabaseRef<&'a mut ContractDatabase<Runtime>>>;
261
262type ServiceCtx<'a, Runtime> = MainnetContext<WrapDatabaseRef<&'a mut ServiceDatabase<Runtime>>>;
263
264pub fn address_to_user_application_id(address: Address) -> ApplicationId {
265    let mut vec = vec![0_u8; 32];
266    vec[..20].copy_from_slice(address.as_ref());
267    ApplicationId::new(CryptoHash::try_from(&vec as &[u8]).unwrap())
268}
269
270/// Some functionalities from the BaseRuntime
271#[derive(Debug, Serialize, Deserialize)]
272enum BaseRuntimePrecompile {
273    /// Calling `chain_id` of `BaseRuntime`
274    ChainId,
275    /// Calling `block_height_id` of `BaseRuntime`
276    BlockHeight,
277    /// Calling `application_creator_chain_id` of `BaseRuntime`
278    ApplicationCreatorChainId,
279    /// Calling `read_system_timestamp` of `BaseRuntime`
280    ReadSystemTimestamp,
281    /// Calling `read_chain_balance` of `BaseRuntime`
282    ReadChainBalance,
283    /// Calling `read_owner_balance` of `BaseRuntime`
284    ReadOwnerBalance(AccountOwner),
285    /// Calling `read_owner_balances` of `BaseRuntime`
286    ReadOwnerBalances,
287    /// Calling `read_balance_owners` of `BaseRuntime`
288    ReadBalanceOwners,
289    /// Calling `chain_ownership` of `BaseRuntime`
290    ChainOwnership,
291    /// Calling `read_data_blob` of `BaseRuntime`
292    ReadDataBlob(DataBlobHash),
293    /// Calling `assert_data_blob_exists` of `BaseRuntime`
294    AssertDataBlobExists(DataBlobHash),
295}
296
297/// Some functionalities from the ContractRuntime not in BaseRuntime
298#[derive(Debug, Serialize, Deserialize)]
299enum ContractRuntimePrecompile {
300    /// Calling `authenticated_owner` of `ContractRuntime`
301    AuthenticatedOwner,
302    /// Calling `message_origin_chain_id` of `ContractRuntime`
303    MessageOriginChainId,
304    /// Calling `message_is_bouncing` of `ContractRuntime`
305    MessageIsBouncing,
306    /// Calling `authenticated_caller_id` of `ContractRuntime`
307    AuthenticatedCallerId,
308    /// Calling `send_message` of `ContractRuntime`
309    SendMessage {
310        destination: ChainId,
311        message: Vec<u8>,
312    },
313    /// Calling `try_call_application` of `ContractRuntime`
314    TryCallApplication {
315        target: ApplicationId,
316        argument: Vec<u8>,
317    },
318    /// Calling `emit` of `ContractRuntime`
319    Emit {
320        stream_name: StreamName,
321        value: Vec<u8>,
322    },
323    /// Calling `read_event` of `ContractRuntime`
324    ReadEvent {
325        chain_id: ChainId,
326        stream_name: StreamName,
327        index: u32,
328    },
329    /// Calling `subscribe_to_events` of `ContractRuntime`
330    SubscribeToEvents {
331        chain_id: ChainId,
332        application_id: ApplicationId,
333        stream_name: StreamName,
334    },
335    /// Calling `unsubscribe_from_events` of `ContractRuntime`
336    UnsubscribeFromEvents {
337        chain_id: ChainId,
338        application_id: ApplicationId,
339        stream_name: StreamName,
340    },
341    /// Calling `query_service` of `ContractRuntime`
342    QueryService {
343        application_id: ApplicationId,
344        query: Vec<u8>,
345    },
346    /// Calling `validation_round` of `ContractRuntime`
347    ValidationRound,
348    /// Calling `transfer` of `ContractRuntime`
349    Transfer {
350        account: Account,
351        amount: AmountU256,
352    },
353}
354
355/// Some functionalities from the ServiceRuntime not in BaseRuntime
356#[derive(Debug, Serialize, Deserialize)]
357enum ServiceRuntimePrecompile {
358    /// Calling `try_query_application` of `ServiceRuntime`
359    TryQueryApplication {
360        target: ApplicationId,
361        argument: Vec<u8>,
362    },
363}
364
365/// Key prefixes used to transmit precompiles.
366#[derive(Debug, Serialize, Deserialize)]
367enum RuntimePrecompile {
368    Base(BaseRuntimePrecompile),
369    Contract(ContractRuntimePrecompile),
370    Service(ServiceRuntimePrecompile),
371}
372
373/// Creates an interpreter result for a successful precompile call with zero gas cost.
374///
375/// # Gas Accounting
376///
377/// Linera-specific precompiles appear to consume zero gas from Revm's perspective
378/// because their actual costs are tracked separately through Linera's fuel system.
379/// The gas is initialized to `gas_limit` with no consumption, making the precompile
380/// call effectively free within Revm's accounting model.
381///
382/// # Arguments
383///
384/// * `output` - The return data from the precompile execution
385/// * `gas_limit` - The gas limit for the call (returned unchanged as remaining gas)
386///
387/// # Returns
388///
389/// An `InterpreterResult` indicating success with the provided output and no gas usage.
390fn get_precompile_output(output: Vec<u8>, gas_limit: u64) -> InterpreterResult {
391    let output = Bytes::from(output);
392    let result = InstructionResult::default();
393    let gas = Gas::new(gas_limit);
394    InterpreterResult {
395        result,
396        output,
397        gas,
398    }
399}
400
401fn get_argument<Ctx: ContextTr>(context: &mut Ctx, input: &CallInput) -> Vec<u8> {
402    match input {
403        CallInput::Bytes(bytes) => bytes.to_vec(),
404        CallInput::SharedBuffer(range) => {
405            match context.local().shared_memory_buffer_slice(range.clone()) {
406                None => Vec::new(),
407                Some(slice) => slice.to_vec(),
408            }
409        }
410    }
411}
412
413fn get_precompile_argument<Ctx: ContextTr>(context: &mut Ctx, inputs: &InputsImpl) -> Vec<u8> {
414    get_argument(context, &inputs.input)
415}
416
417fn base_runtime_call<Runtime: BaseRuntime>(
418    request: &BaseRuntimePrecompile,
419    runtime: &mut Runtime,
420) -> Result<Vec<u8>, ExecutionError> {
421    match request {
422        BaseRuntimePrecompile::ChainId => {
423            let chain_id = runtime.chain_id()?;
424            Ok(bcs::to_bytes(&chain_id)?)
425        }
426        BaseRuntimePrecompile::BlockHeight => {
427            let block_height = runtime.block_height()?;
428            Ok(bcs::to_bytes(&block_height)?)
429        }
430        BaseRuntimePrecompile::ApplicationCreatorChainId => {
431            let chain_id = runtime.application_creator_chain_id()?;
432            Ok(bcs::to_bytes(&chain_id)?)
433        }
434        BaseRuntimePrecompile::ReadSystemTimestamp => {
435            let timestamp = runtime.read_system_timestamp()?;
436            Ok(bcs::to_bytes(&timestamp)?)
437        }
438        BaseRuntimePrecompile::ReadChainBalance => {
439            let balance: linera_base::data_types::Amount = runtime.read_chain_balance()?;
440            let balance: AmountU256 = balance.into();
441            Ok(bcs::to_bytes(&balance)?)
442        }
443        BaseRuntimePrecompile::ReadOwnerBalance(account_owner) => {
444            let balance = runtime.read_owner_balance(*account_owner)?;
445            let balance = Into::<U256>::into(balance);
446            Ok(bcs::to_bytes(&balance)?)
447        }
448        BaseRuntimePrecompile::ReadOwnerBalances => {
449            let owner_balances = runtime.read_owner_balances()?;
450            let owner_balances = owner_balances
451                .into_iter()
452                .map(|(account_owner, balance)| (account_owner, balance.into()))
453                .collect::<Vec<(AccountOwner, AmountU256)>>();
454            Ok(bcs::to_bytes(&owner_balances)?)
455        }
456        BaseRuntimePrecompile::ReadBalanceOwners => {
457            let owners = runtime.read_balance_owners()?;
458            Ok(bcs::to_bytes(&owners)?)
459        }
460        BaseRuntimePrecompile::ChainOwnership => {
461            let chain_ownership = runtime.chain_ownership()?;
462            Ok(bcs::to_bytes(&chain_ownership)?)
463        }
464        BaseRuntimePrecompile::ReadDataBlob(hash) => runtime.read_data_blob(*hash),
465        BaseRuntimePrecompile::AssertDataBlobExists(hash) => {
466            runtime.assert_data_blob_exists(*hash)?;
467            Ok(Vec::new())
468        }
469    }
470}
471
472fn precompile_addresses() -> BTreeSet<Address> {
473    let mut addresses = BTreeSet::new();
474    for address in EthPrecompiles::default().warm_addresses() {
475        addresses.insert(address);
476    }
477    addresses.insert(PRECOMPILE_ADDRESS);
478    addresses
479}
480
481#[derive(Debug, Default)]
482struct ContractPrecompile {
483    inner: EthPrecompiles,
484}
485
486impl<'a, Runtime: ContractRuntime> PrecompileProvider<ContractCtx<'a, Runtime>>
487    for ContractPrecompile
488{
489    type Output = InterpreterResult;
490
491    fn set_spec(
492        &mut self,
493        spec: <<ContractCtx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec,
494    ) -> bool {
495        <EthPrecompiles as PrecompileProvider<ContractCtx<'a, Runtime>>>::set_spec(
496            &mut self.inner,
497            spec,
498        )
499    }
500
501    fn run(
502        &mut self,
503        context: &mut ContractCtx<'a, Runtime>,
504        address: &Address,
505        inputs: &InputsImpl,
506        is_static: bool,
507        gas_limit: u64,
508    ) -> Result<Option<InterpreterResult>, String> {
509        if address == &PRECOMPILE_ADDRESS {
510            let output = Self::call_or_fail(inputs, context)
511                .map_err(|error| format!("ContractPrecompile error: {error}"))?;
512            return Ok(Some(get_precompile_output(output, gas_limit)));
513        }
514        self.inner
515            .run(context, address, inputs, is_static, gas_limit)
516    }
517
518    fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
519        let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
520        addresses.push(PRECOMPILE_ADDRESS);
521        Box::new(addresses.into_iter())
522    }
523
524    fn contains(&self, address: &Address) -> bool {
525        address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
526    }
527}
528
529fn get_evm_destination<Runtime: ContractRuntime>(
530    context: &mut ContractCtx<'_, Runtime>,
531    account: Account,
532) -> Result<Option<Address>, ExecutionError> {
533    let mut runtime = context.db().0.lock_runtime();
534    if runtime.chain_id()? != account.chain_id {
535        return Ok(None);
536    }
537    Ok(account.owner.to_evm_address())
538}
539
540/// We are doing transfers of value from a source to a destination.
541fn revm_transfer<Runtime: ContractRuntime>(
542    context: &mut ContractCtx<'_, Runtime>,
543    source: Address,
544    destination: Address,
545    value: U256,
546) -> Result<(), ExecutionError> {
547    if let Some(error) = context.journal().transfer(source, destination, value)? {
548        let error = format!("{error:?}");
549        let error = EvmExecutionError::TransactError(error);
550        return Err(error.into());
551    }
552    Ok(())
553}
554
555impl<'a> ContractPrecompile {
556    fn contract_runtime_call<Runtime: ContractRuntime>(
557        request: ContractRuntimePrecompile,
558        context: &mut ContractCtx<'a, Runtime>,
559    ) -> Result<Vec<u8>, ExecutionError> {
560        match request {
561            ContractRuntimePrecompile::AuthenticatedOwner => {
562                let mut runtime = context.db().0.lock_runtime();
563                let account_owner = runtime.authenticated_owner()?;
564                Ok(bcs::to_bytes(&account_owner)?)
565            }
566
567            ContractRuntimePrecompile::MessageOriginChainId => {
568                let mut runtime = context.db().0.lock_runtime();
569                let origin_chain_id = runtime.message_origin_chain_id()?;
570                Ok(bcs::to_bytes(&origin_chain_id)?)
571            }
572
573            ContractRuntimePrecompile::MessageIsBouncing => {
574                let mut runtime = context.db().0.lock_runtime();
575                let result = runtime.message_is_bouncing()?;
576                Ok(bcs::to_bytes(&result)?)
577            }
578            ContractRuntimePrecompile::AuthenticatedCallerId => {
579                let mut runtime = context.db().0.lock_runtime();
580                let application_id = runtime.authenticated_caller_id()?;
581                Ok(bcs::to_bytes(&application_id)?)
582            }
583            ContractRuntimePrecompile::SendMessage {
584                destination,
585                message,
586            } => {
587                let authenticated = true;
588                let is_tracked = true;
589                let grant = Resources::default();
590                let send_message_request = SendMessageRequest {
591                    destination,
592                    authenticated,
593                    is_tracked,
594                    grant,
595                    message,
596                };
597                let mut runtime = context.db().0.lock_runtime();
598                runtime.send_message(send_message_request)?;
599                Ok(vec![])
600            }
601            ContractRuntimePrecompile::TryCallApplication { target, argument } => {
602                let authenticated = true;
603                let mut runtime = context.db().0.lock_runtime();
604                ensure!(
605                    target != runtime.application_id()?,
606                    EvmExecutionError::NoSelfCall
607                );
608                runtime.try_call_application(authenticated, target, argument)
609            }
610            ContractRuntimePrecompile::Emit { stream_name, value } => {
611                let mut runtime = context.db().0.lock_runtime();
612                let result = runtime.emit(stream_name, value)?;
613                Ok(bcs::to_bytes(&result)?)
614            }
615            ContractRuntimePrecompile::ReadEvent {
616                chain_id,
617                stream_name,
618                index,
619            } => {
620                let mut runtime = context.db().0.lock_runtime();
621                runtime.read_event(chain_id, stream_name, index)
622            }
623            ContractRuntimePrecompile::SubscribeToEvents {
624                chain_id,
625                application_id,
626                stream_name,
627            } => {
628                let mut runtime = context.db().0.lock_runtime();
629                runtime.subscribe_to_events(chain_id, application_id, stream_name)?;
630                Ok(vec![])
631            }
632            ContractRuntimePrecompile::UnsubscribeFromEvents {
633                chain_id,
634                application_id,
635                stream_name,
636            } => {
637                let mut runtime = context.db().0.lock_runtime();
638                runtime.unsubscribe_from_events(chain_id, application_id, stream_name)?;
639                Ok(vec![])
640            }
641            ContractRuntimePrecompile::QueryService {
642                application_id,
643                query,
644            } => {
645                let mut runtime = context.db().0.lock_runtime();
646                ensure!(
647                    application_id != runtime.application_id()?,
648                    EvmExecutionError::NoSelfCall
649                );
650                runtime.query_service(application_id, query)
651            }
652            ContractRuntimePrecompile::ValidationRound => {
653                let mut runtime = context.db().0.lock_runtime();
654                let value = runtime.validation_round()?;
655                Ok(bcs::to_bytes(&value)?)
656            }
657            ContractRuntimePrecompile::Transfer { account, amount } => {
658                if amount.0 != U256::ZERO {
659                    let destination = {
660                        let destination = get_evm_destination(context, account)?;
661                        destination.unwrap_or(FAUCET_ADDRESS)
662                    };
663                    let application_id = {
664                        let mut runtime = context.db().0.lock_runtime();
665                        let application_id = runtime.application_id()?;
666                        let source = application_id.into();
667                        let value = Amount::try_from(amount.0).map_err(EvmExecutionError::from)?;
668                        runtime.transfer(source, account, value)?;
669                        application_id
670                    };
671                    let source: Address = application_id.evm_address();
672                    revm_transfer(context, source, destination, amount.0)?;
673                }
674                Ok(vec![])
675            }
676        }
677    }
678
679    fn call_or_fail<Runtime: ContractRuntime>(
680        inputs: &InputsImpl,
681        context: &mut ContractCtx<'a, Runtime>,
682    ) -> Result<Vec<u8>, ExecutionError> {
683        let input = get_precompile_argument(context, inputs);
684        match bcs::from_bytes(&input)? {
685            RuntimePrecompile::Base(base_tag) => {
686                let mut runtime = context.db().0.lock_runtime();
687                base_runtime_call(&base_tag, runtime.deref_mut())
688            }
689            RuntimePrecompile::Contract(contract_tag) => {
690                Self::contract_runtime_call(contract_tag, context)
691            }
692            RuntimePrecompile::Service(_) => Err(EvmExecutionError::PrecompileError(
693                "Service tags are not available in GeneralContractCall".to_string(),
694            )
695            .into()),
696        }
697    }
698}
699
700#[derive(Debug, Default)]
701struct ServicePrecompile {
702    inner: EthPrecompiles,
703}
704
705impl<'a> ServicePrecompile {
706    fn service_runtime_call<Runtime: ServiceRuntime>(
707        request: ServiceRuntimePrecompile,
708        context: &mut ServiceCtx<'a, Runtime>,
709    ) -> Result<Vec<u8>, ExecutionError> {
710        let mut runtime = context.db().0.lock_runtime();
711        match request {
712            ServiceRuntimePrecompile::TryQueryApplication { target, argument } => {
713                ensure!(
714                    target != runtime.application_id()?,
715                    EvmExecutionError::NoSelfCall
716                );
717                runtime.try_query_application(target, argument)
718            }
719        }
720    }
721
722    fn call_or_fail<Runtime: ServiceRuntime>(
723        inputs: &InputsImpl,
724        context: &mut ServiceCtx<'a, Runtime>,
725    ) -> Result<Vec<u8>, ExecutionError> {
726        let input = get_precompile_argument(context, inputs);
727        match bcs::from_bytes(&input)? {
728            RuntimePrecompile::Base(base_tag) => {
729                let mut runtime = context.db().0.lock_runtime();
730                base_runtime_call(&base_tag, runtime.deref_mut())
731            }
732            RuntimePrecompile::Contract(_) => Err(EvmExecutionError::PrecompileError(
733                "Contract calls are not available in GeneralServiceCall".to_string(),
734            )
735            .into()),
736            RuntimePrecompile::Service(service_tag) => {
737                Self::service_runtime_call(service_tag, context)
738            }
739        }
740    }
741}
742
743impl<'a, Runtime: ServiceRuntime> PrecompileProvider<ServiceCtx<'a, Runtime>>
744    for ServicePrecompile
745{
746    type Output = InterpreterResult;
747
748    fn set_spec(
749        &mut self,
750        spec: <<ServiceCtx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec,
751    ) -> bool {
752        <EthPrecompiles as PrecompileProvider<ServiceCtx<'a, Runtime>>>::set_spec(
753            &mut self.inner,
754            spec,
755        )
756    }
757
758    fn run(
759        &mut self,
760        context: &mut ServiceCtx<'a, Runtime>,
761        address: &Address,
762        inputs: &InputsImpl,
763        is_static: bool,
764        gas_limit: u64,
765    ) -> Result<Option<InterpreterResult>, String> {
766        if address == &PRECOMPILE_ADDRESS {
767            let output = Self::call_or_fail(inputs, context)
768                .map_err(|error| format!("ServicePrecompile error: {error}"))?;
769            return Ok(Some(get_precompile_output(output, gas_limit)));
770        }
771        self.inner
772            .run(context, address, inputs, is_static, gas_limit)
773    }
774
775    fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
776        let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
777        addresses.push(PRECOMPILE_ADDRESS);
778        Box::new(addresses.into_iter())
779    }
780
781    fn contains(&self, address: &Address) -> bool {
782        address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
783    }
784}
785
786fn map_result_create_outcome<Runtime: BaseRuntime>(
787    database: &InnerDatabase<Runtime>,
788    result: Result<Option<CreateOutcome>, ExecutionError>,
789) -> Option<CreateOutcome> {
790    match result {
791        Err(error) => {
792            database.insert_error(&error);
793            // The use of Revert immediately stops the execution.
794            let result = InstructionResult::Revert;
795            let output = Bytes::default();
796            let gas = Gas::default();
797            let result = InterpreterResult {
798                result,
799                output,
800                gas,
801            };
802            Some(CreateOutcome {
803                result,
804                address: None,
805            })
806        }
807        Ok(result) => result,
808    }
809}
810
811fn map_result_call_outcome<Runtime: BaseRuntime>(
812    database: &InnerDatabase<Runtime>,
813    result: Result<Option<CallOutcome>, ExecutionError>,
814) -> Option<CallOutcome> {
815    match result {
816        Err(error) => {
817            database.insert_error(&error);
818            // The use of Revert immediately stops the execution.
819            let result = InstructionResult::Revert;
820            let output = Bytes::default();
821            let gas = Gas::default();
822            let result = InterpreterResult {
823                result,
824                output,
825                gas,
826            };
827            let memory_offset = Range::default();
828            Some(CallOutcome {
829                result,
830                memory_offset,
831            })
832        }
833        Ok(result) => result,
834    }
835}
836
837struct CallInterceptorContract<Runtime> {
838    db: ContractDatabase<Runtime>,
839    // This is the contract address of the contract being created.
840    contract_address: Address,
841    precompile_addresses: BTreeSet<Address>,
842    error: Arc<Mutex<Option<U256>>>,
843}
844
845impl<Runtime> Clone for CallInterceptorContract<Runtime> {
846    fn clone(&self) -> Self {
847        Self {
848            db: self.db.clone(),
849            contract_address: self.contract_address,
850            precompile_addresses: self.precompile_addresses.clone(),
851            error: self.error.clone(),
852        }
853    }
854}
855
856impl<'a, Runtime: ContractRuntime> Inspector<ContractCtx<'a, Runtime>>
857    for CallInterceptorContract<Runtime>
858{
859    fn create(
860        &mut self,
861        context: &mut ContractCtx<'a, Runtime>,
862        inputs: &mut CreateInputs,
863    ) -> Option<CreateOutcome> {
864        let result = self.create_or_fail(context, inputs);
865        map_result_create_outcome(&self.db.inner, result)
866    }
867
868    fn call(
869        &mut self,
870        context: &mut ContractCtx<'a, Runtime>,
871        inputs: &mut CallInputs,
872    ) -> Option<CallOutcome> {
873        let result = self.call_or_fail(context, inputs);
874        map_result_call_outcome(&self.db.inner, result)
875    }
876}
877
878impl<Runtime: ContractRuntime> CallInterceptorContract<Runtime> {
879    /// Gets the expected `ApplicationId` corresponding to the
880    /// EVM contract being created.
881    /// `module_id` is the module being created.
882    ///
883    /// The index `num_apps` is the index of the application being
884    /// created. This is needed because the calls to `create_applications`
885    /// are done at the end of the execution of the contract.
886    /// So, the `peek_application_index` always returns the same index
887    /// during the execution.
888    ///
889    /// The parameters are empty because there is no argument
890    /// to the creation of the contract. In fact the `.init_code`
891    /// contains the concatenation of the bytecode and the constructor
892    /// argument so no additional argument needs to be added.
893    fn get_expected_application_id(
894        context: &mut ContractCtx<'_, Runtime>,
895        module_id: ModuleId,
896        num_apps: u32,
897    ) -> Result<ApplicationId, ExecutionError> {
898        let mut runtime = context.db().0.lock_runtime();
899        let chain_id = runtime.chain_id()?;
900        let block_height = runtime.block_height()?;
901        let application_index = runtime.peek_application_index()? + num_apps;
902        let parameters = JSON_EMPTY_VECTOR.to_vec(); // No constructor
903        let required_application_ids = Vec::new();
904        let application_description = ApplicationDescription {
905            module_id,
906            creator_chain_id: chain_id,
907            block_height,
908            application_index,
909            parameters: parameters.clone(),
910            required_application_ids,
911        };
912        Ok(ApplicationId::from(&application_description))
913    }
914
915    /// Publishes the `inputs.init_code` as a `ModuleId`.
916    /// There is no need for a separate blob for the service.
917    fn publish_create_inputs(
918        context: &mut ContractCtx<'_, Runtime>,
919        inputs: &CreateInputs,
920    ) -> Result<ModuleId, ExecutionError> {
921        let contract = linera_base::data_types::Bytecode::new(inputs.init_code.to_vec());
922        let service = linera_base::data_types::Bytecode::new(vec![]);
923        let mut runtime = context.db().0.lock_runtime();
924        runtime.publish_module(contract, service, VmRuntime::Evm)
925    }
926
927    /// The function `create` of the `Inspector` trait is called
928    /// when a contract is going to be instantiated. Since the
929    /// function can have some error case which are not supported
930    /// in `fn create`, we call a `fn create_or_fail` that can
931    /// return errors.
932    /// When the database runtime is created, the EVM contract
933    /// may or may not have been created. Therefore, at startup
934    /// we have `is_revm_instantiated = false`. That boolean
935    /// can be updated after `set_is_initialized`.
936    ///
937    /// The inspector can do two things:
938    /// * It can change the inputs in `CreateInputs`. Here we
939    ///   change the address being created.
940    /// * It can return some specific `CreateInputs` to be used.
941    ///
942    /// Therefore, the first case of the call is going to
943    /// be about the creation of the contract with just the
944    /// address being the one chosen by Linera.
945    ///
946    /// The second case occurs when the first contract has
947    /// been created and that contract starts making new
948    /// contracts.
949    /// In relation to EVM bytecode, the following notions are
950    /// relevant:
951    /// * The bytecode is created from the compilation.
952    /// * The bytecode concatenated with the constructor
953    ///   argument. This is what is sent to EVM when we
954    ///   create a new contract.
955    /// * The deployed bytecode. This is essentially the
956    ///   bytecode minus the constructor code.
957    ///
958    /// In relation to that, the following points are
959    /// important:
960    /// * The `inputs.init_code` is formed by the concatenation
961    ///   of compiled bytecode + constructor argument.
962    /// * It is impossible to separate the compiled bytecode
963    ///   from the constructor argument. Think for example
964    ///   of the following two contracts:
965    ///
966    ///   ```
967    ///   constructor(uint a, uint b) {
968    ///   value = a + b
969    ///   }
970    ///   ```
971    ///
972    ///   or
973    ///
974    ///   ```
975    ///   constructor(uint b) {
976    ///   value = 3 + b
977    ///   }
978    ///   ```
979    ///
980    ///   Calling the first constructor with (3,4) leads
981    ///   to the same concatenation as the second constructor
982    ///   with input (4).
983    /// * It turns out that we do not need to determine the
984    ///   constructor argument.
985    /// * What needs to be determined is the deployed bytecode.
986    ///   This is stored in the `AccountInfo` entry. It is
987    ///   the result of the execution by the Revm interpreter
988    ///   and there is no way to do it without doing the execution.
989    ///
990    /// The strategy for creating the contract is thus:
991    /// * For the case of a new contract being created, we proceed
992    ///   like for services. We just adjust the address of the
993    ///   creation.
994    /// * In the second case, we first create the contract and
995    ///   service bytecode (empty, but not used) and then publish
996    ///   the module.
997    /// * The parameters is empty because the constructor argument
998    ///   have already been put in the `init_code`.
999    /// * The instantiation argument is empty since an EVM contract
1000    ///   creating a new contract will not support Linera features.
1001    ///   This is simply not part of create/create2 in the EVM.
1002    /// * The application ID is being computed and used to adjust
1003    ///   the contract creation.
1004    /// * The balance is adjusted so that when it gets created in
1005    ///   Linera it will have the correct balance.
1006    /// * But that is the only change being done. We return `Ok(None)`
1007    ///   which means that the contract creation is done as usual
1008    ///   with Revm.
1009    ///
1010    /// The instantiation in Linera of the separate contracts
1011    /// is done at the end of the contract execution. It goes
1012    /// in the following way.
1013    /// * The `HashMap<ApplicationId, (ModuleId, u32)>` contains
1014    ///   the list of application to create and their index.
1015    /// * The index and module ID allow `create_application`
1016    ///   to create a contract with the right application ID.
1017    /// * `create_application` is in that case just a
1018    ///   writing of the data to storage.
1019    fn create_or_fail(
1020        &mut self,
1021        context: &mut ContractCtx<'_, Runtime>,
1022        inputs: &mut CreateInputs,
1023    ) -> Result<Option<CreateOutcome>, ExecutionError> {
1024        if !self.db.inner.is_revm_instantiated {
1025            self.db.inner.is_revm_instantiated = true;
1026            inputs.scheme = CreateScheme::Custom {
1027                address: self.contract_address,
1028            };
1029            return Ok(None);
1030        }
1031        let module_id = Self::publish_create_inputs(context, inputs)?;
1032        let mut map = self.db.modules.lock().unwrap();
1033        let num_apps = map.len() as u32;
1034        let expected_application_id =
1035            Self::get_expected_application_id(context, module_id, num_apps)?;
1036        map.insert(expected_application_id, (module_id, num_apps));
1037        let address = expected_application_id.evm_address();
1038        if inputs.value != U256::ZERO {
1039            let value = Amount::try_from(inputs.value).map_err(EvmExecutionError::from)?;
1040            let mut runtime = context.db().0.lock_runtime();
1041            let application_id = runtime.application_id()?;
1042            let source = application_id.into();
1043            let chain_id = runtime.chain_id()?;
1044            let account = identifiers::Account {
1045                chain_id,
1046                owner: expected_application_id.into(),
1047            };
1048            runtime.transfer(source, account, value)?;
1049        }
1050        inputs.scheme = CreateScheme::Custom { address };
1051        Ok(None)
1052    }
1053
1054    /// Every call to a contract passes by this function.
1055    /// Three kinds:
1056    /// * Call to the EVM smart contract itself (the first call)
1057    /// * Call to the PRECOMPILE smart contract.
1058    /// * Call to other EVM smart contract
1059    ///
1060    /// All calls are handled by Revm. But the calls have
1061    /// potentially a transfer associated to them.
1062    ///
1063    /// The first call is handled separately.
1064    /// The precompile calls do not have associated transfers.
1065    /// For other contract calls, the corresponding transfer
1066    /// is executed in Linera.
1067    ///
1068    /// Note that in the EVM transferring ethers is the same
1069    /// as calling a function. In Linera, transferring native
1070    /// tokens and calling a function are different operations.
1071    /// However, the block is accepted completely or not at all.
1072    /// Therefore, we can ensure the atomicity of the operations.
1073    fn call_or_fail(
1074        &self,
1075        _context: &mut ContractCtx<'_, Runtime>,
1076        inputs: &CallInputs,
1077    ) -> Result<Option<CallOutcome>, ExecutionError> {
1078        let is_precompile = self.precompile_addresses.contains(&inputs.target_address);
1079        let is_first_call = inputs.target_address == self.contract_address;
1080        if is_precompile {
1081            if let CallValue::Transfer(value) = inputs.value {
1082                ensure!(
1083                    value == U256::ZERO,
1084                    EvmExecutionError::NonZeroTransferPrecompile
1085                );
1086            }
1087        }
1088        if is_precompile || is_first_call {
1089            // Precompile calls are handled by the precompile code.
1090            return Ok(None);
1091        }
1092        // Handling the balances.
1093        if let CallValue::Transfer(value) = inputs.value {
1094            if value != U256::ZERO {
1095                let source: AccountOwner = inputs.caller.into();
1096                let owner: AccountOwner = inputs.bytecode_address.into();
1097                let mut runtime = self.db.lock_runtime();
1098                let amount = Amount::try_from(value).map_err(EvmExecutionError::from)?;
1099                let chain_id = runtime.chain_id()?;
1100                let destination = Account { chain_id, owner };
1101                runtime.transfer(source, destination, amount)?;
1102            }
1103        }
1104        // Other smart contracts calls are handled by the runtime
1105        Ok(None)
1106    }
1107}
1108
1109struct CallInterceptorService<Runtime> {
1110    db: ServiceDatabase<Runtime>,
1111    // This is the contract address of the contract being created.
1112    contract_address: Address,
1113    precompile_addresses: BTreeSet<Address>,
1114}
1115
1116impl<Runtime> Clone for CallInterceptorService<Runtime> {
1117    fn clone(&self) -> Self {
1118        Self {
1119            db: self.db.clone(),
1120            contract_address: self.contract_address,
1121            precompile_addresses: self.precompile_addresses.clone(),
1122        }
1123    }
1124}
1125
1126impl<'a, Runtime: ServiceRuntime> Inspector<ServiceCtx<'a, Runtime>>
1127    for CallInterceptorService<Runtime>
1128{
1129    /// See below on `fn create_or_fail`.
1130    fn create(
1131        &mut self,
1132        context: &mut ServiceCtx<'a, Runtime>,
1133        inputs: &mut CreateInputs,
1134    ) -> Option<CreateOutcome> {
1135        let result = self.create_or_fail(context, inputs);
1136        map_result_create_outcome(&self.db.inner, result)
1137    }
1138}
1139
1140impl<Runtime: ServiceRuntime> CallInterceptorService<Runtime> {
1141    /// The function `fn create` of the inspector trait is called
1142    /// when a contract is going to be instantiated. Since the
1143    /// function can have some error case which are not supported
1144    /// in `fn create`, we call a `fn create_or_fail` that can
1145    /// return errors.
1146    /// When the database runtime is created, the EVM contract
1147    /// may or may not have been created. Therefore, at startup
1148    /// we have `is_revm_instantiated = false`. That boolean
1149    /// can be updated after `set_is_initialized`.
1150    ///
1151    /// The inspector can do two things:
1152    /// * It can change the inputs in `CreateInputs`. Here we
1153    ///   change the address being created.
1154    /// * It can return some specific CreateInput to be used.
1155    ///
1156    /// Therefore, the first case of the call is going to
1157    /// be about the creation of the contract with just the
1158    /// address being the one chosen by Linera.
1159    /// The second case of creating a new contract does not
1160    /// apply in services and so lead to an error.
1161    fn create_or_fail(
1162        &mut self,
1163        _context: &ServiceCtx<'_, Runtime>,
1164        inputs: &mut CreateInputs,
1165    ) -> Result<Option<CreateOutcome>, ExecutionError> {
1166        if !self.db.inner.is_revm_instantiated {
1167            self.db.inner.is_revm_instantiated = true;
1168            inputs.scheme = CreateScheme::Custom {
1169                address: self.contract_address,
1170            };
1171            Ok(None)
1172        } else {
1173            Err(EvmExecutionError::NoContractCreationInService.into())
1174        }
1175    }
1176}
1177
1178pub struct RevmContractInstance<Runtime> {
1179    module: Vec<u8>,
1180    db: ContractDatabase<Runtime>,
1181}
1182
1183/// The type of EVM transaction being executed.
1184#[derive(Debug)]
1185enum EvmTxKind {
1186    /// Contract creation transaction (deploys new contract).
1187    Create,
1188    /// Contract call transaction (invokes existing contract).
1189    Call,
1190}
1191
1192/// Successful EVM execution result with gas usage and output data.
1193#[derive(Debug)]
1194struct ExecutionResultSuccess {
1195    /// Final gas consumed after applying refunds (per EIP-3529).
1196    gas_final: u64,
1197    /// Event logs emitted during execution.
1198    logs: Vec<Log>,
1199    /// Transaction output (contract address for Create, return data for Call).
1200    output: Output,
1201}
1202
1203impl ExecutionResultSuccess {
1204    fn output_and_logs(self) -> (u64, Vec<u8>, Vec<Log>) {
1205        let Output::Call(output) = self.output else {
1206            unreachable!("The output should have been created from a EvmTxKind::Call");
1207        };
1208        let output = output.as_ref().to_vec();
1209        (self.gas_final, output, self.logs)
1210    }
1211
1212    // Checks that the contract has been correctly instantiated
1213    fn check_contract_initialization(&self, expected_address: Address) -> Result<(), String> {
1214        // Checks that the output is the expected one.
1215        let Output::Create(_, contract_address) = self.output else {
1216            return Err("Input should be ExmTxKind::Create".to_string());
1217        };
1218        // Checks that the contract address exists.
1219        let contract_address = contract_address.ok_or("Deployment failed")?;
1220        // Checks that the created contract address is the one of the `ApplicationId`.
1221        if contract_address == expected_address {
1222            Ok(())
1223        } else {
1224            Err("Contract address is not the same as ApplicationId".to_string())
1225        }
1226    }
1227}
1228
1229impl<Runtime> UserContract for RevmContractInstance<Runtime>
1230where
1231    Runtime: ContractRuntime,
1232{
1233    fn instantiate(&mut self, argument: Vec<u8>) -> Result<(), ExecutionError> {
1234        self.db.inner.set_contract_address()?;
1235        let caller = self.get_msg_address()?;
1236        let instantiation_argument = serde_json::from_slice::<EvmInstantiation>(&argument)?;
1237        // This is the case of a contract created by Revm by another contract. We only
1238        // need to write it to storage.
1239        if let Some(remainder) = instantiation_argument
1240            .argument
1241            .as_slice()
1242            .strip_prefix(ALREADY_CREATED_CONTRACT_SELECTOR)
1243        {
1244            let account = bcs::from_bytes::<revm_state::Account>(remainder)?;
1245            return self.db.commit_contract_changes(&account);
1246        }
1247        self.initialize_contract(instantiation_argument.value, caller)?;
1248        if has_selector(&self.module, INSTANTIATE_SELECTOR) {
1249            let argument = get_revm_instantiation_bytes(instantiation_argument.argument);
1250            let result = self.transact_commit(&EvmTxKind::Call, argument, U256::ZERO, caller)?;
1251            self.write_logs(&result.logs, "instantiate")?;
1252        }
1253        Ok(())
1254    }
1255
1256    /// Executes the operation.
1257    /// The first 3 possibilities are internal calls
1258    /// from another Revm instance:
1259    /// * The `GET_ACCOUNT_INFO_SELECTOR` retrieves the
1260    ///   `AccountInfo` of that EVM contract.
1261    /// * The `GET_CONTRACT_STORAGE_SELECTOR` is about
1262    ///   individual storage entries.
1263    /// * The `COMMIT_CONTRACT_CHANGES_SELECTOR` is about
1264    ///   committing the state
1265    ///
1266    /// If not in those cases, then the execution proceeds
1267    /// normally and creates an Revm instance.
1268    fn execute_operation(&mut self, operation: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1269        self.db.inner.set_contract_address()?;
1270        ensure_message_length(operation.len(), 4)?;
1271        if operation == GET_ACCOUNT_INFO_SELECTOR {
1272            let account_info = self.db.inner.get_account_info()?;
1273            return Ok(bcs::to_bytes(&account_info)?);
1274        }
1275        if let Some(remainder) = operation
1276            .as_slice()
1277            .strip_prefix(GET_CONTRACT_STORAGE_SELECTOR)
1278        {
1279            let index = bcs::from_bytes(remainder)?;
1280            let value = self.db.inner.read_from_local_storage(index)?;
1281            return Ok(bcs::to_bytes(&value)?);
1282        }
1283        if let Some(remainder) = operation
1284            .as_slice()
1285            .strip_prefix(COMMIT_CONTRACT_CHANGES_SELECTOR)
1286        {
1287            let account = bcs::from_bytes::<revm_state::Account>(remainder)?;
1288            self.db.commit_contract_changes(&account)?;
1289            return Ok(Vec::new());
1290        }
1291        let caller = self.get_msg_address()?;
1292        forbid_execute_operation_origin(&operation[..4])?;
1293        let evm_call = bcs::from_bytes::<EvmOperation>(&operation)?;
1294        let result = self.init_transact_commit(evm_call.argument, evm_call.value, caller)?;
1295        let (gas_final, output, logs) = result.output_and_logs();
1296        self.consume_fuel(gas_final)?;
1297        self.write_logs(&logs, "operation")?;
1298        Ok(output)
1299    }
1300
1301    fn execute_message(&mut self, message: Vec<u8>) -> Result<(), ExecutionError> {
1302        self.db.inner.set_contract_address()?;
1303        ensure_selector_presence(
1304            &self.module,
1305            EXECUTE_MESSAGE_SELECTOR,
1306            "function execute_message(bytes)",
1307        )?;
1308        let operation = get_revm_execute_message_bytes(message);
1309        let caller = self.get_msg_address()?;
1310        let value = U256::ZERO;
1311        self.execute_no_return_operation(operation, "message", value, caller)
1312    }
1313
1314    fn process_streams(&mut self, streams: Vec<StreamUpdate>) -> Result<(), ExecutionError> {
1315        self.db.inner.set_contract_address()?;
1316        let operation = get_revm_process_streams_bytes(streams);
1317        ensure_selector_presence(
1318            &self.module,
1319            PROCESS_STREAMS_SELECTOR,
1320            "function process_streams(Linera.StreamUpdate[] memory streams)",
1321        )?;
1322        // For process_streams, authenticated_owner and authenticated_called_id are None.
1323        let caller = Address::ZERO;
1324        let value = U256::ZERO;
1325        self.execute_no_return_operation(operation, "process_streams", value, caller)
1326    }
1327
1328    fn finalize(&mut self) -> Result<(), ExecutionError> {
1329        Ok(())
1330    }
1331}
1332
1333fn process_execution_result(
1334    result: ExecutionResult,
1335) -> Result<ExecutionResultSuccess, EvmExecutionError> {
1336    match result {
1337        ExecutionResult::Success {
1338            reason,
1339            gas_used,
1340            gas_refunded,
1341            logs,
1342            output,
1343        } => {
1344            // Apply EIP-3529 refund cap (London fork)
1345            let max_refund = gas_used / 5;
1346            let actual_refund = gas_refunded.min(max_refund);
1347            let gas_final = gas_used - actual_refund;
1348            if !matches!(reason, SuccessReason::Return) {
1349                Err(EvmExecutionError::NoReturnInterpreter {
1350                    reason,
1351                    gas_used,
1352                    gas_refunded,
1353                    logs,
1354                    output,
1355                })
1356            } else {
1357                Ok(ExecutionResultSuccess {
1358                    gas_final,
1359                    logs,
1360                    output,
1361                })
1362            }
1363        }
1364        ExecutionResult::Revert { gas_used, output } => {
1365            Err(EvmExecutionError::Revert { gas_used, output })
1366        }
1367        ExecutionResult::Halt { gas_used, reason } => {
1368            Err(EvmExecutionError::Halt { gas_used, reason })
1369        }
1370    }
1371}
1372
1373impl<Runtime> RevmContractInstance<Runtime>
1374where
1375    Runtime: ContractRuntime,
1376{
1377    pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1378        let db = ContractDatabase::new(runtime);
1379        Self { module, db }
1380    }
1381
1382    fn execute_no_return_operation(
1383        &mut self,
1384        operation: Vec<u8>,
1385        origin: &str,
1386        value: U256,
1387        caller: Address,
1388    ) -> Result<(), ExecutionError> {
1389        let result = self.init_transact_commit(operation, value, caller)?;
1390        let (gas_final, output, logs) = result.output_and_logs();
1391        self.consume_fuel(gas_final)?;
1392        self.write_logs(&logs, origin)?;
1393        assert_eq!(output.len(), 0);
1394        Ok(())
1395    }
1396
1397    /// Executes the transaction. If needed initializes the contract.
1398    fn init_transact_commit(
1399        &mut self,
1400        vec: Vec<u8>,
1401        value: U256,
1402        caller: Address,
1403    ) -> Result<ExecutionResultSuccess, ExecutionError> {
1404        // An application can be instantiated in Linera sense, but not in EVM sense,
1405        // that is the contract entries corresponding to the deployed contract may
1406        // be missing.
1407        if !self.db.inner.set_is_initialized()? {
1408            self.initialize_contract(U256::ZERO, caller)?;
1409        }
1410        self.transact_commit(&EvmTxKind::Call, vec, value, caller)
1411    }
1412
1413    /// Initializes the contract.
1414    fn initialize_contract(&mut self, value: U256, caller: Address) -> Result<(), ExecutionError> {
1415        let mut vec_init = self.module.clone();
1416        let constructor_argument = self.db.inner.constructor_argument()?;
1417        vec_init.extend_from_slice(&constructor_argument);
1418        let result = self.transact_commit(&EvmTxKind::Create, vec_init, value, caller)?;
1419        result
1420            .check_contract_initialization(self.db.inner.contract_address)
1421            .map_err(EvmExecutionError::IncorrectContractCreation)?;
1422        self.write_logs(&result.logs, "deploy")
1423    }
1424
1425    /// Computes the address used in the `msg.sender` variable.
1426    /// It is computed in the following way:
1427    /// * If a Wasm contract calls an EVM contract then it is `Address::ZERO`.
1428    /// * If an EVM contract calls an EVM contract it is the address of the contract.
1429    /// * If a user having an `AccountOwner::Address32` address calls an EVM contract
1430    ///   then it is `Address::ZERO`.
1431    /// * If a user having an `AccountOwner::Address20` address calls an EVM contract
1432    ///   then it is this address.
1433    ///
1434    /// By doing this we ensure that EVM smart contracts works in the same way as
1435    /// on the EVM and that users and contracts outside of that realm can still
1436    /// call EVM smart contracts.
1437    fn get_msg_address(&self) -> Result<Address, ExecutionError> {
1438        let mut runtime = self.db.lock_runtime();
1439        let application_id = runtime.authenticated_caller_id()?;
1440        if let Some(application_id) = application_id {
1441            return Ok(if application_id.is_evm() {
1442                application_id.evm_address()
1443            } else {
1444                Address::ZERO
1445            });
1446        };
1447        let account_owner = runtime.authenticated_owner()?;
1448        if let Some(AccountOwner::Address20(address)) = account_owner {
1449            return Ok(Address::from(address));
1450        };
1451        Ok(ZERO_ADDRESS)
1452    }
1453
1454    fn transact_commit(
1455        &mut self,
1456        tx_kind: &EvmTxKind,
1457        input: Vec<u8>,
1458        value: U256,
1459        caller: Address,
1460    ) -> Result<ExecutionResultSuccess, ExecutionError> {
1461        let contract_address = self.db.inner.contract_address;
1462        self.db.inner.caller = caller;
1463        self.db.inner.value = value;
1464        self.db.inner.deposit_funds()?;
1465        let data = Bytes::from(input);
1466        let kind = match tx_kind {
1467            EvmTxKind::Create => TxKind::Create,
1468            EvmTxKind::Call => TxKind::Call(contract_address),
1469        };
1470        let inspector = CallInterceptorContract {
1471            db: self.db.clone(),
1472            contract_address,
1473            precompile_addresses: precompile_addresses(),
1474            error: Arc::new(Mutex::new(None)),
1475        };
1476        let block_env = self.db.get_block_env()?;
1477        let (max_size_evm_contract, gas_limit) = {
1478            let mut runtime = self.db.lock_runtime();
1479            let gas_limit = runtime.remaining_fuel(VmRuntime::Evm)?;
1480            let max_size_evm_contract = runtime.maximum_blob_size()? as usize;
1481            (max_size_evm_contract, gas_limit)
1482        };
1483        let nonce = self.db.get_nonce(&caller)?;
1484        let result = {
1485            let mut ctx: revm_context::Context<
1486                BlockEnv,
1487                _,
1488                _,
1489                _,
1490                Journal<WrapDatabaseRef<&mut ContractDatabase<Runtime>>>,
1491                (),
1492            > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1493                WrapDatabaseRef(&mut self.db),
1494                SpecId::PRAGUE,
1495            )
1496            .with_block(block_env);
1497            ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1498            let instructions = EthInstructions::new_mainnet();
1499            let mut evm = Evm::new_with_inspector(
1500                ctx,
1501                inspector.clone(),
1502                instructions,
1503                ContractPrecompile::default(),
1504            );
1505            evm.inspect_commit(
1506                TxEnv {
1507                    kind,
1508                    data,
1509                    nonce,
1510                    gas_limit,
1511                    caller,
1512                    value,
1513                    ..TxEnv::default()
1514                },
1515                inspector.clone(),
1516            )
1517            .map_err(|error| {
1518                let error = format!("{:?}", error);
1519                EvmExecutionError::TransactCommitError(error)
1520            })
1521        }?;
1522        self.db.inner.process_any_error()?;
1523        self.db.commit_changes()?;
1524        Ok(process_execution_result(result)?)
1525    }
1526
1527    fn consume_fuel(&self, gas_final: u64) -> Result<(), ExecutionError> {
1528        let mut runtime = self.db.lock_runtime();
1529        runtime.consume_fuel(gas_final, VmRuntime::Evm)
1530    }
1531
1532    fn write_logs(&self, logs: &[Log], origin: &str) -> Result<(), ExecutionError> {
1533        // TODO(#3758): Extracting Ethereum events from the Linera events.
1534        if !logs.is_empty() {
1535            let mut runtime = self.db.lock_runtime();
1536            let block_height = runtime.block_height()?;
1537            let stream_name = bcs::to_bytes("ethereum_event")?;
1538            let stream_name = StreamName(stream_name);
1539            for log in logs {
1540                let value = bcs::to_bytes(&(origin, block_height.0, log))?;
1541                runtime.emit(stream_name.clone(), value)?;
1542            }
1543        }
1544        Ok(())
1545    }
1546}
1547
1548pub struct RevmServiceInstance<Runtime> {
1549    module: Vec<u8>,
1550    db: ServiceDatabase<Runtime>,
1551}
1552
1553impl<Runtime> RevmServiceInstance<Runtime>
1554where
1555    Runtime: ServiceRuntime,
1556{
1557    pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1558        let db = ServiceDatabase::new(runtime);
1559        Self { module, db }
1560    }
1561}
1562
1563impl<Runtime> UserService for RevmServiceInstance<Runtime>
1564where
1565    Runtime: ServiceRuntime,
1566{
1567    fn handle_query(&mut self, argument: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1568        self.db.inner.set_contract_address()?;
1569        let evm_query = serde_json::from_slice(&argument)?;
1570        let query = match evm_query {
1571            EvmQuery::AccountInfo => {
1572                let account_info = self.db.inner.get_account_info()?;
1573                return Ok(serde_json::to_vec(&account_info)?);
1574            }
1575            EvmQuery::Storage(index) => {
1576                let value = self.db.inner.read_from_local_storage(index)?;
1577                return Ok(serde_json::to_vec(&value)?);
1578            }
1579            EvmQuery::Query(vec) => vec,
1580            EvmQuery::Operation(operation) => {
1581                let mut runtime = self.db.lock_runtime();
1582                runtime.schedule_operation(operation)?;
1583                return Ok(Vec::new());
1584            }
1585            EvmQuery::Operations(operations) => {
1586                let mut runtime = self.db.lock_runtime();
1587                for operation in operations {
1588                    runtime.schedule_operation(operation)?;
1589                }
1590                return Ok(Vec::new());
1591            }
1592        };
1593
1594        ensure_message_length(query.len(), 4)?;
1595        // We drop the logs since the "eth_call" execution does not return any log.
1596        // Also, for handle_query, we do not have associated costs.
1597        // More generally, there is gas costs associated to service operation.
1598        let result = self.init_transact(query)?;
1599        let (_gas_final, output, _logs) = result.output_and_logs();
1600        let answer = serde_json::to_vec(&output)?;
1601        Ok(answer)
1602    }
1603}
1604
1605impl<Runtime> RevmServiceInstance<Runtime>
1606where
1607    Runtime: ServiceRuntime,
1608{
1609    fn init_transact(&mut self, vec: Vec<u8>) -> Result<ExecutionResultSuccess, ExecutionError> {
1610        // In case of a shared application, we need to instantiate it first
1611        // However, since in ServiceRuntime, we cannot modify the storage,
1612        // therefore the compiled contract is saved in the changes.
1613        let contract_address = self.db.inner.contract_address;
1614        if !self.db.inner.set_is_initialized()? {
1615            let changes = {
1616                let mut vec_init = self.module.clone();
1617                let constructor_argument = self.db.inner.constructor_argument()?;
1618                vec_init.extend_from_slice(&constructor_argument);
1619                let (result, changes) = self.transact(TxKind::Create, vec_init)?;
1620                result
1621                    .check_contract_initialization(contract_address)
1622                    .map_err(EvmExecutionError::IncorrectContractCreation)?;
1623                changes
1624            };
1625            self.db.inner.changes = changes;
1626        }
1627        ensure_message_length(vec.len(), 4)?;
1628        forbid_execute_operation_origin(&vec[..4])?;
1629        let kind = TxKind::Call(contract_address);
1630        let (execution_result, _) = self.transact(kind, vec)?;
1631        Ok(execution_result)
1632    }
1633
1634    fn transact(
1635        &mut self,
1636        kind: TxKind,
1637        input: Vec<u8>,
1638    ) -> Result<(ExecutionResultSuccess, EvmState), ExecutionError> {
1639        let contract_address = self.db.inner.contract_address;
1640        let caller = SERVICE_ADDRESS;
1641        let value = U256::ZERO;
1642        self.db.inner.caller = caller;
1643        self.db.inner.value = value;
1644        let data = Bytes::from(input);
1645        let block_env = self.db.get_block_env()?;
1646        let inspector = CallInterceptorService {
1647            db: self.db.clone(),
1648            contract_address,
1649            precompile_addresses: precompile_addresses(),
1650        };
1651        let max_size_evm_contract = {
1652            let mut runtime = self.db.lock_runtime();
1653            runtime.maximum_blob_size()? as usize
1654        };
1655        let nonce = self.db.get_nonce(&caller)?;
1656        let result_state = {
1657            let mut ctx: revm_context::Context<
1658                BlockEnv,
1659                _,
1660                _,
1661                _,
1662                Journal<WrapDatabaseRef<&mut ServiceDatabase<Runtime>>>,
1663                (),
1664            > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1665                WrapDatabaseRef(&mut self.db),
1666                SpecId::PRAGUE,
1667            )
1668            .with_block(block_env);
1669            ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1670            let instructions = EthInstructions::new_mainnet();
1671            let mut evm = Evm::new_with_inspector(
1672                ctx,
1673                inspector.clone(),
1674                instructions,
1675                ServicePrecompile::default(),
1676            );
1677            evm.inspect(
1678                TxEnv {
1679                    kind,
1680                    data,
1681                    nonce,
1682                    value,
1683                    caller,
1684                    gas_limit: EVM_SERVICE_GAS_LIMIT,
1685                    ..TxEnv::default()
1686                },
1687                inspector,
1688            )
1689            .map_err(|error| {
1690                let error = format!("{:?}", error);
1691                EvmExecutionError::TransactCommitError(error)
1692            })
1693        }?;
1694        self.db.inner.process_any_error()?;
1695        let result = process_execution_result(result_state.result)?;
1696        Ok((result, result_state.state))
1697    }
1698}