Skip to main content

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