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