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_committee() -> Committee {
41 Committee::make_simple(vec![(
42 ValidatorPublicKey::test_key(0),
43 AccountPublicKey::test_key(0),
44 )])
45}
46
47pub fn dummy_committees() -> BTreeMap<Epoch, Committee> {
48 let committee = dummy_committee();
49 BTreeMap::from([(Epoch::ZERO, committee)])
50}
51
52pub fn dummy_chain_description_with_ownership_and_balance(
53 index: u32,
54 ownership: ChainOwnership,
55 balance: Amount,
56) -> ChainDescription {
57 let origin = ChainOrigin::Root(index);
58 let config = InitialChainConfig {
59 application_permissions: Default::default(),
60 balance,
61 epoch: Epoch::ZERO,
62 min_active_epoch: Epoch::ZERO,
63 max_active_epoch: Epoch::ZERO,
64 ownership,
65 };
66 ChainDescription::new(origin, config, Timestamp::default())
67}
68
69pub fn dummy_chain_description_with_owner(index: u32, owner: AccountOwner) -> ChainDescription {
70 dummy_chain_description_with_ownership_and_balance(
71 index,
72 ChainOwnership::single(owner),
73 Amount::MAX,
74 )
75}
76
77pub fn dummy_chain_description(index: u32) -> ChainDescription {
78 let chain_key = AccountPublicKey::test_key(2 * (index % 128) as u8 + 1);
79 let ownership = ChainOwnership::single(chain_key.into());
80 dummy_chain_description_with_ownership_and_balance(index, ownership, Amount::MAX)
81}
82
83pub fn create_dummy_user_application_description(
85 index: u32,
86) -> (ApplicationDescription, Blob, Blob) {
87 let chain_id = dummy_chain_description(1).id();
88 let mut contract_bytes = b"contract".to_vec();
89 let mut service_bytes = b"service".to_vec();
90 contract_bytes.push(index as u8);
91 service_bytes.push(index as u8);
92 let contract_blob = Blob::new_contract_bytecode(CompressedBytecode {
93 compressed_bytes: contract_bytes,
94 });
95 let service_blob = Blob::new_service_bytecode(CompressedBytecode {
96 compressed_bytes: service_bytes,
97 });
98
99 let vm_runtime = VmRuntime::Wasm;
100 (
101 ApplicationDescription {
102 module_id: ModuleId::new(contract_blob.id().hash, service_blob.id().hash, vm_runtime),
103 creator_chain_id: chain_id,
104 block_height: 0.into(),
105 application_index: index,
106 required_application_ids: vec![],
107 parameters: vec![],
108 },
109 contract_blob,
110 service_blob,
111 )
112}
113
114pub fn create_dummy_operation_context(chain_id: ChainId) -> OperationContext {
116 OperationContext {
117 chain_id,
118 height: BlockHeight(0),
119 round: Some(0),
120 authenticated_signer: None,
121 authenticated_caller_id: None,
122 timestamp: Default::default(),
123 }
124}
125
126pub fn create_dummy_message_context(
128 chain_id: ChainId,
129 authenticated_signer: Option<AccountOwner>,
130) -> MessageContext {
131 MessageContext {
132 chain_id,
133 is_bouncing: false,
134 authenticated_signer,
135 refund_grant_to: None,
136 height: BlockHeight(0),
137 round: Some(0),
138 message_id: MessageId {
139 chain_id,
140 height: BlockHeight(0),
141 index: 0,
142 },
143 timestamp: Default::default(),
144 }
145}
146
147pub fn create_dummy_query_context() -> QueryContext {
149 QueryContext {
150 chain_id: dummy_chain_description(0).id(),
151 next_block_height: BlockHeight(0),
152 local_time: Timestamp::from(0),
153 }
154}
155
156#[allow(async_fn_in_trait)]
158pub trait RegisterMockApplication {
159 fn creator_chain_id(&self) -> ChainId;
163
164 async fn register_mock_application(
167 &mut self,
168 index: u32,
169 ) -> anyhow::Result<(ApplicationId, MockApplication, [BlobId; 3])> {
170 let (description, contract, service) = create_dummy_user_application_description(index);
171 let description_blob_id = Blob::new_application_description(&description).id();
172 let contract_blob_id = contract.id();
173 let service_blob_id = service.id();
174
175 let (app_id, application) = self
176 .register_mock_application_with(description, contract, service)
177 .await?;
178 Ok((
179 app_id,
180 application,
181 [description_blob_id, contract_blob_id, service_blob_id],
182 ))
183 }
184
185 async fn register_mock_application_with(
188 &mut self,
189 description: ApplicationDescription,
190 contract: Blob,
191 service: Blob,
192 ) -> anyhow::Result<(ApplicationId, MockApplication)>;
193}
194
195impl<C> RegisterMockApplication for ExecutionStateView<C>
196where
197 C: Context + Clone + Send + Sync + 'static,
198 C::Extra: ExecutionRuntimeContext,
199{
200 fn creator_chain_id(&self) -> ChainId {
201 self.system.creator_chain_id()
202 }
203
204 async fn register_mock_application_with(
205 &mut self,
206 description: ApplicationDescription,
207 contract: Blob,
208 service: Blob,
209 ) -> anyhow::Result<(ApplicationId, MockApplication)> {
210 self.system
211 .register_mock_application_with(description, contract, service)
212 .await
213 }
214}
215
216impl<C> RegisterMockApplication for SystemExecutionStateView<C>
217where
218 C: Context + Clone + Send + Sync + 'static,
219 C::Extra: ExecutionRuntimeContext,
220{
221 fn creator_chain_id(&self) -> ChainId {
222 self.description.get().as_ref().expect(
223 "Can't register applications on a system state with no associated `ChainDescription`",
224 ).into()
225 }
226
227 async fn register_mock_application_with(
228 &mut self,
229 description: ApplicationDescription,
230 contract: Blob,
231 service: Blob,
232 ) -> anyhow::Result<(ApplicationId, MockApplication)> {
233 let id = From::from(&description);
234 let extra = self.context().extra();
235 let mock_application = MockApplication::default();
236
237 extra
238 .user_contracts()
239 .insert(id, mock_application.clone().into());
240 extra
241 .user_services()
242 .insert(id, mock_application.clone().into());
243 extra
244 .add_blobs([
245 contract,
246 service,
247 Blob::new_application_description(&description),
248 ])
249 .await?;
250
251 Ok((id, mock_application))
252 }
253}
254
255pub async fn create_dummy_user_application_registrations(
256 count: u32,
257) -> anyhow::Result<Vec<(ApplicationId, ApplicationDescription, Blob, Blob)>> {
258 let mut ids = Vec::with_capacity(count as usize);
259
260 for index in 0..count {
261 let (description, contract_blob, service_blob) =
262 create_dummy_user_application_description(index);
263 let id = From::from(&description);
264
265 ids.push((id, description, contract_blob, service_blob));
266 }
267
268 Ok(ids)
269}
270
271impl QueryContext {
272 pub fn spawn_service_runtime_actor(self) -> ServiceRuntimeEndpoint {
276 let (execution_state_sender, incoming_execution_requests) =
277 futures::channel::mpsc::unbounded();
278 let (runtime_request_sender, runtime_request_receiver) = std::sync::mpsc::channel();
279
280 thread::spawn(move || {
281 ServiceSyncRuntime::new(execution_state_sender, self).run(runtime_request_receiver)
282 });
283
284 ServiceRuntimeEndpoint {
285 incoming_execution_requests,
286 runtime_request_sender,
287 }
288 }
289}
290
291pub fn test_accounts_strategy() -> impl Strategy<Value = BTreeMap<AccountOwner, Amount>> {
294 proptest::collection::btree_map(
295 any::<AccountOwner>(),
296 (1_u128..).prop_map(Amount::from_tokens),
297 0..5,
298 )
299}
300
301pub fn blob_oracle_responses<'a>(blobs: impl Iterator<Item = &'a BlobId>) -> Vec<OracleResponse> {
303 blobs
304 .into_iter()
305 .copied()
306 .map(OracleResponse::Blob)
307 .collect()
308}