linera_execution/evm/
inputs.rs1use alloy_primitives::Bytes;
8use linera_base::{
9 crypto::CryptoHash,
10 data_types::StreamUpdate,
11 ensure,
12 identifiers::{ApplicationId, ChainId, GenericApplicationId, StreamId, StreamName},
13};
14use revm_primitives::{address, Address, B256, U256};
15
16use crate::EvmExecutionError;
17
18alloy_sol_types::sol! {
19 struct InternalApplicationId {
20 bytes32 application_description_hash;
21 }
22
23 struct InternalGenericApplicationId {
24 uint8 choice;
25 InternalApplicationId user;
26 }
27
28 struct InternalStreamName {
29 bytes stream_name;
30 }
31
32 struct InternalStreamId {
33 InternalGenericApplicationId application_id;
34 InternalStreamName stream_name;
35 }
36
37 struct InternalChainId {
38 bytes32 value;
39 }
40
41 struct InternalStreamUpdate {
42 InternalChainId chain_id;
43 InternalStreamId stream_id;
44 uint32 previous_index;
45 uint32 next_index;
46 }
47
48 function process_streams(InternalStreamUpdate[] internal_streams);
49
50 function summarize_events(InternalStreamUpdate[] internal_streams);
51}
52
53fn crypto_hash_to_internal_crypto_hash(hash: CryptoHash) -> B256 {
54 let hash = <[u64; 4]>::from(hash);
55 let hash = linera_base::crypto::u64_array_to_be_bytes(hash);
56 hash.into()
57}
58
59impl From<ApplicationId> for InternalApplicationId {
60 fn from(application_id: ApplicationId) -> InternalApplicationId {
61 let application_description_hash =
62 crypto_hash_to_internal_crypto_hash(application_id.application_description_hash);
63 InternalApplicationId {
64 application_description_hash,
65 }
66 }
67}
68
69impl From<GenericApplicationId> for InternalGenericApplicationId {
70 fn from(generic_application_id: GenericApplicationId) -> InternalGenericApplicationId {
71 match generic_application_id {
72 GenericApplicationId::System => {
73 let application_description_hash = B256::ZERO;
74 InternalGenericApplicationId {
75 choice: 0,
76 user: InternalApplicationId {
77 application_description_hash,
78 },
79 }
80 }
81 GenericApplicationId::User(application_id) => InternalGenericApplicationId {
82 choice: 1,
83 user: application_id.into(),
84 },
85 }
86 }
87}
88
89impl From<ChainId> for InternalChainId {
90 fn from(chain_id: ChainId) -> InternalChainId {
91 let value = crypto_hash_to_internal_crypto_hash(chain_id.0);
92 InternalChainId { value }
93 }
94}
95
96impl From<StreamName> for InternalStreamName {
97 fn from(stream_name: StreamName) -> InternalStreamName {
98 let stream_name = Bytes::from(stream_name.0);
99 InternalStreamName { stream_name }
100 }
101}
102
103impl From<StreamId> for InternalStreamId {
104 fn from(stream_id: StreamId) -> InternalStreamId {
105 let application_id = stream_id.application_id.into();
106 let stream_name = stream_id.stream_name.into();
107 InternalStreamId {
108 application_id,
109 stream_name,
110 }
111 }
112}
113
114impl From<StreamUpdate> for InternalStreamUpdate {
115 fn from(stream_update: StreamUpdate) -> InternalStreamUpdate {
116 let chain_id = stream_update.chain_id.into();
117 let stream_id = stream_update.stream_id.into();
118 InternalStreamUpdate {
119 chain_id,
120 stream_id,
121 previous_index: stream_update.previous_index,
122 next_index: stream_update.next_index,
123 }
124 }
125}
126
127pub(crate) const PRECOMPILE_ADDRESS: Address = address!("000000000000000000000000000000000000000b");
130
131pub(crate) const ZERO_ADDRESS: Address = address!("0000000000000000000000000000000000000000");
135
136pub(crate) const SERVICE_ADDRESS: Address = address!("0000000000000000000000000000000000002000");
138
139pub(crate) const FAUCET_ADDRESS: Address = address!("0000000000000000000000000000000000004000");
141pub(crate) const FAUCET_BALANCE: U256 = U256::from_limbs([
142 0xffffffffffffffff,
143 0xffffffffffffffff,
144 0xffffffffffffffff,
145 0x7fffffffffffffff,
146]);
147
148pub(crate) const EXECUTE_MESSAGE_SELECTOR: &[u8] = &[173, 125, 234, 205];
151
152pub(crate) const PROCESS_STREAMS_SELECTOR: &[u8] = &[254, 72, 102, 28];
155
156pub(crate) const SUMMARIZE_EVENTS_SELECTOR: &[u8] =
159 &<summarize_eventsCall as alloy_sol_types::SolCall>::SELECTOR;
160
161pub(crate) const INSTANTIATE_SELECTOR: &[u8] = &[156, 163, 60, 158];
164
165pub(crate) fn forbid_execute_operation_origin(vec: &[u8]) -> Result<(), EvmExecutionError> {
166 ensure!(
167 vec != EXECUTE_MESSAGE_SELECTOR,
168 EvmExecutionError::IllegalOperationCall("function execute_message".to_string(),)
169 );
170 ensure!(
171 vec != PROCESS_STREAMS_SELECTOR,
172 EvmExecutionError::IllegalOperationCall("function process_streams".to_string(),)
173 );
174 ensure!(
175 vec != SUMMARIZE_EVENTS_SELECTOR,
176 EvmExecutionError::IllegalOperationCall("function summarize_events".to_string(),)
177 );
178 ensure!(
179 vec != INSTANTIATE_SELECTOR,
180 EvmExecutionError::IllegalOperationCall("function instantiate".to_string(),)
181 );
182 Ok(())
183}
184
185pub(crate) fn ensure_message_length(
186 actual_length: usize,
187 min_length: usize,
188) -> Result<(), EvmExecutionError> {
189 ensure!(
190 actual_length >= min_length,
191 EvmExecutionError::OperationIsTooShort
192 );
193 Ok(())
194}
195
196pub(crate) fn ensure_selector_presence(
197 module: &[u8],
198 selector: &[u8],
199 fct_name: &str,
200) -> Result<(), EvmExecutionError> {
201 ensure!(
202 has_selector(module, selector),
203 EvmExecutionError::MissingFunction(fct_name.to_string())
204 );
205 Ok(())
206}
207
208pub(crate) fn has_selector(module: &[u8], selector: &[u8]) -> bool {
209 let push4 = 0x63; let mut vec = vec![push4];
211 vec.extend(selector);
212 module.windows(5).any(|window| window == vec)
213}
214
215pub(crate) fn get_revm_instantiation_bytes(value: Vec<u8>) -> Vec<u8> {
216 use alloy_primitives::Bytes;
217 use alloy_sol_types::{sol, SolCall};
218 sol! {
219 function instantiate(bytes value);
220 }
221 let bytes = Bytes::from(value);
222 let argument = instantiateCall { value: bytes };
223 argument.abi_encode()
224}
225
226pub(crate) fn get_revm_execute_message_bytes(value: Vec<u8>) -> Vec<u8> {
227 use alloy_primitives::Bytes;
228 use alloy_sol_types::{sol, SolCall};
229 sol! {
230 function execute_message(bytes value);
231 }
232 let value = Bytes::from(value);
233 let argument = execute_messageCall { value };
234 argument.abi_encode()
235}
236
237pub(crate) fn get_revm_process_streams_bytes(streams: Vec<StreamUpdate>) -> Vec<u8> {
238 use alloy_sol_types::SolCall;
239
240 let internal_streams = streams.into_iter().map(StreamUpdate::into).collect();
241
242 let fct_call = process_streamsCall { internal_streams };
243 fct_call.abi_encode()
244}
245
246pub(crate) fn get_revm_summarize_events_bytes(streams: Vec<StreamUpdate>) -> Vec<u8> {
247 use alloy_sol_types::SolCall;
248
249 let internal_streams = streams.into_iter().map(StreamUpdate::into).collect();
250
251 let fct_call = summarize_eventsCall { internal_streams };
252 fct_call.abi_encode()
253}
254
255#[cfg(test)]
256mod tests {
257 use revm_primitives::keccak256;
258
259 use crate::evm::inputs::{
260 process_streamsCall, EXECUTE_MESSAGE_SELECTOR, INSTANTIATE_SELECTOR,
261 PROCESS_STREAMS_SELECTOR,
262 };
263
264 #[test]
267 fn check_execute_message_selector() {
268 let selector = &keccak256("execute_message(bytes)".as_bytes())[..4];
269 assert_eq!(selector, EXECUTE_MESSAGE_SELECTOR);
270 }
271
272 #[test]
273 fn check_process_streams_selector() {
274 use alloy_sol_types::SolCall;
275 assert_eq!(
276 process_streamsCall::SIGNATURE,
277 "process_streams(((bytes32),((uint8,(bytes32)),(bytes)),uint32,uint32)[])"
278 );
279 assert_eq!(process_streamsCall::SELECTOR, PROCESS_STREAMS_SELECTOR);
280 }
281
282 #[test]
283 fn check_instantiate_selector() {
284 let selector = &keccak256("instantiate(bytes)".as_bytes())[..4];
285 assert_eq!(selector, INSTANTIATE_SELECTOR);
286 }
287}