1mod address_funds;
2mod contract_group_queries;
3mod data_contract_based_queries;
4mod document_history;
5mod document_query;
6mod group_queries;
7mod identity_based_queries;
8mod prefunded_specialized_balances;
9mod proofs;
10mod response_metadata;
11mod service;
12mod shielded;
13mod system;
14mod token_queries;
15mod validator_queries;
16mod voting;
17
18use crate::error::query::QueryError;
19
20use dpp::validation::ValidationResult;
21
22pub use service::QueryService;
23
24pub type QueryValidationResult<TData> = ValidationResult<TData, QueryError>;
26
27#[cfg(test)]
28pub(crate) mod tests {
29 use crate::error::query::QueryError;
30 use crate::platform_types::platform::Platform;
31 use crate::platform_types::platform_state::PlatformState;
32 use crate::platform_types::platform_state::PlatformStateV0Methods;
33 use crate::query::QueryValidationResult;
34 use crate::rpc::core::MockCoreRPCLike;
35 use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder};
36 use dpp::block::block_info::BlockInfo;
37 use dpp::data_contract::DataContract;
38
39 use crate::config::PlatformConfig;
40 use dpp::dashcore::Network;
41 use dpp::data_contract::document_type::DocumentTypeRef;
42 use dpp::document::Document;
43 use dpp::prelude::{CoreBlockHeight, TimestampMillis};
44 use drive::util::batch::DriveOperation::{DataContractOperation, DocumentOperation};
45 use drive::util::batch::{DataContractOperationType, DocumentOperationType};
46 use drive::util::object_size_info::{
47 DataContractInfo, DocumentInfo, DocumentTypeInfo, OwnedDocumentInfo,
48 };
49 use drive::util::storage_flags::StorageFlags;
50 use platform_version::version::{PlatformVersion, ProtocolVersion};
51 use std::borrow::Cow;
52 use std::sync::Arc;
53
54 pub fn setup_platform<'a>(
55 with_genesis_state: Option<(TimestampMillis, CoreBlockHeight)>,
56 network: Network,
57 initial_protocol_version: Option<ProtocolVersion>,
58 ) -> (
59 TempPlatform<MockCoreRPCLike>,
60 Arc<PlatformState>,
61 &'a PlatformVersion,
62 ) {
63 let platform = if let Some((timestamp, activation_core_block_height)) = with_genesis_state {
64 let mut platform_builder = TestPlatformBuilder::new()
65 .with_config(PlatformConfig::default_for_network(network));
66
67 if let Some(initial_protocol_version) = initial_protocol_version {
68 platform_builder =
69 platform_builder.with_initial_protocol_version(initial_protocol_version);
70 }
71
72 platform_builder
73 .build_with_mock_rpc()
74 .set_genesis_state_with_activation_info(timestamp, activation_core_block_height)
75 } else {
76 let mut platform_builder = TestPlatformBuilder::new()
77 .with_config(PlatformConfig::default_for_network(network));
78
79 if let Some(initial_protocol_version) = initial_protocol_version {
80 platform_builder =
81 platform_builder.with_initial_protocol_version(initial_protocol_version);
82 }
83
84 platform_builder
85 .build_with_mock_rpc()
86 .set_initial_state_structure()
87 };
88
89 let platform_state = platform.platform.state.load_full();
92
93 let platform_version = platform_state.current_platform_version().unwrap();
94
95 (platform, platform_state, platform_version)
96 }
97
98 pub fn store_data_contract(
99 platform: &Platform<MockCoreRPCLike>,
100 data_contract: &DataContract,
101 platform_version: &PlatformVersion,
102 ) {
103 let operation = DataContractOperation(DataContractOperationType::ApplyContract {
104 contract: Cow::Owned(data_contract.to_owned()),
105 storage_flags: None,
106 });
107
108 let block_info = BlockInfo::genesis();
109
110 platform
111 .drive
112 .apply_drive_operations(
113 vec![operation],
114 true,
115 &block_info,
116 None,
117 platform_version,
118 None,
119 )
120 .expect("expected to apply drive operations");
121 }
122
123 pub fn store_document(
124 platform: &Platform<MockCoreRPCLike>,
125 data_contract: &DataContract,
126 document_type: DocumentTypeRef,
127 document: &Document,
128 platform_version: &PlatformVersion,
129 ) {
130 let storage_flags = Some(Cow::Owned(StorageFlags::SingleEpoch(0)));
131
132 let operation = DocumentOperation(DocumentOperationType::AddDocument {
133 owned_document_info: OwnedDocumentInfo {
134 document_info: DocumentInfo::DocumentRefInfo((document, storage_flags)),
135 owner_id: None,
136 },
137 contract_info: DataContractInfo::BorrowedDataContract(data_contract),
138 document_type_info: DocumentTypeInfo::DocumentTypeRef(document_type),
139 override_document: false,
140 });
141
142 let block_info = BlockInfo::genesis();
143
144 platform
145 .drive
146 .apply_drive_operations(
147 vec![operation],
148 true,
149 &block_info,
150 None,
151 platform_version,
152 None,
153 )
154 .expect("expected to apply drive operations");
155 }
156
157 pub fn assert_invalid_identifier<TData: Clone>(
158 validation_result: QueryValidationResult<TData>,
159 ) {
160 assert!(matches!(
161 validation_result.errors.as_slice(),
162 [QueryError::InvalidArgument(msg)] if msg.contains("id must be a valid identifier (32 bytes long)")
163 ));
164 }
165
166 #[allow(clippy::type_complexity)]
176 pub fn setup_platform_with_token_state<'a>() -> (
177 TempPlatform<MockCoreRPCLike>,
178 Arc<PlatformState>,
179 &'a PlatformVersion,
180 [u8; 32],
181 [[u8; 32]; 3],
182 [[u8; 32]; 3],
183 ) {
184 use dpp::data_contract::associated_token::token_configuration::v0::TokenConfigurationV0;
185 use dpp::data_contract::associated_token::token_configuration_convention::v0::TokenConfigurationConventionV0;
186 use dpp::data_contract::associated_token::token_distribution_rules::v0::TokenDistributionRulesV0;
187 use dpp::data_contract::associated_token::token_distribution_rules::TokenDistributionRules;
188 use dpp::data_contract::associated_token::token_keeps_history_rules::v0::TokenKeepsHistoryRulesV0;
189 use dpp::data_contract::associated_token::token_marketplace_rules::v0::TokenMarketplaceRulesV0;
190 use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_function::DistributionFunction;
191 use dpp::data_contract::associated_token::token_perpetual_distribution::distribution_recipient::TokenDistributionRecipient;
192 use dpp::data_contract::associated_token::token_perpetual_distribution::reward_distribution_type::RewardDistributionType;
193 use dpp::data_contract::associated_token::token_perpetual_distribution::v0::TokenPerpetualDistributionV0;
194 use dpp::data_contract::associated_token::token_perpetual_distribution::TokenPerpetualDistribution;
195 use dpp::data_contract::associated_token::token_pre_programmed_distribution::v0::TokenPreProgrammedDistributionV0;
196 use dpp::data_contract::associated_token::token_pre_programmed_distribution::TokenPreProgrammedDistribution;
197 use dpp::data_contract::change_control_rules::authorized_action_takers::AuthorizedActionTakers;
198 use dpp::data_contract::change_control_rules::v0::ChangeControlRulesV0;
199 use dpp::data_contract::config::DataContractConfig;
200 use dpp::data_contract::group::v0::GroupV0;
201 use dpp::data_contract::group::Group;
202 use dpp::data_contract::v1::DataContractV1;
203 use dpp::data_contract::{TokenConfiguration, INITIAL_DATA_CONTRACT_VERSION};
204 use dpp::identifier::Identifier;
205 use dpp::identity::accessors::IdentitySettersV0;
206 use dpp::identity::Identity;
207 use dpp::prelude::IdentityPublicKey;
208 use dpp::tokens::calculate_token_id;
209 use dpp::tokens::status::v0::TokenStatusV0;
210 use dpp::tokens::status::TokenStatus;
211 use dpp::tokens::token_pricing_schedule::TokenPricingSchedule;
212 use rand::rngs::StdRng;
213 use rand::SeedableRng;
214 use std::collections::BTreeMap;
215 use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0;
216
217 let (platform, state, version) = setup_platform(Some((1, 1)), Network::Testnet, None);
218
219 let identity_id_1 = [1u8; 32];
220 let identity_id_2 = [2u8; 32];
221 let identity_id_3 = [3u8; 32];
222 let contract_id = [3u8; 32];
223
224 let token_id_0 = calculate_token_id(&contract_id, 0);
225 let token_id_1 = calculate_token_id(&contract_id, 1);
226 let token_id_2 = calculate_token_id(&contract_id, 2);
227
228 let credits_per_identity: u64 = 10_000_000_000_000;
230 let total_credits = credits_per_identity * 3;
231 platform
232 .platform
233 .drive
234 .add_to_system_credits(total_credits, None, version)
235 .expect("expected to add system credits");
236
237 let mut rng = StdRng::seed_from_u64(0u64);
238 let non_unique_key = IdentityPublicKey::random_voting_key_with_rng(11, &mut rng, version)
239 .expect("expected to create voting key");
240
241 for id_bytes in [identity_id_1, identity_id_2, identity_id_3] {
242 let id = Identifier::new(id_bytes);
243 let mut identity =
244 Identity::create_basic_identity(id, version).expect("expected to create identity");
245 identity.set_balance(credits_per_identity);
246
247 let seed = id_bytes[0];
248 let mut rng = StdRng::seed_from_u64(seed as u64);
249 let mut keys =
250 IdentityPublicKey::main_keys_with_random_authentication_keys_with_private_keys_with_rng(
251 3, &mut rng, version,
252 )
253 .expect("expected to create keys");
254
255 let transfer_key =
256 IdentityPublicKey::random_masternode_transfer_key_with_rng(3, &mut rng, version)
257 .expect("expected to create transfer key");
258 keys.push(transfer_key);
259 keys.push(non_unique_key.clone());
260
261 identity.set_public_keys(keys.into_iter().map(|(key, _)| (key.id(), key)).collect());
262
263 platform
264 .platform
265 .drive
266 .add_new_identity(identity, false, &BlockInfo::genesis(), true, None, version)
267 .expect("expected to add identity");
268 }
269
270 let groups = [
272 (
273 0,
274 Group::V0(GroupV0 {
275 members: [
276 (Identifier::new(identity_id_1), 1),
277 (Identifier::new(identity_id_2), 1),
278 ]
279 .into(),
280 required_power: 1,
281 }),
282 ),
283 (
284 1,
285 Group::V0(GroupV0 {
286 members: [
287 (Identifier::new(identity_id_1), 1),
288 (Identifier::new(identity_id_2), 1),
289 (Identifier::new(identity_id_3), 1),
290 ]
291 .into(),
292 required_power: 3,
293 }),
294 ),
295 (
296 2,
297 Group::V0(GroupV0 {
298 members: [
299 (Identifier::new(identity_id_1), 1),
300 (Identifier::new(identity_id_3), 1),
301 ]
302 .into(),
303 required_power: 1,
304 }),
305 ),
306 ]
307 .into();
308
309 let token_configuration = TokenConfiguration::V0(TokenConfigurationV0 {
310 conventions: TokenConfigurationConventionV0 {
311 localizations: Default::default(),
312 decimals: 8,
313 }
314 .into(),
315 conventions_change_rules: ChangeControlRulesV0::default().into(),
316 base_supply: 100000,
317 max_supply: None,
318 keeps_history: TokenKeepsHistoryRulesV0::default().into(),
319 start_as_paused: false,
320 allow_transfer_to_frozen_balance: true,
321 max_supply_change_rules: ChangeControlRulesV0 {
322 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
323 admin_action_takers: Default::default(),
324 changing_authorized_action_takers_to_no_one_allowed: false,
325 changing_admin_action_takers_to_no_one_allowed: false,
326 self_changing_admin_action_takers_allowed: false,
327 }
328 .into(),
329 distribution_rules: TokenDistributionRulesV0 {
330 perpetual_distribution: Some(TokenPerpetualDistribution::V0(
331 TokenPerpetualDistributionV0 {
332 distribution_type: RewardDistributionType::BlockBasedDistribution {
333 interval: 10,
334 function: DistributionFunction::FixedAmount { amount: 100 },
335 },
336 distribution_recipient: TokenDistributionRecipient::ContractOwner,
337 },
338 )),
339 perpetual_distribution_rules: ChangeControlRulesV0::default().into(),
340 pre_programmed_distribution: None,
341 new_tokens_destination_identity: None,
342 new_tokens_destination_identity_rules: ChangeControlRulesV0::default().into(),
343 minting_allow_choosing_destination: true,
344 minting_allow_choosing_destination_rules: ChangeControlRulesV0::default().into(),
345 change_direct_purchase_pricing_rules: ChangeControlRulesV0 {
346 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
347 admin_action_takers: Default::default(),
348 changing_authorized_action_takers_to_no_one_allowed: false,
349 changing_admin_action_takers_to_no_one_allowed: false,
350 self_changing_admin_action_takers_allowed: false,
351 }
352 .into(),
353 }
354 .into(),
355 marketplace_rules: TokenMarketplaceRulesV0 {
356 trade_mode: Default::default(),
357 trade_mode_change_rules: ChangeControlRulesV0::default().into(),
358 }
359 .into(),
360 manual_minting_rules: ChangeControlRulesV0 {
361 authorized_to_make_change: AuthorizedActionTakers::Group(0),
362 admin_action_takers: Default::default(),
363 changing_authorized_action_takers_to_no_one_allowed: false,
364 changing_admin_action_takers_to_no_one_allowed: false,
365 self_changing_admin_action_takers_allowed: false,
366 }
367 .into(),
368 manual_burning_rules: ChangeControlRulesV0 {
369 authorized_to_make_change: AuthorizedActionTakers::Group(2),
370 admin_action_takers: Default::default(),
371 changing_authorized_action_takers_to_no_one_allowed: false,
372 changing_admin_action_takers_to_no_one_allowed: false,
373 self_changing_admin_action_takers_allowed: false,
374 }
375 .into(),
376 freeze_rules: ChangeControlRulesV0 {
377 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
378 admin_action_takers: Default::default(),
379 changing_authorized_action_takers_to_no_one_allowed: false,
380 changing_admin_action_takers_to_no_one_allowed: false,
381 self_changing_admin_action_takers_allowed: false,
382 }
383 .into(),
384 unfreeze_rules: ChangeControlRulesV0 {
385 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
386 admin_action_takers: Default::default(),
387 changing_authorized_action_takers_to_no_one_allowed: false,
388 changing_admin_action_takers_to_no_one_allowed: false,
389 self_changing_admin_action_takers_allowed: false,
390 }
391 .into(),
392 destroy_frozen_funds_rules: ChangeControlRulesV0 {
393 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
394 admin_action_takers: Default::default(),
395 changing_authorized_action_takers_to_no_one_allowed: false,
396 changing_admin_action_takers_to_no_one_allowed: false,
397 self_changing_admin_action_takers_allowed: false,
398 }
399 .into(),
400 emergency_action_rules: ChangeControlRulesV0 {
401 authorized_to_make_change: AuthorizedActionTakers::ContractOwner,
402 admin_action_takers: Default::default(),
403 changing_authorized_action_takers_to_no_one_allowed: false,
404 changing_admin_action_takers_to_no_one_allowed: false,
405 self_changing_admin_action_takers_allowed: false,
406 }
407 .into(),
408 main_control_group: None,
409 main_control_group_can_be_modified: Default::default(),
410 description: Some("Some token description".to_string()),
411 });
412
413 let mut token_configuration_2 = token_configuration.clone();
415 if let TokenConfiguration::V0(ref mut cfg) = token_configuration_2 {
416 if let TokenDistributionRules::V0(ref mut rules) = cfg.distribution_rules {
417 rules.pre_programmed_distribution = Some(TokenPreProgrammedDistribution::V0(
418 TokenPreProgrammedDistributionV0 {
419 distributions: BTreeMap::from([
420 (
421 1000,
422 BTreeMap::from([
423 (Identifier::new(identity_id_1), 500),
424 (Identifier::new(identity_id_2), 300),
425 ]),
426 ),
427 (
428 5000,
429 BTreeMap::from([(Identifier::new(identity_id_1), 1000)]),
430 ),
431 (
432 10000,
433 BTreeMap::from([
434 (Identifier::new(identity_id_2), 750),
435 (Identifier::new(identity_id_3), 250),
436 ]),
437 ),
438 ]),
439 },
440 ));
441 }
442 }
443
444 let tokens = [
445 (0, token_configuration.clone()),
446 (1, token_configuration),
447 (2, token_configuration_2),
448 ]
449 .into();
450
451 let data_contract = DataContract::V1(DataContractV1 {
452 id: Identifier::new(contract_id),
453 config: DataContractConfig::default_for_version(version)
454 .expect("expected contract config"),
455 version: INITIAL_DATA_CONTRACT_VERSION,
456 owner_id: Identifier::new(identity_id_1),
457 document_types: Default::default(),
458 schema_defs: Default::default(),
459 created_at: None,
460 updated_at: None,
461 created_at_block_height: None,
462 updated_at_block_height: None,
463 created_at_epoch: None,
464 updated_at_epoch: None,
465 groups,
466 tokens,
467 keywords: vec!["cat".into(), "white".into()],
468 description: Some("Some contract description".to_string()),
469 });
470
471 let block_info = BlockInfo::genesis();
472
473 platform
474 .platform
475 .drive
476 .apply_contract(&data_contract, block_info, true, None, None, version)
477 .expect("expected to apply contract");
478
479 for (token_id, id, amount) in [
484 (token_id_0, identity_id_1, 100u64),
485 (token_id_0, identity_id_2, 100),
486 (token_id_1, identity_id_1, 200),
487 (token_id_1, identity_id_3, 100),
488 (token_id_2, identity_id_1, 300),
489 (token_id_2, identity_id_2, 200),
490 ] {
491 platform
492 .platform
493 .drive
494 .token_mint(
495 token_id,
496 id,
497 amount,
498 false,
499 false,
500 &block_info,
501 true,
502 None,
503 version,
504 )
505 .expect("expected to mint tokens");
506 }
507
508 platform
510 .platform
511 .drive
512 .token_freeze(
513 Identifier::new(token_id_0),
514 Identifier::new(identity_id_2),
515 &block_info,
516 true,
517 None,
518 version,
519 )
520 .expect("expected to freeze");
521
522 let status = TokenStatus::V0(TokenStatusV0 { paused: true });
524 platform
525 .platform
526 .drive
527 .token_apply_status(token_id_1, status, &block_info, true, None, version)
528 .expect("expected to apply status");
529
530 platform
532 .platform
533 .drive
534 .token_set_direct_purchase_price(
535 token_id_1,
536 Some(TokenPricingSchedule::SinglePrice(25)),
537 &block_info,
538 true,
539 None,
540 version,
541 )
542 .expect("expected to set direct purchase price");
543
544 let pricing = TokenPricingSchedule::SetPrices(
545 (0..=900)
546 .step_by(100)
547 .map(|amount| (amount, 1000 - amount))
548 .collect(),
549 );
550 platform
551 .platform
552 .drive
553 .token_set_direct_purchase_price(
554 token_id_2,
555 Some(pricing),
556 &block_info,
557 true,
558 None,
559 version,
560 )
561 .expect("expected to set direct purchase price");
562
563 (
564 platform,
565 state,
566 version,
567 contract_id,
568 [token_id_0, token_id_1, token_id_2],
569 [identity_id_1, identity_id_2, identity_id_3],
570 )
571 }
572}