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>(
414    context: &mut Ctx,
415    inputs: &InputsImpl,
416) -> Result<Vec<u8>, ExecutionError> {
417    Ok(get_argument(context, &inputs.input))
418}
419
420fn base_runtime_call<Runtime: BaseRuntime>(
421    request: BaseRuntimePrecompile,
422    runtime: &mut Runtime,
423) -> Result<Vec<u8>, ExecutionError> {
424    match request {
425        BaseRuntimePrecompile::ChainId => {
426            let chain_id = runtime.chain_id()?;
427            Ok(bcs::to_bytes(&chain_id)?)
428        }
429        BaseRuntimePrecompile::BlockHeight => {
430            let block_height = runtime.block_height()?;
431            Ok(bcs::to_bytes(&block_height)?)
432        }
433        BaseRuntimePrecompile::ApplicationCreatorChainId => {
434            let chain_id = runtime.application_creator_chain_id()?;
435            Ok(bcs::to_bytes(&chain_id)?)
436        }
437        BaseRuntimePrecompile::ReadSystemTimestamp => {
438            let timestamp = runtime.read_system_timestamp()?;
439            Ok(bcs::to_bytes(&timestamp)?)
440        }
441        BaseRuntimePrecompile::ReadChainBalance => {
442            let balance: linera_base::data_types::Amount = runtime.read_chain_balance()?;
443            let balance: AmountU256 = balance.into();
444            Ok(bcs::to_bytes(&balance)?)
445        }
446        BaseRuntimePrecompile::ReadOwnerBalance(account_owner) => {
447            let balance = runtime.read_owner_balance(account_owner)?;
448            let balance = Into::<U256>::into(balance);
449            Ok(bcs::to_bytes(&balance)?)
450        }
451        BaseRuntimePrecompile::ReadOwnerBalances => {
452            let owner_balances = runtime.read_owner_balances()?;
453            let owner_balances = owner_balances
454                .into_iter()
455                .map(|(account_owner, balance)| (account_owner, balance.into()))
456                .collect::<Vec<(AccountOwner, AmountU256)>>();
457            Ok(bcs::to_bytes(&owner_balances)?)
458        }
459        BaseRuntimePrecompile::ReadBalanceOwners => {
460            let owners = runtime.read_balance_owners()?;
461            Ok(bcs::to_bytes(&owners)?)
462        }
463        BaseRuntimePrecompile::ChainOwnership => {
464            let chain_ownership = runtime.chain_ownership()?;
465            Ok(bcs::to_bytes(&chain_ownership)?)
466        }
467        BaseRuntimePrecompile::ReadDataBlob(hash) => runtime.read_data_blob(hash),
468        BaseRuntimePrecompile::AssertDataBlobExists(hash) => {
469            runtime.assert_data_blob_exists(hash)?;
470            Ok(Vec::new())
471        }
472    }
473}
474
475fn precompile_addresses() -> BTreeSet<Address> {
476    let mut addresses = BTreeSet::new();
477    for address in EthPrecompiles::default().warm_addresses() {
478        addresses.insert(address);
479    }
480    addresses.insert(PRECOMPILE_ADDRESS);
481    addresses
482}
483
484#[derive(Debug, Default)]
485struct ContractPrecompile {
486    inner: EthPrecompiles,
487}
488
489impl<'a, Runtime: ContractRuntime> PrecompileProvider<ContractCtx<'a, Runtime>>
490    for ContractPrecompile
491{
492    type Output = InterpreterResult;
493
494    fn set_spec(
495        &mut self,
496        spec: <<ContractCtx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec,
497    ) -> bool {
498        <EthPrecompiles as PrecompileProvider<ContractCtx<'a, Runtime>>>::set_spec(
499            &mut self.inner,
500            spec,
501        )
502    }
503
504    fn run(
505        &mut self,
506        context: &mut ContractCtx<'a, Runtime>,
507        address: &Address,
508        inputs: &InputsImpl,
509        is_static: bool,
510        gas_limit: u64,
511    ) -> Result<Option<InterpreterResult>, String> {
512        if address == &PRECOMPILE_ADDRESS {
513            let output = Self::call_or_fail(inputs, context)
514                .map_err(|error| format!("ContractPrecompile error: {error}"))?;
515            return Ok(Some(get_precompile_output(output, gas_limit)));
516        }
517        self.inner
518            .run(context, address, inputs, is_static, gas_limit)
519    }
520
521    fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
522        let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
523        addresses.push(PRECOMPILE_ADDRESS);
524        Box::new(addresses.into_iter())
525    }
526
527    fn contains(&self, address: &Address) -> bool {
528        address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
529    }
530}
531
532fn get_evm_destination<Runtime: ContractRuntime>(
533    context: &mut ContractCtx<'_, Runtime>,
534    account: Account,
535) -> Result<Option<Address>, ExecutionError> {
536    let mut runtime = context.db().0.lock_runtime();
537    if runtime.chain_id()? != account.chain_id {
538        return Ok(None);
539    }
540    Ok(account.owner.to_evm_address())
541}
542
543/// We are doing transfers of value from a source to a destination.
544fn revm_transfer<Runtime: ContractRuntime>(
545    context: &mut ContractCtx<'_, Runtime>,
546    source: Address,
547    destination: Address,
548    value: U256,
549) -> Result<(), ExecutionError> {
550    if let Some(error) = context.journal().transfer(source, destination, value)? {
551        let error = format!("{error:?}");
552        let error = EvmExecutionError::TransactError(error);
553        return Err(error.into());
554    }
555    Ok(())
556}
557
558impl<'a> ContractPrecompile {
559    fn contract_runtime_call<Runtime: ContractRuntime>(
560        request: ContractRuntimePrecompile,
561        context: &mut ContractCtx<'a, Runtime>,
562    ) -> Result<Vec<u8>, ExecutionError> {
563        match request {
564            ContractRuntimePrecompile::AuthenticatedOwner => {
565                let mut runtime = context.db().0.lock_runtime();
566                let account_owner = runtime.authenticated_owner()?;
567                Ok(bcs::to_bytes(&account_owner)?)
568            }
569
570            ContractRuntimePrecompile::MessageOriginChainId => {
571                let mut runtime = context.db().0.lock_runtime();
572                let origin_chain_id = runtime.message_origin_chain_id()?;
573                Ok(bcs::to_bytes(&origin_chain_id)?)
574            }
575
576            ContractRuntimePrecompile::MessageIsBouncing => {
577                let mut runtime = context.db().0.lock_runtime();
578                let result = runtime.message_is_bouncing()?;
579                Ok(bcs::to_bytes(&result)?)
580            }
581            ContractRuntimePrecompile::AuthenticatedCallerId => {
582                let mut runtime = context.db().0.lock_runtime();
583                let application_id = runtime.authenticated_caller_id()?;
584                Ok(bcs::to_bytes(&application_id)?)
585            }
586            ContractRuntimePrecompile::SendMessage {
587                destination,
588                message,
589            } => {
590                let authenticated = true;
591                let is_tracked = true;
592                let grant = Resources::default();
593                let send_message_request = SendMessageRequest {
594                    destination,
595                    authenticated,
596                    is_tracked,
597                    grant,
598                    message,
599                };
600                let mut runtime = context.db().0.lock_runtime();
601                runtime.send_message(send_message_request)?;
602                Ok(vec![])
603            }
604            ContractRuntimePrecompile::TryCallApplication { target, argument } => {
605                let authenticated = true;
606                let mut runtime = context.db().0.lock_runtime();
607                ensure!(
608                    target != runtime.application_id()?,
609                    EvmExecutionError::NoSelfCall
610                );
611                runtime.try_call_application(authenticated, target, argument)
612            }
613            ContractRuntimePrecompile::Emit { stream_name, value } => {
614                let mut runtime = context.db().0.lock_runtime();
615                let result = runtime.emit(stream_name, value)?;
616                Ok(bcs::to_bytes(&result)?)
617            }
618            ContractRuntimePrecompile::ReadEvent {
619                chain_id,
620                stream_name,
621                index,
622            } => {
623                let mut runtime = context.db().0.lock_runtime();
624                runtime.read_event(chain_id, stream_name, index)
625            }
626            ContractRuntimePrecompile::SubscribeToEvents {
627                chain_id,
628                application_id,
629                stream_name,
630            } => {
631                let mut runtime = context.db().0.lock_runtime();
632                runtime.subscribe_to_events(chain_id, application_id, stream_name)?;
633                Ok(vec![])
634            }
635            ContractRuntimePrecompile::UnsubscribeFromEvents {
636                chain_id,
637                application_id,
638                stream_name,
639            } => {
640                let mut runtime = context.db().0.lock_runtime();
641                runtime.unsubscribe_from_events(chain_id, application_id, stream_name)?;
642                Ok(vec![])
643            }
644            ContractRuntimePrecompile::QueryService {
645                application_id,
646                query,
647            } => {
648                let mut runtime = context.db().0.lock_runtime();
649                ensure!(
650                    application_id != runtime.application_id()?,
651                    EvmExecutionError::NoSelfCall
652                );
653                runtime.query_service(application_id, query)
654            }
655            ContractRuntimePrecompile::ValidationRound => {
656                let mut runtime = context.db().0.lock_runtime();
657                let value = runtime.validation_round()?;
658                Ok(bcs::to_bytes(&value)?)
659            }
660            ContractRuntimePrecompile::Transfer { account, amount } => {
661                if amount.0 != U256::ZERO {
662                    let destination = {
663                        let destination = get_evm_destination(context, account)?;
664                        destination.unwrap_or(FAUCET_ADDRESS)
665                    };
666                    let application_id = {
667                        let mut runtime = context.db().0.lock_runtime();
668                        let application_id = runtime.application_id()?;
669                        let source = application_id.into();
670                        let value = Amount::try_from(amount.0).map_err(EvmExecutionError::from)?;
671                        runtime.transfer(source, account, value)?;
672                        application_id
673                    };
674                    let source: Address = application_id.evm_address();
675                    revm_transfer(context, source, destination, amount.0)?;
676                }
677                Ok(vec![])
678            }
679        }
680    }
681
682    fn call_or_fail<Runtime: ContractRuntime>(
683        inputs: &InputsImpl,
684        context: &mut ContractCtx<'a, Runtime>,
685    ) -> Result<Vec<u8>, ExecutionError> {
686        let input = get_precompile_argument(context, inputs)?;
687        match bcs::from_bytes(&input)? {
688            RuntimePrecompile::Base(base_tag) => {
689                let mut runtime = context.db().0.lock_runtime();
690                base_runtime_call(base_tag, runtime.deref_mut())
691            }
692            RuntimePrecompile::Contract(contract_tag) => {
693                Self::contract_runtime_call(contract_tag, context)
694            }
695            RuntimePrecompile::Service(_) => Err(EvmExecutionError::PrecompileError(
696                "Service tags are not available in GeneralContractCall".to_string(),
697            )
698            .into()),
699        }
700    }
701}
702
703#[derive(Debug, Default)]
704struct ServicePrecompile {
705    inner: EthPrecompiles,
706}
707
708impl<'a> ServicePrecompile {
709    fn service_runtime_call<Runtime: ServiceRuntime>(
710        request: ServiceRuntimePrecompile,
711        context: &mut ServiceCtx<'a, Runtime>,
712    ) -> Result<Vec<u8>, ExecutionError> {
713        let mut runtime = context.db().0.lock_runtime();
714        match request {
715            ServiceRuntimePrecompile::TryQueryApplication { target, argument } => {
716                ensure!(
717                    target != runtime.application_id()?,
718                    EvmExecutionError::NoSelfCall
719                );
720                runtime.try_query_application(target, argument)
721            }
722        }
723    }
724
725    fn call_or_fail<Runtime: ServiceRuntime>(
726        inputs: &InputsImpl,
727        context: &mut ServiceCtx<'a, Runtime>,
728    ) -> Result<Vec<u8>, ExecutionError> {
729        let input = get_precompile_argument(context, inputs)?;
730        match bcs::from_bytes(&input)? {
731            RuntimePrecompile::Base(base_tag) => {
732                let mut runtime = context.db().0.lock_runtime();
733                base_runtime_call(base_tag, runtime.deref_mut())
734            }
735            RuntimePrecompile::Contract(_) => Err(EvmExecutionError::PrecompileError(
736                "Contract calls are not available in GeneralServiceCall".to_string(),
737            )
738            .into()),
739            RuntimePrecompile::Service(service_tag) => {
740                Self::service_runtime_call(service_tag, context)
741            }
742        }
743    }
744}
745
746impl<'a, Runtime: ServiceRuntime> PrecompileProvider<ServiceCtx<'a, Runtime>>
747    for ServicePrecompile
748{
749    type Output = InterpreterResult;
750
751    fn set_spec(
752        &mut self,
753        spec: <<ServiceCtx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec,
754    ) -> bool {
755        <EthPrecompiles as PrecompileProvider<ServiceCtx<'a, Runtime>>>::set_spec(
756            &mut self.inner,
757            spec,
758        )
759    }
760
761    fn run(
762        &mut self,
763        context: &mut ServiceCtx<'a, Runtime>,
764        address: &Address,
765        inputs: &InputsImpl,
766        is_static: bool,
767        gas_limit: u64,
768    ) -> Result<Option<InterpreterResult>, String> {
769        if address == &PRECOMPILE_ADDRESS {
770            let output = Self::call_or_fail(inputs, context)
771                .map_err(|error| format!("ServicePrecompile error: {error}"))?;
772            return Ok(Some(get_precompile_output(output, gas_limit)));
773        }
774        self.inner
775            .run(context, address, inputs, is_static, gas_limit)
776    }
777
778    fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
779        let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
780        addresses.push(PRECOMPILE_ADDRESS);
781        Box::new(addresses.into_iter())
782    }
783
784    fn contains(&self, address: &Address) -> bool {
785        address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
786    }
787}
788
789fn map_result_create_outcome<Runtime: BaseRuntime>(
790    database: &InnerDatabase<Runtime>,
791    result: Result<Option<CreateOutcome>, ExecutionError>,
792) -> Option<CreateOutcome> {
793    match result {
794        Err(error) => {
795            database.insert_error(error);
796            // The use of Revert immediately stops the execution.
797            let result = InstructionResult::Revert;
798            let output = Bytes::default();
799            let gas = Gas::default();
800            let result = InterpreterResult {
801                result,
802                output,
803                gas,
804            };
805            Some(CreateOutcome {
806                result,
807                address: None,
808            })
809        }
810        Ok(result) => result,
811    }
812}
813
814fn map_result_call_outcome<Runtime: BaseRuntime>(
815    database: &InnerDatabase<Runtime>,
816    result: Result<Option<CallOutcome>, ExecutionError>,
817) -> Option<CallOutcome> {
818    match result {
819        Err(error) => {
820            database.insert_error(error);
821            // The use of Revert immediately stops the execution.
822            let result = InstructionResult::Revert;
823            let output = Bytes::default();
824            let gas = Gas::default();
825            let result = InterpreterResult {
826                result,
827                output,
828                gas,
829            };
830            let memory_offset = Range::default();
831            Some(CallOutcome {
832                result,
833                memory_offset,
834            })
835        }
836        Ok(result) => result,
837    }
838}
839
840struct CallInterceptorContract<Runtime> {
841    db: ContractDatabase<Runtime>,
842    // This is the contract address of the contract being created.
843    contract_address: Address,
844    precompile_addresses: BTreeSet<Address>,
845    error: Arc<Mutex<Option<U256>>>,
846}
847
848impl<Runtime> Clone for CallInterceptorContract<Runtime> {
849    fn clone(&self) -> Self {
850        Self {
851            db: self.db.clone(),
852            contract_address: self.contract_address,
853            precompile_addresses: self.precompile_addresses.clone(),
854            error: self.error.clone(),
855        }
856    }
857}
858
859impl<'a, Runtime: ContractRuntime> Inspector<ContractCtx<'a, Runtime>>
860    for CallInterceptorContract<Runtime>
861{
862    fn create(
863        &mut self,
864        context: &mut ContractCtx<'a, Runtime>,
865        inputs: &mut CreateInputs,
866    ) -> Option<CreateOutcome> {
867        let result = self.create_or_fail(context, inputs);
868        map_result_create_outcome(&self.db.inner, result)
869    }
870
871    fn call(
872        &mut self,
873        context: &mut ContractCtx<'a, Runtime>,
874        inputs: &mut CallInputs,
875    ) -> Option<CallOutcome> {
876        let result = self.call_or_fail(context, inputs);
877        map_result_call_outcome(&self.db.inner, result)
878    }
879}
880
881impl<Runtime: ContractRuntime> CallInterceptorContract<Runtime> {
882    /// Gets the expected `ApplicationId` corresponding to the
883    /// EVM contract being created.
884    /// `module_id` is the module being created.
885    ///
886    /// The index `num_apps` is the index of the application being
887    /// created. This is needed because the calls to `create_applications`
888    /// are done at the end of the execution of the contract.
889    /// So, the `peek_application_index` always returns the same index
890    /// during the execution.
891    ///
892    /// The parameters are empty because there is no argument
893    /// to the creation of the contract. In fact the `.init_code`
894    /// contains the concatenation of the bytecode and the constructor
895    /// argument so no additional argument needs to be added.
896    fn get_expected_application_id(
897        context: &mut ContractCtx<'_, Runtime>,
898        module_id: ModuleId,
899        num_apps: u32,
900    ) -> Result<ApplicationId, ExecutionError> {
901        let mut runtime = context.db().0.lock_runtime();
902        let chain_id = runtime.chain_id()?;
903        let block_height = runtime.block_height()?;
904        let application_index = runtime.peek_application_index()? + num_apps;
905        let parameters = JSON_EMPTY_VECTOR.to_vec(); // No constructor
906        let required_application_ids = Vec::new();
907        let application_description = ApplicationDescription {
908            module_id,
909            creator_chain_id: chain_id,
910            block_height,
911            application_index,
912            parameters: parameters.clone(),
913            required_application_ids,
914        };
915        Ok(ApplicationId::from(&application_description))
916    }
917
918    /// Publishes the `inputs.init_code` as a `ModuleId`.
919    /// There is no need for a separate blob for the service.
920    fn publish_create_inputs(
921        context: &mut ContractCtx<'_, Runtime>,
922        inputs: &mut CreateInputs,
923    ) -> Result<ModuleId, ExecutionError> {
924        let contract = linera_base::data_types::Bytecode::new(inputs.init_code.to_vec());
925        let service = linera_base::data_types::Bytecode::new(vec![]);
926        let mut runtime = context.db().0.lock_runtime();
927        runtime.publish_module(contract, service, VmRuntime::Evm)
928    }
929
930    /// The function `create` of the `Inspector` trait is called
931    /// when a contract is going to be instantiated. Since the
932    /// function can have some error case which are not supported
933    /// in `fn create`, we call a `fn create_or_fail` that can
934    /// return errors.
935    /// When the database runtime is created, the EVM contract
936    /// may or may not have been created. Therefore, at startup
937    /// we have `is_revm_instantiated = false`. That boolean
938    /// can be updated after `set_is_initialized`.
939    ///
940    /// The inspector can do two things:
941    /// * It can change the inputs in `CreateInputs`. Here we
942    ///   change the address being created.
943    /// * It can return some specific `CreateInputs` to be used.
944    ///
945    /// Therefore, the first case of the call is going to
946    /// be about the creation of the contract with just the
947    /// address being the one chosen by Linera.
948    ///
949    /// The second case occurs when the first contract has
950    /// been created and that contract starts making new
951    /// contracts.
952    /// In relation to EVM bytecode, the following notions are
953    /// relevant:
954    /// * The bytecode is created from the compilation.
955    /// * The bytecode concatenated with the constructor
956    ///   argument. This is what is sent to EVM when we
957    ///   create a new contract.
958    /// * The deployed bytecode. This is essentially the
959    ///   bytecode minus the constructor code.
960    ///
961    /// In relation to that, the following points are
962    /// important:
963    /// * The `inputs.init_code` is formed by the concatenation
964    ///   of compiled bytecode + constructor argument.
965    /// * It is impossible to separate the compiled bytecode
966    ///   from the constructor argument. Think for example
967    ///   of the following two contracts:
968    ///
969    ///   ```
970    ///   constructor(uint a, uint b) {
971    ///   value = a + b
972    ///   }
973    ///   ```
974    ///
975    ///   or
976    ///
977    ///   ```
978    ///   constructor(uint b) {
979    ///   value = 3 + b
980    ///   }
981    ///   ```
982    ///
983    ///   Calling the first constructor with (3,4) leads
984    ///   to the same concatenation as the second constructor
985    ///   with input (4).
986    /// * It turns out that we do not need to determine the
987    ///   constructor argument.
988    /// * What needs to be determined is the deployed bytecode.
989    ///   This is stored in the `AccountInfo` entry. It is
990    ///   the result of the execution by the Revm interpreter
991    ///   and there is no way to do it without doing the execution.
992    ///
993    /// The strategy for creating the contract is thus:
994    /// * For the case of a new contract being created, we proceed
995    ///   like for services. We just adjust the address of the
996    ///   creation.
997    /// * In the second case, we first create the contract and
998    ///   service bytecode (empty, but not used) and then publish
999    ///   the module.
1000    /// * The parameters is empty because the constructor argument
1001    ///   have already been put in the `init_code`.
1002    /// * The instantiation argument is empty since an EVM contract
1003    ///   creating a new contract will not support Linera features.
1004    ///   This is simply not part of create/create2 in the EVM.
1005    /// * The application ID is being computed and used to adjust
1006    ///   the contract creation.
1007    /// * The balance is adjusted so that when it gets created in
1008    ///   Linera it will have the correct balance.
1009    /// * But that is the only change being done. We return `Ok(None)`
1010    ///   which means that the contract creation is done as usual
1011    ///   with Revm.
1012    ///
1013    /// The instantiation in Linera of the separate contracts
1014    /// is done at the end of the contract execution. It goes
1015    /// in the following way.
1016    /// * The `HashMap<ApplicationId, (ModuleId, u32)>` contains
1017    ///   the list of application to create and their index.
1018    /// * The index and module ID allow `create_application`
1019    ///   to create a contract with the right application ID.
1020    /// * `create_application` is in that case just a
1021    ///   writing of the data to storage.
1022    fn create_or_fail(
1023        &mut self,
1024        context: &mut ContractCtx<'_, Runtime>,
1025        inputs: &mut CreateInputs,
1026    ) -> Result<Option<CreateOutcome>, ExecutionError> {
1027        if !self.db.inner.is_revm_instantiated {
1028            self.db.inner.is_revm_instantiated = true;
1029            inputs.scheme = CreateScheme::Custom {
1030                address: self.contract_address,
1031            };
1032            return Ok(None);
1033        }
1034        let module_id = Self::publish_create_inputs(context, inputs)?;
1035        let mut map = self.db.modules.lock().unwrap();
1036        let num_apps = map.len() as u32;
1037        let expected_application_id =
1038            Self::get_expected_application_id(context, module_id, num_apps)?;
1039        map.insert(expected_application_id, (module_id, num_apps));
1040        let address = expected_application_id.evm_address();
1041        if inputs.value != U256::ZERO {
1042            let value = Amount::try_from(inputs.value).map_err(EvmExecutionError::from)?;
1043            let mut runtime = context.db().0.lock_runtime();
1044            let application_id = runtime.application_id()?;
1045            let source = application_id.into();
1046            let chain_id = runtime.chain_id()?;
1047            let account = identifiers::Account {
1048                chain_id,
1049                owner: expected_application_id.into(),
1050            };
1051            runtime.transfer(source, account, value)?;
1052        }
1053        inputs.scheme = CreateScheme::Custom { address };
1054        Ok(None)
1055    }
1056
1057    /// Every call to a contract passes by this function.
1058    /// Three kinds:
1059    /// * Call to the EVM smart contract itself (the first call)
1060    /// * Call to the PRECOMPILE smart contract.
1061    /// * Call to other EVM smart contract
1062    ///
1063    /// All calls are handled by Revm. But the calls have
1064    /// potentially a transfer associated to them.
1065    ///
1066    /// The first call is handled separately.
1067    /// The precompile calls do not have associated transfers.
1068    /// For other contract calls, the corresponding transfer
1069    /// is executed in Linera.
1070    ///
1071    /// Note that in the EVM transferring ethers is the same
1072    /// as calling a function. In Linera, transferring native
1073    /// tokens and calling a function are different operations.
1074    /// However, the block is accepted completely or not at all.
1075    /// Therefore, we can ensure the atomicity of the operations.
1076    fn call_or_fail(
1077        &mut self,
1078        _context: &mut ContractCtx<'_, Runtime>,
1079        inputs: &mut CallInputs,
1080    ) -> Result<Option<CallOutcome>, ExecutionError> {
1081        let is_precompile = self.precompile_addresses.contains(&inputs.target_address);
1082        let is_first_call = inputs.target_address == self.contract_address;
1083        if is_precompile {
1084            if let CallValue::Transfer(value) = inputs.value {
1085                ensure!(
1086                    value == U256::ZERO,
1087                    EvmExecutionError::NonZeroTransferPrecompile
1088                );
1089            }
1090        }
1091        if is_precompile || is_first_call {
1092            // Precompile calls are handled by the precompile code.
1093            return Ok(None);
1094        }
1095        // Handling the balances.
1096        if let CallValue::Transfer(value) = inputs.value {
1097            if value != U256::ZERO {
1098                let source: AccountOwner = inputs.caller.into();
1099                let owner: AccountOwner = inputs.bytecode_address.into();
1100                let mut runtime = self.db.lock_runtime();
1101                let amount = Amount::try_from(value).map_err(EvmExecutionError::from)?;
1102                let chain_id = runtime.chain_id()?;
1103                let destination = Account { chain_id, owner };
1104                runtime.transfer(source, destination, amount)?;
1105            }
1106        }
1107        // Other smart contracts calls are handled by the runtime
1108        Ok(None)
1109    }
1110}
1111
1112struct CallInterceptorService<Runtime> {
1113    db: ServiceDatabase<Runtime>,
1114    // This is the contract address of the contract being created.
1115    contract_address: Address,
1116    precompile_addresses: BTreeSet<Address>,
1117}
1118
1119impl<Runtime> Clone for CallInterceptorService<Runtime> {
1120    fn clone(&self) -> Self {
1121        Self {
1122            db: self.db.clone(),
1123            contract_address: self.contract_address,
1124            precompile_addresses: self.precompile_addresses.clone(),
1125        }
1126    }
1127}
1128
1129impl<'a, Runtime: ServiceRuntime> Inspector<ServiceCtx<'a, Runtime>>
1130    for CallInterceptorService<Runtime>
1131{
1132    /// See below on `fn create_or_fail`.
1133    fn create(
1134        &mut self,
1135        context: &mut ServiceCtx<'a, Runtime>,
1136        inputs: &mut CreateInputs,
1137    ) -> Option<CreateOutcome> {
1138        let result = self.create_or_fail(context, inputs);
1139        map_result_create_outcome(&self.db.inner, result)
1140    }
1141}
1142
1143impl<Runtime: ServiceRuntime> CallInterceptorService<Runtime> {
1144    /// The function `fn create` of the inspector trait is called
1145    /// when a contract is going to be instantiated. Since the
1146    /// function can have some error case which are not supported
1147    /// in `fn create`, we call a `fn create_or_fail` that can
1148    /// return errors.
1149    /// When the database runtime is created, the EVM contract
1150    /// may or may not have been created. Therefore, at startup
1151    /// we have `is_revm_instantiated = false`. That boolean
1152    /// can be updated after `set_is_initialized`.
1153    ///
1154    /// The inspector can do two things:
1155    /// * It can change the inputs in `CreateInputs`. Here we
1156    ///   change the address being created.
1157    /// * It can return some specific CreateInput to be used.
1158    ///
1159    /// Therefore, the first case of the call is going to
1160    /// be about the creation of the contract with just the
1161    /// address being the one chosen by Linera.
1162    /// The second case of creating a new contract does not
1163    /// apply in services and so lead to an error.
1164    fn create_or_fail(
1165        &mut self,
1166        _context: &mut ServiceCtx<'_, Runtime>,
1167        inputs: &mut CreateInputs,
1168    ) -> Result<Option<CreateOutcome>, ExecutionError> {
1169        if !self.db.inner.is_revm_instantiated {
1170            self.db.inner.is_revm_instantiated = true;
1171            inputs.scheme = CreateScheme::Custom {
1172                address: self.contract_address,
1173            };
1174            Ok(None)
1175        } else {
1176            Err(EvmExecutionError::NoContractCreationInService.into())
1177        }
1178    }
1179}
1180
1181pub struct RevmContractInstance<Runtime> {
1182    module: Vec<u8>,
1183    db: ContractDatabase<Runtime>,
1184}
1185
1186/// The type of EVM transaction being executed.
1187#[derive(Debug)]
1188enum EvmTxKind {
1189    /// Contract creation transaction (deploys new contract).
1190    Create,
1191    /// Contract call transaction (invokes existing contract).
1192    Call,
1193}
1194
1195/// Successful EVM execution result with gas usage and output data.
1196#[derive(Debug)]
1197struct ExecutionResultSuccess {
1198    /// Final gas consumed after applying refunds (per EIP-3529).
1199    gas_final: u64,
1200    /// Event logs emitted during execution.
1201    logs: Vec<Log>,
1202    /// Transaction output (contract address for Create, return data for Call).
1203    output: Output,
1204}
1205
1206impl ExecutionResultSuccess {
1207    fn output_and_logs(self) -> (u64, Vec<u8>, Vec<Log>) {
1208        let Output::Call(output) = self.output else {
1209            unreachable!("The output should have been created from a EvmTxKind::Call");
1210        };
1211        let output = output.as_ref().to_vec();
1212        (self.gas_final, output, self.logs)
1213    }
1214
1215    // Checks that the contract has been correctly instantiated
1216    fn check_contract_initialization(&self, expected_address: Address) -> Result<(), String> {
1217        // Checks that the output is the expected one.
1218        let Output::Create(_, contract_address) = self.output else {
1219            return Err("Input should be ExmTxKind::Create".to_string());
1220        };
1221        // Checks that the contract address exists.
1222        let contract_address = contract_address.ok_or("Deployment failed")?;
1223        // Checks that the created contract address is the one of the `ApplicationId`.
1224        if contract_address == expected_address {
1225            Ok(())
1226        } else {
1227            Err("Contract address is not the same as ApplicationId".to_string())
1228        }
1229    }
1230}
1231
1232impl<Runtime> UserContract for RevmContractInstance<Runtime>
1233where
1234    Runtime: ContractRuntime,
1235{
1236    fn instantiate(&mut self, argument: Vec<u8>) -> Result<(), ExecutionError> {
1237        self.db.inner.set_contract_address()?;
1238        let caller = self.get_msg_address()?;
1239        let instantiation_argument = serde_json::from_slice::<EvmInstantiation>(&argument)?;
1240        // This is the case of a contract created by Revm by another contract. We only
1241        // need to write it to storage.
1242        if let Some(remainder) = instantiation_argument
1243            .argument
1244            .as_slice()
1245            .strip_prefix(ALREADY_CREATED_CONTRACT_SELECTOR)
1246        {
1247            let account = bcs::from_bytes::<revm_state::Account>(remainder)?;
1248            return self.db.commit_contract_changes(&account);
1249        }
1250        self.initialize_contract(instantiation_argument.value, caller)?;
1251        if has_selector(&self.module, INSTANTIATE_SELECTOR) {
1252            let argument = get_revm_instantiation_bytes(instantiation_argument.argument);
1253            let result = self.transact_commit(EvmTxKind::Call, argument, U256::ZERO, caller)?;
1254            self.write_logs(result.logs, "instantiate")?;
1255        }
1256        Ok(())
1257    }
1258
1259    /// Executes the operation.
1260    /// The first 3 possibilities are internal calls
1261    /// from another Revm instance:
1262    /// * The `GET_ACCOUNT_INFO_SELECTOR` retrieves the
1263    ///   `AccountInfo` of that EVM contract.
1264    /// * The `GET_CONTRACT_STORAGE_SELECTOR` is about
1265    ///   individual storage entries.
1266    /// * The `COMMIT_CONTRACT_CHANGES_SELECTOR` is about
1267    ///   committing the state
1268    ///
1269    /// If not in those cases, then the execution proceeds
1270    /// normally and creates an Revm instance.
1271    fn execute_operation(&mut self, operation: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1272        self.db.inner.set_contract_address()?;
1273        ensure_message_length(operation.len(), 4)?;
1274        if operation == GET_ACCOUNT_INFO_SELECTOR {
1275            let account_info = self.db.inner.get_account_info()?;
1276            return Ok(bcs::to_bytes(&account_info)?);
1277        }
1278        if let Some(remainder) = operation
1279            .as_slice()
1280            .strip_prefix(GET_CONTRACT_STORAGE_SELECTOR)
1281        {
1282            let index = bcs::from_bytes(remainder)?;
1283            let value = self.db.inner.read_from_local_storage(index)?;
1284            return Ok(bcs::to_bytes(&value)?);
1285        }
1286        if let Some(remainder) = operation
1287            .as_slice()
1288            .strip_prefix(COMMIT_CONTRACT_CHANGES_SELECTOR)
1289        {
1290            let account = bcs::from_bytes::<revm_state::Account>(remainder)?;
1291            self.db.commit_contract_changes(&account)?;
1292            return Ok(Vec::new());
1293        }
1294        let caller = self.get_msg_address()?;
1295        forbid_execute_operation_origin(&operation[..4])?;
1296        let evm_call = bcs::from_bytes::<EvmOperation>(&operation)?;
1297        let result = self.init_transact_commit(evm_call.argument, evm_call.value, caller)?;
1298        let (gas_final, output, logs) = result.output_and_logs();
1299        self.consume_fuel(gas_final)?;
1300        self.write_logs(logs, "operation")?;
1301        Ok(output)
1302    }
1303
1304    fn execute_message(&mut self, message: Vec<u8>) -> Result<(), ExecutionError> {
1305        self.db.inner.set_contract_address()?;
1306        ensure_selector_presence(
1307            &self.module,
1308            EXECUTE_MESSAGE_SELECTOR,
1309            "function execute_message(bytes)",
1310        )?;
1311        let operation = get_revm_execute_message_bytes(message);
1312        let caller = self.get_msg_address()?;
1313        let value = U256::ZERO;
1314        self.execute_no_return_operation(operation, "message", value, caller)
1315    }
1316
1317    fn process_streams(&mut self, streams: Vec<StreamUpdate>) -> Result<(), ExecutionError> {
1318        self.db.inner.set_contract_address()?;
1319        let operation = get_revm_process_streams_bytes(streams);
1320        ensure_selector_presence(
1321            &self.module,
1322            PROCESS_STREAMS_SELECTOR,
1323            "function process_streams(Linera.StreamUpdate[] memory streams)",
1324        )?;
1325        // For process_streams, authenticated_owner and authenticated_called_id are None.
1326        let caller = Address::ZERO;
1327        let value = U256::ZERO;
1328        self.execute_no_return_operation(operation, "process_streams", value, caller)
1329    }
1330
1331    fn finalize(&mut self) -> Result<(), ExecutionError> {
1332        Ok(())
1333    }
1334}
1335
1336fn process_execution_result(
1337    result: ExecutionResult,
1338) -> Result<ExecutionResultSuccess, EvmExecutionError> {
1339    match result {
1340        ExecutionResult::Success {
1341            reason,
1342            gas_used,
1343            gas_refunded,
1344            logs,
1345            output,
1346        } => {
1347            // Apply EIP-3529 refund cap (London fork)
1348            let max_refund = gas_used / 5;
1349            let actual_refund = gas_refunded.min(max_refund);
1350            let gas_final = gas_used - actual_refund;
1351            if !matches!(reason, SuccessReason::Return) {
1352                Err(EvmExecutionError::NoReturnInterpreter {
1353                    reason,
1354                    gas_used,
1355                    gas_refunded,
1356                    logs,
1357                    output,
1358                })
1359            } else {
1360                Ok(ExecutionResultSuccess {
1361                    gas_final,
1362                    logs,
1363                    output,
1364                })
1365            }
1366        }
1367        ExecutionResult::Revert { gas_used, output } => {
1368            Err(EvmExecutionError::Revert { gas_used, output })
1369        }
1370        ExecutionResult::Halt { gas_used, reason } => {
1371            Err(EvmExecutionError::Halt { gas_used, reason })
1372        }
1373    }
1374}
1375
1376impl<Runtime> RevmContractInstance<Runtime>
1377where
1378    Runtime: ContractRuntime,
1379{
1380    pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1381        let db = ContractDatabase::new(runtime);
1382        Self { module, db }
1383    }
1384
1385    fn execute_no_return_operation(
1386        &mut self,
1387        operation: Vec<u8>,
1388        origin: &str,
1389        value: U256,
1390        caller: Address,
1391    ) -> Result<(), ExecutionError> {
1392        let result = self.init_transact_commit(operation, value, caller)?;
1393        let (gas_final, output, logs) = result.output_and_logs();
1394        self.consume_fuel(gas_final)?;
1395        self.write_logs(logs, origin)?;
1396        assert_eq!(output.len(), 0);
1397        Ok(())
1398    }
1399
1400    /// Executes the transaction. If needed initializes the contract.
1401    fn init_transact_commit(
1402        &mut self,
1403        vec: Vec<u8>,
1404        value: U256,
1405        caller: Address,
1406    ) -> Result<ExecutionResultSuccess, ExecutionError> {
1407        // An application can be instantiated in Linera sense, but not in EVM sense,
1408        // that is the contract entries corresponding to the deployed contract may
1409        // be missing.
1410        if !self.db.inner.set_is_initialized()? {
1411            self.initialize_contract(U256::ZERO, caller)?;
1412        }
1413        self.transact_commit(EvmTxKind::Call, vec, value, caller)
1414    }
1415
1416    /// Initializes the contract.
1417    fn initialize_contract(&mut self, value: U256, caller: Address) -> Result<(), ExecutionError> {
1418        let mut vec_init = self.module.clone();
1419        let constructor_argument = self.db.inner.constructor_argument()?;
1420        vec_init.extend_from_slice(&constructor_argument);
1421        let result = self.transact_commit(EvmTxKind::Create, vec_init, value, caller)?;
1422        result
1423            .check_contract_initialization(self.db.inner.contract_address)
1424            .map_err(EvmExecutionError::IncorrectContractCreation)?;
1425        self.write_logs(result.logs, "deploy")
1426    }
1427
1428    /// Computes the address used in the `msg.sender` variable.
1429    /// It is computed in the following way:
1430    /// * If a Wasm contract calls an EVM contract then it is `Address::ZERO`.
1431    /// * If an EVM contract calls an EVM contract it is the address of the contract.
1432    /// * If a user having an `AccountOwner::Address32` address calls an EVM contract
1433    ///   then it is `Address::ZERO`.
1434    /// * If a user having an `AccountOwner::Address20` address calls an EVM contract
1435    ///   then it is this address.
1436    ///
1437    /// By doing this we ensure that EVM smart contracts works in the same way as
1438    /// on the EVM and that users and contracts outside of that realm can still
1439    /// call EVM smart contracts.
1440    fn get_msg_address(&self) -> Result<Address, ExecutionError> {
1441        let mut runtime = self.db.lock_runtime();
1442        let application_id = runtime.authenticated_caller_id()?;
1443        if let Some(application_id) = application_id {
1444            return Ok(if application_id.is_evm() {
1445                application_id.evm_address()
1446            } else {
1447                Address::ZERO
1448            });
1449        };
1450        let account_owner = runtime.authenticated_owner()?;
1451        if let Some(AccountOwner::Address20(address)) = account_owner {
1452            return Ok(Address::from(address));
1453        };
1454        Ok(ZERO_ADDRESS)
1455    }
1456
1457    fn transact_commit(
1458        &mut self,
1459        tx_kind: EvmTxKind,
1460        input: Vec<u8>,
1461        value: U256,
1462        caller: Address,
1463    ) -> Result<ExecutionResultSuccess, ExecutionError> {
1464        let contract_address = self.db.inner.contract_address;
1465        self.db.inner.caller = caller;
1466        self.db.inner.value = value;
1467        self.db.inner.deposit_funds()?;
1468        let data = Bytes::from(input);
1469        let kind = match tx_kind {
1470            EvmTxKind::Create => TxKind::Create,
1471            EvmTxKind::Call => TxKind::Call(contract_address),
1472        };
1473        let inspector = CallInterceptorContract {
1474            db: self.db.clone(),
1475            contract_address,
1476            precompile_addresses: precompile_addresses(),
1477            error: Arc::new(Mutex::new(None)),
1478        };
1479        let block_env = self.db.get_block_env()?;
1480        let (max_size_evm_contract, gas_limit) = {
1481            let mut runtime = self.db.lock_runtime();
1482            let gas_limit = runtime.remaining_fuel(VmRuntime::Evm)?;
1483            let max_size_evm_contract = runtime.maximum_blob_size()? as usize;
1484            (max_size_evm_contract, gas_limit)
1485        };
1486        let nonce = self.db.get_nonce(&caller)?;
1487        let result = {
1488            let mut ctx: revm_context::Context<
1489                BlockEnv,
1490                _,
1491                _,
1492                _,
1493                Journal<WrapDatabaseRef<&mut ContractDatabase<Runtime>>>,
1494                (),
1495            > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1496                WrapDatabaseRef(&mut self.db),
1497                SpecId::PRAGUE,
1498            )
1499            .with_block(block_env);
1500            ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1501            let instructions = EthInstructions::new_mainnet();
1502            let mut evm = Evm::new_with_inspector(
1503                ctx,
1504                inspector.clone(),
1505                instructions,
1506                ContractPrecompile::default(),
1507            );
1508            evm.inspect_commit(
1509                TxEnv {
1510                    kind,
1511                    data,
1512                    nonce,
1513                    gas_limit,
1514                    caller,
1515                    value,
1516                    ..TxEnv::default()
1517                },
1518                inspector.clone(),
1519            )
1520            .map_err(|error| {
1521                let error = format!("{:?}", error);
1522                EvmExecutionError::TransactCommitError(error)
1523            })
1524        }?;
1525        self.db.inner.process_any_error()?;
1526        self.db.commit_changes()?;
1527        Ok(process_execution_result(result)?)
1528    }
1529
1530    fn consume_fuel(&mut self, gas_final: u64) -> Result<(), ExecutionError> {
1531        let mut runtime = self.db.lock_runtime();
1532        runtime.consume_fuel(gas_final, VmRuntime::Evm)
1533    }
1534
1535    fn write_logs(&mut self, logs: Vec<Log>, origin: &str) -> Result<(), ExecutionError> {
1536        // TODO(#3758): Extracting Ethereum events from the Linera events.
1537        if !logs.is_empty() {
1538            let mut runtime = self.db.lock_runtime();
1539            let block_height = runtime.block_height()?;
1540            let stream_name = bcs::to_bytes("ethereum_event")?;
1541            let stream_name = StreamName(stream_name);
1542            for log in &logs {
1543                let value = bcs::to_bytes(&(origin, block_height.0, log))?;
1544                runtime.emit(stream_name.clone(), value)?;
1545            }
1546        }
1547        Ok(())
1548    }
1549}
1550
1551pub struct RevmServiceInstance<Runtime> {
1552    module: Vec<u8>,
1553    db: ServiceDatabase<Runtime>,
1554}
1555
1556impl<Runtime> RevmServiceInstance<Runtime>
1557where
1558    Runtime: ServiceRuntime,
1559{
1560    pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1561        let db = ServiceDatabase::new(runtime);
1562        Self { module, db }
1563    }
1564}
1565
1566impl<Runtime> UserService for RevmServiceInstance<Runtime>
1567where
1568    Runtime: ServiceRuntime,
1569{
1570    fn handle_query(&mut self, argument: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1571        self.db.inner.set_contract_address()?;
1572        let evm_query = serde_json::from_slice(&argument)?;
1573        let query = match evm_query {
1574            EvmQuery::AccountInfo => {
1575                let account_info = self.db.inner.get_account_info()?;
1576                return Ok(serde_json::to_vec(&account_info)?);
1577            }
1578            EvmQuery::Storage(index) => {
1579                let value = self.db.inner.read_from_local_storage(index)?;
1580                return Ok(serde_json::to_vec(&value)?);
1581            }
1582            EvmQuery::Query(vec) => vec,
1583            EvmQuery::Operation(operation) => {
1584                let mut runtime = self.db.lock_runtime();
1585                runtime.schedule_operation(operation)?;
1586                return Ok(Vec::new());
1587            }
1588            EvmQuery::Operations(operations) => {
1589                let mut runtime = self.db.lock_runtime();
1590                for operation in operations {
1591                    runtime.schedule_operation(operation)?;
1592                }
1593                return Ok(Vec::new());
1594            }
1595        };
1596
1597        ensure_message_length(query.len(), 4)?;
1598        // We drop the logs since the "eth_call" execution does not return any log.
1599        // Also, for handle_query, we do not have associated costs.
1600        // More generally, there is gas costs associated to service operation.
1601        let result = self.init_transact(query)?;
1602        let (_gas_final, output, _logs) = result.output_and_logs();
1603        let answer = serde_json::to_vec(&output)?;
1604        Ok(answer)
1605    }
1606}
1607
1608impl<Runtime> RevmServiceInstance<Runtime>
1609where
1610    Runtime: ServiceRuntime,
1611{
1612    fn init_transact(&mut self, vec: Vec<u8>) -> Result<ExecutionResultSuccess, ExecutionError> {
1613        // In case of a shared application, we need to instantiate it first
1614        // However, since in ServiceRuntime, we cannot modify the storage,
1615        // therefore the compiled contract is saved in the changes.
1616        let contract_address = self.db.inner.contract_address;
1617        if !self.db.inner.set_is_initialized()? {
1618            let changes = {
1619                let mut vec_init = self.module.clone();
1620                let constructor_argument = self.db.inner.constructor_argument()?;
1621                vec_init.extend_from_slice(&constructor_argument);
1622                let (result, changes) = self.transact(TxKind::Create, vec_init)?;
1623                result
1624                    .check_contract_initialization(contract_address)
1625                    .map_err(EvmExecutionError::IncorrectContractCreation)?;
1626                changes
1627            };
1628            self.db.inner.changes = changes;
1629        }
1630        ensure_message_length(vec.len(), 4)?;
1631        forbid_execute_operation_origin(&vec[..4])?;
1632        let kind = TxKind::Call(contract_address);
1633        let (execution_result, _) = self.transact(kind, vec)?;
1634        Ok(execution_result)
1635    }
1636
1637    fn transact(
1638        &mut self,
1639        kind: TxKind,
1640        input: Vec<u8>,
1641    ) -> Result<(ExecutionResultSuccess, EvmState), ExecutionError> {
1642        let contract_address = self.db.inner.contract_address;
1643        let caller = SERVICE_ADDRESS;
1644        let value = U256::ZERO;
1645        self.db.inner.caller = caller;
1646        self.db.inner.value = value;
1647        let data = Bytes::from(input);
1648        let block_env = self.db.get_block_env()?;
1649        let inspector = CallInterceptorService {
1650            db: self.db.clone(),
1651            contract_address,
1652            precompile_addresses: precompile_addresses(),
1653        };
1654        let max_size_evm_contract = {
1655            let mut runtime = self.db.lock_runtime();
1656            runtime.maximum_blob_size()? as usize
1657        };
1658        let nonce = self.db.get_nonce(&caller)?;
1659        let result_state = {
1660            let mut ctx: revm_context::Context<
1661                BlockEnv,
1662                _,
1663                _,
1664                _,
1665                Journal<WrapDatabaseRef<&mut ServiceDatabase<Runtime>>>,
1666                (),
1667            > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1668                WrapDatabaseRef(&mut self.db),
1669                SpecId::PRAGUE,
1670            )
1671            .with_block(block_env);
1672            ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1673            let instructions = EthInstructions::new_mainnet();
1674            let mut evm = Evm::new_with_inspector(
1675                ctx,
1676                inspector.clone(),
1677                instructions,
1678                ServicePrecompile::default(),
1679            );
1680            evm.inspect(
1681                TxEnv {
1682                    kind,
1683                    data,
1684                    nonce,
1685                    value,
1686                    caller,
1687                    gas_limit: EVM_SERVICE_GAS_LIMIT,
1688                    ..TxEnv::default()
1689                },
1690                inspector,
1691            )
1692            .map_err(|error| {
1693                let error = format!("{:?}", error);
1694                EvmExecutionError::TransactCommitError(error)
1695            })
1696        }?;
1697        self.db.inner.process_any_error()?;
1698        let result = process_execution_result(result_state.result)?;
1699        Ok((result, result_state.state))
1700    }
1701}