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