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