1use core::ops::Range;
7use std::{collections::BTreeSet, convert::TryFrom};
8
9#[cfg(with_metrics)]
10use linera_base::prometheus_util::MeasureLatency as _;
11use linera_base::{
12 crypto::CryptoHash,
13 data_types::{Bytecode, Resources, SendMessageRequest, StreamUpdate},
14 ensure,
15 identifiers::{ApplicationId, ChainId, StreamName},
16 vm::{EvmQuery, VmRuntime},
17};
18use revm::{primitives::Bytes, InspectCommitEvm, InspectEvm, Inspector};
19use revm_context::{
20 result::{ExecutionResult, Output, SuccessReason},
21 BlockEnv, Cfg, ContextTr, Evm, Journal, LocalContextTr, TxEnv,
22};
23use revm_database::WrapDatabaseRef;
24use revm_handler::{
25 instructions::EthInstructions, EthPrecompiles, MainnetContext, PrecompileProvider,
26};
27use revm_interpreter::{
28 CallInput, CallInputs, CallOutcome, CreateInputs, CreateOutcome, CreateScheme, Gas, InputsImpl,
29 InstructionResult, InterpreterResult,
30};
31use revm_primitives::{address, hardfork::SpecId, Address, Log, TxKind};
32use revm_state::EvmState;
33use serde::{Deserialize, Serialize};
34
35use crate::{
36 evm::database::{DatabaseRuntime, StorageStats, EVM_SERVICE_GAS_LIMIT},
37 BaseRuntime, ContractRuntime, ContractSyncRuntimeHandle, EvmExecutionError, EvmRuntime,
38 ExecutionError, ServiceRuntime, ServiceSyncRuntimeHandle, UserContract, UserContractInstance,
39 UserContractModule, UserService, UserServiceInstance, UserServiceModule,
40};
41
42const EXECUTE_MESSAGE_SELECTOR: &[u8] = &[173, 125, 234, 205];
45
46const PROCESS_STREAMS_SELECTOR: &[u8] = &[227, 9, 189, 153];
49
50const INSTANTIATE_SELECTOR: &[u8] = &[156, 163, 60, 158];
53
54fn forbid_execute_operation_origin(vec: &[u8]) -> Result<(), EvmExecutionError> {
55 if vec == EXECUTE_MESSAGE_SELECTOR {
56 return Err(EvmExecutionError::IllegalOperationCall(
57 "function execute_message".to_string(),
58 ));
59 }
60 if vec == PROCESS_STREAMS_SELECTOR {
61 return Err(EvmExecutionError::IllegalOperationCall(
62 "function process_streams".to_string(),
63 ));
64 }
65 if vec == INSTANTIATE_SELECTOR {
66 return Err(EvmExecutionError::IllegalOperationCall(
67 "function instantiate".to_string(),
68 ));
69 }
70 Ok(())
71}
72
73fn ensure_message_length(actual_length: usize, min_length: usize) -> Result<(), EvmExecutionError> {
74 ensure!(
75 actual_length >= min_length,
76 EvmExecutionError::OperationIsTooShort
77 );
78 Ok(())
79}
80
81fn ensure_selector_presence(
82 module: &[u8],
83 selector: &[u8],
84 fct_name: &str,
85) -> Result<(), EvmExecutionError> {
86 if !has_selector(module, selector) {
87 return Err(EvmExecutionError::MissingFunction(fct_name.to_string()));
88 }
89 Ok(())
90}
91
92const INTERPRETER_RESULT_SELECTOR: &[u8] = &[1, 2, 3, 4];
95
96#[cfg(test)]
97mod tests {
98 use revm_primitives::keccak256;
99
100 use crate::evm::revm::{
101 EXECUTE_MESSAGE_SELECTOR, INSTANTIATE_SELECTOR, PROCESS_STREAMS_SELECTOR,
102 };
103
104 #[test]
107 fn check_execute_message_selector() {
108 let selector = &keccak256("execute_message(bytes)".as_bytes())[..4];
109 assert_eq!(selector, EXECUTE_MESSAGE_SELECTOR);
110 }
111
112 #[test]
113 fn check_process_streams_selector() {
114 use alloy_sol_types::{sol, SolCall};
115 sol! {
116 struct InternalCryptoHash {
117 bytes32 value;
118 }
119
120 struct InternalApplicationId {
121 InternalCryptoHash application_description_hash;
122 }
123
124 struct InternalGenericApplicationId {
125 uint8 choice;
126 InternalApplicationId user;
127 }
128
129 struct InternalStreamName {
130 bytes stream_name;
131 }
132
133 struct InternalStreamId {
134 InternalGenericApplicationId application_id;
135 InternalStreamName stream_name;
136 }
137
138 struct InternalChainId {
139 InternalCryptoHash value;
140 }
141
142 struct InternalStreamUpdate {
143 InternalChainId chain_id;
144 InternalStreamId stream_id;
145 uint32 previous_index;
146 uint32 next_index;
147 }
148
149 function process_streams(InternalStreamUpdate[] internal_streams);
150 }
151 assert_eq!(
152 process_streamsCall::SIGNATURE,
153 "process_streams((((bytes32)),((uint8,((bytes32))),(bytes)),uint32,uint32)[])"
154 );
155 assert_eq!(process_streamsCall::SELECTOR, PROCESS_STREAMS_SELECTOR);
156 }
157
158 #[test]
159 fn check_instantiate_selector() {
160 let selector = &keccak256("instantiate(bytes)".as_bytes())[..4];
161 assert_eq!(selector, INSTANTIATE_SELECTOR);
162 }
163}
164
165fn has_selector(module: &[u8], selector: &[u8]) -> bool {
166 let push4 = 0x63; let mut vec = vec![push4];
168 vec.extend(selector);
169 module.windows(5).any(|window| window == vec)
170}
171
172#[cfg(with_metrics)]
173mod metrics {
174 use std::sync::LazyLock;
175
176 use linera_base::prometheus_util::{exponential_bucket_latencies, register_histogram_vec};
177 use prometheus::HistogramVec;
178
179 pub static CONTRACT_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
180 register_histogram_vec(
181 "evm_contract_instantiation_latency",
182 "EVM contract instantiation latency",
183 &[],
184 exponential_bucket_latencies(1.0),
185 )
186 });
187
188 pub static SERVICE_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
189 register_histogram_vec(
190 "evm_service_instantiation_latency",
191 "EVM service instantiation latency",
192 &[],
193 exponential_bucket_latencies(1.0),
194 )
195 });
196}
197
198fn get_revm_instantiation_bytes(value: Vec<u8>) -> Vec<u8> {
199 use alloy_primitives::Bytes;
200 use alloy_sol_types::{sol, SolCall};
201 sol! {
202 function instantiate(bytes value);
203 }
204 let bytes = Bytes::from(value);
205 let argument = instantiateCall { value: bytes };
206 argument.abi_encode()
207}
208
209fn get_revm_execute_message_bytes(value: Vec<u8>) -> Vec<u8> {
210 use alloy_primitives::Bytes;
211 use alloy_sol_types::{sol, SolCall};
212 sol! {
213 function execute_message(bytes value);
214 }
215 let value = Bytes::from(value);
216 let argument = execute_messageCall { value };
217 argument.abi_encode()
218}
219
220fn get_revm_process_streams_bytes(streams: Vec<StreamUpdate>) -> Vec<u8> {
221 use alloy_primitives::{Bytes, B256};
223 use alloy_sol_types::{sol, SolCall};
224 use linera_base::identifiers::{GenericApplicationId, StreamId};
225 sol! {
226 struct InternalCryptoHash {
227 bytes32 value;
228 }
229
230 struct InternalApplicationId {
231 InternalCryptoHash application_description_hash;
232 }
233
234 struct InternalGenericApplicationId {
235 uint8 choice;
236 InternalApplicationId user;
237 }
238
239 struct InternalStreamName {
240 bytes stream_name;
241 }
242
243 struct InternalStreamId {
244 InternalGenericApplicationId application_id;
245 InternalStreamName stream_name;
246 }
247
248 struct InternalChainId {
249 InternalCryptoHash value;
250 }
251
252 struct InternalStreamUpdate {
253 InternalChainId chain_id;
254 InternalStreamId stream_id;
255 uint32 previous_index;
256 uint32 next_index;
257 }
258
259 function process_streams(InternalStreamUpdate[] internal_streams);
260 }
261
262 fn crypto_hash_to_internal_crypto_hash(hash: CryptoHash) -> InternalCryptoHash {
263 let hash: [u64; 4] = <[u64; 4]>::from(hash);
264 let hash: [u8; 32] = linera_base::crypto::u64_array_to_be_bytes(hash);
265 let value: B256 = hash.into();
266 InternalCryptoHash { value }
267 }
268
269 fn chain_id_to_internal_chain_id(chain_id: ChainId) -> InternalChainId {
270 let value = crypto_hash_to_internal_crypto_hash(chain_id.0);
271 InternalChainId { value }
272 }
273
274 fn application_id_to_internal_application_id(
275 application_id: ApplicationId,
276 ) -> InternalApplicationId {
277 let application_description_hash =
278 crypto_hash_to_internal_crypto_hash(application_id.application_description_hash);
279 InternalApplicationId {
280 application_description_hash,
281 }
282 }
283
284 fn stream_name_to_internal_stream_name(stream_name: StreamName) -> InternalStreamName {
285 let stream_name = Bytes::from(stream_name.0);
286 InternalStreamName { stream_name }
287 }
288
289 fn generic_application_id_to_internal_generic_application_id(
290 generic_application_id: GenericApplicationId,
291 ) -> InternalGenericApplicationId {
292 match generic_application_id {
293 GenericApplicationId::System => {
294 let application_description_hash = InternalCryptoHash { value: B256::ZERO };
295 InternalGenericApplicationId {
296 choice: 0,
297 user: InternalApplicationId {
298 application_description_hash,
299 },
300 }
301 }
302 GenericApplicationId::User(application_id) => InternalGenericApplicationId {
303 choice: 1,
304 user: application_id_to_internal_application_id(application_id),
305 },
306 }
307 }
308
309 fn stream_id_to_internal_stream_id(stream_id: StreamId) -> InternalStreamId {
310 let application_id =
311 generic_application_id_to_internal_generic_application_id(stream_id.application_id);
312 let stream_name = stream_name_to_internal_stream_name(stream_id.stream_name);
313 InternalStreamId {
314 application_id,
315 stream_name,
316 }
317 }
318
319 fn stream_update_to_internal_stream_update(
320 stream_update: StreamUpdate,
321 ) -> InternalStreamUpdate {
322 let chain_id = chain_id_to_internal_chain_id(stream_update.chain_id);
323 let stream_id = stream_id_to_internal_stream_id(stream_update.stream_id);
324 InternalStreamUpdate {
325 chain_id,
326 stream_id,
327 previous_index: stream_update.previous_index,
328 next_index: stream_update.next_index,
329 }
330 }
331
332 let internal_streams = streams
333 .into_iter()
334 .map(stream_update_to_internal_stream_update)
335 .collect::<Vec<_>>();
336
337 let fct_call = process_streamsCall { internal_streams };
338 fct_call.abi_encode()
339}
340
341#[derive(Clone)]
342pub enum EvmContractModule {
343 #[cfg(with_revm)]
344 Revm { module: Vec<u8> },
345}
346
347impl EvmContractModule {
348 pub async fn new(
350 contract_bytecode: Bytecode,
351 runtime: EvmRuntime,
352 ) -> Result<Self, EvmExecutionError> {
353 match runtime {
354 #[cfg(with_revm)]
355 EvmRuntime::Revm => Self::from_revm(contract_bytecode).await,
356 }
357 }
358
359 #[cfg(with_fs)]
361 pub async fn from_file(
362 contract_bytecode_file: impl AsRef<std::path::Path>,
363 runtime: EvmRuntime,
364 ) -> Result<Self, EvmExecutionError> {
365 Self::new(
366 Bytecode::load_from_file(contract_bytecode_file)
367 .await
368 .map_err(anyhow::Error::from)
369 .map_err(EvmExecutionError::LoadContractModule)?,
370 runtime,
371 )
372 .await
373 }
374
375 pub async fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
377 let module = contract_bytecode.bytes;
378 Ok(EvmContractModule::Revm { module })
379 }
380}
381
382impl UserContractModule for EvmContractModule {
383 fn instantiate(
384 &self,
385 runtime: ContractSyncRuntimeHandle,
386 ) -> Result<UserContractInstance, ExecutionError> {
387 #[cfg(with_metrics)]
388 let _instantiation_latency = metrics::CONTRACT_INSTANTIATION_LATENCY.measure_latency();
389
390 let instance: UserContractInstance = match self {
391 #[cfg(with_revm)]
392 EvmContractModule::Revm { module } => {
393 Box::new(RevmContractInstance::prepare(module.to_vec(), runtime))
394 }
395 };
396
397 Ok(instance)
398 }
399}
400
401#[derive(Clone)]
403pub enum EvmServiceModule {
404 #[cfg(with_revm)]
405 Revm { module: Vec<u8> },
406}
407
408impl EvmServiceModule {
409 pub async fn new(
411 service_bytecode: Bytecode,
412 runtime: EvmRuntime,
413 ) -> Result<Self, EvmExecutionError> {
414 match runtime {
415 #[cfg(with_revm)]
416 EvmRuntime::Revm => Self::from_revm(service_bytecode).await,
417 }
418 }
419
420 #[cfg(with_fs)]
422 pub async fn from_file(
423 service_bytecode_file: impl AsRef<std::path::Path>,
424 runtime: EvmRuntime,
425 ) -> Result<Self, EvmExecutionError> {
426 Self::new(
427 Bytecode::load_from_file(service_bytecode_file)
428 .await
429 .map_err(anyhow::Error::from)
430 .map_err(EvmExecutionError::LoadServiceModule)?,
431 runtime,
432 )
433 .await
434 }
435
436 pub async fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
438 let module = contract_bytecode.bytes;
439 Ok(EvmServiceModule::Revm { module })
440 }
441}
442
443impl UserServiceModule for EvmServiceModule {
444 fn instantiate(
445 &self,
446 runtime: ServiceSyncRuntimeHandle,
447 ) -> Result<UserServiceInstance, ExecutionError> {
448 #[cfg(with_metrics)]
449 let _instantiation_latency = metrics::SERVICE_INSTANTIATION_LATENCY.measure_latency();
450
451 let instance: UserServiceInstance = match self {
452 #[cfg(with_revm)]
453 EvmServiceModule::Revm { module } => {
454 Box::new(RevmServiceInstance::prepare(module.to_vec(), runtime))
455 }
456 };
457
458 Ok(instance)
459 }
460}
461
462type Ctx<'a, Runtime> = MainnetContext<WrapDatabaseRef<&'a mut DatabaseRuntime<Runtime>>>;
463
464const PRECOMPILE_ADDRESS: Address = address!("000000000000000000000000000000000000000b");
467
468const ZERO_ADDRESS: Address = address!("0000000000000000000000000000000000000000");
470
471fn address_to_user_application_id(address: Address) -> ApplicationId {
472 let mut vec = vec![0_u8; 32];
473 vec[..20].copy_from_slice(address.as_ref());
474 ApplicationId::new(CryptoHash::try_from(&vec as &[u8]).unwrap())
475}
476
477#[derive(Debug, Serialize, Deserialize)]
479enum BaseRuntimePrecompile {
480 ChainId,
482 ApplicationCreatorChainId,
484 ChainOwnership,
486 ReadDataBlob { hash: CryptoHash },
488 AssertDataBlobExists { hash: CryptoHash },
490}
491
492#[derive(Debug, Serialize, Deserialize)]
494enum ContractRuntimePrecompile {
495 TryCallApplication {
497 target: ApplicationId,
498 argument: Vec<u8>,
499 },
500 ValidationRound,
502 SendMessage {
504 destination: ChainId,
505 message: Vec<u8>,
506 },
507 MessageId,
509 MessageIsBouncing,
511 Emit {
513 stream_name: StreamName,
514 value: Vec<u8>,
515 },
516 ReadEvent {
518 chain_id: ChainId,
519 stream_name: StreamName,
520 index: u32,
521 },
522 SubscribeToEvents {
524 chain_id: ChainId,
525 application_id: ApplicationId,
526 stream_name: StreamName,
527 },
528 UnsubscribeFromEvents {
530 chain_id: ChainId,
531 application_id: ApplicationId,
532 stream_name: StreamName,
533 },
534}
535
536#[derive(Debug, Serialize, Deserialize)]
538enum ServiceRuntimePrecompile {
539 TryQueryApplication {
541 target: ApplicationId,
542 argument: Vec<u8>,
543 },
544}
545
546#[derive(Debug, Serialize, Deserialize)]
548enum RuntimePrecompile {
549 Base(BaseRuntimePrecompile),
550 Contract(ContractRuntimePrecompile),
551 Service(ServiceRuntimePrecompile),
552}
553
554fn get_precompile_output(
555 output: Vec<u8>,
556 gas_limit: u64,
557) -> Result<Option<InterpreterResult>, String> {
558 let output = Bytes::from(output);
563 let result = InstructionResult::default();
564 let gas = Gas::new(gas_limit);
565 Ok(Some(InterpreterResult {
566 result,
567 output,
568 gas,
569 }))
570}
571
572fn get_precompile_argument<Ctx: ContextTr>(context: &mut Ctx, input: &CallInput) -> Vec<u8> {
573 let mut argument = Vec::new();
574 get_argument(context, &mut argument, input);
575 argument
576}
577
578fn base_runtime_call<Runtime: BaseRuntime>(
579 request: BaseRuntimePrecompile,
580 context: &mut Ctx<'_, Runtime>,
581) -> Result<Vec<u8>, ExecutionError> {
582 let mut runtime = context
583 .db()
584 .0
585 .runtime
586 .lock()
587 .expect("The lock should be possible");
588 match request {
589 BaseRuntimePrecompile::ChainId => {
590 let chain_id = runtime.chain_id()?;
591 Ok(bcs::to_bytes(&chain_id)?)
592 }
593 BaseRuntimePrecompile::ApplicationCreatorChainId => {
594 let chain_id = runtime.application_creator_chain_id()?;
595 Ok(bcs::to_bytes(&chain_id)?)
596 }
597 BaseRuntimePrecompile::ChainOwnership => {
598 let chain_ownership = runtime.chain_ownership()?;
599 Ok(bcs::to_bytes(&chain_ownership)?)
600 }
601 BaseRuntimePrecompile::ReadDataBlob { hash } => runtime.read_data_blob(&hash),
602 BaseRuntimePrecompile::AssertDataBlobExists { hash } => {
603 runtime.assert_data_blob_exists(&hash)?;
604 Ok(Vec::new())
605 }
606 }
607}
608
609fn precompile_addresses() -> BTreeSet<Address> {
610 let mut addresses = BTreeSet::new();
611 for address in EthPrecompiles::default().warm_addresses() {
612 addresses.insert(address);
613 }
614 addresses.insert(PRECOMPILE_ADDRESS);
615 addresses
616}
617
618#[derive(Debug, Default)]
619struct ContractPrecompile {
620 inner: EthPrecompiles,
621}
622
623impl<'a, Runtime: ContractRuntime> PrecompileProvider<Ctx<'a, Runtime>> for ContractPrecompile {
624 type Output = InterpreterResult;
625
626 fn set_spec(&mut self, spec: <<Ctx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec) -> bool {
627 <EthPrecompiles as PrecompileProvider<Ctx<'a, Runtime>>>::set_spec(&mut self.inner, spec)
628 }
629
630 fn run(
631 &mut self,
632 context: &mut Ctx<'a, Runtime>,
633 address: &Address,
634 inputs: &InputsImpl,
635 is_static: bool,
636 gas_limit: u64,
637 ) -> Result<Option<InterpreterResult>, String> {
638 if address == &PRECOMPILE_ADDRESS {
639 let input = get_precompile_argument(context, &inputs.input);
640 let output = Self::call_or_fail(&input, context)
641 .map_err(|error| format!("ContractPrecompile error: {error}"))?;
642 return get_precompile_output(output, gas_limit);
643 }
644 self.inner
645 .run(context, address, inputs, is_static, gas_limit)
646 }
647
648 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
649 let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
650 addresses.push(PRECOMPILE_ADDRESS);
651 Box::new(addresses.into_iter())
652 }
653
654 fn contains(&self, address: &Address) -> bool {
655 address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
656 }
657}
658
659impl<'a> ContractPrecompile {
660 fn contract_runtime_call<Runtime: ContractRuntime>(
661 request: ContractRuntimePrecompile,
662 context: &mut Ctx<'a, Runtime>,
663 ) -> Result<Vec<u8>, ExecutionError> {
664 let mut runtime = context
665 .db()
666 .0
667 .runtime
668 .lock()
669 .expect("The lock should be possible");
670 match request {
671 ContractRuntimePrecompile::TryCallApplication { target, argument } => {
672 let authenticated = true;
673 runtime.try_call_application(authenticated, target, argument)
674 }
675 ContractRuntimePrecompile::ValidationRound => {
676 let value = runtime.validation_round()?;
677 Ok(bcs::to_bytes(&value)?)
678 }
679 ContractRuntimePrecompile::SendMessage {
680 destination,
681 message,
682 } => {
683 let authenticated = true;
684 let is_tracked = true;
685 let grant = Resources::default();
686 let send_message_request = SendMessageRequest {
687 destination,
688 authenticated,
689 is_tracked,
690 grant,
691 message,
692 };
693 runtime.send_message(send_message_request)?;
694 Ok(vec![])
695 }
696 ContractRuntimePrecompile::MessageId => {
697 let message_id = runtime.message_id()?;
698 Ok(bcs::to_bytes(&message_id)?)
699 }
700 ContractRuntimePrecompile::MessageIsBouncing => {
701 let result = runtime.message_is_bouncing()?;
702 Ok(bcs::to_bytes(&result)?)
703 }
704 ContractRuntimePrecompile::Emit { stream_name, value } => {
705 let result = runtime.emit(stream_name, value)?;
706 Ok(bcs::to_bytes(&result)?)
707 }
708 ContractRuntimePrecompile::ReadEvent {
709 chain_id,
710 stream_name,
711 index,
712 } => runtime.read_event(chain_id, stream_name, index),
713 ContractRuntimePrecompile::SubscribeToEvents {
714 chain_id,
715 application_id,
716 stream_name,
717 } => {
718 runtime.subscribe_to_events(chain_id, application_id, stream_name)?;
719 Ok(vec![])
720 }
721 ContractRuntimePrecompile::UnsubscribeFromEvents {
722 chain_id,
723 application_id,
724 stream_name,
725 } => {
726 runtime.unsubscribe_from_events(chain_id, application_id, stream_name)?;
727 Ok(vec![])
728 }
729 }
730 }
731
732 fn call_or_fail<Runtime: ContractRuntime>(
733 input: &[u8],
734 context: &mut Ctx<'a, Runtime>,
735 ) -> Result<Vec<u8>, ExecutionError> {
736 match bcs::from_bytes(input)? {
737 RuntimePrecompile::Base(base_tag) => base_runtime_call(base_tag, context),
738 RuntimePrecompile::Contract(contract_tag) => {
739 Self::contract_runtime_call(contract_tag, context)
740 }
741 RuntimePrecompile::Service(_) => Err(EvmExecutionError::PrecompileError(
742 "Service tags are not available in GeneralContractCall".to_string(),
743 )
744 .into()),
745 }
746 }
747}
748
749#[derive(Debug, Default)]
750struct ServicePrecompile {
751 inner: EthPrecompiles,
752}
753
754impl<'a> ServicePrecompile {
755 fn service_runtime_call<Runtime: ServiceRuntime>(
756 request: ServiceRuntimePrecompile,
757 context: &mut Ctx<'a, Runtime>,
758 ) -> Result<Vec<u8>, ExecutionError> {
759 let mut runtime = context
760 .db()
761 .0
762 .runtime
763 .lock()
764 .expect("The lock should be possible");
765 match request {
766 ServiceRuntimePrecompile::TryQueryApplication { target, argument } => {
767 runtime.try_query_application(target, argument)
768 }
769 }
770 }
771
772 fn call_or_fail<Runtime: ServiceRuntime>(
773 input: &[u8],
774 context: &mut Ctx<'a, Runtime>,
775 ) -> Result<Vec<u8>, ExecutionError> {
776 match bcs::from_bytes(input)? {
777 RuntimePrecompile::Base(base_tag) => base_runtime_call(base_tag, context),
778 RuntimePrecompile::Contract(_) => Err(EvmExecutionError::PrecompileError(
779 "Contract calls are not available in GeneralServiceCall".to_string(),
780 )
781 .into()),
782 RuntimePrecompile::Service(service_tag) => {
783 Self::service_runtime_call(service_tag, context)
784 }
785 }
786 }
787}
788
789impl<'a, Runtime: ServiceRuntime> PrecompileProvider<Ctx<'a, Runtime>> for ServicePrecompile {
790 type Output = InterpreterResult;
791
792 fn set_spec(&mut self, spec: <<Ctx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec) -> bool {
793 <EthPrecompiles as PrecompileProvider<Ctx<'a, Runtime>>>::set_spec(&mut self.inner, spec)
794 }
795
796 fn run(
797 &mut self,
798 context: &mut Ctx<'a, Runtime>,
799 address: &Address,
800 inputs: &InputsImpl,
801 is_static: bool,
802 gas_limit: u64,
803 ) -> Result<Option<InterpreterResult>, String> {
804 if address == &PRECOMPILE_ADDRESS {
805 let input = get_precompile_argument(context, &inputs.input);
806 let output = Self::call_or_fail(&input, context)
807 .map_err(|error| format!("ServicePrecompile error: {error}"))?;
808 return get_precompile_output(output, gas_limit);
809 }
810 self.inner
811 .run(context, address, inputs, is_static, gas_limit)
812 }
813
814 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
815 let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
816 addresses.push(PRECOMPILE_ADDRESS);
817 Box::new(addresses.into_iter())
818 }
819
820 fn contains(&self, address: &Address) -> bool {
821 address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
822 }
823}
824
825fn map_result_call_outcome(
826 result: Result<Option<CallOutcome>, ExecutionError>,
827) -> Option<CallOutcome> {
828 match result {
829 Err(_error) => {
830 let result = InstructionResult::Revert;
834 let output = Bytes::default();
835 let gas = Gas::default();
836 let result = InterpreterResult {
837 result,
838 output,
839 gas,
840 };
841 let memory_offset = Range::default();
842 Some(CallOutcome {
843 result,
844 memory_offset,
845 })
846 }
847 Ok(result) => result,
848 }
849}
850
851fn get_interpreter_result(
852 result: &[u8],
853 inputs: &mut CallInputs,
854) -> Result<InterpreterResult, ExecutionError> {
855 let mut result = bcs::from_bytes::<InterpreterResult>(result)?;
856 result.gas = Gas::new(inputs.gas_limit);
859 Ok(result)
860}
861
862struct CallInterceptorContract<Runtime> {
863 db: DatabaseRuntime<Runtime>,
864 contract_address: Address,
866 precompile_addresses: BTreeSet<Address>,
867}
868
869impl<Runtime> Clone for CallInterceptorContract<Runtime> {
870 fn clone(&self) -> Self {
871 Self {
872 db: self.db.clone(),
873 contract_address: self.contract_address,
874 precompile_addresses: self.precompile_addresses.clone(),
875 }
876 }
877}
878
879fn get_argument<Ctx: ContextTr>(context: &mut Ctx, argument: &mut Vec<u8>, input: &CallInput) {
880 match input {
881 CallInput::Bytes(bytes) => {
882 argument.extend(bytes.to_vec());
883 }
884 CallInput::SharedBuffer(range) => {
885 if let Some(slice) = context.local().shared_memory_buffer_slice(range.clone()) {
886 argument.extend(&*slice);
887 }
888 }
889 };
890}
891
892fn get_call_argument<Ctx: ContextTr>(context: &mut Ctx, input: &CallInput) -> Vec<u8> {
893 let mut argument: Vec<u8> = INTERPRETER_RESULT_SELECTOR.to_vec();
894 get_argument(context, &mut argument, input);
895 argument
896}
897
898impl<'a, Runtime: ContractRuntime> Inspector<Ctx<'a, Runtime>>
899 for CallInterceptorContract<Runtime>
900{
901 fn create(
902 &mut self,
903 _context: &mut Ctx<'a, Runtime>,
904 inputs: &mut CreateInputs,
905 ) -> Option<CreateOutcome> {
906 inputs.scheme = CreateScheme::Custom {
907 address: self.contract_address,
908 };
909 None
910 }
911
912 fn call(
913 &mut self,
914 context: &mut Ctx<'a, Runtime>,
915 inputs: &mut CallInputs,
916 ) -> Option<CallOutcome> {
917 let result = self.call_or_fail(context, inputs);
918 map_result_call_outcome(result)
919 }
920}
921
922impl<Runtime: ContractRuntime> CallInterceptorContract<Runtime> {
923 fn call_or_fail(
924 &mut self,
925 context: &mut Ctx<'_, Runtime>,
926 inputs: &mut CallInputs,
927 ) -> Result<Option<CallOutcome>, ExecutionError> {
928 if self.precompile_addresses.contains(&inputs.target_address)
934 || inputs.target_address == self.contract_address
935 {
936 return Ok(None);
939 }
940 let target = address_to_user_application_id(inputs.target_address);
942 let argument = get_call_argument(context, &inputs.input);
943 let authenticated = true;
944 let result = {
945 let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
946 runtime.try_call_application(authenticated, target, argument)?
947 };
948 let call_outcome = CallOutcome {
949 result: get_interpreter_result(&result, inputs)?,
950 memory_offset: inputs.return_memory_offset.clone(),
951 };
952 Ok(Some(call_outcome))
953 }
954}
955
956struct CallInterceptorService<Runtime> {
957 db: DatabaseRuntime<Runtime>,
958 contract_address: Address,
960 precompile_addresses: BTreeSet<Address>,
961}
962
963impl<Runtime> Clone for CallInterceptorService<Runtime> {
964 fn clone(&self) -> Self {
965 Self {
966 db: self.db.clone(),
967 contract_address: self.contract_address,
968 precompile_addresses: self.precompile_addresses.clone(),
969 }
970 }
971}
972
973impl<'a, Runtime: ServiceRuntime> Inspector<Ctx<'a, Runtime>> for CallInterceptorService<Runtime> {
974 fn create(
975 &mut self,
976 _context: &mut Ctx<'a, Runtime>,
977 inputs: &mut CreateInputs,
978 ) -> Option<CreateOutcome> {
979 inputs.scheme = CreateScheme::Custom {
980 address: self.contract_address,
981 };
982 None
983 }
984
985 fn call(
986 &mut self,
987 context: &mut Ctx<'a, Runtime>,
988 inputs: &mut CallInputs,
989 ) -> Option<CallOutcome> {
990 let result = self.call_or_fail(context, inputs);
991 map_result_call_outcome(result)
992 }
993}
994
995impl<Runtime: ServiceRuntime> CallInterceptorService<Runtime> {
996 fn call_or_fail(
997 &mut self,
998 context: &mut Ctx<'_, Runtime>,
999 inputs: &mut CallInputs,
1000 ) -> Result<Option<CallOutcome>, ExecutionError> {
1001 if self.precompile_addresses.contains(&inputs.target_address)
1007 || inputs.target_address == self.contract_address
1008 {
1009 return Ok(None);
1012 }
1013 let target = address_to_user_application_id(inputs.target_address);
1015 let argument = get_call_argument(context, &inputs.input);
1016 let result = {
1017 let evm_query = EvmQuery::Query(argument);
1018 let evm_query = serde_json::to_vec(&evm_query)?;
1019 let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1020 runtime.try_query_application(target, evm_query)?
1021 };
1022 let call_outcome = CallOutcome {
1023 result: get_interpreter_result(&result, inputs)?,
1024 memory_offset: inputs.return_memory_offset.clone(),
1025 };
1026 Ok(Some(call_outcome))
1027 }
1028}
1029
1030pub struct RevmContractInstance<Runtime> {
1031 module: Vec<u8>,
1032 db: DatabaseRuntime<Runtime>,
1033}
1034
1035enum EvmTxKind {
1036 Create,
1037 Call,
1038}
1039
1040#[derive(Debug)]
1041struct ExecutionResultSuccess {
1042 reason: SuccessReason,
1043 gas_final: u64,
1044 logs: Vec<Log>,
1045 output: Output,
1046}
1047
1048impl ExecutionResultSuccess {
1049 fn interpreter_result_and_logs(self) -> Result<(u64, Vec<u8>, Vec<Log>), ExecutionError> {
1050 let result: InstructionResult = self.reason.into();
1051 let Output::Call(output) = self.output else {
1052 unreachable!("The output should have been created from a EvmTxKind::Call");
1053 };
1054 let gas = Gas::new(0);
1055 let result = InterpreterResult {
1056 result,
1057 output,
1058 gas,
1059 };
1060 let result = bcs::to_bytes(&result)?;
1061 Ok((self.gas_final, result, self.logs))
1062 }
1063
1064 fn output_and_logs(self) -> (u64, Vec<u8>, Vec<Log>) {
1065 let Output::Call(output) = self.output else {
1066 unreachable!("The output should have been created from a EvmTxKind::Call");
1067 };
1068 let output = output.as_ref().to_vec();
1069 (self.gas_final, output, self.logs)
1070 }
1071
1072 fn check_contract_initialization(&self, expected_address: Address) -> Result<(), String> {
1074 let Output::Create(_, contract_address) = self.output else {
1076 return Err("Input should be ExmTxKind::Create".to_string());
1077 };
1078 let contract_address = contract_address.ok_or("Deployment failed")?;
1080 if contract_address == expected_address {
1082 Ok(())
1083 } else {
1084 Err("Contract address is not the same as ApplicationId".to_string())
1085 }
1086 }
1087}
1088
1089impl<Runtime> UserContract for RevmContractInstance<Runtime>
1090where
1091 Runtime: ContractRuntime,
1092{
1093 fn instantiate(&mut self, argument: Vec<u8>) -> Result<(), ExecutionError> {
1094 self.db.set_contract_address()?;
1095 self.initialize_contract()?;
1096 if has_selector(&self.module, INSTANTIATE_SELECTOR) {
1097 let instantiation_argument = serde_json::from_slice::<Vec<u8>>(&argument)?;
1098 let argument = get_revm_instantiation_bytes(instantiation_argument);
1099 let result = self.transact_commit(EvmTxKind::Call, argument)?;
1100 self.write_logs(result.logs, "instantiate")?;
1101 }
1102 Ok(())
1103 }
1104
1105 fn execute_operation(&mut self, operation: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1106 self.db.set_contract_address()?;
1107 ensure_message_length(operation.len(), 4)?;
1108 let (gas_final, output, logs) = if &operation[..4] == INTERPRETER_RESULT_SELECTOR {
1109 ensure_message_length(operation.len(), 8)?;
1110 forbid_execute_operation_origin(&operation[4..8])?;
1111 let result = self.init_transact_commit(operation[4..].to_vec())?;
1112 result.interpreter_result_and_logs()?
1113 } else {
1114 ensure_message_length(operation.len(), 4)?;
1115 forbid_execute_operation_origin(&operation[..4])?;
1116 let result = self.init_transact_commit(operation)?;
1117 result.output_and_logs()
1118 };
1119 self.consume_fuel(gas_final)?;
1120 self.write_logs(logs, "operation")?;
1121 Ok(output)
1122 }
1123
1124 fn execute_message(&mut self, message: Vec<u8>) -> Result<(), ExecutionError> {
1125 self.db.set_contract_address()?;
1126 ensure_selector_presence(
1127 &self.module,
1128 EXECUTE_MESSAGE_SELECTOR,
1129 "function execute_message(bytes)",
1130 )?;
1131 let operation = get_revm_execute_message_bytes(message);
1132 self.execute_no_return_operation(operation, "message")
1133 }
1134
1135 fn process_streams(&mut self, streams: Vec<StreamUpdate>) -> Result<(), ExecutionError> {
1136 self.db.set_contract_address()?;
1137 let operation = get_revm_process_streams_bytes(streams);
1138 ensure_selector_presence(
1139 &self.module,
1140 PROCESS_STREAMS_SELECTOR,
1141 "function process_streams(LineraTypes.StreamUpdate[] memory streams)",
1142 )?;
1143 self.execute_no_return_operation(operation, "process_streams")
1144 }
1145
1146 fn finalize(&mut self) -> Result<(), ExecutionError> {
1147 Ok(())
1148 }
1149}
1150
1151fn process_execution_result(
1152 storage_stats: StorageStats,
1153 result: ExecutionResult,
1154) -> Result<ExecutionResultSuccess, EvmExecutionError> {
1155 match result {
1156 ExecutionResult::Success {
1157 reason,
1158 gas_used,
1159 gas_refunded,
1160 logs,
1161 output,
1162 } => {
1163 let mut gas_final = gas_used;
1164 gas_final -= storage_stats.storage_costs();
1165 assert_eq!(gas_refunded, storage_stats.storage_refund());
1166 if !matches!(reason, SuccessReason::Return) {
1167 Err(EvmExecutionError::NoReturnInterpreter {
1168 reason,
1169 gas_used,
1170 gas_refunded,
1171 logs,
1172 output,
1173 })
1174 } else {
1175 Ok(ExecutionResultSuccess {
1176 reason,
1177 gas_final,
1178 logs,
1179 output,
1180 })
1181 }
1182 }
1183 ExecutionResult::Revert { gas_used, output } => {
1184 Err(EvmExecutionError::Revert { gas_used, output })
1185 }
1186 ExecutionResult::Halt { gas_used, reason } => {
1187 Err(EvmExecutionError::Halt { gas_used, reason })
1188 }
1189 }
1190}
1191
1192impl<Runtime> RevmContractInstance<Runtime>
1193where
1194 Runtime: ContractRuntime,
1195{
1196 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1197 let db = DatabaseRuntime::new(runtime);
1198 Self { module, db }
1199 }
1200
1201 fn execute_no_return_operation(
1202 &mut self,
1203 operation: Vec<u8>,
1204 origin: &str,
1205 ) -> Result<(), ExecutionError> {
1206 let result = self.init_transact_commit(operation)?;
1207 let (gas_final, output, logs) = result.output_and_logs();
1208 self.consume_fuel(gas_final)?;
1209 self.write_logs(logs, origin)?;
1210 assert_eq!(output.len(), 0);
1211 Ok(())
1212 }
1213
1214 fn init_transact_commit(
1216 &mut self,
1217 vec: Vec<u8>,
1218 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1219 if !self.db.is_initialized()? {
1223 self.initialize_contract()?;
1224 }
1225 self.transact_commit(EvmTxKind::Call, vec)
1226 }
1227
1228 fn initialize_contract(&mut self) -> Result<(), ExecutionError> {
1230 let mut vec_init = self.module.clone();
1231 let constructor_argument = self.db.constructor_argument()?;
1232 vec_init.extend_from_slice(&constructor_argument);
1233 let result = self.transact_commit(EvmTxKind::Create, vec_init)?;
1234 result
1235 .check_contract_initialization(self.db.contract_address)
1236 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1237 self.write_logs(result.logs, "deploy")
1238 }
1239
1240 fn transact_commit(
1241 &mut self,
1242 ch: EvmTxKind,
1243 input: Vec<u8>,
1244 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1245 let data = Bytes::from(input);
1246 let kind = match ch {
1247 EvmTxKind::Create => TxKind::Create,
1248 EvmTxKind::Call => TxKind::Call(self.db.contract_address),
1249 };
1250 let inspector = CallInterceptorContract {
1251 db: self.db.clone(),
1252 contract_address: self.db.contract_address,
1253 precompile_addresses: precompile_addresses(),
1254 };
1255 let block_env = self.db.get_contract_block_env()?;
1256 let gas_limit = {
1257 let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1258 runtime.remaining_fuel(VmRuntime::Evm)?
1259 };
1260 let nonce = self.db.get_nonce(&ZERO_ADDRESS)?;
1261 let result = {
1262 let ctx: revm_context::Context<
1263 BlockEnv,
1264 _,
1265 _,
1266 _,
1267 Journal<WrapDatabaseRef<&mut DatabaseRuntime<Runtime>>>,
1268 (),
1269 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1270 WrapDatabaseRef(&mut self.db),
1271 SpecId::PRAGUE,
1272 )
1273 .with_block(block_env);
1274 let instructions = EthInstructions::new_mainnet();
1275 let mut evm = Evm::new_with_inspector(
1276 ctx,
1277 inspector.clone(),
1278 instructions,
1279 ContractPrecompile::default(),
1280 );
1281 evm.inspect_commit(
1282 TxEnv {
1283 kind,
1284 data,
1285 nonce,
1286 gas_limit,
1287 ..TxEnv::default()
1288 },
1289 inspector,
1290 )
1291 .map_err(|error| {
1292 let error = format!("{:?}", error);
1293 EvmExecutionError::TransactCommitError(error)
1294 })
1295 }?;
1296 let storage_stats = self.db.take_storage_stats();
1297 self.db.commit_changes()?;
1298 Ok(process_execution_result(storage_stats, result)?)
1299 }
1300
1301 fn consume_fuel(&mut self, gas_final: u64) -> Result<(), ExecutionError> {
1302 let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1303 runtime.consume_fuel(gas_final, VmRuntime::Evm)
1304 }
1305
1306 fn write_logs(&mut self, logs: Vec<Log>, origin: &str) -> Result<(), ExecutionError> {
1307 if !logs.is_empty() {
1309 let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1310 let block_height = runtime.block_height()?;
1311 let stream_name = bcs::to_bytes("ethereum_event")?;
1312 let stream_name = StreamName(stream_name);
1313 for log in &logs {
1314 let value = bcs::to_bytes(&(origin, block_height.0, log))?;
1315 runtime.emit(stream_name.clone(), value)?;
1316 }
1317 }
1318 Ok(())
1319 }
1320}
1321
1322pub struct RevmServiceInstance<Runtime> {
1323 module: Vec<u8>,
1324 db: DatabaseRuntime<Runtime>,
1325}
1326
1327impl<Runtime> RevmServiceInstance<Runtime>
1328where
1329 Runtime: ServiceRuntime,
1330{
1331 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1332 let db = DatabaseRuntime::new(runtime);
1333 Self { module, db }
1334 }
1335}
1336
1337impl<Runtime> UserService for RevmServiceInstance<Runtime>
1338where
1339 Runtime: ServiceRuntime,
1340{
1341 fn handle_query(&mut self, argument: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1342 self.db.set_contract_address()?;
1343 let evm_query = serde_json::from_slice(&argument)?;
1344 let query = match evm_query {
1345 EvmQuery::Query(vec) => vec,
1346 EvmQuery::Mutation(operation) => {
1347 let mut runtime = self.db.runtime.lock().expect("The lock should be possible");
1348 runtime.schedule_operation(operation)?;
1349 return Ok(Vec::new());
1350 }
1351 };
1352
1353 ensure_message_length(query.len(), 4)?;
1354 let answer = if &query[..4] == INTERPRETER_RESULT_SELECTOR {
1358 let result = self.init_transact(query[4..].to_vec())?;
1359 let (_gas_final, answer, _logs) = result.interpreter_result_and_logs()?;
1360 answer
1361 } else {
1362 let result = self.init_transact(query)?;
1363 let (_gas_final, output, _logs) = result.output_and_logs();
1364 serde_json::to_vec(&output)?
1365 };
1366 Ok(answer)
1367 }
1368}
1369
1370impl<Runtime> RevmServiceInstance<Runtime>
1371where
1372 Runtime: ServiceRuntime,
1373{
1374 fn init_transact(&mut self, vec: Vec<u8>) -> Result<ExecutionResultSuccess, ExecutionError> {
1375 if !self.db.is_initialized()? {
1379 let changes = {
1380 let mut vec_init = self.module.clone();
1381 let constructor_argument = self.db.constructor_argument()?;
1382 vec_init.extend_from_slice(&constructor_argument);
1383 let (result, changes) = self.transact(TxKind::Create, vec_init)?;
1384 result
1385 .check_contract_initialization(self.db.contract_address)
1386 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1387 changes
1388 };
1389 self.db.changes = changes;
1390 }
1391 ensure_message_length(vec.len(), 4)?;
1392 forbid_execute_operation_origin(&vec[..4])?;
1393 let kind = TxKind::Call(self.db.contract_address);
1394 let (execution_result, _) = self.transact(kind, vec)?;
1395 Ok(execution_result)
1396 }
1397
1398 fn transact(
1399 &mut self,
1400 kind: TxKind,
1401 input: Vec<u8>,
1402 ) -> Result<(ExecutionResultSuccess, EvmState), ExecutionError> {
1403 let data = Bytes::from(input);
1404
1405 let block_env = self.db.get_service_block_env()?;
1406 let inspector = CallInterceptorService {
1407 db: self.db.clone(),
1408 contract_address: self.db.contract_address,
1409 precompile_addresses: precompile_addresses(),
1410 };
1411 let nonce = self.db.get_nonce(&ZERO_ADDRESS)?;
1412 let result_state = {
1413 let ctx: revm_context::Context<
1414 BlockEnv,
1415 _,
1416 _,
1417 _,
1418 Journal<WrapDatabaseRef<&mut DatabaseRuntime<Runtime>>>,
1419 (),
1420 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1421 WrapDatabaseRef(&mut self.db),
1422 SpecId::PRAGUE,
1423 )
1424 .with_block(block_env);
1425 let instructions = EthInstructions::new_mainnet();
1426 let mut evm = Evm::new_with_inspector(
1427 ctx,
1428 inspector.clone(),
1429 instructions,
1430 ServicePrecompile::default(),
1431 );
1432 evm.inspect(
1433 TxEnv {
1434 kind,
1435 data,
1436 nonce,
1437 gas_limit: EVM_SERVICE_GAS_LIMIT,
1438 ..TxEnv::default()
1439 },
1440 inspector,
1441 )
1442 .map_err(|error| {
1443 let error = format!("{:?}", error);
1444 EvmExecutionError::TransactCommitError(error)
1445 })
1446 }?;
1447 let storage_stats = self.db.take_storage_stats();
1448 Ok((
1449 process_execution_result(storage_stats, result_state.result)?,
1450 result_state.state,
1451 ))
1452 }
1453}