1use core::ops::Range;
7use std::{
8 collections::BTreeSet,
9 convert::TryFrom,
10 sync::{Arc, Mutex},
11};
12
13#[cfg(with_metrics)]
14use linera_base::prometheus_util::MeasureLatency as _;
15use linera_base::{
16 crypto::CryptoHash,
17 data_types::{
18 Amount, ApplicationDescription, Bytecode, Resources, SendMessageRequest, StreamUpdate,
19 },
20 ensure,
21 identifiers::{Account, AccountOwner, ApplicationId, ChainId, ModuleId, StreamName},
22 vm::{EvmInstantiation, EvmOperation, EvmQuery, VmRuntime},
23};
24use revm::{primitives::Bytes, InspectCommitEvm, InspectEvm, Inspector};
25use revm_context::{
26 result::{ExecutionResult, Output, SuccessReason},
27 BlockEnv, Cfg, ContextTr, Evm, Journal, JournalTr, LocalContextTr as _, TxEnv,
28};
29use revm_database::WrapDatabaseRef;
30use revm_handler::{
31 instructions::EthInstructions, EthPrecompiles, MainnetContext, PrecompileProvider,
32};
33use revm_interpreter::{
34 CallInput, CallInputs, CallOutcome, CallValue, CreateInputs, CreateOutcome, CreateScheme, Gas,
35 InputsImpl, InstructionResult, InterpreterResult,
36};
37use revm_primitives::{hardfork::SpecId, Address, Log, TxKind, U256};
38use revm_state::EvmState;
39use serde::{Deserialize, Serialize};
40
41use crate::{
42 evm::{
43 data_types::AmountU256,
44 database::{DatabaseRuntime, StorageStats, EVM_SERVICE_GAS_LIMIT},
45 inputs::{
46 ensure_message_length, ensure_selector_presence, forbid_execute_operation_origin,
47 get_revm_execute_message_bytes, get_revm_instantiation_bytes,
48 get_revm_process_streams_bytes, has_selector, EXECUTE_MESSAGE_SELECTOR, FAUCET_ADDRESS,
49 INSTANTIATE_SELECTOR, PRECOMPILE_ADDRESS, PROCESS_STREAMS_SELECTOR, SERVICE_ADDRESS,
50 ZERO_ADDRESS,
51 },
52 },
53 BaseRuntime, ContractRuntime, ContractSyncRuntimeHandle, DataBlobHash, EvmExecutionError,
54 EvmRuntime, ExecutionError, ServiceRuntime, ServiceSyncRuntimeHandle, UserContract,
55 UserContractInstance, UserContractModule, UserService, UserServiceInstance, UserServiceModule,
56};
57
58const INTERPRETER_RESULT_SELECTOR: &[u8] = &[1, 2, 3, 4];
61
62const GET_DEPLOYED_BYTECODE_SELECTOR: &[u8] = &[21, 34, 55, 89];
65
66const JSON_EMPTY_VECTOR: &[u8] = &[91, 93];
68
69#[cfg(with_metrics)]
70mod metrics {
71 use std::sync::LazyLock;
72
73 use linera_base::prometheus_util::{exponential_bucket_latencies, register_histogram_vec};
74 use prometheus::HistogramVec;
75
76 pub static CONTRACT_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
77 register_histogram_vec(
78 "evm_contract_instantiation_latency",
79 "EVM contract instantiation latency",
80 &[],
81 exponential_bucket_latencies(1.0),
82 )
83 });
84
85 pub static SERVICE_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
86 register_histogram_vec(
87 "evm_service_instantiation_latency",
88 "EVM service instantiation latency",
89 &[],
90 exponential_bucket_latencies(1.0),
91 )
92 });
93}
94
95#[derive(Clone)]
96pub enum EvmContractModule {
97 #[cfg(with_revm)]
98 Revm { module: Vec<u8> },
99}
100
101impl EvmContractModule {
102 pub fn new(
104 contract_bytecode: Bytecode,
105 runtime: EvmRuntime,
106 ) -> Result<Self, EvmExecutionError> {
107 match runtime {
108 #[cfg(with_revm)]
109 EvmRuntime::Revm => Self::from_revm(contract_bytecode),
110 }
111 }
112
113 #[cfg(with_fs)]
115 pub fn from_file(
116 contract_bytecode_file: impl AsRef<std::path::Path>,
117 runtime: EvmRuntime,
118 ) -> Result<Self, EvmExecutionError> {
119 Self::new(
120 Bytecode::load_from_file(contract_bytecode_file)
121 .map_err(anyhow::Error::from)
122 .map_err(EvmExecutionError::LoadContractModule)?,
123 runtime,
124 )
125 }
126
127 pub fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
129 let module = contract_bytecode.bytes;
130 Ok(EvmContractModule::Revm { module })
131 }
132}
133
134impl UserContractModule for EvmContractModule {
135 fn instantiate(
136 &self,
137 runtime: ContractSyncRuntimeHandle,
138 ) -> Result<UserContractInstance, ExecutionError> {
139 #[cfg(with_metrics)]
140 let _instantiation_latency = metrics::CONTRACT_INSTANTIATION_LATENCY.measure_latency();
141
142 let instance: UserContractInstance = match self {
143 #[cfg(with_revm)]
144 EvmContractModule::Revm { module } => {
145 Box::new(RevmContractInstance::prepare(module.to_vec(), runtime))
146 }
147 };
148
149 Ok(instance)
150 }
151}
152
153#[derive(Clone)]
155pub enum EvmServiceModule {
156 #[cfg(with_revm)]
157 Revm { module: Vec<u8> },
158}
159
160impl EvmServiceModule {
161 pub fn new(service_bytecode: Bytecode, runtime: EvmRuntime) -> Result<Self, EvmExecutionError> {
163 match runtime {
164 #[cfg(with_revm)]
165 EvmRuntime::Revm => Self::from_revm(service_bytecode),
166 }
167 }
168
169 #[cfg(with_fs)]
171 pub fn from_file(
172 service_bytecode_file: impl AsRef<std::path::Path>,
173 runtime: EvmRuntime,
174 ) -> Result<Self, EvmExecutionError> {
175 Self::new(
176 Bytecode::load_from_file(service_bytecode_file)
177 .map_err(anyhow::Error::from)
178 .map_err(EvmExecutionError::LoadServiceModule)?,
179 runtime,
180 )
181 }
182
183 pub fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
185 let module = contract_bytecode.bytes;
186 Ok(EvmServiceModule::Revm { module })
187 }
188}
189
190impl UserServiceModule for EvmServiceModule {
191 fn instantiate(
192 &self,
193 runtime: ServiceSyncRuntimeHandle,
194 ) -> Result<UserServiceInstance, ExecutionError> {
195 #[cfg(with_metrics)]
196 let _instantiation_latency = metrics::SERVICE_INSTANTIATION_LATENCY.measure_latency();
197
198 let instance: UserServiceInstance = match self {
199 #[cfg(with_revm)]
200 EvmServiceModule::Revm { module } => {
201 Box::new(RevmServiceInstance::prepare(module.to_vec(), runtime))
202 }
203 };
204
205 Ok(instance)
206 }
207}
208
209type Ctx<'a, Runtime> = MainnetContext<WrapDatabaseRef<&'a mut DatabaseRuntime<Runtime>>>;
210
211fn address_to_user_application_id(address: Address) -> ApplicationId {
212 let mut vec = vec![0_u8; 32];
213 vec[..20].copy_from_slice(address.as_ref());
214 ApplicationId::new(CryptoHash::try_from(&vec as &[u8]).unwrap())
215}
216
217#[derive(Debug, Serialize, Deserialize)]
219enum BaseRuntimePrecompile {
220 ChainId,
222 BlockHeight,
224 ApplicationCreatorChainId,
226 ReadSystemTimestamp,
228 ReadChainBalance,
230 ReadOwnerBalance(AccountOwner),
232 ReadOwnerBalances,
234 ReadBalanceOwners,
236 ChainOwnership,
238 ReadDataBlob(DataBlobHash),
240 AssertDataBlobExists(DataBlobHash),
242}
243
244#[derive(Debug, Serialize, Deserialize)]
246enum ContractRuntimePrecompile {
247 AuthenticatedOwner,
249 MessageOriginChainId,
251 MessageIsBouncing,
253 AuthenticatedCallerId,
255 SendMessage {
257 destination: ChainId,
258 message: Vec<u8>,
259 },
260 TryCallApplication {
262 target: ApplicationId,
263 argument: Vec<u8>,
264 },
265 Emit {
267 stream_name: StreamName,
268 value: Vec<u8>,
269 },
270 ReadEvent {
272 chain_id: ChainId,
273 stream_name: StreamName,
274 index: u32,
275 },
276 SubscribeToEvents {
278 chain_id: ChainId,
279 application_id: ApplicationId,
280 stream_name: StreamName,
281 },
282 UnsubscribeFromEvents {
284 chain_id: ChainId,
285 application_id: ApplicationId,
286 stream_name: StreamName,
287 },
288 QueryService {
290 application_id: ApplicationId,
291 query: Vec<u8>,
292 },
293 ValidationRound,
295 Transfer {
297 account: Account,
298 amount: AmountU256,
299 },
300}
301
302#[derive(Debug, Serialize, Deserialize)]
304enum ServiceRuntimePrecompile {
305 TryQueryApplication {
307 target: ApplicationId,
308 argument: Vec<u8>,
309 },
310}
311
312#[derive(Debug, Serialize, Deserialize)]
314enum RuntimePrecompile {
315 Base(BaseRuntimePrecompile),
316 Contract(ContractRuntimePrecompile),
317 Service(ServiceRuntimePrecompile),
318}
319
320fn get_precompile_output(output: Vec<u8>, gas_limit: u64) -> InterpreterResult {
321 let output = Bytes::from(output);
326 let result = InstructionResult::default();
327 let gas = Gas::new(gas_limit);
328 InterpreterResult {
329 result,
330 output,
331 gas,
332 }
333}
334
335fn get_argument<Ctx: ContextTr>(context: &mut Ctx, input: &CallInput) -> Vec<u8> {
336 match input {
337 CallInput::Bytes(bytes) => bytes.to_vec(),
338 CallInput::SharedBuffer(range) => {
339 match context.local().shared_memory_buffer_slice(range.clone()) {
340 None => Vec::new(),
341 Some(slice) => slice.to_vec(),
342 }
343 }
344 }
345}
346
347fn get_value(call_value: &CallValue) -> Result<U256, EvmExecutionError> {
348 match call_value {
349 CallValue::Transfer(value) => Ok(*value),
350 CallValue::Apparent(_) => Err(EvmExecutionError::NoDelegateCall),
351 }
352}
353
354fn get_precompile_argument<Ctx: ContextTr>(
355 context: &mut Ctx,
356 inputs: &InputsImpl,
357) -> Result<Vec<u8>, ExecutionError> {
358 Ok(get_argument(context, &inputs.input))
359}
360
361fn get_call_service_argument<Ctx: ContextTr>(
362 context: &mut Ctx,
363 inputs: &CallInputs,
364) -> Result<Vec<u8>, ExecutionError> {
365 ensure!(
366 get_value(&inputs.value)? == U256::ZERO,
367 EvmExecutionError::NoTransferInServices
368 );
369 let mut argument = INTERPRETER_RESULT_SELECTOR.to_vec();
370 argument.extend(&get_argument(context, &inputs.input));
371 Ok(argument)
372}
373
374fn get_call_contract_argument<Ctx: ContextTr>(
375 context: &mut Ctx,
376 inputs: &CallInputs,
377) -> Result<(Vec<u8>, usize), ExecutionError> {
378 let mut final_argument = INTERPRETER_RESULT_SELECTOR.to_vec();
379 let value = get_value(&inputs.value)?;
380 let argument = get_argument(context, &inputs.input);
381 let n_input = argument.len();
382 let evm_operation = EvmOperation { value, argument };
383 let argument = bcs::to_bytes(&evm_operation)?;
384 final_argument.extend(&argument);
385 Ok((final_argument, n_input))
386}
387
388fn base_runtime_call<Runtime: BaseRuntime>(
389 request: BaseRuntimePrecompile,
390 context: &mut Ctx<'_, Runtime>,
391) -> Result<Vec<u8>, ExecutionError> {
392 let mut runtime = context.db().0.runtime.lock().unwrap();
393 match request {
394 BaseRuntimePrecompile::ChainId => {
395 let chain_id = runtime.chain_id()?;
396 Ok(bcs::to_bytes(&chain_id)?)
397 }
398 BaseRuntimePrecompile::BlockHeight => {
399 let block_height = runtime.block_height()?;
400 Ok(bcs::to_bytes(&block_height)?)
401 }
402 BaseRuntimePrecompile::ApplicationCreatorChainId => {
403 let chain_id = runtime.application_creator_chain_id()?;
404 Ok(bcs::to_bytes(&chain_id)?)
405 }
406 BaseRuntimePrecompile::ReadSystemTimestamp => {
407 let timestamp = runtime.read_system_timestamp()?;
408 Ok(bcs::to_bytes(×tamp)?)
409 }
410 BaseRuntimePrecompile::ReadChainBalance => {
411 let balance: linera_base::data_types::Amount = runtime.read_chain_balance()?;
412 let balance: AmountU256 = balance.into();
413 Ok(bcs::to_bytes(&balance)?)
414 }
415 BaseRuntimePrecompile::ReadOwnerBalance(account_owner) => {
416 let balance = runtime.read_owner_balance(account_owner)?;
417 let balance = Into::<U256>::into(balance);
418 Ok(bcs::to_bytes(&balance)?)
419 }
420 BaseRuntimePrecompile::ReadOwnerBalances => {
421 let owner_balances = runtime.read_owner_balances()?;
422 let owner_balances = owner_balances
423 .into_iter()
424 .map(|(account_owner, balance)| (account_owner, balance.into()))
425 .collect::<Vec<(AccountOwner, AmountU256)>>();
426 Ok(bcs::to_bytes(&owner_balances)?)
427 }
428 BaseRuntimePrecompile::ReadBalanceOwners => {
429 let owners = runtime.read_balance_owners()?;
430 Ok(bcs::to_bytes(&owners)?)
431 }
432 BaseRuntimePrecompile::ChainOwnership => {
433 let chain_ownership = runtime.chain_ownership()?;
434 Ok(bcs::to_bytes(&chain_ownership)?)
435 }
436 BaseRuntimePrecompile::ReadDataBlob(hash) => runtime.read_data_blob(hash),
437 BaseRuntimePrecompile::AssertDataBlobExists(hash) => {
438 runtime.assert_data_blob_exists(hash)?;
439 Ok(Vec::new())
440 }
441 }
442}
443
444fn precompile_addresses() -> BTreeSet<Address> {
445 let mut addresses = BTreeSet::new();
446 for address in EthPrecompiles::default().warm_addresses() {
447 addresses.insert(address);
448 }
449 addresses.insert(PRECOMPILE_ADDRESS);
450 addresses
451}
452
453#[derive(Debug, Default)]
454struct ContractPrecompile {
455 inner: EthPrecompiles,
456}
457
458impl<'a, Runtime: ContractRuntime> PrecompileProvider<Ctx<'a, Runtime>> for ContractPrecompile {
459 type Output = InterpreterResult;
460
461 fn set_spec(&mut self, spec: <<Ctx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec) -> bool {
462 <EthPrecompiles as PrecompileProvider<Ctx<'a, Runtime>>>::set_spec(&mut self.inner, spec)
463 }
464
465 fn run(
466 &mut self,
467 context: &mut Ctx<'a, Runtime>,
468 address: &Address,
469 inputs: &InputsImpl,
470 is_static: bool,
471 gas_limit: u64,
472 ) -> Result<Option<InterpreterResult>, String> {
473 if address == &PRECOMPILE_ADDRESS {
474 let output = Self::call_or_fail(inputs, context)
475 .map_err(|error| format!("ContractPrecompile error: {error}"))?;
476 return Ok(Some(get_precompile_output(output, gas_limit)));
477 }
478 self.inner
479 .run(context, address, inputs, is_static, gas_limit)
480 }
481
482 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
483 let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
484 addresses.push(PRECOMPILE_ADDRESS);
485 Box::new(addresses.into_iter())
486 }
487
488 fn contains(&self, address: &Address) -> bool {
489 address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
490 }
491}
492
493fn get_evm_destination<Runtime: ContractRuntime>(
494 context: &mut Ctx<'_, Runtime>,
495 account: Account,
496) -> Result<Option<Address>, ExecutionError> {
497 let mut runtime = context.db().0.runtime.lock().unwrap();
498 if runtime.chain_id()? != account.chain_id {
499 return Ok(None);
500 }
501 Ok(account.owner.to_evm_address())
502}
503
504fn revm_transfer<Runtime: ContractRuntime>(
506 context: &mut Ctx<'_, Runtime>,
507 source: Address,
508 destination: Address,
509 value: U256,
510) -> Result<(), ExecutionError> {
511 if let Some(error) = context.journal().transfer(source, destination, value)? {
512 let error = format!("{error:?}");
513 let error = EvmExecutionError::TransactError(error);
514 return Err(error.into());
515 }
516 Ok(())
517}
518
519impl<'a> ContractPrecompile {
520 fn contract_runtime_call<Runtime: ContractRuntime>(
521 request: ContractRuntimePrecompile,
522 context: &mut Ctx<'a, Runtime>,
523 ) -> Result<Vec<u8>, ExecutionError> {
524 match request {
525 ContractRuntimePrecompile::AuthenticatedOwner => {
526 let mut runtime = context.db().0.runtime.lock().unwrap();
527 let account_owner = runtime.authenticated_owner()?;
528 Ok(bcs::to_bytes(&account_owner)?)
529 }
530
531 ContractRuntimePrecompile::MessageOriginChainId => {
532 let mut runtime = context.db().0.runtime.lock().unwrap();
533 let origin_chain_id = runtime.message_origin_chain_id()?;
534 Ok(bcs::to_bytes(&origin_chain_id)?)
535 }
536
537 ContractRuntimePrecompile::MessageIsBouncing => {
538 let mut runtime = context.db().0.runtime.lock().unwrap();
539 let result = runtime.message_is_bouncing()?;
540 Ok(bcs::to_bytes(&result)?)
541 }
542 ContractRuntimePrecompile::AuthenticatedCallerId => {
543 let mut runtime = context.db().0.runtime.lock().unwrap();
544 let application_id = runtime.authenticated_caller_id()?;
545 Ok(bcs::to_bytes(&application_id)?)
546 }
547 ContractRuntimePrecompile::SendMessage {
548 destination,
549 message,
550 } => {
551 let authenticated = true;
552 let is_tracked = true;
553 let grant = Resources::default();
554 let send_message_request = SendMessageRequest {
555 destination,
556 authenticated,
557 is_tracked,
558 grant,
559 message,
560 };
561 let mut runtime = context.db().0.runtime.lock().unwrap();
562 runtime.send_message(send_message_request)?;
563 Ok(vec![])
564 }
565 ContractRuntimePrecompile::TryCallApplication { target, argument } => {
566 let authenticated = true;
567 let mut runtime = context.db().0.runtime.lock().unwrap();
568 ensure!(
569 target != runtime.application_id()?,
570 EvmExecutionError::NoSelfCall
571 );
572 runtime.try_call_application(authenticated, target, argument)
573 }
574 ContractRuntimePrecompile::Emit { stream_name, value } => {
575 let mut runtime = context.db().0.runtime.lock().unwrap();
576 let result = runtime.emit(stream_name, value)?;
577 Ok(bcs::to_bytes(&result)?)
578 }
579 ContractRuntimePrecompile::ReadEvent {
580 chain_id,
581 stream_name,
582 index,
583 } => {
584 let mut runtime = context.db().0.runtime.lock().unwrap();
585 runtime.read_event(chain_id, stream_name, index)
586 }
587 ContractRuntimePrecompile::SubscribeToEvents {
588 chain_id,
589 application_id,
590 stream_name,
591 } => {
592 let mut runtime = context.db().0.runtime.lock().unwrap();
593 runtime.subscribe_to_events(chain_id, application_id, stream_name)?;
594 Ok(vec![])
595 }
596 ContractRuntimePrecompile::UnsubscribeFromEvents {
597 chain_id,
598 application_id,
599 stream_name,
600 } => {
601 let mut runtime = context.db().0.runtime.lock().unwrap();
602 runtime.unsubscribe_from_events(chain_id, application_id, stream_name)?;
603 Ok(vec![])
604 }
605 ContractRuntimePrecompile::QueryService {
606 application_id,
607 query,
608 } => {
609 let mut runtime = context.db().0.runtime.lock().unwrap();
610 ensure!(
611 application_id != runtime.application_id()?,
612 EvmExecutionError::NoSelfCall
613 );
614 runtime.query_service(application_id, query)
615 }
616 ContractRuntimePrecompile::ValidationRound => {
617 let mut runtime = context.db().0.runtime.lock().unwrap();
618 let value = runtime.validation_round()?;
619 Ok(bcs::to_bytes(&value)?)
620 }
621 ContractRuntimePrecompile::Transfer { account, amount } => {
622 if amount.0 != U256::ZERO {
623 let destination = {
624 let destination = get_evm_destination(context, account)?;
625 destination.unwrap_or(FAUCET_ADDRESS)
626 };
627 let application_id = {
628 let mut runtime = context.db().0.runtime.lock().unwrap();
629 let application_id = runtime.application_id()?;
630 let source = application_id.into();
631 let value = Amount::try_from(amount.0).map_err(EvmExecutionError::from)?;
632 runtime.transfer(source, account, value)?;
633 application_id
634 };
635 let source: Address = application_id.evm_address();
636 revm_transfer(context, source, destination, amount.0)?;
637 }
638 Ok(vec![])
639 }
640 }
641 }
642
643 fn call_or_fail<Runtime: ContractRuntime>(
644 inputs: &InputsImpl,
645 context: &mut Ctx<'a, Runtime>,
646 ) -> Result<Vec<u8>, ExecutionError> {
647 let input = get_precompile_argument(context, inputs)?;
648 match bcs::from_bytes(&input)? {
649 RuntimePrecompile::Base(base_tag) => base_runtime_call(base_tag, context),
650 RuntimePrecompile::Contract(contract_tag) => {
651 Self::contract_runtime_call(contract_tag, context)
652 }
653 RuntimePrecompile::Service(_) => Err(EvmExecutionError::PrecompileError(
654 "Service tags are not available in GeneralContractCall".to_string(),
655 )
656 .into()),
657 }
658 }
659}
660
661#[derive(Debug, Default)]
662struct ServicePrecompile {
663 inner: EthPrecompiles,
664}
665
666impl<'a> ServicePrecompile {
667 fn service_runtime_call<Runtime: ServiceRuntime>(
668 request: ServiceRuntimePrecompile,
669 context: &mut Ctx<'a, Runtime>,
670 ) -> Result<Vec<u8>, ExecutionError> {
671 let mut runtime = context.db().0.runtime.lock().unwrap();
672 match request {
673 ServiceRuntimePrecompile::TryQueryApplication { target, argument } => {
674 ensure!(
675 target != runtime.application_id()?,
676 EvmExecutionError::NoSelfCall
677 );
678 runtime.try_query_application(target, argument)
679 }
680 }
681 }
682
683 fn call_or_fail<Runtime: ServiceRuntime>(
684 inputs: &InputsImpl,
685 context: &mut Ctx<'a, Runtime>,
686 ) -> Result<Vec<u8>, ExecutionError> {
687 let input = get_precompile_argument(context, inputs)?;
688 match bcs::from_bytes(&input)? {
689 RuntimePrecompile::Base(base_tag) => base_runtime_call(base_tag, context),
690 RuntimePrecompile::Contract(_) => Err(EvmExecutionError::PrecompileError(
691 "Contract calls are not available in GeneralServiceCall".to_string(),
692 )
693 .into()),
694 RuntimePrecompile::Service(service_tag) => {
695 Self::service_runtime_call(service_tag, context)
696 }
697 }
698 }
699}
700
701impl<'a, Runtime: ServiceRuntime> PrecompileProvider<Ctx<'a, Runtime>> for ServicePrecompile {
702 type Output = InterpreterResult;
703
704 fn set_spec(&mut self, spec: <<Ctx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec) -> bool {
705 <EthPrecompiles as PrecompileProvider<Ctx<'a, Runtime>>>::set_spec(&mut self.inner, spec)
706 }
707
708 fn run(
709 &mut self,
710 context: &mut Ctx<'a, Runtime>,
711 address: &Address,
712 inputs: &InputsImpl,
713 is_static: bool,
714 gas_limit: u64,
715 ) -> Result<Option<InterpreterResult>, String> {
716 if address == &PRECOMPILE_ADDRESS {
717 let output = Self::call_or_fail(inputs, context)
718 .map_err(|error| format!("ServicePrecompile error: {error}"))?;
719 return Ok(Some(get_precompile_output(output, gas_limit)));
720 }
721 self.inner
722 .run(context, address, inputs, is_static, gas_limit)
723 }
724
725 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
726 let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
727 addresses.push(PRECOMPILE_ADDRESS);
728 Box::new(addresses.into_iter())
729 }
730
731 fn contains(&self, address: &Address) -> bool {
732 address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
733 }
734}
735
736fn map_result_create_outcome<Runtime: BaseRuntime>(
737 database: &DatabaseRuntime<Runtime>,
738 result: Result<Option<CreateOutcome>, ExecutionError>,
739) -> Option<CreateOutcome> {
740 match result {
741 Err(error) => {
742 database.insert_error(error);
743 let result = InstructionResult::Revert;
745 let output = Bytes::default();
746 let gas = Gas::default();
747 let result = InterpreterResult {
748 result,
749 output,
750 gas,
751 };
752 Some(CreateOutcome {
753 result,
754 address: None,
755 })
756 }
757 Ok(result) => result,
758 }
759}
760
761fn map_result_call_outcome<Runtime: BaseRuntime>(
762 database: &DatabaseRuntime<Runtime>,
763 result: Result<Option<CallOutcome>, ExecutionError>,
764) -> Option<CallOutcome> {
765 match result {
766 Err(error) => {
767 database.insert_error(error);
768 let result = InstructionResult::Revert;
770 let output = Bytes::default();
771 let gas = Gas::default();
772 let result = InterpreterResult {
773 result,
774 output,
775 gas,
776 };
777 let memory_offset = Range::default();
778 Some(CallOutcome {
779 result,
780 memory_offset,
781 })
782 }
783 Ok(result) => result,
784 }
785}
786
787fn get_interpreter_result(
788 result: &[u8],
789 inputs: &mut CallInputs,
790) -> Result<InterpreterResult, ExecutionError> {
791 let mut result = bcs::from_bytes::<InterpreterResult>(result)?;
792 result.gas = Gas::new(inputs.gas_limit);
795 Ok(result)
796}
797
798struct CallInterceptorContract<Runtime> {
799 db: DatabaseRuntime<Runtime>,
800 contract_address: Address,
802 precompile_addresses: BTreeSet<Address>,
803 error: Arc<Mutex<Option<U256>>>,
804}
805
806impl<Runtime> Clone for CallInterceptorContract<Runtime> {
807 fn clone(&self) -> Self {
808 Self {
809 db: self.db.clone(),
810 contract_address: self.contract_address,
811 precompile_addresses: self.precompile_addresses.clone(),
812 error: self.error.clone(),
813 }
814 }
815}
816
817impl<'a, Runtime: ContractRuntime> Inspector<Ctx<'a, Runtime>>
818 for CallInterceptorContract<Runtime>
819{
820 fn create(
821 &mut self,
822 context: &mut Ctx<'a, Runtime>,
823 inputs: &mut CreateInputs,
824 ) -> Option<CreateOutcome> {
825 let result = self.create_or_fail(context, inputs);
826 map_result_create_outcome(&self.db, result)
827 }
828
829 fn call(
830 &mut self,
831 context: &mut Ctx<'a, Runtime>,
832 inputs: &mut CallInputs,
833 ) -> Option<CallOutcome> {
834 let result = self.call_or_fail(context, inputs);
835 map_result_call_outcome(&self.db, result)
836 }
837}
838
839impl<Runtime: ContractRuntime> CallInterceptorContract<Runtime> {
840 fn get_expected_application_id(
844 runtime: &mut Runtime,
845 module_id: ModuleId,
846 ) -> Result<ApplicationId, ExecutionError> {
847 let chain_id = runtime.chain_id()?;
848 let block_height = runtime.block_height()?;
849 let application_index = runtime.peek_application_index()?;
850 let parameters = JSON_EMPTY_VECTOR.to_vec(); let required_application_ids = Vec::new();
852 let application_description = ApplicationDescription {
853 module_id,
854 creator_chain_id: chain_id,
855 block_height,
856 application_index,
857 parameters: parameters.clone(),
858 required_application_ids,
859 };
860 Ok(ApplicationId::from(&application_description))
861 }
862
863 fn publish_create_inputs(
865 context: &mut Ctx<'_, Runtime>,
866 inputs: &mut CreateInputs,
867 ) -> Result<ModuleId, ExecutionError> {
868 let contract = linera_base::data_types::Bytecode::new(inputs.init_code.to_vec());
869 let service = linera_base::data_types::Bytecode::new(vec![]);
870 let mut runtime = context.db().0.runtime.lock().unwrap();
871 runtime.publish_module(contract, service, VmRuntime::Evm)
872 }
873
874 fn create_or_fail(
963 &mut self,
964 context: &mut Ctx<'_, Runtime>,
965 inputs: &mut CreateInputs,
966 ) -> Result<Option<CreateOutcome>, ExecutionError> {
967 if !self.db.is_revm_instantiated {
968 self.db.is_revm_instantiated = true;
969 inputs.scheme = CreateScheme::Custom {
970 address: self.contract_address,
971 };
972 Ok(None)
973 } else {
974 if inputs.value != U256::ZERO {
975 revm_transfer(
981 context,
982 self.db.contract_address,
983 FAUCET_ADDRESS,
984 inputs.value,
985 )?;
986 }
987 let module_id = Self::publish_create_inputs(context, inputs)?;
988 let mut runtime = context.db().0.runtime.lock().unwrap();
989 let chain_id = runtime.chain_id()?;
990 let application_id = runtime.application_id()?;
991 let expected_application_id =
992 Self::get_expected_application_id(&mut runtime, module_id)?;
993 if inputs.value != U256::ZERO {
994 let amount = Amount::try_from(inputs.value).map_err(EvmExecutionError::from)?;
995 let destination = Account {
996 chain_id,
997 owner: expected_application_id.into(),
998 };
999 let source = application_id.into();
1000 runtime.transfer(source, destination, amount)?;
1001 }
1002 let parameters = JSON_EMPTY_VECTOR.to_vec(); let evm_call = EvmInstantiation {
1004 value: inputs.value,
1005 argument: Vec::new(),
1006 };
1007 let argument = serde_json::to_vec(&evm_call)?;
1008 let required_application_ids = Vec::new();
1009 let created_application_id = runtime.create_application(
1010 module_id,
1011 parameters,
1012 argument,
1013 required_application_ids,
1014 )?;
1015 assert_eq!(expected_application_id, created_application_id);
1016 let argument = GET_DEPLOYED_BYTECODE_SELECTOR.to_vec();
1017 let deployed_bytecode: Vec<u8> =
1018 runtime.try_call_application(false, created_application_id, argument)?;
1019 let result = InterpreterResult {
1020 result: InstructionResult::Return, output: Bytes::from(deployed_bytecode),
1022 gas: Gas::new(inputs.gas_limit),
1023 };
1024 let address = created_application_id.evm_address();
1025 let creation_outcome = CreateOutcome {
1026 result,
1027 address: Some(address),
1028 };
1029 Ok(Some(creation_outcome))
1030 }
1031 }
1032
1033 fn call_or_fail(
1054 &mut self,
1055 context: &mut Ctx<'_, Runtime>,
1056 inputs: &mut CallInputs,
1057 ) -> Result<Option<CallOutcome>, ExecutionError> {
1058 if self.precompile_addresses.contains(&inputs.target_address)
1059 || inputs.target_address == self.contract_address
1060 {
1061 return Ok(None);
1064 }
1065 if let CallValue::Transfer(value) = inputs.value {
1067 let source: AccountOwner = inputs.caller.into();
1068 let owner: AccountOwner = inputs.bytecode_address.into();
1069 if value != U256::ZERO {
1070 {
1072 let mut runtime = context
1073 .db()
1074 .0
1075 .runtime
1076 .lock()
1077 .expect("The lock should be possible");
1078 let amount = Amount::try_from(value).map_err(EvmExecutionError::from)?;
1079 let chain_id = runtime.chain_id()?;
1080 let destination = Account { chain_id, owner };
1081 runtime.transfer(source, destination, amount)?;
1082 }
1083 revm_transfer(context, inputs.caller, inputs.target_address, value)?;
1084 }
1085 }
1086 let target = address_to_user_application_id(inputs.target_address);
1088 let (argument, n_input) = get_call_contract_argument(context, inputs)?;
1089 let contract_call = {
1090 if n_input > 0 {
1091 true
1093 } else {
1094 let mut runtime = self.db.runtime.lock().unwrap();
1099 !runtime.has_empty_storage(target)?
1100 }
1101 };
1102 let result = if contract_call {
1103 let authenticated = true;
1104 let result = {
1105 let mut runtime = self.db.runtime.lock().unwrap();
1106 runtime.try_call_application(authenticated, target, argument)?
1107 };
1108 get_interpreter_result(&result, inputs)?
1109 } else {
1110 InterpreterResult {
1112 result: InstructionResult::Stop,
1113 output: Bytes::default(),
1114 gas: Gas::new(inputs.gas_limit),
1115 }
1116 };
1117 let call_outcome = CallOutcome {
1118 result,
1119 memory_offset: inputs.return_memory_offset.clone(),
1120 };
1121 Ok(Some(call_outcome))
1122 }
1123}
1124
1125struct CallInterceptorService<Runtime> {
1126 db: DatabaseRuntime<Runtime>,
1127 contract_address: Address,
1129 precompile_addresses: BTreeSet<Address>,
1130}
1131
1132impl<Runtime> Clone for CallInterceptorService<Runtime> {
1133 fn clone(&self) -> Self {
1134 Self {
1135 db: self.db.clone(),
1136 contract_address: self.contract_address,
1137 precompile_addresses: self.precompile_addresses.clone(),
1138 }
1139 }
1140}
1141
1142impl<'a, Runtime: ServiceRuntime> Inspector<Ctx<'a, Runtime>> for CallInterceptorService<Runtime> {
1143 fn create(
1145 &mut self,
1146 context: &mut Ctx<'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, result)
1151 }
1152
1153 fn call(
1155 &mut self,
1156 context: &mut Ctx<'a, Runtime>,
1157 inputs: &mut CallInputs,
1158 ) -> Option<CallOutcome> {
1159 let result = self.call_or_fail(context, inputs);
1160 map_result_call_outcome(&self.db, result)
1161 }
1162}
1163
1164impl<Runtime: ServiceRuntime> CallInterceptorService<Runtime> {
1165 fn create_or_fail(
1186 &mut self,
1187 _context: &mut Ctx<'_, Runtime>,
1188 inputs: &mut CreateInputs,
1189 ) -> Result<Option<CreateOutcome>, ExecutionError> {
1190 if !self.db.is_revm_instantiated {
1191 self.db.is_revm_instantiated = true;
1192 inputs.scheme = CreateScheme::Custom {
1193 address: self.contract_address,
1194 };
1195 Ok(None)
1196 } else {
1197 Err(EvmExecutionError::NoContractCreationInService.into())
1198 }
1199 }
1200
1201 fn call_or_fail(
1214 &mut self,
1215 context: &mut Ctx<'_, Runtime>,
1216 inputs: &mut CallInputs,
1217 ) -> Result<Option<CallOutcome>, ExecutionError> {
1218 if self.precompile_addresses.contains(&inputs.target_address)
1219 || inputs.target_address == self.contract_address
1220 {
1221 return Ok(None);
1224 }
1225 let target = address_to_user_application_id(inputs.target_address);
1227 let argument = get_call_service_argument(context, inputs)?;
1228 let result = {
1229 let evm_query = EvmQuery::Query(argument);
1230 let evm_query = serde_json::to_vec(&evm_query)?;
1231 let mut runtime = self.db.runtime.lock().unwrap();
1232 runtime.try_query_application(target, evm_query)?
1233 };
1234 let call_outcome = CallOutcome {
1235 result: get_interpreter_result(&result, inputs)?,
1236 memory_offset: inputs.return_memory_offset.clone(),
1237 };
1238 Ok(Some(call_outcome))
1239 }
1240}
1241
1242pub struct RevmContractInstance<Runtime> {
1243 module: Vec<u8>,
1244 db: DatabaseRuntime<Runtime>,
1245}
1246
1247#[derive(Debug)]
1248enum EvmTxKind {
1249 Create,
1250 Call,
1251}
1252
1253#[derive(Debug)]
1254struct ExecutionResultSuccess {
1255 reason: SuccessReason,
1256 gas_final: u64,
1257 logs: Vec<Log>,
1258 output: Output,
1259}
1260
1261impl ExecutionResultSuccess {
1262 fn interpreter_result_and_logs(self) -> Result<(u64, Vec<u8>, Vec<Log>), ExecutionError> {
1263 let result: InstructionResult = self.reason.into();
1264 let Output::Call(output) = self.output else {
1265 unreachable!("The output should have been created from a EvmTxKind::Call");
1266 };
1267 let gas = Gas::new(0);
1268 let result = InterpreterResult {
1269 result,
1270 output,
1271 gas,
1272 };
1273 let result = bcs::to_bytes(&result)?;
1274 Ok((self.gas_final, result, self.logs))
1275 }
1276
1277 fn output_and_logs(self) -> (u64, Vec<u8>, Vec<Log>) {
1278 let Output::Call(output) = self.output else {
1279 unreachable!("The output should have been created from a EvmTxKind::Call");
1280 };
1281 let output = output.as_ref().to_vec();
1282 (self.gas_final, output, self.logs)
1283 }
1284
1285 fn check_contract_initialization(&self, expected_address: Address) -> Result<(), String> {
1287 let Output::Create(_, contract_address) = self.output else {
1289 return Err("Input should be ExmTxKind::Create".to_string());
1290 };
1291 let contract_address = contract_address.ok_or("Deployment failed")?;
1293 if contract_address == expected_address {
1295 Ok(())
1296 } else {
1297 Err("Contract address is not the same as ApplicationId".to_string())
1298 }
1299 }
1300}
1301
1302impl<Runtime> UserContract for RevmContractInstance<Runtime>
1303where
1304 Runtime: ContractRuntime,
1305{
1306 fn instantiate(&mut self, argument: Vec<u8>) -> Result<(), ExecutionError> {
1307 self.db.set_contract_address()?;
1308 let caller = self.get_msg_address()?;
1309 let instantiation_argument = serde_json::from_slice::<EvmInstantiation>(&argument)?;
1310 self.initialize_contract(instantiation_argument.value, caller)?;
1311 if has_selector(&self.module, INSTANTIATE_SELECTOR) {
1312 let argument = get_revm_instantiation_bytes(instantiation_argument.argument);
1313 let result = self.transact_commit(EvmTxKind::Call, argument, U256::ZERO, caller)?;
1314 self.write_logs(result.logs, "instantiate")?;
1315 }
1316 Ok(())
1317 }
1318
1319 fn execute_operation(&mut self, operation: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1320 self.db.set_contract_address()?;
1321 ensure_message_length(operation.len(), 4)?;
1322 if operation == GET_DEPLOYED_BYTECODE_SELECTOR {
1323 return self.db.get_deployed_bytecode();
1324 }
1325 let caller = self.get_msg_address()?;
1326 let (gas_final, output, logs) = if &operation[..4] == INTERPRETER_RESULT_SELECTOR {
1327 ensure_message_length(operation.len(), 8)?;
1328 forbid_execute_operation_origin(&operation[4..8])?;
1329 let evm_call = bcs::from_bytes::<EvmOperation>(&operation[4..])?;
1330 let result = self.init_transact_commit(evm_call.argument, evm_call.value, caller)?;
1331 result.interpreter_result_and_logs()?
1332 } else {
1333 forbid_execute_operation_origin(&operation[..4])?;
1334 let evm_call = bcs::from_bytes::<EvmOperation>(&operation)?;
1335 let result = self.init_transact_commit(evm_call.argument, evm_call.value, caller)?;
1336 result.output_and_logs()
1337 };
1338 self.consume_fuel(gas_final)?;
1339 self.write_logs(logs, "operation")?;
1340 Ok(output)
1341 }
1342
1343 fn execute_message(&mut self, message: Vec<u8>) -> Result<(), ExecutionError> {
1344 self.db.set_contract_address()?;
1345 ensure_selector_presence(
1346 &self.module,
1347 EXECUTE_MESSAGE_SELECTOR,
1348 "function execute_message(bytes)",
1349 )?;
1350 let operation = get_revm_execute_message_bytes(message);
1351 let caller = self.get_msg_address()?;
1352 let value = U256::ZERO;
1353 self.execute_no_return_operation(operation, "message", value, caller)
1354 }
1355
1356 fn process_streams(&mut self, streams: Vec<StreamUpdate>) -> Result<(), ExecutionError> {
1357 self.db.set_contract_address()?;
1358 let operation = get_revm_process_streams_bytes(streams);
1359 ensure_selector_presence(
1360 &self.module,
1361 PROCESS_STREAMS_SELECTOR,
1362 "function process_streams(Linera.StreamUpdate[] memory streams)",
1363 )?;
1364 let caller = Address::ZERO;
1366 let value = U256::ZERO;
1367 self.execute_no_return_operation(operation, "process_streams", value, caller)
1368 }
1369
1370 fn finalize(&mut self) -> Result<(), ExecutionError> {
1371 Ok(())
1372 }
1373}
1374
1375fn process_execution_result(
1376 storage_stats: StorageStats,
1377 result: ExecutionResult,
1378) -> Result<ExecutionResultSuccess, EvmExecutionError> {
1379 match result {
1380 ExecutionResult::Success {
1381 reason,
1382 gas_used,
1383 gas_refunded,
1384 logs,
1385 output,
1386 } => {
1387 let mut gas_final = gas_used;
1388 gas_final -= storage_stats.storage_costs();
1389 assert_eq!(gas_refunded, storage_stats.storage_refund());
1390 if !matches!(reason, SuccessReason::Return) {
1391 Err(EvmExecutionError::NoReturnInterpreter {
1392 reason,
1393 gas_used,
1394 gas_refunded,
1395 logs,
1396 output,
1397 })
1398 } else {
1399 Ok(ExecutionResultSuccess {
1400 reason,
1401 gas_final,
1402 logs,
1403 output,
1404 })
1405 }
1406 }
1407 ExecutionResult::Revert { gas_used, output } => {
1408 Err(EvmExecutionError::Revert { gas_used, output })
1409 }
1410 ExecutionResult::Halt { gas_used, reason } => {
1411 Err(EvmExecutionError::Halt { gas_used, reason })
1412 }
1413 }
1414}
1415
1416impl<Runtime> RevmContractInstance<Runtime>
1417where
1418 Runtime: ContractRuntime,
1419{
1420 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1421 let db = DatabaseRuntime::new(runtime);
1422 Self { module, db }
1423 }
1424
1425 fn execute_no_return_operation(
1426 &mut self,
1427 operation: Vec<u8>,
1428 origin: &str,
1429 value: U256,
1430 caller: Address,
1431 ) -> Result<(), ExecutionError> {
1432 let result = self.init_transact_commit(operation, value, caller)?;
1433 let (gas_final, output, logs) = result.output_and_logs();
1434 self.consume_fuel(gas_final)?;
1435 self.write_logs(logs, origin)?;
1436 assert_eq!(output.len(), 0);
1437 Ok(())
1438 }
1439
1440 fn init_transact_commit(
1442 &mut self,
1443 vec: Vec<u8>,
1444 value: U256,
1445 caller: Address,
1446 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1447 if !self.db.set_is_initialized()? {
1451 self.initialize_contract(U256::ZERO, caller)?;
1452 }
1453 self.transact_commit(EvmTxKind::Call, vec, value, caller)
1454 }
1455
1456 fn initialize_contract(&mut self, value: U256, caller: Address) -> Result<(), ExecutionError> {
1458 let mut vec_init = self.module.clone();
1459 let constructor_argument = self.db.constructor_argument()?;
1460 vec_init.extend_from_slice(&constructor_argument);
1461 let result = self.transact_commit(EvmTxKind::Create, vec_init, value, caller)?;
1462 result
1463 .check_contract_initialization(self.db.contract_address)
1464 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1465 self.write_logs(result.logs, "deploy")
1466 }
1467
1468 fn get_msg_address(&self) -> Result<Address, ExecutionError> {
1481 let mut runtime = self.db.runtime.lock().unwrap();
1482 let application_id = runtime.authenticated_caller_id()?;
1483 if let Some(application_id) = application_id {
1484 return Ok(if application_id.is_evm() {
1485 application_id.evm_address()
1486 } else {
1487 Address::ZERO
1488 });
1489 };
1490 let account_owner = runtime.authenticated_owner()?;
1491 if let Some(AccountOwner::Address20(address)) = account_owner {
1492 return Ok(Address::from(address));
1493 };
1494 Ok(ZERO_ADDRESS)
1495 }
1496
1497 fn transact_commit(
1498 &mut self,
1499 ch: EvmTxKind,
1500 input: Vec<u8>,
1501 value: U256,
1502 caller: Address,
1503 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1504 self.db.caller = caller;
1505 self.db.value = value;
1506 self.db.deposit_funds()?;
1507 let data = Bytes::from(input);
1508 let kind = match ch {
1509 EvmTxKind::Create => TxKind::Create,
1510 EvmTxKind::Call => TxKind::Call(self.db.contract_address),
1511 };
1512 let inspector = CallInterceptorContract {
1513 db: self.db.clone(),
1514 contract_address: self.db.contract_address,
1515 precompile_addresses: precompile_addresses(),
1516 error: Arc::new(Mutex::new(None)),
1517 };
1518 let block_env = self.db.get_contract_block_env()?;
1519 let (max_size_evm_contract, gas_limit) = {
1520 let mut runtime = self.db.runtime.lock().unwrap();
1521 let gas_limit = runtime.remaining_fuel(VmRuntime::Evm)?;
1522 let max_size_evm_contract = runtime.maximum_blob_size()? as usize;
1523 (max_size_evm_contract, gas_limit)
1524 };
1525 let nonce = self.db.get_nonce(&caller)?;
1526 let result = {
1527 let mut ctx: revm_context::Context<
1528 BlockEnv,
1529 _,
1530 _,
1531 _,
1532 Journal<WrapDatabaseRef<&mut DatabaseRuntime<Runtime>>>,
1533 (),
1534 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1535 WrapDatabaseRef(&mut self.db),
1536 SpecId::PRAGUE,
1537 )
1538 .with_block(block_env);
1539 ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1540 let instructions = EthInstructions::new_mainnet();
1541 let mut evm = Evm::new_with_inspector(
1542 ctx,
1543 inspector.clone(),
1544 instructions,
1545 ContractPrecompile::default(),
1546 );
1547 evm.inspect_commit(
1548 TxEnv {
1549 kind,
1550 data,
1551 nonce,
1552 gas_limit,
1553 caller,
1554 value,
1555 ..TxEnv::default()
1556 },
1557 inspector.clone(),
1558 )
1559 .map_err(|error| {
1560 let error = format!("{:?}", error);
1561 EvmExecutionError::TransactCommitError(error)
1562 })
1563 }?;
1564 self.db.process_any_error()?;
1565 let storage_stats = self.db.take_storage_stats();
1566 self.db.commit_changes()?;
1567 let result = process_execution_result(storage_stats, result)?;
1568 Ok(result)
1569 }
1570
1571 fn consume_fuel(&mut self, gas_final: u64) -> Result<(), ExecutionError> {
1572 let mut runtime = self.db.runtime.lock().unwrap();
1573 runtime.consume_fuel(gas_final, VmRuntime::Evm)
1574 }
1575
1576 fn write_logs(&mut self, logs: Vec<Log>, origin: &str) -> Result<(), ExecutionError> {
1577 if !logs.is_empty() {
1579 let mut runtime = self.db.runtime.lock().unwrap();
1580 let block_height = runtime.block_height()?;
1581 let stream_name = bcs::to_bytes("ethereum_event")?;
1582 let stream_name = StreamName(stream_name);
1583 for log in &logs {
1584 let value = bcs::to_bytes(&(origin, block_height.0, log))?;
1585 runtime.emit(stream_name.clone(), value)?;
1586 }
1587 }
1588 Ok(())
1589 }
1590}
1591
1592pub struct RevmServiceInstance<Runtime> {
1593 module: Vec<u8>,
1594 db: DatabaseRuntime<Runtime>,
1595}
1596
1597impl<Runtime> RevmServiceInstance<Runtime>
1598where
1599 Runtime: ServiceRuntime,
1600{
1601 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1602 let db = DatabaseRuntime::new(runtime);
1603 Self { module, db }
1604 }
1605}
1606
1607impl<Runtime> UserService for RevmServiceInstance<Runtime>
1608where
1609 Runtime: ServiceRuntime,
1610{
1611 fn handle_query(&mut self, argument: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1612 self.db.set_contract_address()?;
1613 let evm_query = serde_json::from_slice(&argument)?;
1614 let query = match evm_query {
1615 EvmQuery::Query(vec) => vec,
1616 EvmQuery::Operation(operation) => {
1617 let mut runtime = self.db.runtime.lock().unwrap();
1618 runtime.schedule_operation(operation)?;
1619 return Ok(Vec::new());
1620 }
1621 EvmQuery::Operations(operations) => {
1622 let mut runtime = self.db.runtime.lock().unwrap();
1623 for operation in operations {
1624 runtime.schedule_operation(operation)?;
1625 }
1626 return Ok(Vec::new());
1627 }
1628 };
1629
1630 ensure_message_length(query.len(), 4)?;
1631 let answer = if &query[..4] == INTERPRETER_RESULT_SELECTOR {
1635 let result = self.init_transact(query[4..].to_vec())?;
1636 let (_gas_final, answer, _logs) = result.interpreter_result_and_logs()?;
1637 answer
1638 } else {
1639 let result = self.init_transact(query)?;
1640 let (_gas_final, output, _logs) = result.output_and_logs();
1641 serde_json::to_vec(&output)?
1642 };
1643 Ok(answer)
1644 }
1645}
1646
1647impl<Runtime> RevmServiceInstance<Runtime>
1648where
1649 Runtime: ServiceRuntime,
1650{
1651 fn init_transact(&mut self, vec: Vec<u8>) -> Result<ExecutionResultSuccess, ExecutionError> {
1652 if !self.db.set_is_initialized()? {
1656 let changes = {
1657 let mut vec_init = self.module.clone();
1658 let constructor_argument = self.db.constructor_argument()?;
1659 vec_init.extend_from_slice(&constructor_argument);
1660 let (result, changes) = self.transact(TxKind::Create, vec_init)?;
1661 result
1662 .check_contract_initialization(self.db.contract_address)
1663 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1664 changes
1665 };
1666 self.db.changes = changes;
1667 }
1668 ensure_message_length(vec.len(), 4)?;
1669 forbid_execute_operation_origin(&vec[..4])?;
1670 let kind = TxKind::Call(self.db.contract_address);
1671 let (execution_result, _) = self.transact(kind, vec)?;
1672 Ok(execution_result)
1673 }
1674
1675 fn transact(
1676 &mut self,
1677 kind: TxKind,
1678 input: Vec<u8>,
1679 ) -> Result<(ExecutionResultSuccess, EvmState), ExecutionError> {
1680 let caller = SERVICE_ADDRESS;
1681 let value = U256::ZERO;
1682 self.db.caller = caller;
1683 self.db.value = value;
1684 let data = Bytes::from(input);
1685 let block_env = self.db.get_service_block_env()?;
1686 let inspector = CallInterceptorService {
1687 db: self.db.clone(),
1688 contract_address: self.db.contract_address,
1689 precompile_addresses: precompile_addresses(),
1690 };
1691 let max_size_evm_contract = {
1692 let mut runtime = self.db.runtime.lock().unwrap();
1693 runtime.maximum_blob_size()? as usize
1694 };
1695 let nonce = self.db.get_nonce(&caller)?;
1696 let result_state = {
1697 let mut ctx: revm_context::Context<
1698 BlockEnv,
1699 _,
1700 _,
1701 _,
1702 Journal<WrapDatabaseRef<&mut DatabaseRuntime<Runtime>>>,
1703 (),
1704 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1705 WrapDatabaseRef(&mut self.db),
1706 SpecId::PRAGUE,
1707 )
1708 .with_block(block_env);
1709 ctx.cfg.limit_contract_code_size = Some(max_size_evm_contract);
1710 let instructions = EthInstructions::new_mainnet();
1711 let mut evm = Evm::new_with_inspector(
1712 ctx,
1713 inspector.clone(),
1714 instructions,
1715 ServicePrecompile::default(),
1716 );
1717 evm.inspect(
1718 TxEnv {
1719 kind,
1720 data,
1721 nonce,
1722 value,
1723 caller,
1724 gas_limit: EVM_SERVICE_GAS_LIMIT,
1725 ..TxEnv::default()
1726 },
1727 inspector,
1728 )
1729 .map_err(|error| {
1730 let error = format!("{:?}", error);
1731 EvmExecutionError::TransactCommitError(error)
1732 })
1733 }?;
1734 self.db.process_any_error()?;
1735 let storage_stats = self.db.take_storage_stats();
1736 Ok((
1737 process_execution_result(storage_stats, result_state.result)?,
1738 result_state.state,
1739 ))
1740 }
1741}