1#![allow(unused_imports)]
7
8mod mock_application;
9#[cfg(with_revm)]
10pub mod solidity;
11mod system_execution_state;
12
13use std::{collections::BTreeMap, sync::Arc, thread, vec};
14
15use linera_base::{
16 crypto::{AccountPublicKey, BcsSignable, CryptoHash, ValidatorPublicKey},
17 data_types::{
18 Amount, Blob, BlockHeight, ChainDescription, ChainOrigin, CompressedBytecode, Epoch,
19 InitialChainConfig, OracleResponse, Timestamp,
20 },
21 identifiers::{AccountOwner, ApplicationId, BlobId, BlobType, ChainId, MessageId, ModuleId},
22 ownership::ChainOwnership,
23 vm::VmRuntime,
24};
25use linera_views::{context::Context, views::View, ViewError};
26use proptest::{prelude::any, strategy::Strategy};
27use serde::{Deserialize, Serialize};
28
29pub use self::{
30 mock_application::{ExpectedCall, MockApplication, MockApplicationInstance},
31 system_execution_state::SystemExecutionState,
32};
33use crate::{
34 committee::Committee, ApplicationDescription, ExecutionRequest, ExecutionRuntimeContext,
35 ExecutionStateView, MessageContext, OperationContext, QueryContext, ServiceRuntimeEndpoint,
36 ServiceRuntimeRequest, ServiceSyncRuntime, SystemExecutionStateView,
37 TestExecutionRuntimeContext,
38};
39
40pub fn dummy_chain_description_with_ownership_and_balance(
41 index: u32,
42 ownership: ChainOwnership,
43 balance: Amount,
44) -> ChainDescription {
45 let committee = Committee::make_simple(vec![(
46 ValidatorPublicKey::test_key(index as u8),
47 AccountPublicKey::test_key(2 * (index % 128) as u8),
48 )]);
49 let committees = BTreeMap::from([(
50 Epoch::ZERO,
51 bcs::to_bytes(&committee).expect("serializing a committee shouldn't fail"),
52 )]);
53 let origin = ChainOrigin::Root(index);
54 let config = InitialChainConfig {
55 application_permissions: Default::default(),
56 balance,
57 committees,
58 epoch: Epoch::ZERO,
59 ownership,
60 };
61 ChainDescription::new(origin, config, Timestamp::default())
62}
63
64pub fn dummy_chain_description_with_owner(index: u32, owner: AccountOwner) -> ChainDescription {
65 dummy_chain_description_with_ownership_and_balance(
66 index,
67 ChainOwnership::single(owner),
68 Amount::MAX,
69 )
70}
71
72pub fn dummy_chain_description(index: u32) -> ChainDescription {
73 let chain_key = AccountPublicKey::test_key(2 * (index % 128) as u8 + 1);
74 let ownership = ChainOwnership::single(chain_key.into());
75 dummy_chain_description_with_ownership_and_balance(index, ownership, Amount::MAX)
76}
77
78pub fn create_dummy_user_application_description(
80 index: u32,
81) -> (ApplicationDescription, Blob, Blob) {
82 let chain_id = dummy_chain_description(1).id();
83 let mut contract_bytes = b"contract".to_vec();
84 let mut service_bytes = b"service".to_vec();
85 contract_bytes.push(index as u8);
86 service_bytes.push(index as u8);
87 let contract_blob = Blob::new_contract_bytecode(CompressedBytecode {
88 compressed_bytes: contract_bytes,
89 });
90 let service_blob = Blob::new_service_bytecode(CompressedBytecode {
91 compressed_bytes: service_bytes,
92 });
93
94 let vm_runtime = VmRuntime::Wasm;
95 (
96 ApplicationDescription {
97 module_id: ModuleId::new(contract_blob.id().hash, service_blob.id().hash, vm_runtime),
98 creator_chain_id: chain_id,
99 block_height: 0.into(),
100 application_index: index,
101 required_application_ids: vec![],
102 parameters: vec![],
103 },
104 contract_blob,
105 service_blob,
106 )
107}
108
109pub fn create_dummy_operation_context(chain_id: ChainId) -> OperationContext {
111 OperationContext {
112 chain_id,
113 height: BlockHeight(0),
114 round: Some(0),
115 authenticated_signer: None,
116 authenticated_caller_id: None,
117 timestamp: Default::default(),
118 }
119}
120
121pub fn create_dummy_message_context(
123 chain_id: ChainId,
124 authenticated_signer: Option<AccountOwner>,
125) -> MessageContext {
126 MessageContext {
127 chain_id,
128 is_bouncing: false,
129 authenticated_signer,
130 refund_grant_to: None,
131 height: BlockHeight(0),
132 round: Some(0),
133 message_id: MessageId {
134 chain_id,
135 height: BlockHeight(0),
136 index: 0,
137 },
138 timestamp: Default::default(),
139 }
140}
141
142pub fn create_dummy_query_context() -> QueryContext {
144 QueryContext {
145 chain_id: dummy_chain_description(0).id(),
146 next_block_height: BlockHeight(0),
147 local_time: Timestamp::from(0),
148 }
149}
150
151#[allow(async_fn_in_trait)]
153pub trait RegisterMockApplication {
154 fn creator_chain_id(&self) -> ChainId;
158
159 async fn register_mock_application(
162 &mut self,
163 index: u32,
164 ) -> anyhow::Result<(ApplicationId, MockApplication, [BlobId; 3])> {
165 let (description, contract, service) = create_dummy_user_application_description(index);
166 let description_blob_id = Blob::new_application_description(&description).id();
167 let contract_blob_id = contract.id();
168 let service_blob_id = service.id();
169
170 let (app_id, application) = self
171 .register_mock_application_with(description, contract, service)
172 .await?;
173 Ok((
174 app_id,
175 application,
176 [description_blob_id, contract_blob_id, service_blob_id],
177 ))
178 }
179
180 async fn register_mock_application_with(
183 &mut self,
184 description: ApplicationDescription,
185 contract: Blob,
186 service: Blob,
187 ) -> anyhow::Result<(ApplicationId, MockApplication)>;
188}
189
190impl<C> RegisterMockApplication for ExecutionStateView<C>
191where
192 C: Context + Clone + Send + Sync + 'static,
193 C::Extra: ExecutionRuntimeContext,
194{
195 fn creator_chain_id(&self) -> ChainId {
196 self.system.creator_chain_id()
197 }
198
199 async fn register_mock_application_with(
200 &mut self,
201 description: ApplicationDescription,
202 contract: Blob,
203 service: Blob,
204 ) -> anyhow::Result<(ApplicationId, MockApplication)> {
205 self.system
206 .register_mock_application_with(description, contract, service)
207 .await
208 }
209}
210
211impl<C> RegisterMockApplication for SystemExecutionStateView<C>
212where
213 C: Context + Clone + Send + Sync + 'static,
214 C::Extra: ExecutionRuntimeContext,
215{
216 fn creator_chain_id(&self) -> ChainId {
217 self.description.get().as_ref().expect(
218 "Can't register applications on a system state with no associated `ChainDescription`",
219 ).into()
220 }
221
222 async fn register_mock_application_with(
223 &mut self,
224 description: ApplicationDescription,
225 contract: Blob,
226 service: Blob,
227 ) -> anyhow::Result<(ApplicationId, MockApplication)> {
228 let id = From::from(&description);
229 let extra = self.context().extra();
230 let mock_application = MockApplication::default();
231
232 extra
233 .user_contracts()
234 .insert(id, mock_application.clone().into());
235 extra
236 .user_services()
237 .insert(id, mock_application.clone().into());
238 extra
239 .add_blobs([
240 contract,
241 service,
242 Blob::new_application_description(&description),
243 ])
244 .await?;
245
246 Ok((id, mock_application))
247 }
248}
249
250pub async fn create_dummy_user_application_registrations(
251 count: u32,
252) -> anyhow::Result<Vec<(ApplicationId, ApplicationDescription, Blob, Blob)>> {
253 let mut ids = Vec::with_capacity(count as usize);
254
255 for index in 0..count {
256 let (description, contract_blob, service_blob) =
257 create_dummy_user_application_description(index);
258 let id = From::from(&description);
259
260 ids.push((id, description, contract_blob, service_blob));
261 }
262
263 Ok(ids)
264}
265
266impl QueryContext {
267 pub fn spawn_service_runtime_actor(self) -> ServiceRuntimeEndpoint {
271 let (execution_state_sender, incoming_execution_requests) =
272 futures::channel::mpsc::unbounded();
273 let (runtime_request_sender, runtime_request_receiver) = std::sync::mpsc::channel();
274
275 thread::spawn(move || {
276 ServiceSyncRuntime::new(execution_state_sender, self).run(runtime_request_receiver)
277 });
278
279 ServiceRuntimeEndpoint {
280 incoming_execution_requests,
281 runtime_request_sender,
282 }
283 }
284}
285
286pub fn test_accounts_strategy() -> impl Strategy<Value = BTreeMap<AccountOwner, Amount>> {
289 proptest::collection::btree_map(
290 any::<AccountOwner>(),
291 (1_u128..).prop_map(Amount::from_tokens),
292 0..5,
293 )
294}
295
296pub fn blob_oracle_responses<'a>(blobs: impl Iterator<Item = &'a BlobId>) -> Vec<OracleResponse> {
298 blobs
299 .into_iter()
300 .copied()
301 .map(OracleResponse::Blob)
302 .collect()
303}