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::{AccountOwner, 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, U256};
32use revm_state::EvmState;
33use serde::{Deserialize, Serialize};
34
35use crate::{
36 evm::{
37 data_types::AmountU256,
38 database::{DatabaseRuntime, StorageStats, EVM_SERVICE_GAS_LIMIT},
39 },
40 BaseRuntime, ContractRuntime, ContractSyncRuntimeHandle, DataBlobHash, EvmExecutionError,
41 EvmRuntime, ExecutionError, ServiceRuntime, ServiceSyncRuntimeHandle, UserContract,
42 UserContractInstance, UserContractModule, UserService, UserServiceInstance, UserServiceModule,
43};
44
45const EXECUTE_MESSAGE_SELECTOR: &[u8] = &[173, 125, 234, 205];
48
49const PROCESS_STREAMS_SELECTOR: &[u8] = &[254, 72, 102, 28];
52
53const INSTANTIATE_SELECTOR: &[u8] = &[156, 163, 60, 158];
56
57const INTERPRETER_RESULT_SELECTOR: &[u8] = &[1, 2, 3, 4];
60
61const GET_DEPLOYED_BYTECODE_SELECTOR: &[u8] = &[21, 34, 55, 89];
64
65const JSON_EMPTY_VECTOR: &[u8] = &[91, 93];
67
68fn forbid_execute_operation_origin(vec: &[u8]) -> Result<(), EvmExecutionError> {
69 if vec == EXECUTE_MESSAGE_SELECTOR {
70 return Err(EvmExecutionError::IllegalOperationCall(
71 "function execute_message".to_string(),
72 ));
73 }
74 if vec == PROCESS_STREAMS_SELECTOR {
75 return Err(EvmExecutionError::IllegalOperationCall(
76 "function process_streams".to_string(),
77 ));
78 }
79 if vec == INSTANTIATE_SELECTOR {
80 return Err(EvmExecutionError::IllegalOperationCall(
81 "function instantiate".to_string(),
82 ));
83 }
84 Ok(())
85}
86
87fn ensure_message_length(actual_length: usize, min_length: usize) -> Result<(), EvmExecutionError> {
88 ensure!(
89 actual_length >= min_length,
90 EvmExecutionError::OperationIsTooShort
91 );
92 Ok(())
93}
94
95fn ensure_selector_presence(
96 module: &[u8],
97 selector: &[u8],
98 fct_name: &str,
99) -> Result<(), EvmExecutionError> {
100 if !has_selector(module, selector) {
101 return Err(EvmExecutionError::MissingFunction(fct_name.to_string()));
102 }
103 Ok(())
104}
105
106#[cfg(test)]
107mod tests {
108 use revm_primitives::keccak256;
109
110 use crate::evm::revm::{
111 EXECUTE_MESSAGE_SELECTOR, INSTANTIATE_SELECTOR, PROCESS_STREAMS_SELECTOR,
112 };
113
114 #[test]
117 fn check_execute_message_selector() {
118 let selector = &keccak256("execute_message(bytes)".as_bytes())[..4];
119 assert_eq!(selector, EXECUTE_MESSAGE_SELECTOR);
120 }
121
122 #[test]
123 fn check_process_streams_selector() {
124 use alloy_sol_types::{sol, SolCall};
125 sol! {
126 struct InternalApplicationId {
127 bytes32 application_description_hash;
128 }
129
130 struct InternalGenericApplicationId {
131 uint8 choice;
132 InternalApplicationId user;
133 }
134
135 struct InternalStreamName {
136 bytes stream_name;
137 }
138
139 struct InternalStreamId {
140 InternalGenericApplicationId application_id;
141 InternalStreamName stream_name;
142 }
143
144 struct InternalChainId {
145 bytes32 value;
146 }
147
148 struct InternalStreamUpdate {
149 InternalChainId chain_id;
150 InternalStreamId stream_id;
151 uint32 previous_index;
152 uint32 next_index;
153 }
154
155 function process_streams(InternalStreamUpdate[] internal_streams);
156 }
157 assert_eq!(
158 process_streamsCall::SIGNATURE,
159 "process_streams(((bytes32),((uint8,(bytes32)),(bytes)),uint32,uint32)[])"
160 );
161 assert_eq!(process_streamsCall::SELECTOR, PROCESS_STREAMS_SELECTOR);
162 }
163
164 #[test]
165 fn check_instantiate_selector() {
166 let selector = &keccak256("instantiate(bytes)".as_bytes())[..4];
167 assert_eq!(selector, INSTANTIATE_SELECTOR);
168 }
169}
170
171fn has_selector(module: &[u8], selector: &[u8]) -> bool {
172 let push4 = 0x63; let mut vec = vec![push4];
174 vec.extend(selector);
175 module.windows(5).any(|window| window == vec)
176}
177
178#[cfg(with_metrics)]
179mod metrics {
180 use std::sync::LazyLock;
181
182 use linera_base::prometheus_util::{exponential_bucket_latencies, register_histogram_vec};
183 use prometheus::HistogramVec;
184
185 pub static CONTRACT_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
186 register_histogram_vec(
187 "evm_contract_instantiation_latency",
188 "EVM contract instantiation latency",
189 &[],
190 exponential_bucket_latencies(1.0),
191 )
192 });
193
194 pub static SERVICE_INSTANTIATION_LATENCY: LazyLock<HistogramVec> = LazyLock::new(|| {
195 register_histogram_vec(
196 "evm_service_instantiation_latency",
197 "EVM service instantiation latency",
198 &[],
199 exponential_bucket_latencies(1.0),
200 )
201 });
202}
203
204fn get_revm_instantiation_bytes(value: Vec<u8>) -> Vec<u8> {
205 use alloy_primitives::Bytes;
206 use alloy_sol_types::{sol, SolCall};
207 sol! {
208 function instantiate(bytes value);
209 }
210 let bytes = Bytes::from(value);
211 let argument = instantiateCall { value: bytes };
212 argument.abi_encode()
213}
214
215fn get_revm_execute_message_bytes(value: Vec<u8>) -> Vec<u8> {
216 use alloy_primitives::Bytes;
217 use alloy_sol_types::{sol, SolCall};
218 sol! {
219 function execute_message(bytes value);
220 }
221 let value = Bytes::from(value);
222 let argument = execute_messageCall { value };
223 argument.abi_encode()
224}
225
226fn get_revm_process_streams_bytes(streams: Vec<StreamUpdate>) -> Vec<u8> {
227 use alloy_primitives::{Bytes, B256};
229 use alloy_sol_types::{sol, SolCall};
230 use linera_base::identifiers::{GenericApplicationId, StreamId};
231 sol! {
232 struct InternalApplicationId {
233 bytes32 application_description_hash;
234 }
235
236 struct InternalGenericApplicationId {
237 uint8 choice;
238 InternalApplicationId user;
239 }
240
241 struct InternalStreamName {
242 bytes stream_name;
243 }
244
245 struct InternalStreamId {
246 InternalGenericApplicationId application_id;
247 InternalStreamName stream_name;
248 }
249
250 struct InternalChainId {
251 bytes32 value;
252 }
253
254 struct InternalStreamUpdate {
255 InternalChainId chain_id;
256 InternalStreamId stream_id;
257 uint32 previous_index;
258 uint32 next_index;
259 }
260
261 function process_streams(InternalStreamUpdate[] internal_streams);
262 }
263
264 fn crypto_hash_to_internal_crypto_hash(hash: CryptoHash) -> B256 {
265 let hash: [u64; 4] = <[u64; 4]>::from(hash);
266 let hash: [u8; 32] = linera_base::crypto::u64_array_to_be_bytes(hash);
267 hash.into()
268 }
269
270 fn chain_id_to_internal_chain_id(chain_id: ChainId) -> InternalChainId {
271 let value = crypto_hash_to_internal_crypto_hash(chain_id.0);
272 InternalChainId { value }
273 }
274
275 fn application_id_to_internal_application_id(
276 application_id: ApplicationId,
277 ) -> InternalApplicationId {
278 let application_description_hash =
279 crypto_hash_to_internal_crypto_hash(application_id.application_description_hash);
280 InternalApplicationId {
281 application_description_hash,
282 }
283 }
284
285 fn stream_name_to_internal_stream_name(stream_name: StreamName) -> InternalStreamName {
286 let stream_name = Bytes::from(stream_name.0);
287 InternalStreamName { stream_name }
288 }
289
290 fn generic_application_id_to_internal_generic_application_id(
291 generic_application_id: GenericApplicationId,
292 ) -> InternalGenericApplicationId {
293 match generic_application_id {
294 GenericApplicationId::System => {
295 let application_description_hash = B256::ZERO;
296 InternalGenericApplicationId {
297 choice: 0,
298 user: InternalApplicationId {
299 application_description_hash,
300 },
301 }
302 }
303 GenericApplicationId::User(application_id) => InternalGenericApplicationId {
304 choice: 1,
305 user: application_id_to_internal_application_id(application_id),
306 },
307 }
308 }
309
310 fn stream_id_to_internal_stream_id(stream_id: StreamId) -> InternalStreamId {
311 let application_id =
312 generic_application_id_to_internal_generic_application_id(stream_id.application_id);
313 let stream_name = stream_name_to_internal_stream_name(stream_id.stream_name);
314 InternalStreamId {
315 application_id,
316 stream_name,
317 }
318 }
319
320 fn stream_update_to_internal_stream_update(
321 stream_update: StreamUpdate,
322 ) -> InternalStreamUpdate {
323 let chain_id = chain_id_to_internal_chain_id(stream_update.chain_id);
324 let stream_id = stream_id_to_internal_stream_id(stream_update.stream_id);
325 InternalStreamUpdate {
326 chain_id,
327 stream_id,
328 previous_index: stream_update.previous_index,
329 next_index: stream_update.next_index,
330 }
331 }
332
333 let internal_streams = streams
334 .into_iter()
335 .map(stream_update_to_internal_stream_update)
336 .collect::<Vec<_>>();
337
338 let fct_call = process_streamsCall { internal_streams };
339 fct_call.abi_encode()
340}
341
342#[derive(Clone)]
343pub enum EvmContractModule {
344 #[cfg(with_revm)]
345 Revm { module: Vec<u8> },
346}
347
348impl EvmContractModule {
349 pub fn new(
351 contract_bytecode: Bytecode,
352 runtime: EvmRuntime,
353 ) -> Result<Self, EvmExecutionError> {
354 match runtime {
355 #[cfg(with_revm)]
356 EvmRuntime::Revm => Self::from_revm(contract_bytecode),
357 }
358 }
359
360 #[cfg(with_fs)]
362 pub fn from_file(
363 contract_bytecode_file: impl AsRef<std::path::Path>,
364 runtime: EvmRuntime,
365 ) -> Result<Self, EvmExecutionError> {
366 Self::new(
367 Bytecode::load_from_file(contract_bytecode_file)
368 .map_err(anyhow::Error::from)
369 .map_err(EvmExecutionError::LoadContractModule)?,
370 runtime,
371 )
372 }
373
374 pub fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
376 let module = contract_bytecode.bytes;
377 Ok(EvmContractModule::Revm { module })
378 }
379}
380
381impl UserContractModule for EvmContractModule {
382 fn instantiate(
383 &self,
384 runtime: ContractSyncRuntimeHandle,
385 ) -> Result<UserContractInstance, ExecutionError> {
386 #[cfg(with_metrics)]
387 let _instantiation_latency = metrics::CONTRACT_INSTANTIATION_LATENCY.measure_latency();
388
389 let instance: UserContractInstance = match self {
390 #[cfg(with_revm)]
391 EvmContractModule::Revm { module } => {
392 Box::new(RevmContractInstance::prepare(module.to_vec(), runtime))
393 }
394 };
395
396 Ok(instance)
397 }
398}
399
400#[derive(Clone)]
402pub enum EvmServiceModule {
403 #[cfg(with_revm)]
404 Revm { module: Vec<u8> },
405}
406
407impl EvmServiceModule {
408 pub fn new(service_bytecode: Bytecode, runtime: EvmRuntime) -> Result<Self, EvmExecutionError> {
410 match runtime {
411 #[cfg(with_revm)]
412 EvmRuntime::Revm => Self::from_revm(service_bytecode),
413 }
414 }
415
416 #[cfg(with_fs)]
418 pub fn from_file(
419 service_bytecode_file: impl AsRef<std::path::Path>,
420 runtime: EvmRuntime,
421 ) -> Result<Self, EvmExecutionError> {
422 Self::new(
423 Bytecode::load_from_file(service_bytecode_file)
424 .map_err(anyhow::Error::from)
425 .map_err(EvmExecutionError::LoadServiceModule)?,
426 runtime,
427 )
428 }
429
430 pub fn from_revm(contract_bytecode: Bytecode) -> Result<Self, EvmExecutionError> {
432 let module = contract_bytecode.bytes;
433 Ok(EvmServiceModule::Revm { module })
434 }
435}
436
437impl UserServiceModule for EvmServiceModule {
438 fn instantiate(
439 &self,
440 runtime: ServiceSyncRuntimeHandle,
441 ) -> Result<UserServiceInstance, ExecutionError> {
442 #[cfg(with_metrics)]
443 let _instantiation_latency = metrics::SERVICE_INSTANTIATION_LATENCY.measure_latency();
444
445 let instance: UserServiceInstance = match self {
446 #[cfg(with_revm)]
447 EvmServiceModule::Revm { module } => {
448 Box::new(RevmServiceInstance::prepare(module.to_vec(), runtime))
449 }
450 };
451
452 Ok(instance)
453 }
454}
455
456type Ctx<'a, Runtime> = MainnetContext<WrapDatabaseRef<&'a mut DatabaseRuntime<Runtime>>>;
457
458const PRECOMPILE_ADDRESS: Address = address!("000000000000000000000000000000000000000b");
461
462const ZERO_ADDRESS: Address = address!("0000000000000000000000000000000000000000");
466
467const SERVICE_ADDRESS: Address = address!("0000000000000000000000000000000000002000");
469
470fn address_to_user_application_id(address: Address) -> ApplicationId {
471 let mut vec = vec![0_u8; 32];
472 vec[..20].copy_from_slice(address.as_ref());
473 ApplicationId::new(CryptoHash::try_from(&vec as &[u8]).unwrap())
474}
475
476#[derive(Debug, Serialize, Deserialize)]
478enum BaseRuntimePrecompile {
479 ChainId,
481 BlockHeight,
483 ApplicationCreatorChainId,
485 ReadSystemTimestamp,
487 ReadChainBalance,
489 ReadOwnerBalance(AccountOwner),
491 ReadOwnerBalances,
493 ReadBalanceOwners,
495 ChainOwnership,
497 ReadDataBlob(DataBlobHash),
499 AssertDataBlobExists(DataBlobHash),
501}
502
503#[derive(Debug, Serialize, Deserialize)]
505enum ContractRuntimePrecompile {
506 AuthenticatedSigner,
508 MessageOriginChainId,
510 MessageIsBouncing,
512 AuthenticatedCallerId,
514 SendMessage {
516 destination: ChainId,
517 message: Vec<u8>,
518 },
519 TryCallApplication {
521 target: ApplicationId,
522 argument: Vec<u8>,
523 },
524 Emit {
526 stream_name: StreamName,
527 value: Vec<u8>,
528 },
529 ReadEvent {
531 chain_id: ChainId,
532 stream_name: StreamName,
533 index: u32,
534 },
535 SubscribeToEvents {
537 chain_id: ChainId,
538 application_id: ApplicationId,
539 stream_name: StreamName,
540 },
541 UnsubscribeFromEvents {
543 chain_id: ChainId,
544 application_id: ApplicationId,
545 stream_name: StreamName,
546 },
547 QueryService {
549 application_id: ApplicationId,
550 query: Vec<u8>,
551 },
552 ValidationRound,
554}
555
556#[derive(Debug, Serialize, Deserialize)]
558enum ServiceRuntimePrecompile {
559 TryQueryApplication {
561 target: ApplicationId,
562 argument: Vec<u8>,
563 },
564}
565
566#[derive(Debug, Serialize, Deserialize)]
568enum RuntimePrecompile {
569 Base(BaseRuntimePrecompile),
570 Contract(ContractRuntimePrecompile),
571 Service(ServiceRuntimePrecompile),
572}
573
574fn get_precompile_output(output: Vec<u8>, gas_limit: u64) -> InterpreterResult {
575 let output = Bytes::from(output);
580 let result = InstructionResult::default();
581 let gas = Gas::new(gas_limit);
582 InterpreterResult {
583 result,
584 output,
585 gas,
586 }
587}
588
589fn get_precompile_argument<Ctx: ContextTr>(context: &mut Ctx, input: &CallInput) -> Vec<u8> {
590 let mut argument = Vec::new();
591 get_argument(context, &mut argument, input);
592 argument
593}
594
595fn base_runtime_call<Runtime: BaseRuntime>(
596 request: BaseRuntimePrecompile,
597 context: &mut Ctx<'_, Runtime>,
598) -> Result<Vec<u8>, ExecutionError> {
599 let mut runtime = context.db().0.runtime.lock().unwrap();
600 match request {
601 BaseRuntimePrecompile::ChainId => {
602 let chain_id = runtime.chain_id()?;
603 Ok(bcs::to_bytes(&chain_id)?)
604 }
605 BaseRuntimePrecompile::BlockHeight => {
606 let block_height = runtime.block_height()?;
607 Ok(bcs::to_bytes(&block_height)?)
608 }
609 BaseRuntimePrecompile::ApplicationCreatorChainId => {
610 let chain_id = runtime.application_creator_chain_id()?;
611 Ok(bcs::to_bytes(&chain_id)?)
612 }
613 BaseRuntimePrecompile::ReadSystemTimestamp => {
614 let timestamp = runtime.read_system_timestamp()?;
615 Ok(bcs::to_bytes(×tamp)?)
616 }
617 BaseRuntimePrecompile::ReadChainBalance => {
618 let balance: linera_base::data_types::Amount = runtime.read_chain_balance()?;
619 let balance: AmountU256 = balance.into();
620 Ok(bcs::to_bytes(&balance)?)
621 }
622 BaseRuntimePrecompile::ReadOwnerBalance(account_owner) => {
623 let balance = runtime.read_owner_balance(account_owner)?;
624 let balance = Into::<U256>::into(balance);
625 Ok(bcs::to_bytes(&balance)?)
626 }
627 BaseRuntimePrecompile::ReadOwnerBalances => {
628 let owner_balances = runtime.read_owner_balances()?;
629 let owner_balances = owner_balances
630 .into_iter()
631 .map(|(account_owner, balance)| (account_owner, balance.into()))
632 .collect::<Vec<(AccountOwner, AmountU256)>>();
633 Ok(bcs::to_bytes(&owner_balances)?)
634 }
635 BaseRuntimePrecompile::ReadBalanceOwners => {
636 let owners = runtime.read_balance_owners()?;
637 Ok(bcs::to_bytes(&owners)?)
638 }
639 BaseRuntimePrecompile::ChainOwnership => {
640 let chain_ownership = runtime.chain_ownership()?;
641 Ok(bcs::to_bytes(&chain_ownership)?)
642 }
643 BaseRuntimePrecompile::ReadDataBlob(hash) => runtime.read_data_blob(hash),
644 BaseRuntimePrecompile::AssertDataBlobExists(hash) => {
645 runtime.assert_data_blob_exists(hash)?;
646 Ok(Vec::new())
647 }
648 }
649}
650
651fn precompile_addresses() -> BTreeSet<Address> {
652 let mut addresses = BTreeSet::new();
653 for address in EthPrecompiles::default().warm_addresses() {
654 addresses.insert(address);
655 }
656 addresses.insert(PRECOMPILE_ADDRESS);
657 addresses
658}
659
660#[derive(Debug, Default)]
661struct ContractPrecompile {
662 inner: EthPrecompiles,
663}
664
665impl<'a, Runtime: ContractRuntime> PrecompileProvider<Ctx<'a, Runtime>> for ContractPrecompile {
666 type Output = InterpreterResult;
667
668 fn set_spec(&mut self, spec: <<Ctx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec) -> bool {
669 <EthPrecompiles as PrecompileProvider<Ctx<'a, Runtime>>>::set_spec(&mut self.inner, spec)
670 }
671
672 fn run(
673 &mut self,
674 context: &mut Ctx<'a, Runtime>,
675 address: &Address,
676 inputs: &InputsImpl,
677 is_static: bool,
678 gas_limit: u64,
679 ) -> Result<Option<InterpreterResult>, String> {
680 if address == &PRECOMPILE_ADDRESS {
681 let input = get_precompile_argument(context, &inputs.input);
682 let output = Self::call_or_fail(&input, context)
683 .map_err(|error| format!("ContractPrecompile error: {error}"))?;
684 return Ok(Some(get_precompile_output(output, gas_limit)));
685 }
686 self.inner
687 .run(context, address, inputs, is_static, gas_limit)
688 }
689
690 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
691 let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
692 addresses.push(PRECOMPILE_ADDRESS);
693 Box::new(addresses.into_iter())
694 }
695
696 fn contains(&self, address: &Address) -> bool {
697 address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
698 }
699}
700
701impl<'a> ContractPrecompile {
702 fn contract_runtime_call<Runtime: ContractRuntime>(
703 request: ContractRuntimePrecompile,
704 context: &mut Ctx<'a, Runtime>,
705 ) -> Result<Vec<u8>, ExecutionError> {
706 let mut runtime = context.db().0.runtime.lock().unwrap();
707 match request {
708 ContractRuntimePrecompile::AuthenticatedSigner => {
709 let account_owner = runtime.authenticated_signer()?;
710 Ok(bcs::to_bytes(&account_owner)?)
711 }
712
713 ContractRuntimePrecompile::MessageOriginChainId => {
714 let origin_chain_id = runtime.message_origin_chain_id()?;
715 Ok(bcs::to_bytes(&origin_chain_id)?)
716 }
717
718 ContractRuntimePrecompile::MessageIsBouncing => {
719 let result = runtime.message_is_bouncing()?;
720 Ok(bcs::to_bytes(&result)?)
721 }
722 ContractRuntimePrecompile::AuthenticatedCallerId => {
723 let application_id = runtime.authenticated_caller_id()?;
724 Ok(bcs::to_bytes(&application_id)?)
725 }
726 ContractRuntimePrecompile::SendMessage {
727 destination,
728 message,
729 } => {
730 let authenticated = true;
731 let is_tracked = true;
732 let grant = Resources::default();
733 let send_message_request = SendMessageRequest {
734 destination,
735 authenticated,
736 is_tracked,
737 grant,
738 message,
739 };
740 runtime.send_message(send_message_request)?;
741 Ok(vec![])
742 }
743 ContractRuntimePrecompile::TryCallApplication { target, argument } => {
744 let authenticated = true;
745 runtime.try_call_application(authenticated, target, argument)
746 }
747 ContractRuntimePrecompile::Emit { stream_name, value } => {
748 let result = runtime.emit(stream_name, value)?;
749 Ok(bcs::to_bytes(&result)?)
750 }
751 ContractRuntimePrecompile::ReadEvent {
752 chain_id,
753 stream_name,
754 index,
755 } => runtime.read_event(chain_id, stream_name, index),
756 ContractRuntimePrecompile::SubscribeToEvents {
757 chain_id,
758 application_id,
759 stream_name,
760 } => {
761 runtime.subscribe_to_events(chain_id, application_id, stream_name)?;
762 Ok(vec![])
763 }
764 ContractRuntimePrecompile::UnsubscribeFromEvents {
765 chain_id,
766 application_id,
767 stream_name,
768 } => {
769 runtime.unsubscribe_from_events(chain_id, application_id, stream_name)?;
770 Ok(vec![])
771 }
772 ContractRuntimePrecompile::QueryService {
773 application_id,
774 query,
775 } => runtime.query_service(application_id, query),
776 ContractRuntimePrecompile::ValidationRound => {
777 let value = runtime.validation_round()?;
778 Ok(bcs::to_bytes(&value)?)
779 }
780 }
781 }
782
783 fn call_or_fail<Runtime: ContractRuntime>(
784 input: &[u8],
785 context: &mut Ctx<'a, Runtime>,
786 ) -> Result<Vec<u8>, ExecutionError> {
787 match bcs::from_bytes(input)? {
788 RuntimePrecompile::Base(base_tag) => base_runtime_call(base_tag, context),
789 RuntimePrecompile::Contract(contract_tag) => {
790 Self::contract_runtime_call(contract_tag, context)
791 }
792 RuntimePrecompile::Service(_) => Err(EvmExecutionError::PrecompileError(
793 "Service tags are not available in GeneralContractCall".to_string(),
794 )
795 .into()),
796 }
797 }
798}
799
800#[derive(Debug, Default)]
801struct ServicePrecompile {
802 inner: EthPrecompiles,
803}
804
805impl<'a> ServicePrecompile {
806 fn service_runtime_call<Runtime: ServiceRuntime>(
807 request: ServiceRuntimePrecompile,
808 context: &mut Ctx<'a, Runtime>,
809 ) -> Result<Vec<u8>, ExecutionError> {
810 let mut runtime = context.db().0.runtime.lock().unwrap();
811 match request {
812 ServiceRuntimePrecompile::TryQueryApplication { target, argument } => {
813 runtime.try_query_application(target, argument)
814 }
815 }
816 }
817
818 fn call_or_fail<Runtime: ServiceRuntime>(
819 input: &[u8],
820 context: &mut Ctx<'a, Runtime>,
821 ) -> Result<Vec<u8>, ExecutionError> {
822 match bcs::from_bytes(input)? {
823 RuntimePrecompile::Base(base_tag) => base_runtime_call(base_tag, context),
824 RuntimePrecompile::Contract(_) => Err(EvmExecutionError::PrecompileError(
825 "Contract calls are not available in GeneralServiceCall".to_string(),
826 )
827 .into()),
828 RuntimePrecompile::Service(service_tag) => {
829 Self::service_runtime_call(service_tag, context)
830 }
831 }
832 }
833}
834
835impl<'a, Runtime: ServiceRuntime> PrecompileProvider<Ctx<'a, Runtime>> for ServicePrecompile {
836 type Output = InterpreterResult;
837
838 fn set_spec(&mut self, spec: <<Ctx<'a, Runtime> as ContextTr>::Cfg as Cfg>::Spec) -> bool {
839 <EthPrecompiles as PrecompileProvider<Ctx<'a, Runtime>>>::set_spec(&mut self.inner, spec)
840 }
841
842 fn run(
843 &mut self,
844 context: &mut Ctx<'a, Runtime>,
845 address: &Address,
846 inputs: &InputsImpl,
847 is_static: bool,
848 gas_limit: u64,
849 ) -> Result<Option<InterpreterResult>, String> {
850 if address == &PRECOMPILE_ADDRESS {
851 let input = get_precompile_argument(context, &inputs.input);
852 let output = Self::call_or_fail(&input, context)
853 .map_err(|error| format!("ServicePrecompile error: {error}"))?;
854 return Ok(Some(get_precompile_output(output, gas_limit)));
855 }
856 self.inner
857 .run(context, address, inputs, is_static, gas_limit)
858 }
859
860 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
861 let mut addresses = self.inner.warm_addresses().collect::<Vec<Address>>();
862 addresses.push(PRECOMPILE_ADDRESS);
863 Box::new(addresses.into_iter())
864 }
865
866 fn contains(&self, address: &Address) -> bool {
867 address == &PRECOMPILE_ADDRESS || self.inner.contains(address)
868 }
869}
870
871fn map_result_create_outcome<Runtime: BaseRuntime>(
872 database: &DatabaseRuntime<Runtime>,
873 result: Result<Option<CreateOutcome>, ExecutionError>,
874) -> Option<CreateOutcome> {
875 match result {
876 Err(error) => {
877 database.insert_error(error);
878 let result = InstructionResult::Revert;
880 let output = Bytes::default();
881 let gas = Gas::default();
882 let result = InterpreterResult {
883 result,
884 output,
885 gas,
886 };
887 Some(CreateOutcome {
888 result,
889 address: None,
890 })
891 }
892 Ok(result) => result,
893 }
894}
895
896fn map_result_call_outcome<Runtime: BaseRuntime>(
897 database: &DatabaseRuntime<Runtime>,
898 result: Result<Option<CallOutcome>, ExecutionError>,
899) -> Option<CallOutcome> {
900 match result {
901 Err(error) => {
902 database.insert_error(error);
903 let result = InstructionResult::Revert;
905 let output = Bytes::default();
906 let gas = Gas::default();
907 let result = InterpreterResult {
908 result,
909 output,
910 gas,
911 };
912 let memory_offset = Range::default();
913 Some(CallOutcome {
914 result,
915 memory_offset,
916 })
917 }
918 Ok(result) => result,
919 }
920}
921
922fn get_interpreter_result(
923 result: &[u8],
924 inputs: &mut CallInputs,
925) -> Result<InterpreterResult, ExecutionError> {
926 let mut result = bcs::from_bytes::<InterpreterResult>(result)?;
927 result.gas = Gas::new(inputs.gas_limit);
930 Ok(result)
931}
932
933struct CallInterceptorContract<Runtime> {
934 db: DatabaseRuntime<Runtime>,
935 contract_address: Address,
937 precompile_addresses: BTreeSet<Address>,
938}
939
940impl<Runtime> Clone for CallInterceptorContract<Runtime> {
941 fn clone(&self) -> Self {
942 Self {
943 db: self.db.clone(),
944 contract_address: self.contract_address,
945 precompile_addresses: self.precompile_addresses.clone(),
946 }
947 }
948}
949
950fn get_argument<Ctx: ContextTr>(context: &mut Ctx, argument: &mut Vec<u8>, input: &CallInput) {
951 match input {
952 CallInput::Bytes(bytes) => {
953 argument.extend(bytes.to_vec());
954 }
955 CallInput::SharedBuffer(range) => {
956 if let Some(slice) = context.local().shared_memory_buffer_slice(range.clone()) {
957 argument.extend(&*slice);
958 }
959 }
960 };
961}
962
963fn get_call_argument<Ctx: ContextTr>(context: &mut Ctx, inputs: &CallInputs) -> Vec<u8> {
964 let mut argument = INTERPRETER_RESULT_SELECTOR.to_vec();
965 get_argument(context, &mut argument, &inputs.input);
966 argument
967}
968
969impl<'a, Runtime: ContractRuntime> Inspector<Ctx<'a, Runtime>>
970 for CallInterceptorContract<Runtime>
971{
972 fn create(
973 &mut self,
974 context: &mut Ctx<'a, Runtime>,
975 inputs: &mut CreateInputs,
976 ) -> Option<CreateOutcome> {
977 let result = self.create_or_fail(context, inputs);
978 map_result_create_outcome(&self.db, result)
979 }
980
981 fn call(
982 &mut self,
983 context: &mut Ctx<'a, Runtime>,
984 inputs: &mut CallInputs,
985 ) -> Option<CallOutcome> {
986 let result = self.call_or_fail(context, inputs);
987 map_result_call_outcome(&self.db, result)
988 }
989}
990
991impl<Runtime: ContractRuntime> CallInterceptorContract<Runtime> {
992 fn create_or_fail(
1070 &mut self,
1071 context: &mut Ctx<'_, Runtime>,
1072 inputs: &mut CreateInputs,
1073 ) -> Result<Option<CreateOutcome>, ExecutionError> {
1074 if !self.db.is_revm_instantiated {
1075 self.db.is_revm_instantiated = true;
1076 inputs.scheme = CreateScheme::Custom {
1077 address: self.contract_address,
1078 };
1079 Ok(None)
1080 } else {
1081 let contract = linera_base::data_types::Bytecode::new(inputs.init_code.to_vec());
1082 let service = linera_base::data_types::Bytecode::new(vec![]);
1083 let mut runtime = context.db().0.runtime.lock().unwrap();
1084 let module_id = runtime.publish_module(contract, service, VmRuntime::Evm)?;
1085 let parameters = JSON_EMPTY_VECTOR.to_vec(); let argument = JSON_EMPTY_VECTOR.to_vec(); let required_application_ids = Vec::new();
1088 let application_id = runtime.create_application(
1089 module_id,
1090 parameters,
1091 argument,
1092 required_application_ids,
1093 )?;
1094 let argument = GET_DEPLOYED_BYTECODE_SELECTOR.to_vec();
1095 let deployed_bytecode: Vec<u8> =
1096 runtime.try_call_application(false, application_id, argument)?;
1097 let result = InterpreterResult {
1098 result: InstructionResult::Return, output: Bytes::from(deployed_bytecode),
1100 gas: Gas::new(inputs.gas_limit),
1101 };
1102 let address = application_id.evm_address();
1103 let creation_outcome = CreateOutcome {
1104 result,
1105 address: Some(address),
1106 };
1107 Ok(Some(creation_outcome))
1108 }
1109 }
1110
1111 fn call_or_fail(
1112 &mut self,
1113 context: &mut Ctx<'_, Runtime>,
1114 inputs: &mut CallInputs,
1115 ) -> Result<Option<CallOutcome>, ExecutionError> {
1116 if self.precompile_addresses.contains(&inputs.target_address)
1122 || inputs.target_address == self.contract_address
1123 {
1124 return Ok(None);
1127 }
1128 let target = address_to_user_application_id(inputs.target_address);
1130 let argument = get_call_argument(context, inputs);
1131 let authenticated = true;
1132 let result = {
1133 let mut runtime = self.db.runtime.lock().unwrap();
1134 runtime.try_call_application(authenticated, target, argument)?
1135 };
1136 let call_outcome = CallOutcome {
1137 result: get_interpreter_result(&result, inputs)?,
1138 memory_offset: inputs.return_memory_offset.clone(),
1139 };
1140 Ok(Some(call_outcome))
1141 }
1142}
1143
1144struct CallInterceptorService<Runtime> {
1145 db: DatabaseRuntime<Runtime>,
1146 contract_address: Address,
1148 precompile_addresses: BTreeSet<Address>,
1149}
1150
1151impl<Runtime> Clone for CallInterceptorService<Runtime> {
1152 fn clone(&self) -> Self {
1153 Self {
1154 db: self.db.clone(),
1155 contract_address: self.contract_address,
1156 precompile_addresses: self.precompile_addresses.clone(),
1157 }
1158 }
1159}
1160
1161impl<'a, Runtime: ServiceRuntime> Inspector<Ctx<'a, Runtime>> for CallInterceptorService<Runtime> {
1162 fn create(
1164 &mut self,
1165 context: &mut Ctx<'a, Runtime>,
1166 inputs: &mut CreateInputs,
1167 ) -> Option<CreateOutcome> {
1168 let result = self.create_or_fail(context, inputs);
1169 map_result_create_outcome(&self.db, result)
1170 }
1171
1172 fn call(
1174 &mut self,
1175 context: &mut Ctx<'a, Runtime>,
1176 inputs: &mut CallInputs,
1177 ) -> Option<CallOutcome> {
1178 let result = self.call_or_fail(context, inputs);
1179 map_result_call_outcome(&self.db, result)
1180 }
1181}
1182
1183impl<Runtime: ServiceRuntime> CallInterceptorService<Runtime> {
1184 fn create_or_fail(
1205 &mut self,
1206 _context: &mut Ctx<'_, Runtime>,
1207 inputs: &mut CreateInputs,
1208 ) -> Result<Option<CreateOutcome>, ExecutionError> {
1209 if !self.db.is_revm_instantiated {
1210 self.db.is_revm_instantiated = true;
1211 inputs.scheme = CreateScheme::Custom {
1212 address: self.contract_address,
1213 };
1214 Ok(None)
1215 } else {
1216 Err(EvmExecutionError::NoContractCreationInService.into())
1217 }
1218 }
1219
1220 fn call_or_fail(
1233 &mut self,
1234 context: &mut Ctx<'_, Runtime>,
1235 inputs: &mut CallInputs,
1236 ) -> Result<Option<CallOutcome>, ExecutionError> {
1237 if self.precompile_addresses.contains(&inputs.target_address)
1238 || inputs.target_address == self.contract_address
1239 {
1240 return Ok(None);
1243 }
1244 let target = address_to_user_application_id(inputs.target_address);
1246 let argument = get_call_argument(context, inputs);
1247 let result = {
1248 let evm_query = EvmQuery::Query(argument);
1249 let evm_query = serde_json::to_vec(&evm_query)?;
1250 let mut runtime = self.db.runtime.lock().unwrap();
1251 runtime.try_query_application(target, evm_query)?
1252 };
1253 let call_outcome = CallOutcome {
1254 result: get_interpreter_result(&result, inputs)?,
1255 memory_offset: inputs.return_memory_offset.clone(),
1256 };
1257 Ok(Some(call_outcome))
1258 }
1259}
1260
1261pub struct RevmContractInstance<Runtime> {
1262 module: Vec<u8>,
1263 db: DatabaseRuntime<Runtime>,
1264}
1265
1266#[derive(Debug)]
1267enum EvmTxKind {
1268 Create,
1269 Call,
1270}
1271
1272#[derive(Debug)]
1273struct ExecutionResultSuccess {
1274 reason: SuccessReason,
1275 gas_final: u64,
1276 logs: Vec<Log>,
1277 output: Output,
1278}
1279
1280impl ExecutionResultSuccess {
1281 fn interpreter_result_and_logs(self) -> Result<(u64, Vec<u8>, Vec<Log>), ExecutionError> {
1282 let result: InstructionResult = self.reason.into();
1283 let Output::Call(output) = self.output else {
1284 unreachable!("The output should have been created from a EvmTxKind::Call");
1285 };
1286 let gas = Gas::new(0);
1287 let result = InterpreterResult {
1288 result,
1289 output,
1290 gas,
1291 };
1292 let result = bcs::to_bytes(&result)?;
1293 Ok((self.gas_final, result, self.logs))
1294 }
1295
1296 fn output_and_logs(self) -> (u64, Vec<u8>, Vec<Log>) {
1297 let Output::Call(output) = self.output else {
1298 unreachable!("The output should have been created from a EvmTxKind::Call");
1299 };
1300 let output = output.as_ref().to_vec();
1301 (self.gas_final, output, self.logs)
1302 }
1303
1304 fn check_contract_initialization(&self, expected_address: Address) -> Result<(), String> {
1306 let Output::Create(_, contract_address) = self.output else {
1308 return Err("Input should be ExmTxKind::Create".to_string());
1309 };
1310 let contract_address = contract_address.ok_or("Deployment failed")?;
1312 if contract_address == expected_address {
1314 Ok(())
1315 } else {
1316 Err("Contract address is not the same as ApplicationId".to_string())
1317 }
1318 }
1319}
1320
1321impl<Runtime> UserContract for RevmContractInstance<Runtime>
1322where
1323 Runtime: ContractRuntime,
1324{
1325 fn instantiate(&mut self, argument: Vec<u8>) -> Result<(), ExecutionError> {
1326 self.db.set_contract_address()?;
1327 let caller = self.get_msg_address()?;
1328 self.initialize_contract(caller)?;
1329 if has_selector(&self.module, INSTANTIATE_SELECTOR) {
1330 let instantiation_argument = serde_json::from_slice::<Vec<u8>>(&argument)?;
1331 let argument = get_revm_instantiation_bytes(instantiation_argument);
1332 let result = self.transact_commit(EvmTxKind::Call, argument, caller)?;
1333 self.write_logs(result.logs, "instantiate")?;
1334 }
1335 Ok(())
1336 }
1337
1338 fn execute_operation(&mut self, operation: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1339 self.db.set_contract_address()?;
1340 ensure_message_length(operation.len(), 4)?;
1341 if operation == GET_DEPLOYED_BYTECODE_SELECTOR {
1342 return self.db.get_deployed_bytecode();
1343 }
1344 let caller = self.get_msg_address()?;
1345 let (gas_final, output, logs) = if &operation[..4] == INTERPRETER_RESULT_SELECTOR {
1346 ensure_message_length(operation.len(), 8)?;
1347 forbid_execute_operation_origin(&operation[4..8])?;
1348 let result = self.init_transact_commit(operation[4..].to_vec(), caller)?;
1349 result.interpreter_result_and_logs()?
1350 } else {
1351 ensure_message_length(operation.len(), 4)?;
1352 forbid_execute_operation_origin(&operation[..4])?;
1353 let result = self.init_transact_commit(operation, caller)?;
1354 result.output_and_logs()
1355 };
1356 self.consume_fuel(gas_final)?;
1357 self.write_logs(logs, "operation")?;
1358 Ok(output)
1359 }
1360
1361 fn execute_message(&mut self, message: Vec<u8>) -> Result<(), ExecutionError> {
1362 self.db.set_contract_address()?;
1363 ensure_selector_presence(
1364 &self.module,
1365 EXECUTE_MESSAGE_SELECTOR,
1366 "function execute_message(bytes)",
1367 )?;
1368 let operation = get_revm_execute_message_bytes(message);
1369 let caller = self.get_msg_address()?;
1370 self.execute_no_return_operation(operation, "message", caller)
1371 }
1372
1373 fn process_streams(&mut self, streams: Vec<StreamUpdate>) -> Result<(), ExecutionError> {
1374 self.db.set_contract_address()?;
1375 let operation = get_revm_process_streams_bytes(streams);
1376 ensure_selector_presence(
1377 &self.module,
1378 PROCESS_STREAMS_SELECTOR,
1379 "function process_streams(Linera.StreamUpdate[] memory streams)",
1380 )?;
1381 let caller = Address::ZERO;
1383 self.execute_no_return_operation(operation, "process_streams", caller)
1384 }
1385
1386 fn finalize(&mut self) -> Result<(), ExecutionError> {
1387 Ok(())
1388 }
1389}
1390
1391fn process_execution_result(
1392 storage_stats: StorageStats,
1393 result: ExecutionResult,
1394) -> Result<ExecutionResultSuccess, EvmExecutionError> {
1395 match result {
1396 ExecutionResult::Success {
1397 reason,
1398 gas_used,
1399 gas_refunded,
1400 logs,
1401 output,
1402 } => {
1403 let mut gas_final = gas_used;
1404 gas_final -= storage_stats.storage_costs();
1405 assert_eq!(gas_refunded, storage_stats.storage_refund());
1406 if !matches!(reason, SuccessReason::Return) {
1407 Err(EvmExecutionError::NoReturnInterpreter {
1408 reason,
1409 gas_used,
1410 gas_refunded,
1411 logs,
1412 output,
1413 })
1414 } else {
1415 Ok(ExecutionResultSuccess {
1416 reason,
1417 gas_final,
1418 logs,
1419 output,
1420 })
1421 }
1422 }
1423 ExecutionResult::Revert { gas_used, output } => {
1424 Err(EvmExecutionError::Revert { gas_used, output })
1425 }
1426 ExecutionResult::Halt { gas_used, reason } => {
1427 Err(EvmExecutionError::Halt { gas_used, reason })
1428 }
1429 }
1430}
1431
1432impl<Runtime> RevmContractInstance<Runtime>
1433where
1434 Runtime: ContractRuntime,
1435{
1436 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1437 let db = DatabaseRuntime::new(runtime);
1438 Self { module, db }
1439 }
1440
1441 fn execute_no_return_operation(
1442 &mut self,
1443 operation: Vec<u8>,
1444 origin: &str,
1445 caller: Address,
1446 ) -> Result<(), ExecutionError> {
1447 let result = self.init_transact_commit(operation, caller)?;
1448 let (gas_final, output, logs) = result.output_and_logs();
1449 self.consume_fuel(gas_final)?;
1450 self.write_logs(logs, origin)?;
1451 assert_eq!(output.len(), 0);
1452 Ok(())
1453 }
1454
1455 fn init_transact_commit(
1457 &mut self,
1458 vec: Vec<u8>,
1459 caller: Address,
1460 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1461 if !self.db.set_is_initialized()? {
1465 self.initialize_contract(caller)?;
1466 }
1467 self.transact_commit(EvmTxKind::Call, vec, caller)
1468 }
1469
1470 fn initialize_contract(&mut self, caller: Address) -> Result<(), ExecutionError> {
1472 let mut vec_init = self.module.clone();
1473 let constructor_argument = self.db.constructor_argument()?;
1474 vec_init.extend_from_slice(&constructor_argument);
1475 let result = self.transact_commit(EvmTxKind::Create, vec_init, caller)?;
1476 result
1477 .check_contract_initialization(self.db.contract_address)
1478 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1479 self.write_logs(result.logs, "deploy")
1480 }
1481
1482 fn get_msg_address(&self) -> Result<Address, ExecutionError> {
1495 let mut runtime = self.db.runtime.lock().unwrap();
1496 let application_id = runtime.authenticated_caller_id()?;
1497 if let Some(application_id) = application_id {
1498 return Ok(if application_id.is_evm() {
1499 application_id.evm_address()
1500 } else {
1501 Address::ZERO
1502 });
1503 };
1504 let account_owner = runtime.authenticated_signer()?;
1505 if let Some(AccountOwner::Address20(address)) = account_owner {
1506 return Ok(Address::from(address));
1507 };
1508 Ok(ZERO_ADDRESS)
1509 }
1510
1511 fn transact_commit(
1512 &mut self,
1513 ch: EvmTxKind,
1514 input: Vec<u8>,
1515 caller: Address,
1516 ) -> Result<ExecutionResultSuccess, ExecutionError> {
1517 let data = Bytes::from(input);
1518 let kind = match ch {
1519 EvmTxKind::Create => TxKind::Create,
1520 EvmTxKind::Call => TxKind::Call(self.db.contract_address),
1521 };
1522 let inspector = CallInterceptorContract {
1523 db: self.db.clone(),
1524 contract_address: self.db.contract_address,
1525 precompile_addresses: precompile_addresses(),
1526 };
1527 let block_env = self.db.get_contract_block_env()?;
1528 let gas_limit = {
1529 let mut runtime = self.db.runtime.lock().unwrap();
1530 runtime.remaining_fuel(VmRuntime::Evm)?
1531 };
1532 let nonce = self.db.get_nonce(&caller)?;
1533 let result = {
1534 let ctx: revm_context::Context<
1535 BlockEnv,
1536 _,
1537 _,
1538 _,
1539 Journal<WrapDatabaseRef<&mut DatabaseRuntime<Runtime>>>,
1540 (),
1541 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1542 WrapDatabaseRef(&mut self.db),
1543 SpecId::PRAGUE,
1544 )
1545 .with_block(block_env);
1546 let instructions = EthInstructions::new_mainnet();
1547 let mut evm = Evm::new_with_inspector(
1548 ctx,
1549 inspector.clone(),
1550 instructions,
1551 ContractPrecompile::default(),
1552 );
1553 evm.inspect_commit(
1554 TxEnv {
1555 kind,
1556 data,
1557 nonce,
1558 gas_limit,
1559 caller,
1560 ..TxEnv::default()
1561 },
1562 inspector,
1563 )
1564 .map_err(|error| {
1565 let error = format!("{:?}", error);
1566 EvmExecutionError::TransactCommitError(error)
1567 })
1568 }?;
1569 self.db.process_any_error()?;
1570 let storage_stats = self.db.take_storage_stats();
1571 self.db.commit_changes()?;
1572 let result = process_execution_result(storage_stats, result)?;
1573 Ok(result)
1574 }
1575
1576 fn consume_fuel(&mut self, gas_final: u64) -> Result<(), ExecutionError> {
1577 let mut runtime = self.db.runtime.lock().unwrap();
1578 runtime.consume_fuel(gas_final, VmRuntime::Evm)
1579 }
1580
1581 fn write_logs(&mut self, logs: Vec<Log>, origin: &str) -> Result<(), ExecutionError> {
1582 if !logs.is_empty() {
1584 let mut runtime = self.db.runtime.lock().unwrap();
1585 let block_height = runtime.block_height()?;
1586 let stream_name = bcs::to_bytes("ethereum_event")?;
1587 let stream_name = StreamName(stream_name);
1588 for log in &logs {
1589 let value = bcs::to_bytes(&(origin, block_height.0, log))?;
1590 runtime.emit(stream_name.clone(), value)?;
1591 }
1592 }
1593 Ok(())
1594 }
1595}
1596
1597pub struct RevmServiceInstance<Runtime> {
1598 module: Vec<u8>,
1599 db: DatabaseRuntime<Runtime>,
1600}
1601
1602impl<Runtime> RevmServiceInstance<Runtime>
1603where
1604 Runtime: ServiceRuntime,
1605{
1606 pub fn prepare(module: Vec<u8>, runtime: Runtime) -> Self {
1607 let db = DatabaseRuntime::new(runtime);
1608 Self { module, db }
1609 }
1610}
1611
1612impl<Runtime> UserService for RevmServiceInstance<Runtime>
1613where
1614 Runtime: ServiceRuntime,
1615{
1616 fn handle_query(&mut self, argument: Vec<u8>) -> Result<Vec<u8>, ExecutionError> {
1617 self.db.set_contract_address()?;
1618 let evm_query = serde_json::from_slice(&argument)?;
1619 let query = match evm_query {
1620 EvmQuery::Query(vec) => vec,
1621 EvmQuery::Mutation(operation) => {
1622 let mut runtime = self.db.runtime.lock().unwrap();
1623 runtime.schedule_operation(operation)?;
1624 return Ok(Vec::new());
1625 }
1626 };
1627
1628 ensure_message_length(query.len(), 4)?;
1629 let answer = if &query[..4] == INTERPRETER_RESULT_SELECTOR {
1633 let result = self.init_transact(query[4..].to_vec())?;
1634 let (_gas_final, answer, _logs) = result.interpreter_result_and_logs()?;
1635 answer
1636 } else {
1637 let result = self.init_transact(query)?;
1638 let (_gas_final, output, _logs) = result.output_and_logs();
1639 serde_json::to_vec(&output)?
1640 };
1641 Ok(answer)
1642 }
1643}
1644
1645impl<Runtime> RevmServiceInstance<Runtime>
1646where
1647 Runtime: ServiceRuntime,
1648{
1649 fn init_transact(&mut self, vec: Vec<u8>) -> Result<ExecutionResultSuccess, ExecutionError> {
1650 if !self.db.set_is_initialized()? {
1654 let changes = {
1655 let mut vec_init = self.module.clone();
1656 let constructor_argument = self.db.constructor_argument()?;
1657 vec_init.extend_from_slice(&constructor_argument);
1658 let (result, changes) = self.transact(TxKind::Create, vec_init)?;
1659 result
1660 .check_contract_initialization(self.db.contract_address)
1661 .map_err(EvmExecutionError::IncorrectContractCreation)?;
1662 changes
1663 };
1664 self.db.changes = changes;
1665 }
1666 ensure_message_length(vec.len(), 4)?;
1667 forbid_execute_operation_origin(&vec[..4])?;
1668 let kind = TxKind::Call(self.db.contract_address);
1669 let (execution_result, _) = self.transact(kind, vec)?;
1670 Ok(execution_result)
1671 }
1672
1673 fn transact(
1674 &mut self,
1675 kind: TxKind,
1676 input: Vec<u8>,
1677 ) -> Result<(ExecutionResultSuccess, EvmState), ExecutionError> {
1678 let data = Bytes::from(input);
1679 let block_env = self.db.get_service_block_env()?;
1680 let inspector = CallInterceptorService {
1681 db: self.db.clone(),
1682 contract_address: self.db.contract_address,
1683 precompile_addresses: precompile_addresses(),
1684 };
1685 let caller = SERVICE_ADDRESS;
1686 let nonce = self.db.get_nonce(&caller)?;
1687 let result_state = {
1688 let ctx: revm_context::Context<
1689 BlockEnv,
1690 _,
1691 _,
1692 _,
1693 Journal<WrapDatabaseRef<&mut DatabaseRuntime<Runtime>>>,
1694 (),
1695 > = revm_context::Context::<BlockEnv, _, _, _, _, _>::new(
1696 WrapDatabaseRef(&mut self.db),
1697 SpecId::PRAGUE,
1698 )
1699 .with_block(block_env);
1700 let instructions = EthInstructions::new_mainnet();
1701 let mut evm = Evm::new_with_inspector(
1702 ctx,
1703 inspector.clone(),
1704 instructions,
1705 ServicePrecompile::default(),
1706 );
1707 evm.inspect(
1708 TxEnv {
1709 kind,
1710 data,
1711 nonce,
1712 caller,
1713 gas_limit: EVM_SERVICE_GAS_LIMIT,
1714 ..TxEnv::default()
1715 },
1716 inspector,
1717 )
1718 .map_err(|error| {
1719 let error = format!("{:?}", error);
1720 EvmExecutionError::TransactCommitError(error)
1721 })
1722 }?;
1723 self.db.process_any_error()?;
1724 let storage_stats = self.db.take_storage_stats();
1725 Ok((
1726 process_execution_result(storage_stats, result_state.result)?,
1727 result_state.state,
1728 ))
1729 }
1730}