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