1pub mod batch;
3
4pub mod identity_create;
6
7pub mod identity_credit_transfer;
9
10pub mod identity_credit_withdrawal;
12
13pub mod identity_top_up;
15
16pub mod identity_update;
18
19pub mod data_contract_create;
21
22pub mod data_contract_update;
24
25pub mod masternode_vote;
27
28pub mod identity_create_from_addresses;
30
31pub mod address_funding_from_asset_lock;
33
34pub mod identity_credit_transfer_to_addresses;
36
37pub mod address_credit_withdrawal;
39
40pub mod address_funds_transfer;
42mod identity_top_up_from_addresses;
43
44pub mod shield;
46pub mod shield_from_asset_lock;
48pub mod shielded_common;
50pub mod shielded_transfer;
52pub mod shielded_withdrawal;
54pub mod unshield;
56
57#[derive(Clone, Copy, Debug, Eq, PartialEq)]
59pub enum ValidationMode {
60 CheckTx,
62 RecheckTx,
64 Validator,
66 NoValidation,
68}
69
70impl ValidationMode {
71 pub fn can_alter_cache(&self) -> bool {
73 match self {
74 ValidationMode::CheckTx => false,
75 ValidationMode::RecheckTx => false,
76 ValidationMode::Validator => true,
77 ValidationMode::NoValidation => false,
78 }
79 }
80}
81
82#[cfg(test)]
83pub(in crate::execution) mod test_helpers;
84
85#[cfg(test)]
86pub(in crate::execution) mod tests {
87 use crate::rpc::core::MockCoreRPCLike;
88 use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder};
89 use dpp::block::block_info::BlockInfo;
90 use dpp::data_contracts::SystemDataContract;
91 use dpp::fee::Credits;
92 use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0;
93 use dpp::identity::{Identity, IdentityPublicKey, IdentityV0, KeyID, KeyType, Purpose, SecurityLevel, TimestampMillis};
94 use dpp::prelude::{BlockHeight, Identifier, IdentityNonce};
95 use dpp::state_transition::data_contract_create_transition::methods::DataContractCreateTransitionMethodsV0;
96 use dpp::state_transition::data_contract_create_transition::DataContractCreateTransition;
97 use dpp::system_data_contracts::load_system_data_contract;
98 use dpp::tests::json_document::json_document_to_contract_with_ids;
99 use drive::drive::document::query::QueryDocumentsOutcomeV0Methods;
100 use drive::query::DriveDocumentQuery;
101 use platform_version::version::PlatformVersion;
102 use rand::prelude::StdRng;
103 use rand::{Rng, SeedableRng};
104 use simple_signer::signer::SimpleSigner;
105 use std::borrow::Cow;
106 use std::collections::BTreeMap;
107 use std::net::{IpAddr, Ipv4Addr, SocketAddr};
108 use std::ops::Deref;
109 use std::sync::Arc;
110 use arc_swap::Guard;
111 use assert_matches::assert_matches;
112 use dpp::dashcore_rpc::dashcore_rpc_json::{DMNState, MasternodeListItem, MasternodeType};
113 use dapi_grpc::platform::v0::{get_contested_resource_vote_state_request, get_contested_resource_vote_state_response, GetContestedResourceVoteStateRequest, GetContestedResourceVoteStateResponse};
114 use dapi_grpc::platform::v0::get_contested_resource_vote_state_request::get_contested_resource_vote_state_request_v0::ResultType;
115 use dapi_grpc::platform::v0::get_contested_resource_vote_state_request::{get_contested_resource_vote_state_request_v0, GetContestedResourceVoteStateRequestV0};
116 use dapi_grpc::platform::v0::get_contested_resource_vote_state_response::{get_contested_resource_vote_state_response_v0, GetContestedResourceVoteStateResponseV0};
117 use dapi_grpc::platform::v0::get_contested_resource_vote_state_response::get_contested_resource_vote_state_response_v0::FinishedVoteInfo;
118 use dpp::balances::credits::TokenAmount;
119 use dpp::dash_to_credits;
120 use dpp::dashcore::{ProTxHash, Txid};
121 use dpp::dashcore::hashes::Hash;
122 use dpp::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters};
123 use dpp::data_contract::accessors::v1::{DataContractV1Getters, DataContractV1Setters};
124 use dpp::data_contract::{DataContract, GroupContractPosition, TokenContractPosition};
125 use dpp::data_contract::document_type::accessors::{DocumentTypeV0Getters, DocumentTypeV1Setters};
126 use dpp::data_contract::document_type::random_document::{CreateRandomDocument, DocumentFieldFillSize, DocumentFieldFillType};
127 use dpp::document::{Document, DocumentV0Getters, DocumentV0Setters};
128 use dpp::document::serialization_traits::DocumentPlatformConversionMethodsV0;
129 use dpp::fee::fee_result::FeeResult;
130 use dpp::identifier::MasternodeIdentifiers;
131 use dpp::identity::accessors::IdentityGettersV0;
132 use dpp::identity::contract_bounds::ContractBounds;
133 use dpp::identity::hash::IdentityPublicKeyHashMethodsV0;
134 use dpp::platform_value::{Bytes32, Value};
135 use dpp::serialization::PlatformSerializable;
136 use dpp::state_transition::batch_transition::BatchTransition;
137 use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0;
138 use dpp::state_transition::masternode_vote_transition::MasternodeVoteTransition;
139 use dpp::state_transition::masternode_vote_transition::methods::MasternodeVoteTransitionMethodsV0;
140 use dpp::state_transition::StateTransition;
141 use dpp::tokens::calculate_token_id;
142 use dpp::util::hash::hash_double;
143 use dpp::util::strings::convert_to_homograph_safe_chars;
144 use dpp::voting::contender_structs::{Contender, ContenderV0};
145 use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice;
146 use dpp::voting::vote_info_storage::contested_document_vote_poll_winner_info::ContestedDocumentVotePollWinnerInfo;
147 use dpp::voting::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePoll;
148 use dpp::voting::vote_polls::VotePoll;
149 use dpp::voting::votes::resource_vote::ResourceVote;
150 use dpp::voting::votes::resource_vote::v0::ResourceVoteV0;
151 use dpp::voting::votes::Vote;
152 use drive::util::object_size_info::DataContractResolvedInfo;
153 use drive::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed;
154 use drive::query::vote_poll_vote_state_query::ContestedDocumentVotePollDriveQueryResultType::DocumentsAndVoteTally;
155 use drive::query::vote_poll_vote_state_query::{ContestedDocumentVotePollDriveQueryResultType, ResolvedContestedDocumentVotePollDriveQuery};
156 use drive::util::test_helpers::setup_contract;
157 use crate::execution::types::block_execution_context::BlockExecutionContext;
158 use crate::execution::types::block_execution_context::v0::BlockExecutionContextV0;
159 use crate::expect_match;
160 use crate::platform_types::platform_state::PlatformState;
161 use crate::platform_types::platform_state::PlatformStateV0Methods;
162 use crate::platform_types::state_transitions_processing_result::{StateTransitionExecutionResult, StateTransitionsProcessingResult};
163 use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult::{SuccessfulExecution, UnpaidConsensusError};
164 use crate::execution::types::block_state_info::BlockStateInfo;
165 use crate::execution::types::block_state_info::v0::BlockStateInfoV0;
166 use crate::platform_types::epoch_info::EpochInfo;
167 use crate::platform_types::epoch_info::v0::EpochInfoV0;
168 use crate::execution::types::block_fees::v0::BlockFeesV0;
169 use crate::execution::types::processed_block_fees_outcome::v0::ProcessedBlockFeesOutcome;
170 use dpp::data_contract::associated_token::token_configuration::TokenConfiguration;
171 use dpp::data_contract::group::Group;
172 use dpp::tokens::gas_fees_paid_by::GasFeesPaidBy;
173 use dpp::tokens::token_amount_on_contract_token::{DocumentActionTokenCost, DocumentActionTokenEffect};
174 use dpp::data_contract::document_type::accessors::DocumentTypeV0MutGetters;
175 use dpp::serialization::PlatformDeserializableWithPotentialValidationFromVersionedStructure;
176
177 pub(in crate::execution) fn setup_identity_with_system_credits(
179 platform: &mut TempPlatform<MockCoreRPCLike>,
180 seed: u64,
181 credits: Credits,
182 ) -> (Identity, SimpleSigner, IdentityPublicKey) {
183 let platform_version = PlatformVersion::latest();
184 platform
185 .drive
186 .add_to_system_credits(credits, None, platform_version)
187 .expect("expected to add to system credits");
188 setup_identity(platform, seed, credits)
189 }
190
191 pub(in crate::execution) fn setup_identity(
192 platform: &mut TempPlatform<MockCoreRPCLike>,
193 seed: u64,
194 credits: Credits,
195 ) -> (Identity, SimpleSigner, IdentityPublicKey) {
196 let platform_version = PlatformVersion::latest();
197 let mut signer = SimpleSigner::default();
198
199 let mut rng = StdRng::seed_from_u64(seed);
200
201 let (master_key, master_private_key) =
202 IdentityPublicKey::random_ecdsa_master_authentication_key_with_rng(
203 0,
204 &mut rng,
205 platform_version,
206 )
207 .expect("expected to get key pair");
208
209 signer.add_identity_public_key(master_key.clone(), master_private_key);
210
211 let (critical_public_key, private_key) =
212 IdentityPublicKey::random_ecdsa_critical_level_authentication_key_with_rng(
213 1,
214 &mut rng,
215 platform_version,
216 )
217 .expect("expected to get key pair");
218
219 signer.add_identity_public_key(critical_public_key.clone(), private_key);
220
221 let identity: Identity = IdentityV0 {
222 id: Identifier::random_with_rng(&mut rng),
223 public_keys: BTreeMap::from([
224 (0, master_key.clone()),
225 (1, critical_public_key.clone()),
226 ]),
227 balance: credits,
228 revision: 0,
229 }
230 .into();
231
232 platform
235 .drive
236 .add_new_identity(
237 identity.clone(),
238 false,
239 &BlockInfo::default(),
240 true,
241 None,
242 platform_version,
243 )
244 .expect("expected to add a new identity");
245
246 (identity, signer, critical_public_key)
247 }
248
249 pub(in crate::execution) fn setup_identity_without_adding_it(
250 seed: u64,
251 credits: Credits,
252 ) -> (Identity, SimpleSigner, IdentityPublicKey) {
253 let platform_version = PlatformVersion::latest();
254 let mut signer = SimpleSigner::default();
255
256 let mut rng = StdRng::seed_from_u64(seed);
257
258 let (master_key, master_private_key) =
259 IdentityPublicKey::random_ecdsa_master_authentication_key_with_rng(
260 0,
261 &mut rng,
262 platform_version,
263 )
264 .expect("expected to get key pair");
265
266 signer.add_identity_public_key(master_key.clone(), master_private_key);
267
268 let (critical_public_key, private_key) =
269 IdentityPublicKey::random_ecdsa_critical_level_authentication_key_with_rng(
270 1,
271 &mut rng,
272 platform_version,
273 )
274 .expect("expected to get key pair");
275
276 signer.add_identity_public_key(critical_public_key.clone(), private_key);
277
278 let identity: Identity = IdentityV0 {
279 id: Identifier::random_with_rng(&mut rng),
280 public_keys: BTreeMap::from([
281 (0, master_key.clone()),
282 (1, critical_public_key.clone()),
283 ]),
284 balance: credits,
285 revision: 0,
286 }
287 .into();
288
289 (identity, signer, critical_public_key)
290 }
291
292 pub(in crate::execution) fn setup_identity_return_master_key(
293 platform: &mut TempPlatform<MockCoreRPCLike>,
294 seed: u64,
295 credits: Credits,
296 ) -> (Identity, SimpleSigner, IdentityPublicKey, IdentityPublicKey) {
297 let platform_version = PlatformVersion::latest();
298 let mut signer = SimpleSigner::default();
299
300 let mut rng = StdRng::seed_from_u64(seed);
301
302 let (master_key, master_private_key) =
303 IdentityPublicKey::random_ecdsa_master_authentication_key_with_rng(
304 0,
305 &mut rng,
306 platform_version,
307 )
308 .expect("expected to get key pair");
309
310 signer.add_identity_public_key(master_key.clone(), master_private_key);
311
312 let (critical_public_key, private_key) =
313 IdentityPublicKey::random_ecdsa_critical_level_authentication_key_with_rng(
314 1,
315 &mut rng,
316 platform_version,
317 )
318 .expect("expected to get key pair");
319
320 signer.add_identity_public_key(critical_public_key.clone(), private_key);
321
322 let identity: Identity = IdentityV0 {
323 id: Identifier::random_with_rng(&mut rng),
324 public_keys: BTreeMap::from([
325 (0, master_key.clone()),
326 (1, critical_public_key.clone()),
327 ]),
328 balance: credits,
329 revision: 0,
330 }
331 .into();
332
333 platform
336 .drive
337 .add_new_identity(
338 identity.clone(),
339 false,
340 &BlockInfo::default(),
341 true,
342 None,
343 platform_version,
344 )
345 .expect("expected to add a new identity");
346
347 (identity, signer, critical_public_key, master_key)
348 }
349
350 #[allow(clippy::too_many_arguments)]
351 pub(crate) fn setup_add_key_to_identity(
352 platform: &mut TempPlatform<MockCoreRPCLike>,
353 identity: &mut Identity,
354 signer: &mut SimpleSigner,
355 seed: u64,
356 key_id: KeyID,
357 purpose: Purpose,
358 security_level: SecurityLevel,
359 key_type: KeyType,
360 contract_bounds: Option<ContractBounds>,
361 ) -> IdentityPublicKey {
362 let platform_version = PlatformVersion::latest();
363
364 let mut rng = StdRng::seed_from_u64(seed);
365
366 let (key, private_key) = IdentityPublicKey::random_key_with_known_attributes(
367 key_id,
368 &mut rng,
369 purpose,
370 security_level,
371 key_type,
372 contract_bounds,
373 platform_version,
374 )
375 .expect("expected to get key pair");
376
377 signer.add_identity_public_key(key.clone(), private_key);
378
379 identity.add_public_key(key.clone());
380
381 platform
382 .drive
383 .add_new_unique_keys_to_identity(
384 identity.id().to_buffer(),
385 vec![key.clone()],
386 &BlockInfo::default(),
387 true,
388 None,
389 platform_version,
390 )
391 .expect("expected to add a new key");
392
393 key
394 }
395
396 pub(in crate::execution) fn setup_identity_with_withdrawal_key_and_system_credits(
397 platform: &mut TempPlatform<MockCoreRPCLike>,
398 seed: u64,
399 withdrawal_key_type: KeyType,
400 credits: Credits,
401 ) -> (Identity, SimpleSigner, IdentityPublicKey, IdentityPublicKey) {
402 let platform_version = PlatformVersion::latest();
403 platform
404 .drive
405 .add_to_system_credits(credits, None, platform_version)
406 .expect("expected to add to system credits");
407 let mut signer = SimpleSigner::default();
408
409 let mut rng = StdRng::seed_from_u64(seed);
410
411 let (master_key, master_private_key) =
412 IdentityPublicKey::random_ecdsa_master_authentication_key_with_rng(
413 0,
414 &mut rng,
415 platform_version,
416 )
417 .expect("expected to get key pair");
418
419 signer.add_identity_public_key(master_key.clone(), master_private_key);
420
421 let (critical_public_key, private_key) =
422 IdentityPublicKey::random_ecdsa_critical_level_authentication_key_with_rng(
423 1,
424 &mut rng,
425 platform_version,
426 )
427 .expect("expected to get key pair");
428
429 signer.add_identity_public_key(critical_public_key.clone(), private_key);
430
431 let (withdrawal_public_key, withdrawal_private_key) =
432 IdentityPublicKey::random_key_with_known_attributes(
433 2,
434 &mut rng,
435 Purpose::TRANSFER,
436 SecurityLevel::CRITICAL,
437 withdrawal_key_type,
438 None,
439 platform_version,
440 )
441 .expect("expected to get key pair");
442
443 signer.add_identity_public_key(withdrawal_public_key.clone(), withdrawal_private_key);
444
445 let identity: Identity = IdentityV0 {
446 id: Identifier::random_with_rng(&mut rng),
447 public_keys: BTreeMap::from([
448 (0, master_key.clone()),
449 (1, critical_public_key.clone()),
450 (2, withdrawal_public_key.clone()),
451 ]),
452 balance: credits,
453 revision: 0,
454 }
455 .into();
456
457 platform
460 .drive
461 .add_new_identity(
462 identity.clone(),
463 false,
464 &BlockInfo::default(),
465 true,
466 None,
467 platform_version,
468 )
469 .expect("expected to add a new identity");
470
471 (identity, signer, critical_public_key, withdrawal_public_key)
472 }
473
474 pub(in crate::execution) fn add_tokens_to_identity(
475 platform: &TempPlatform<MockCoreRPCLike>,
476 token_id: Identifier,
477 identity_id: Identifier,
478 balance_to_add: Credits,
479 ) {
480 let platform_version = PlatformVersion::latest();
481 platform
482 .drive
483 .add_to_identity_token_balance(
484 token_id.to_buffer(),
485 identity_id.to_buffer(),
486 balance_to_add,
487 &BlockInfo::default(),
488 true,
489 None,
490 platform_version,
491 None,
492 )
493 .expect("expected to add token balance to identity");
494 platform
495 .drive
496 .add_to_token_total_supply(
497 token_id.to_buffer(),
498 balance_to_add,
499 true,
500 false,
501 true,
502 &BlockInfo::default(),
503 None,
504 platform_version,
505 )
506 .expect("expected to add to total supply");
507 }
508
509 pub(in crate::execution) fn process_state_transitions(
510 platform: &TempPlatform<MockCoreRPCLike>,
511 state_transitions: &[StateTransition],
512 block_info: BlockInfo,
513 platform_state: &PlatformState,
514 ) -> (Vec<FeeResult>, ProcessedBlockFeesOutcome) {
515 let platform_version = PlatformVersion::latest();
516
517 let raw_state_transitions = state_transitions
518 .iter()
519 .map(|a| a.serialize_to_bytes().expect("expected to serialize"))
520 .collect::<Vec<_>>();
521
522 let transaction = platform.drive.grove.start_transaction();
523
524 let processing_result = platform
525 .platform
526 .process_raw_state_transitions(
527 &raw_state_transitions,
528 platform_state,
529 &block_info,
530 &transaction,
531 platform_version,
532 false,
533 None,
534 )
535 .expect("expected to process state transition");
536
537 let fee_results = processing_result.execution_results().iter().map(|result| {
538 let fee_result = expect_match!(result, StateTransitionExecutionResult::SuccessfulExecution{ fee_result, .. } => fee_result);
539 fee_result.clone()
540 }).collect();
541
542 let block_fees_v0: BlockFeesV0 = processing_result.aggregated_fees().clone().into();
544
545 let block_execution_context = BlockExecutionContext::V0(BlockExecutionContextV0 {
546 block_state_info: BlockStateInfo::V0(BlockStateInfoV0 {
547 height: block_info.height,
548 round: 0,
549 block_time_ms: block_info.time_ms,
550 previous_block_time_ms: platform_state.last_committed_block_time_ms(),
551 proposer_pro_tx_hash: Default::default(),
552 core_chain_locked_height: 0,
553 block_hash: None,
554 app_hash: None,
555 }),
556 epoch_info: EpochInfo::V0(EpochInfoV0::default()),
557 unsigned_withdrawal_transactions: Default::default(),
558 block_address_balance_changes: Default::default(),
559 block_platform_state: platform_state.clone(),
560 proposer_results: None,
561 });
562
563 let processed_block_fees = platform
565 .process_block_fees_and_validate_sum_trees(
566 &block_execution_context,
567 block_fees_v0.into(),
568 &transaction,
569 platform_version,
570 )
571 .expect("expected to process block fees");
572
573 platform
574 .drive
575 .grove
576 .commit_transaction(transaction)
577 .unwrap()
578 .expect("expected to commit");
579
580 (fee_results, processed_block_fees)
581 }
582
583 pub(in crate::execution) fn fetch_expected_identity_balance(
584 platform: &TempPlatform<MockCoreRPCLike>,
585 identity_id: Identifier,
586 platform_version: &PlatformVersion,
587 expected_balance: Credits,
588 ) {
589 assert_eq!(
590 expected_balance,
591 platform
592 .drive
593 .fetch_identity_balance(identity_id.to_buffer(), None, platform_version)
594 .expect("expected to be able to fetch balance")
595 .expect("expected a balance")
596 );
597 }
598
599 pub(in crate::execution) fn setup_masternode_owner_identity(
600 platform: &mut TempPlatform<MockCoreRPCLike>,
601 seed: u64,
602 credits: Credits,
603 platform_version: &PlatformVersion,
604 ) -> (Identity, SimpleSigner, IdentityPublicKey, IdentityPublicKey) {
605 let mut signer = SimpleSigner::default();
606
607 platform
608 .drive
609 .add_to_system_credits(credits, None, platform_version)
610 .expect("expected to add to system credits");
611
612 let mut rng = StdRng::seed_from_u64(seed);
613
614 let (transfer_key, transfer_private_key) =
615 IdentityPublicKey::random_masternode_transfer_key_with_rng(
616 0,
617 &mut rng,
618 platform_version,
619 )
620 .expect("expected to get key pair");
621
622 let (owner_key, owner_private_key) =
623 IdentityPublicKey::random_masternode_owner_key_with_rng(1, &mut rng, platform_version)
624 .expect("expected to get key pair");
625
626 let owner_address = owner_key
627 .public_key_hash()
628 .expect("expected a public key hash");
629
630 let payout_address = transfer_key
631 .public_key_hash()
632 .expect("expected a public key hash");
633
634 signer.add_identity_public_key(transfer_key.clone(), transfer_private_key);
635 signer.add_identity_public_key(owner_key.clone(), owner_private_key);
636
637 let pro_tx_hash_bytes: [u8; 32] = rng.gen();
638
639 let identity: Identity = IdentityV0 {
640 id: pro_tx_hash_bytes.into(),
641 public_keys: BTreeMap::from([(0, transfer_key.clone()), (1, owner_key.clone())]),
642 balance: credits,
643 revision: 0,
644 }
645 .into();
646
647 platform
650 .drive
651 .add_new_identity(
652 identity.clone(),
653 true,
654 &BlockInfo::default(),
655 true,
656 None,
657 platform_version,
658 )
659 .expect("expected to add a new identity");
660
661 let mut platform_state = platform.state.load().clone().deref().clone();
662
663 let pro_tx_hash = ProTxHash::from_byte_array(pro_tx_hash_bytes);
664
665 let random_ip = Ipv4Addr::new(
666 rng.gen_range(0..255),
667 rng.gen_range(0..255),
668 rng.gen_range(0..255),
669 rng.gen_range(0..255),
670 );
671
672 platform_state.full_masternode_list_mut().insert(
673 pro_tx_hash,
674 MasternodeListItem {
675 node_type: MasternodeType::Regular,
676 pro_tx_hash,
677 collateral_hash: Txid::from_byte_array(rng.gen()),
678 collateral_index: 0,
679 collateral_address: rng.gen(),
680 operator_reward: 0.0,
681 state: DMNState {
682 service: SocketAddr::new(IpAddr::V4(random_ip), 19999),
683 registered_height: 0,
684 pose_revived_height: None,
685 pose_ban_height: None,
686 revocation_reason: 0,
687 owner_address,
688 voting_address: rng.gen(),
689 payout_address,
690 pub_key_operator: vec![],
691 operator_payout_address: None,
692 platform_node_id: None,
693 platform_p2p_port: None,
694 platform_http_port: None,
695 },
696 },
697 );
698
699 platform.state.store(Arc::new(platform_state));
700
701 (identity, signer, owner_key, transfer_key)
702 }
703
704 pub(in crate::execution) fn setup_masternode_voting_identity(
705 platform: &mut TempPlatform<MockCoreRPCLike>,
706 seed: u64,
707 platform_version: &PlatformVersion,
708 ) -> (Identifier, Identity, SimpleSigner, IdentityPublicKey) {
709 let mut signer = SimpleSigner::default();
710
711 let mut rng = StdRng::seed_from_u64(seed);
712
713 let (voting_key, voting_private_key) =
714 IdentityPublicKey::random_voting_key_with_rng(0, &mut rng, platform_version)
715 .expect("expected to get key pair");
716
717 signer.add_identity_public_key(voting_key.clone(), voting_private_key);
718
719 let pro_tx_hash_bytes: [u8; 32] = rng.gen();
720
721 let voting_address = voting_key
722 .public_key_hash()
723 .expect("expected a public key hash");
724
725 let voter_identifier =
726 Identifier::create_voter_identifier(&pro_tx_hash_bytes, &voting_address);
727
728 let identity: Identity = IdentityV0 {
729 id: voter_identifier,
730 public_keys: BTreeMap::from([(0, voting_key.clone())]),
731 balance: 0,
732 revision: 0,
733 }
734 .into();
735
736 platform
739 .drive
740 .add_new_identity(
741 identity.clone(),
742 true,
743 &BlockInfo::default(),
744 true,
745 None,
746 platform_version,
747 )
748 .expect("expected to add a new identity");
749
750 let mut platform_state = platform.state.load().clone().deref().clone();
751
752 let pro_tx_hash = ProTxHash::from_byte_array(pro_tx_hash_bytes);
753
754 let random_ip = Ipv4Addr::new(
755 rng.gen_range(0..255),
756 rng.gen_range(0..255),
757 rng.gen_range(0..255),
758 rng.gen_range(0..255),
759 );
760
761 platform_state.full_masternode_list_mut().insert(
762 pro_tx_hash,
763 MasternodeListItem {
764 node_type: MasternodeType::Regular,
765 pro_tx_hash,
766 collateral_hash: Txid::from_byte_array(rng.gen()),
767 collateral_index: 0,
768 collateral_address: rng.gen(),
769 operator_reward: 0.0,
770 state: DMNState {
771 service: SocketAddr::new(IpAddr::V4(random_ip), 19999),
772 registered_height: 0,
773 pose_revived_height: None,
774 pose_ban_height: None,
775 revocation_reason: 0,
776 owner_address: rng.gen(),
777 voting_address,
778 payout_address: rng.gen(),
779 pub_key_operator: vec![],
780 operator_payout_address: None,
781 platform_node_id: None,
782 platform_p2p_port: None,
783 platform_http_port: None,
784 },
785 },
786 );
787
788 platform.state.store(Arc::new(platform_state));
789
790 (pro_tx_hash_bytes.into(), identity, signer, voting_key)
791 }
792
793 pub(in crate::execution) fn take_down_masternode_identities(
794 platform: &mut TempPlatform<MockCoreRPCLike>,
795 masternode_identities: &Vec<Identifier>,
796 ) {
797 let mut platform_state = platform.state.load().clone().deref().clone();
798
799 let list = platform_state.full_masternode_list_mut();
800
801 for masternode_identifiers in masternode_identities {
802 let pro_tx_hash = ProTxHash::from_byte_array(masternode_identifiers.to_buffer());
803
804 list.remove(&pro_tx_hash);
805 }
806
807 platform.state.store(Arc::new(platform_state));
808 }
809
810 #[allow(dead_code)]
811 pub(in crate::execution) enum IdentityTestInfo<'a> {
812 Given {
813 identity: &'a Identity,
814 signer: &'a SimpleSigner,
815 public_key: &'a IdentityPublicKey,
816 identity_nonce: IdentityNonce,
817 },
818 UseSeed(u64),
819 UseRng(&'a mut StdRng),
820 }
821
822 pub(in crate::execution) async fn register_contract_from_bytes(
823 platform: &mut TempPlatform<MockCoreRPCLike>,
824 platform_state: &PlatformState,
825 contract_bytes: Vec<u8>,
826 identity_info: IdentityTestInfo<'_>,
827 platform_version: &PlatformVersion,
828 ) -> DataContract {
829 let mut data_contract =
831 DataContract::versioned_deserialize(&contract_bytes, false, platform_version)
832 .expect("expected to deserialize data contract");
833
834 let (identity_cow, signer_cow, key_cow, nonce) = match identity_info {
836 IdentityTestInfo::Given {
837 identity,
838 signer,
839 public_key,
840 identity_nonce,
841 } => (
842 Cow::Borrowed(identity),
843 Cow::Borrowed(signer),
844 Cow::Borrowed(public_key),
845 identity_nonce,
846 ),
847 IdentityTestInfo::UseSeed(seed) => {
848 let (identity, signer, key) = setup_identity(platform, seed, dash_to_credits!(1));
849 (Cow::Owned(identity), Cow::Owned(signer), Cow::Owned(key), 1)
850 }
851 IdentityTestInfo::UseRng(rng) => {
852 let seed = rng.gen();
853 let (identity, signer, key) = setup_identity(platform, seed, dash_to_credits!(1));
854 (Cow::Owned(identity), Cow::Owned(signer), Cow::Owned(key), 1)
855 }
856 };
857
858 let contract_id = DataContract::generate_data_contract_id_v0(identity_cow.id(), nonce);
859
860 data_contract.set_id(contract_id);
861
862 let state_transition = DataContractCreateTransition::new_from_data_contract(
864 data_contract.clone(),
865 nonce,
866 &identity_cow.as_ref().clone().into_partial_identity_info(),
867 key_cow.id(),
868 signer_cow.as_ref(),
869 platform_version,
870 None,
871 )
872 .await
873 .expect("expected to create and sign data contract create transition");
874
875 let state_transition_bytes = state_transition
877 .serialize_to_bytes()
878 .expect("expected to serialize state transition");
879
880 let transaction = platform.drive.grove.start_transaction();
881
882 let processing_result = platform
883 .platform
884 .process_raw_state_transitions(
885 &[state_transition_bytes],
886 platform_state,
887 &BlockInfo::default(),
888 &transaction,
889 platform_version,
890 false,
891 None,
892 )
893 .expect("expected to process state transition");
894
895 platform
896 .drive
897 .grove
898 .commit_transaction(transaction)
899 .unwrap()
900 .expect("expected to commit transaction");
901
902 let execution_result = processing_result.into_execution_results().remove(0);
903 assert_matches!(execution_result, SuccessfulExecution { .. });
904
905 data_contract
906 }
907
908 pub(in crate::execution) async fn create_dpns_name_contest_give_key_info(
909 platform: &mut TempPlatform<MockCoreRPCLike>,
910 platform_state: &PlatformState,
911 seed: u64,
912 name: &str,
913 platform_version: &PlatformVersion,
914 ) -> (
915 (
916 Identity,
917 SimpleSigner,
918 IdentityPublicKey,
919 (Document, Bytes32),
920 (Document, Bytes32),
921 ),
922 (
923 Identity,
924 SimpleSigner,
925 IdentityPublicKey,
926 (Document, Bytes32),
927 (Document, Bytes32),
928 ),
929 Arc<DataContract>,
930 ) {
931 let mut rng = StdRng::seed_from_u64(seed);
932
933 let identity_1_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
934
935 let identity_2_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
936
937 let (identity_1_info, identity_2_info) = if identity_1_info.0.id() < identity_2_info.0.id()
939 {
940 (identity_1_info, identity_2_info)
941 } else {
942 (identity_2_info, identity_1_info)
943 };
944
945 let ((preorder_document_1, document_1), (preorder_document_2, document_2), dpns_contract) =
946 create_dpns_name_contest_on_identities(
947 platform,
948 &identity_1_info,
949 &identity_2_info,
950 platform_state,
951 rng,
952 name,
953 None,
954 false,
955 platform_version,
956 )
957 .await;
958
959 let (identity_1, signer_1, identity_key_1) = identity_1_info;
960
961 let (identity_2, signer_2, identity_key_2) = identity_2_info;
962
963 (
964 (
965 identity_1,
966 signer_1,
967 identity_key_1,
968 preorder_document_1,
969 document_1,
970 ),
971 (
972 identity_2,
973 signer_2,
974 identity_key_2,
975 preorder_document_2,
976 document_2,
977 ),
978 dpns_contract,
979 )
980 }
981
982 pub(in crate::execution) async fn create_dpns_identity_name_contest(
983 platform: &mut TempPlatform<MockCoreRPCLike>,
984 platform_state: &PlatformState,
985 seed: u64,
986 name: &str,
987 platform_version: &PlatformVersion,
988 ) -> (Identity, Identity, Arc<DataContract>) {
989 let mut rng = StdRng::seed_from_u64(seed);
990
991 let identity_1_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
992
993 let identity_2_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
994
995 let (identity_1_info, identity_2_info) = if identity_1_info.0.id() < identity_2_info.0.id()
997 {
998 (identity_1_info, identity_2_info)
999 } else {
1000 (identity_2_info, identity_1_info)
1001 };
1002
1003 let (_, _, dpns_contract) = create_dpns_name_contest_on_identities(
1004 platform,
1005 &identity_1_info,
1006 &identity_2_info,
1007 platform_state,
1008 rng,
1009 name,
1010 None,
1011 false,
1012 platform_version,
1013 )
1014 .await;
1015 (identity_1_info.0, identity_2_info.0, dpns_contract)
1016 }
1017
1018 pub(in crate::execution) async fn create_dpns_identity_name_contest_skip_creating_identities(
1020 platform: &mut TempPlatform<MockCoreRPCLike>,
1021 platform_state: &PlatformState,
1022 seed: u64,
1023 name: &str,
1024 nonce_offset: Option<IdentityNonce>,
1025 platform_version: &PlatformVersion,
1026 ) -> (Identity, Identity, Arc<DataContract>) {
1027 let mut rng = StdRng::seed_from_u64(seed);
1028
1029 let identity_1_info = setup_identity_without_adding_it(rng.gen(), dash_to_credits!(0.5));
1030
1031 let identity_2_info = setup_identity_without_adding_it(rng.gen(), dash_to_credits!(0.5));
1032
1033 let (identity_1_info, identity_2_info) = if identity_1_info.0.id() < identity_2_info.0.id()
1035 {
1036 (identity_1_info, identity_2_info)
1037 } else {
1038 (identity_2_info, identity_1_info)
1039 };
1040
1041 let (_, _, dpns_contract) = create_dpns_name_contest_on_identities(
1042 platform,
1043 &identity_1_info,
1044 &identity_2_info,
1045 platform_state,
1046 rng,
1047 name,
1048 nonce_offset,
1049 true, platform_version,
1051 )
1052 .await;
1053 (identity_1_info.0, identity_2_info.0, dpns_contract)
1054 }
1055
1056 pub(in crate::execution) async fn create_dpns_contract_name_contest(
1057 platform: &mut TempPlatform<MockCoreRPCLike>,
1058 platform_state: &PlatformState,
1059 seed: u64,
1060 name: &str,
1061 platform_version: &PlatformVersion,
1062 ) -> (Identity, Identity, DataContract) {
1063 let mut rng = StdRng::seed_from_u64(seed);
1064
1065 let identity_1_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
1066
1067 let identity_2_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
1068
1069 let (identity_1_info, identity_2_info) = if identity_1_info.0.id() < identity_2_info.0.id()
1071 {
1072 (identity_1_info, identity_2_info)
1073 } else {
1074 (identity_2_info, identity_1_info)
1075 };
1076
1077 let dashpay_contract = setup_contract(
1078 &platform.drive,
1079 "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json",
1080 None,
1081 None,
1082 None::<fn(&mut DataContract)>,
1083 None,
1084 None,
1085 );
1086
1087 let card_game = setup_contract(
1088 &platform.drive,
1089 "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json",
1090 None,
1091 None,
1092 None::<fn(&mut DataContract)>,
1093 None,
1094 None,
1095 );
1096
1097 let (_, _, dpns_contract) = create_dpns_name_contest_on_identities_for_contract_records(
1098 platform,
1099 &identity_1_info,
1100 &identity_2_info,
1101 &dashpay_contract,
1102 &card_game,
1103 platform_state,
1104 rng,
1105 name,
1106 platform_version,
1107 )
1108 .await;
1109 (identity_1_info.0, identity_2_info.0, dpns_contract)
1110 }
1111
1112 #[allow(clippy::too_many_arguments)]
1113 async fn create_dpns_name_contest_on_identities(
1114 platform: &mut TempPlatform<MockCoreRPCLike>,
1115 identity_1: &(Identity, SimpleSigner, IdentityPublicKey),
1116 identity_2: &(Identity, SimpleSigner, IdentityPublicKey),
1117 platform_state: &PlatformState,
1118 mut rng: StdRng,
1119 name: &str,
1120 nonce_offset: Option<IdentityNonce>,
1121 skip_preorder: bool,
1122 platform_version: &PlatformVersion,
1123 ) -> (
1124 ((Document, Bytes32), (Document, Bytes32)),
1125 ((Document, Bytes32), (Document, Bytes32)),
1126 Arc<DataContract>,
1127 ) {
1128 let (identity_1, signer_1, key_1) = identity_1;
1129
1130 let (identity_2, signer_2, key_2) = identity_2;
1131
1132 let dpns = platform.drive.cache.system_data_contracts.load_dpns();
1133 let dpns_contract = dpns.clone();
1134
1135 let preorder = dpns_contract
1136 .document_type_for_name("preorder")
1137 .expect("expected a profile document type");
1138
1139 assert!(!preorder.documents_mutable());
1140 assert!(preorder.documents_can_be_deleted());
1141 assert!(!preorder.documents_transferable().is_transferable());
1142
1143 let domain = dpns_contract
1144 .document_type_for_name("domain")
1145 .expect("expected a profile document type");
1146
1147 assert!(!domain.documents_mutable());
1148 assert!(domain.documents_can_be_deleted());
1150 assert!(domain.documents_transferable().is_transferable());
1151
1152 let entropy = Bytes32::random_with_rng(&mut rng);
1153
1154 let mut preorder_document_1 = preorder
1155 .random_document_with_identifier_and_entropy(
1156 &mut rng,
1157 identity_1.id(),
1158 entropy,
1159 DocumentFieldFillType::FillIfNotRequired,
1160 DocumentFieldFillSize::AnyDocumentFillSize,
1161 platform_version,
1162 )
1163 .expect("expected a random document");
1164
1165 let mut preorder_document_2 = preorder
1166 .random_document_with_identifier_and_entropy(
1167 &mut rng,
1168 identity_2.id(),
1169 entropy,
1170 DocumentFieldFillType::FillIfNotRequired,
1171 DocumentFieldFillSize::AnyDocumentFillSize,
1172 platform_version,
1173 )
1174 .expect("expected a random document");
1175
1176 let mut document_1 = domain
1177 .random_document_with_identifier_and_entropy(
1178 &mut rng,
1179 identity_1.id(),
1180 entropy,
1181 DocumentFieldFillType::FillIfNotRequired,
1182 DocumentFieldFillSize::AnyDocumentFillSize,
1183 platform_version,
1184 )
1185 .expect("expected a random document");
1186
1187 let mut document_2 = domain
1188 .random_document_with_identifier_and_entropy(
1189 &mut rng,
1190 identity_2.id(),
1191 entropy,
1192 DocumentFieldFillType::FillIfNotRequired,
1193 DocumentFieldFillSize::AnyDocumentFillSize,
1194 platform_version,
1195 )
1196 .expect("expected a random document");
1197
1198 document_1.set("parentDomainName", "dash".into());
1199 document_1.set("normalizedParentDomainName", "dash".into());
1200 document_1.set("label", name.into());
1201 document_1.set(
1202 "normalizedLabel",
1203 convert_to_homograph_safe_chars(name).into(),
1204 );
1205 document_1.set("records.identity", document_1.owner_id().into());
1206 document_1.set("subdomainRules.allowSubdomains", false.into());
1207
1208 document_2.set("parentDomainName", "dash".into());
1209 document_2.set("normalizedParentDomainName", "dash".into());
1210 document_2.set("label", name.into());
1211 document_2.set(
1212 "normalizedLabel",
1213 convert_to_homograph_safe_chars(name).into(),
1214 );
1215 document_2.set("records.identity", document_2.owner_id().into());
1216 document_2.set("subdomainRules.allowSubdomains", false.into());
1217
1218 let salt_1: [u8; 32] = rng.gen();
1219 let salt_2: [u8; 32] = rng.gen();
1220
1221 let mut salted_domain_buffer_1: Vec<u8> = vec![];
1222 salted_domain_buffer_1.extend(salt_1);
1223 salted_domain_buffer_1.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes());
1224
1225 let salted_domain_hash_1 = hash_double(salted_domain_buffer_1);
1226
1227 let mut salted_domain_buffer_2: Vec<u8> = vec![];
1228 salted_domain_buffer_2.extend(salt_2);
1229 salted_domain_buffer_2.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes());
1230
1231 let salted_domain_hash_2 = hash_double(salted_domain_buffer_2);
1232
1233 preorder_document_1.set("saltedDomainHash", salted_domain_hash_1.into());
1234 preorder_document_2.set("saltedDomainHash", salted_domain_hash_2.into());
1235
1236 document_1.set("preorderSalt", salt_1.into());
1237 document_2.set("preorderSalt", salt_2.into());
1238
1239 let documents_batch_create_preorder_transition_1 =
1240 BatchTransition::new_document_creation_transition_from_document(
1241 preorder_document_1.clone(),
1242 preorder,
1243 entropy.0,
1244 key_1,
1245 2 + nonce_offset.unwrap_or_default(),
1246 0,
1247 None,
1248 signer_1,
1249 platform_version,
1250 None,
1251 )
1252 .await
1253 .expect("expect to create documents batch transition");
1254
1255 let documents_batch_create_serialized_preorder_transition_1 =
1256 documents_batch_create_preorder_transition_1
1257 .serialize_to_bytes()
1258 .expect("expected documents batch serialized state transition");
1259
1260 let documents_batch_create_preorder_transition_2 =
1261 BatchTransition::new_document_creation_transition_from_document(
1262 preorder_document_2.clone(),
1263 preorder,
1264 entropy.0,
1265 key_2,
1266 2 + nonce_offset.unwrap_or_default(),
1267 0,
1268 None,
1269 signer_2,
1270 platform_version,
1271 None,
1272 )
1273 .await
1274 .expect("expect to create documents batch transition");
1275
1276 let documents_batch_create_serialized_preorder_transition_2 =
1277 documents_batch_create_preorder_transition_2
1278 .serialize_to_bytes()
1279 .expect("expected documents batch serialized state transition");
1280
1281 let documents_batch_create_transition_1 =
1282 BatchTransition::new_document_creation_transition_from_document(
1283 document_1.clone(),
1284 domain,
1285 entropy.0,
1286 key_1,
1287 3 + nonce_offset.unwrap_or_default(),
1288 0,
1289 None,
1290 signer_1,
1291 platform_version,
1292 None,
1293 )
1294 .await
1295 .expect("expect to create documents batch transition");
1296
1297 let documents_batch_create_serialized_transition_1 = documents_batch_create_transition_1
1298 .serialize_to_bytes()
1299 .expect("expected documents batch serialized state transition");
1300
1301 let documents_batch_create_transition_2 =
1302 BatchTransition::new_document_creation_transition_from_document(
1303 document_2.clone(),
1304 domain,
1305 entropy.0,
1306 key_2,
1307 3 + nonce_offset.unwrap_or_default(),
1308 0,
1309 None,
1310 signer_2,
1311 platform_version,
1312 None,
1313 )
1314 .await
1315 .expect("expect to create documents batch transition");
1316
1317 let documents_batch_create_serialized_transition_2 = documents_batch_create_transition_2
1318 .serialize_to_bytes()
1319 .expect("expected documents batch serialized state transition");
1320
1321 if !skip_preorder {
1322 let transaction = platform.drive.grove.start_transaction();
1323
1324 let processing_result = platform
1325 .platform
1326 .process_raw_state_transitions(
1327 &[
1328 documents_batch_create_serialized_preorder_transition_1.clone(),
1329 documents_batch_create_serialized_preorder_transition_2.clone(),
1330 ],
1331 platform_state,
1332 &BlockInfo::default_with_time(
1333 platform_state
1334 .last_committed_block_time_ms()
1335 .unwrap_or_default()
1336 + 3000,
1337 ),
1338 &transaction,
1339 platform_version,
1340 false,
1341 None,
1342 )
1343 .expect("expected to process state transition");
1344
1345 platform
1346 .drive
1347 .grove
1348 .commit_transaction(transaction)
1349 .unwrap()
1350 .expect("expected to commit transaction");
1351
1352 let successful_count = processing_result
1353 .execution_results()
1354 .iter()
1355 .filter(|result| {
1356 assert_matches!(
1357 result,
1358 StateTransitionExecutionResult::SuccessfulExecution { .. }
1359 );
1360 true
1361 })
1362 .count();
1363
1364 assert_eq!(successful_count, 2);
1365 }
1366
1367 let transaction = platform.drive.grove.start_transaction();
1368
1369 let processing_result = platform
1370 .platform
1371 .process_raw_state_transitions(
1372 &[
1373 documents_batch_create_serialized_transition_1.clone(),
1374 documents_batch_create_serialized_transition_2.clone(),
1375 ],
1376 platform_state,
1377 &BlockInfo::default_with_time(
1378 platform_state
1379 .last_committed_block_time_ms()
1380 .unwrap_or_default()
1381 + 3000,
1382 ),
1383 &transaction,
1384 platform_version,
1385 false,
1386 None,
1387 )
1388 .expect("expected to process state transition");
1389
1390 platform
1391 .drive
1392 .grove
1393 .commit_transaction(transaction)
1394 .unwrap()
1395 .expect("expected to commit transaction");
1396
1397 let successful_count = processing_result
1398 .execution_results()
1399 .iter()
1400 .filter(|result| {
1401 assert_matches!(
1402 result,
1403 StateTransitionExecutionResult::SuccessfulExecution { .. }
1404 );
1405 true
1406 })
1407 .count();
1408
1409 assert_eq!(successful_count, 2);
1410 (
1411 ((preorder_document_1, entropy), (document_1, entropy)),
1412 ((preorder_document_2, entropy), (document_2, entropy)),
1413 dpns_contract,
1414 )
1415 }
1416
1417 #[allow(clippy::too_many_arguments)]
1418 async fn create_dpns_name_contest_on_identities_for_contract_records(
1419 platform: &mut TempPlatform<MockCoreRPCLike>,
1420 identity_1: &(Identity, SimpleSigner, IdentityPublicKey),
1421 identity_2: &(Identity, SimpleSigner, IdentityPublicKey),
1422 contract_1: &DataContract,
1423 contract_2: &DataContract,
1424 platform_state: &PlatformState,
1425 mut rng: StdRng,
1426 name: &str,
1427 platform_version: &PlatformVersion,
1428 ) -> (
1429 ((Document, Bytes32), (Document, Bytes32)),
1430 ((Document, Bytes32), (Document, Bytes32)),
1431 DataContract,
1432 ) {
1433 let (identity_1, signer_1, key_1) = identity_1;
1434
1435 let (identity_2, signer_2, key_2) = identity_2;
1436
1437 let dpns_contract = setup_contract(
1438 &platform.drive,
1439 "tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id.json",
1440 None,
1441 None,
1442 None::<fn(&mut DataContract)>,
1443 None,
1444 None,
1445 );
1446
1447 let preorder = dpns_contract
1448 .document_type_for_name("preorder")
1449 .expect("expected a profile document type");
1450
1451 assert!(!preorder.documents_mutable());
1452 assert!(preorder.documents_can_be_deleted());
1453 assert!(!preorder.documents_transferable().is_transferable());
1454
1455 let domain = dpns_contract
1456 .document_type_for_name("domain")
1457 .expect("expected a profile document type");
1458
1459 assert!(!domain.documents_mutable());
1460 assert!(domain.documents_can_be_deleted());
1462 assert!(domain.documents_transferable().is_transferable());
1463
1464 let entropy = Bytes32::random_with_rng(&mut rng);
1465
1466 let mut preorder_document_1 = preorder
1467 .random_document_with_identifier_and_entropy(
1468 &mut rng,
1469 identity_1.id(),
1470 entropy,
1471 DocumentFieldFillType::FillIfNotRequired,
1472 DocumentFieldFillSize::AnyDocumentFillSize,
1473 platform_version,
1474 )
1475 .expect("expected a random document");
1476
1477 let mut preorder_document_2 = preorder
1478 .random_document_with_identifier_and_entropy(
1479 &mut rng,
1480 identity_2.id(),
1481 entropy,
1482 DocumentFieldFillType::FillIfNotRequired,
1483 DocumentFieldFillSize::AnyDocumentFillSize,
1484 platform_version,
1485 )
1486 .expect("expected a random document");
1487
1488 let mut document_1 = domain
1489 .random_document_with_identifier_and_entropy(
1490 &mut rng,
1491 identity_1.id(),
1492 entropy,
1493 DocumentFieldFillType::FillIfNotRequired,
1494 DocumentFieldFillSize::AnyDocumentFillSize,
1495 platform_version,
1496 )
1497 .expect("expected a random document");
1498
1499 let mut document_2 = domain
1500 .random_document_with_identifier_and_entropy(
1501 &mut rng,
1502 identity_2.id(),
1503 entropy,
1504 DocumentFieldFillType::FillIfNotRequired,
1505 DocumentFieldFillSize::AnyDocumentFillSize,
1506 platform_version,
1507 )
1508 .expect("expected a random document");
1509
1510 document_1.set("parentDomainName", "dash".into());
1511 document_1.set("normalizedParentDomainName", "dash".into());
1512 document_1.set("label", name.into());
1513 document_1.set(
1514 "normalizedLabel",
1515 convert_to_homograph_safe_chars(name).into(),
1516 );
1517 document_1.remove("records.identity");
1518 document_1.set("records.contract", contract_1.id().into());
1519 document_1.set("subdomainRules.allowSubdomains", false.into());
1520
1521 document_2.set("parentDomainName", "dash".into());
1522 document_2.set("normalizedParentDomainName", "dash".into());
1523 document_2.set("label", name.into());
1524 document_2.set(
1525 "normalizedLabel",
1526 convert_to_homograph_safe_chars(name).into(),
1527 );
1528 document_2.remove("records.identity");
1529 document_2.set("records.contract", contract_2.id().into());
1530 document_2.set("subdomainRules.allowSubdomains", false.into());
1531
1532 let salt_1: [u8; 32] = rng.gen();
1533 let salt_2: [u8; 32] = rng.gen();
1534
1535 let mut salted_domain_buffer_1: Vec<u8> = vec![];
1536 salted_domain_buffer_1.extend(salt_1);
1537 salted_domain_buffer_1.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes());
1538
1539 let salted_domain_hash_1 = hash_double(salted_domain_buffer_1);
1540
1541 let mut salted_domain_buffer_2: Vec<u8> = vec![];
1542 salted_domain_buffer_2.extend(salt_2);
1543 salted_domain_buffer_2.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes());
1544
1545 let salted_domain_hash_2 = hash_double(salted_domain_buffer_2);
1546
1547 preorder_document_1.set("saltedDomainHash", salted_domain_hash_1.into());
1548 preorder_document_2.set("saltedDomainHash", salted_domain_hash_2.into());
1549
1550 document_1.set("preorderSalt", salt_1.into());
1551 document_2.set("preorderSalt", salt_2.into());
1552
1553 let documents_batch_create_preorder_transition_1 =
1554 BatchTransition::new_document_creation_transition_from_document(
1555 preorder_document_1.clone(),
1556 preorder,
1557 entropy.0,
1558 key_1,
1559 2,
1560 0,
1561 None,
1562 signer_1,
1563 platform_version,
1564 None,
1565 )
1566 .await
1567 .expect("expect to create documents batch transition");
1568
1569 let documents_batch_create_serialized_preorder_transition_1 =
1570 documents_batch_create_preorder_transition_1
1571 .serialize_to_bytes()
1572 .expect("expected documents batch serialized state transition");
1573
1574 let documents_batch_create_preorder_transition_2 =
1575 BatchTransition::new_document_creation_transition_from_document(
1576 preorder_document_2.clone(),
1577 preorder,
1578 entropy.0,
1579 key_2,
1580 2,
1581 0,
1582 None,
1583 signer_2,
1584 platform_version,
1585 None,
1586 )
1587 .await
1588 .expect("expect to create documents batch transition");
1589
1590 let documents_batch_create_serialized_preorder_transition_2 =
1591 documents_batch_create_preorder_transition_2
1592 .serialize_to_bytes()
1593 .expect("expected documents batch serialized state transition");
1594
1595 let documents_batch_create_transition_1 =
1596 BatchTransition::new_document_creation_transition_from_document(
1597 document_1.clone(),
1598 domain,
1599 entropy.0,
1600 key_1,
1601 3,
1602 0,
1603 None,
1604 signer_1,
1605 platform_version,
1606 None,
1607 )
1608 .await
1609 .expect("expect to create documents batch transition");
1610
1611 let documents_batch_create_serialized_transition_1 = documents_batch_create_transition_1
1612 .serialize_to_bytes()
1613 .expect("expected documents batch serialized state transition");
1614
1615 let documents_batch_create_transition_2 =
1616 BatchTransition::new_document_creation_transition_from_document(
1617 document_2.clone(),
1618 domain,
1619 entropy.0,
1620 key_2,
1621 3,
1622 0,
1623 None,
1624 signer_2,
1625 platform_version,
1626 None,
1627 )
1628 .await
1629 .expect("expect to create documents batch transition");
1630
1631 let documents_batch_create_serialized_transition_2 = documents_batch_create_transition_2
1632 .serialize_to_bytes()
1633 .expect("expected documents batch serialized state transition");
1634
1635 let transaction = platform.drive.grove.start_transaction();
1636
1637 let processing_result = platform
1638 .platform
1639 .process_raw_state_transitions(
1640 &[
1641 documents_batch_create_serialized_preorder_transition_1.clone(),
1642 documents_batch_create_serialized_preorder_transition_2.clone(),
1643 ],
1644 platform_state,
1645 &BlockInfo::default_with_time(
1646 platform_state
1647 .last_committed_block_time_ms()
1648 .unwrap_or_default()
1649 + 3000,
1650 ),
1651 &transaction,
1652 platform_version,
1653 false,
1654 None,
1655 )
1656 .expect("expected to process state transition");
1657
1658 platform
1659 .drive
1660 .grove
1661 .commit_transaction(transaction)
1662 .unwrap()
1663 .expect("expected to commit transaction");
1664
1665 assert_eq!(processing_result.valid_count(), 2);
1666
1667 let transaction = platform.drive.grove.start_transaction();
1668
1669 let processing_result = platform
1670 .platform
1671 .process_raw_state_transitions(
1672 &[
1673 documents_batch_create_serialized_transition_1.clone(),
1674 documents_batch_create_serialized_transition_2.clone(),
1675 ],
1676 platform_state,
1677 &BlockInfo::default_with_time(
1678 platform_state
1679 .last_committed_block_time_ms()
1680 .unwrap_or_default()
1681 + 3000,
1682 ),
1683 &transaction,
1684 platform_version,
1685 false,
1686 None,
1687 )
1688 .expect("expected to process state transition");
1689
1690 platform
1691 .drive
1692 .grove
1693 .commit_transaction(transaction)
1694 .unwrap()
1695 .expect("expected to commit transaction");
1696
1697 assert_eq!(processing_result.valid_count(), 2);
1698 (
1699 ((preorder_document_1, entropy), (document_1, entropy)),
1700 ((preorder_document_2, entropy), (document_2, entropy)),
1701 dpns_contract,
1702 )
1703 }
1704
1705 pub(in crate::execution) async fn add_contender_to_dpns_name_contest(
1706 platform: &mut TempPlatform<MockCoreRPCLike>,
1707 platform_state: &PlatformState,
1708 seed: u64,
1709 name: &str,
1710 expect_err: Option<&str>,
1711 platform_version: &PlatformVersion,
1712 ) -> Identity {
1713 let mut rng = StdRng::seed_from_u64(seed);
1714
1715 let (identity_1, signer_1, key_1) =
1716 setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
1717
1718 let dpns = platform.drive.cache.system_data_contracts.load_dpns();
1719 let dpns_contract = dpns.clone();
1720
1721 let preorder = dpns_contract
1722 .document_type_for_name("preorder")
1723 .expect("expected a profile document type");
1724
1725 let domain = dpns_contract
1726 .document_type_for_name("domain")
1727 .expect("expected a profile document type");
1728
1729 let entropy = Bytes32::random_with_rng(&mut rng);
1730
1731 let mut preorder_document_1 = preorder
1732 .random_document_with_identifier_and_entropy(
1733 &mut rng,
1734 identity_1.id(),
1735 entropy,
1736 DocumentFieldFillType::FillIfNotRequired,
1737 DocumentFieldFillSize::AnyDocumentFillSize,
1738 platform_version,
1739 )
1740 .expect("expected a random document");
1741
1742 let mut document_1 = domain
1743 .random_document_with_identifier_and_entropy(
1744 &mut rng,
1745 identity_1.id(),
1746 entropy,
1747 DocumentFieldFillType::FillIfNotRequired,
1748 DocumentFieldFillSize::AnyDocumentFillSize,
1749 platform_version,
1750 )
1751 .expect("expected a random document");
1752
1753 document_1.set("parentDomainName", "dash".into());
1754 document_1.set("normalizedParentDomainName", "dash".into());
1755 document_1.set("label", name.into());
1756 document_1.set(
1757 "normalizedLabel",
1758 convert_to_homograph_safe_chars(name).into(),
1759 );
1760 document_1.set("records.identity", document_1.owner_id().into());
1761 document_1.set("subdomainRules.allowSubdomains", false.into());
1762
1763 let salt_1: [u8; 32] = rng.gen();
1764
1765 let mut salted_domain_buffer_1: Vec<u8> = vec![];
1766 salted_domain_buffer_1.extend(salt_1);
1767 salted_domain_buffer_1.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes());
1768
1769 let salted_domain_hash_1 = hash_double(salted_domain_buffer_1);
1770
1771 preorder_document_1.set("saltedDomainHash", salted_domain_hash_1.into());
1772
1773 document_1.set("preorderSalt", salt_1.into());
1774
1775 let documents_batch_create_preorder_transition_1 =
1776 BatchTransition::new_document_creation_transition_from_document(
1777 preorder_document_1,
1778 preorder,
1779 entropy.0,
1780 &key_1,
1781 2,
1782 0,
1783 None,
1784 &signer_1,
1785 platform_version,
1786 None,
1787 )
1788 .await
1789 .expect("expect to create documents batch transition");
1790
1791 let documents_batch_create_serialized_preorder_transition_1 =
1792 documents_batch_create_preorder_transition_1
1793 .serialize_to_bytes()
1794 .expect("expected documents batch serialized state transition");
1795
1796 let documents_batch_create_transition_1 =
1797 BatchTransition::new_document_creation_transition_from_document(
1798 document_1,
1799 domain,
1800 entropy.0,
1801 &key_1,
1802 3,
1803 0,
1804 None,
1805 &signer_1,
1806 platform_version,
1807 None,
1808 )
1809 .await
1810 .expect("expect to create documents batch transition");
1811
1812 let documents_batch_create_serialized_transition_1 = documents_batch_create_transition_1
1813 .serialize_to_bytes()
1814 .expect("expected documents batch serialized state transition");
1815
1816 let transaction = platform.drive.grove.start_transaction();
1817
1818 let processing_result = platform
1819 .platform
1820 .process_raw_state_transitions(
1821 &[documents_batch_create_serialized_preorder_transition_1.clone()],
1822 platform_state,
1823 &BlockInfo::default_with_time(
1824 platform_state
1825 .last_committed_block_time_ms()
1826 .unwrap_or_default()
1827 + 3000,
1828 ),
1829 &transaction,
1830 platform_version,
1831 false,
1832 None,
1833 )
1834 .expect("expected to process state transition");
1835
1836 platform
1837 .drive
1838 .grove
1839 .commit_transaction(transaction)
1840 .unwrap()
1841 .expect("expected to commit transaction");
1842
1843 assert_eq!(processing_result.valid_count(), 1);
1844
1845 let transaction = platform.drive.grove.start_transaction();
1846
1847 let processing_result = platform
1848 .platform
1849 .process_raw_state_transitions(
1850 &[documents_batch_create_serialized_transition_1.clone()],
1851 platform_state,
1852 &BlockInfo::default_with_time(
1853 platform_state
1854 .last_committed_block_time_ms()
1855 .unwrap_or_default()
1856 + 3000,
1857 ),
1858 &transaction,
1859 platform_version,
1860 false,
1861 None,
1862 )
1863 .expect("expected to process state transition");
1864
1865 platform
1866 .drive
1867 .grove
1868 .commit_transaction(transaction)
1869 .unwrap()
1870 .expect("expected to commit transaction");
1871
1872 if let Some(expected_err) = expect_err {
1873 let result = processing_result.into_execution_results().remove(0);
1874
1875 let StateTransitionExecutionResult::PaidConsensusError {
1876 error: consensus_error,
1877 ..
1878 } = result
1879 else {
1880 panic!("expected a paid consensus error");
1881 };
1882 assert_eq!(consensus_error.to_string(), expected_err);
1883 } else {
1884 assert_eq!(processing_result.valid_count(), 1);
1885 }
1886 identity_1
1887 }
1888
1889 pub(in crate::execution) fn verify_dpns_name_contest(
1890 platform: &mut TempPlatform<MockCoreRPCLike>,
1891 platform_state: &Guard<Arc<PlatformState>>,
1892 dpns_contract: &DataContract,
1893 identity_1: &Identity,
1894 identity_2: &Identity,
1895 name: &str,
1896 platform_version: &PlatformVersion,
1897 ) {
1898 let domain = dpns_contract
1901 .document_type_for_name("domain")
1902 .expect("expected a profile document type");
1903
1904 let config = bincode::config::standard()
1905 .with_big_endian()
1906 .with_no_limit();
1907
1908 let dash_encoded = bincode::encode_to_vec(Value::Text("dash".to_string()), config)
1909 .expect("expected to encode the word dash");
1910
1911 let quantum_encoded =
1912 bincode::encode_to_vec(Value::Text(convert_to_homograph_safe_chars(name)), config)
1913 .expect("expected to encode the word quantum");
1914
1915 let index_name = "parentNameAndLabel".to_string();
1916
1917 let query_validation_result = platform
1918 .query_contested_resource_vote_state(
1919 GetContestedResourceVoteStateRequest {
1920 version: Some(get_contested_resource_vote_state_request::Version::V0(
1921 GetContestedResourceVoteStateRequestV0 {
1922 contract_id: dpns_contract.id().to_vec(),
1923 document_type_name: domain.name().clone(),
1924 index_name: index_name.clone(),
1925 index_values: vec![dash_encoded.clone(), quantum_encoded.clone()],
1926 result_type: ResultType::DocumentsAndVoteTally as i32,
1927 allow_include_locked_and_abstaining_vote_tally: true,
1928 start_at_identifier_info: None,
1929 count: None,
1930 prove: false,
1931 },
1932 )),
1933 },
1934 platform_state,
1935 platform_version,
1936 )
1937 .expect("expected to execute query")
1938 .into_data()
1939 .expect("expected query to be valid");
1940
1941 let get_contested_resource_vote_state_response::Version::V0(
1942 GetContestedResourceVoteStateResponseV0 {
1943 metadata: _,
1944 result,
1945 },
1946 ) = query_validation_result.version.expect("expected a version");
1947
1948 let Some(
1949 get_contested_resource_vote_state_response_v0::Result::ContestedResourceContenders(
1950 get_contested_resource_vote_state_response_v0::ContestedResourceContenders {
1951 contenders,
1952 ..
1953 },
1954 ),
1955 ) = result
1956 else {
1957 panic!("expected contenders")
1958 };
1959
1960 assert_eq!(contenders.len(), 2);
1961
1962 let first_contender = contenders.first().unwrap();
1963
1964 let second_contender = contenders.last().unwrap();
1965
1966 let first_contender_document = Document::from_bytes(
1967 first_contender
1968 .document
1969 .as_ref()
1970 .expect("expected a document")
1971 .as_slice(),
1972 domain,
1973 platform_version,
1974 )
1975 .expect("expected to get document");
1976
1977 let second_contender_document = Document::from_bytes(
1978 second_contender
1979 .document
1980 .as_ref()
1981 .expect("expected a document")
1982 .as_slice(),
1983 domain,
1984 platform_version,
1985 )
1986 .expect("expected to get document");
1987
1988 assert_ne!(first_contender_document, second_contender_document);
1989
1990 assert_eq!(first_contender.identifier, identity_1.id().to_vec());
1991
1992 assert_eq!(second_contender.identifier, identity_2.id().to_vec());
1993
1994 assert_eq!(first_contender.vote_count, Some(0));
1995
1996 assert_eq!(second_contender.vote_count, Some(0));
1997
1998 let GetContestedResourceVoteStateResponse { version } = platform
1999 .query_contested_resource_vote_state(
2000 GetContestedResourceVoteStateRequest {
2001 version: Some(get_contested_resource_vote_state_request::Version::V0(
2002 GetContestedResourceVoteStateRequestV0 {
2003 contract_id: dpns_contract.id().to_vec(),
2004 document_type_name: domain.name().clone(),
2005 index_name: "parentNameAndLabel".to_string(),
2006 index_values: vec![dash_encoded, quantum_encoded],
2007 result_type: ResultType::DocumentsAndVoteTally as i32,
2008 allow_include_locked_and_abstaining_vote_tally: true,
2009 start_at_identifier_info: None,
2010 count: None,
2011 prove: true,
2012 },
2013 )),
2014 },
2015 platform_state,
2016 platform_version,
2017 )
2018 .expect("expected to execute query")
2019 .into_data()
2020 .expect("expected query to be valid");
2021
2022 let get_contested_resource_vote_state_response::Version::V0(
2023 GetContestedResourceVoteStateResponseV0 {
2024 metadata: _,
2025 result,
2026 },
2027 ) = version.expect("expected a version");
2028
2029 let Some(get_contested_resource_vote_state_response_v0::Result::Proof(proof)) = result
2030 else {
2031 panic!("expected contenders")
2032 };
2033
2034 let resolved_contested_document_vote_poll_drive_query =
2035 ResolvedContestedDocumentVotePollDriveQuery {
2036 vote_poll: ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed {
2037 contract: DataContractResolvedInfo::BorrowedDataContract(dpns_contract),
2038 document_type_name: domain.name().clone(),
2039 index_name: index_name.clone(),
2040 index_values: vec![
2041 Value::Text("dash".to_string()),
2042 Value::Text(convert_to_homograph_safe_chars(name)),
2043 ],
2044 },
2045 result_type: DocumentsAndVoteTally,
2046 offset: None,
2047 limit: None,
2048 start_at: None,
2049 allow_include_locked_and_abstaining_vote_tally: true,
2050 };
2051
2052 let (_, result) = resolved_contested_document_vote_poll_drive_query
2053 .verify_vote_poll_vote_state_proof(proof.grovedb_proof.as_ref(), platform_version)
2054 .expect("expected to verify proof");
2055
2056 let contenders = result.contenders;
2057
2058 assert_eq!(contenders.len(), 2);
2059
2060 let first_contender = contenders.first().unwrap();
2061
2062 let second_contender = contenders.last().unwrap();
2063
2064 let first_contender_document = Document::from_bytes(
2065 first_contender
2066 .serialized_document()
2067 .as_ref()
2068 .expect("expected a document")
2069 .as_slice(),
2070 domain,
2071 platform_version,
2072 )
2073 .expect("expected to get document");
2074
2075 let second_contender_document = Document::from_bytes(
2076 second_contender
2077 .serialized_document()
2078 .as_ref()
2079 .expect("expected a document")
2080 .as_slice(),
2081 domain,
2082 platform_version,
2083 )
2084 .expect("expected to get document");
2085
2086 assert_ne!(first_contender_document, second_contender_document);
2087
2088 assert_eq!(first_contender.identity_id(), identity_1.id());
2089
2090 assert_eq!(second_contender.identity_id(), identity_2.id());
2091
2092 assert_eq!(first_contender.vote_tally(), Some(0));
2093
2094 assert_eq!(second_contender.vote_tally(), Some(0));
2095 }
2096
2097 #[allow(clippy::too_many_arguments)]
2098 pub(in crate::execution) async fn perform_vote(
2099 platform: &mut TempPlatform<MockCoreRPCLike>,
2100 platform_state: &Guard<Arc<PlatformState>>,
2101 dpns_contract: &DataContract,
2102 resource_vote_choice: ResourceVoteChoice,
2103 name: &str,
2104 signer: &SimpleSigner,
2105 pro_tx_hash: Identifier,
2106 voting_key: &IdentityPublicKey,
2107 nonce: IdentityNonce,
2108 expect_error: Option<&str>,
2109 platform_version: &PlatformVersion,
2110 ) {
2111 let vote = Vote::ResourceVote(ResourceVote::V0(ResourceVoteV0 {
2114 vote_poll: VotePoll::ContestedDocumentResourceVotePoll(
2115 ContestedDocumentResourceVotePoll {
2116 contract_id: dpns_contract.id(),
2117 document_type_name: "domain".to_string(),
2118 index_name: "parentNameAndLabel".to_string(),
2119 index_values: vec![
2120 Value::Text("dash".to_string()),
2121 Value::Text(convert_to_homograph_safe_chars(name)),
2122 ],
2123 },
2124 ),
2125 resource_vote_choice,
2126 }));
2127
2128 let masternode_vote_transition = MasternodeVoteTransition::try_from_vote_with_signer(
2129 vote,
2130 signer,
2131 pro_tx_hash,
2132 voting_key,
2133 nonce,
2134 platform_version,
2135 None,
2136 )
2137 .await
2138 .expect("expected to make transition vote");
2139
2140 let masternode_vote_serialized_transition = masternode_vote_transition
2141 .serialize_to_bytes()
2142 .expect("expected documents batch serialized state transition");
2143
2144 let transaction = platform.drive.grove.start_transaction();
2145
2146 let processing_result = platform
2147 .platform
2148 .process_raw_state_transitions(
2149 &[masternode_vote_serialized_transition.clone()],
2150 platform_state,
2151 &BlockInfo::default(),
2152 &transaction,
2153 platform_version,
2154 false,
2155 None,
2156 )
2157 .expect("expected to process state transition");
2158
2159 platform
2160 .drive
2161 .grove
2162 .commit_transaction(transaction)
2163 .unwrap()
2164 .expect("expected to commit transaction");
2165
2166 let execution_result = processing_result.into_execution_results().remove(0);
2167 if let Some(error_msg) = expect_error {
2168 assert_matches!(execution_result, UnpaidConsensusError(..));
2169 let UnpaidConsensusError(consensus_error) = execution_result else {
2170 panic!()
2171 };
2172 assert_eq!(consensus_error.to_string(), error_msg)
2173 } else {
2174 assert_matches!(execution_result, SuccessfulExecution { .. });
2175 }
2176 }
2177
2178 #[allow(clippy::too_many_arguments)]
2179 pub(in crate::execution) async fn perform_votes(
2180 platform: &mut TempPlatform<MockCoreRPCLike>,
2181 dpns_contract: &DataContract,
2182 resource_vote_choice: ResourceVoteChoice,
2183 name: &str,
2184 count: u64,
2185 start_seed: u64,
2186 nonce_offset: Option<IdentityNonce>,
2187 platform_version: &PlatformVersion,
2188 ) -> Vec<(Identifier, Identity, SimpleSigner, IdentityPublicKey)> {
2189 let mut masternode_infos = vec![];
2190 for i in 0..count {
2191 let (pro_tx_hash_bytes, voting_identity, signer, voting_key) =
2192 setup_masternode_voting_identity(platform, start_seed + i, platform_version);
2193
2194 let platform_state = platform.state.load();
2195
2196 perform_vote(
2197 platform,
2198 &platform_state,
2199 dpns_contract,
2200 resource_vote_choice,
2201 name,
2202 &signer,
2203 pro_tx_hash_bytes,
2204 &voting_key,
2205 1 + nonce_offset.unwrap_or_default(),
2206 None,
2207 platform_version,
2208 )
2209 .await;
2210
2211 masternode_infos.push((pro_tx_hash_bytes, voting_identity, signer, voting_key));
2212 }
2213 masternode_infos
2214 }
2215
2216 pub(in crate::execution) async fn perform_votes_multi(
2217 platform: &mut TempPlatform<MockCoreRPCLike>,
2218 dpns_contract: &DataContract,
2219 resource_vote_choices: Vec<(ResourceVoteChoice, u64)>,
2220 name: &str,
2221 start_seed: u64,
2222 nonce_offset: Option<IdentityNonce>,
2223 platform_version: &PlatformVersion,
2224 ) -> BTreeMap<ResourceVoteChoice, Vec<(Identifier, Identity, SimpleSigner, IdentityPublicKey)>>
2225 {
2226 let mut count_aggregate = start_seed;
2227 let mut masternodes_by_vote_choice = BTreeMap::new();
2228 for (resource_vote_choice, count) in resource_vote_choices.into_iter() {
2229 let masternode_infos = perform_votes(
2230 platform,
2231 dpns_contract,
2232 resource_vote_choice,
2233 name,
2234 count,
2235 count_aggregate,
2236 nonce_offset,
2237 platform_version,
2238 )
2239 .await;
2240 masternodes_by_vote_choice.insert(resource_vote_choice, masternode_infos);
2241 count_aggregate += count;
2242 }
2243 masternodes_by_vote_choice
2244 }
2245
2246 #[allow(clippy::too_many_arguments)]
2247 pub(in crate::execution) fn get_vote_states(
2248 platform: &TempPlatform<MockCoreRPCLike>,
2249 platform_state: &PlatformState,
2250 dpns_contract: &DataContract,
2251 name: &str,
2252 count: Option<u32>,
2253 allow_include_locked_and_abstaining_vote_tally: bool,
2254 start_at_identifier_info: Option<
2255 get_contested_resource_vote_state_request_v0::StartAtIdentifierInfo,
2256 >,
2257 result_type: ResultType,
2258 platform_version: &PlatformVersion,
2259 ) -> (
2260 Vec<Contender>,
2261 Option<u32>,
2262 Option<u32>,
2263 Option<FinishedVoteInfo>,
2264 ) {
2265 let domain = dpns_contract
2268 .document_type_for_name("domain")
2269 .expect("expected a profile document type");
2270
2271 let config = bincode::config::standard()
2272 .with_big_endian()
2273 .with_no_limit();
2274
2275 let dash_encoded = bincode::encode_to_vec(Value::Text("dash".to_string()), config)
2276 .expect("expected to encode the word dash");
2277
2278 let name_encoded =
2279 bincode::encode_to_vec(Value::Text(convert_to_homograph_safe_chars(name)), config)
2280 .expect("expected to encode the word quantum");
2281
2282 let index_name = "parentNameAndLabel".to_string();
2283
2284 let query_validation_result = platform
2285 .query_contested_resource_vote_state(
2286 GetContestedResourceVoteStateRequest {
2287 version: Some(get_contested_resource_vote_state_request::Version::V0(
2288 GetContestedResourceVoteStateRequestV0 {
2289 contract_id: dpns_contract.id().to_vec(),
2290 document_type_name: domain.name().clone(),
2291 index_name: index_name.clone(),
2292 index_values: vec![dash_encoded.clone(), name_encoded.clone()],
2293 result_type: result_type as i32,
2294 allow_include_locked_and_abstaining_vote_tally,
2295 start_at_identifier_info,
2296 count,
2297 prove: false,
2298 },
2299 )),
2300 },
2301 platform_state,
2302 platform_version,
2303 )
2304 .expect("expected to execute query")
2305 .into_data()
2306 .expect("expected query to be valid");
2307
2308 let get_contested_resource_vote_state_response::Version::V0(
2309 GetContestedResourceVoteStateResponseV0 {
2310 metadata: _,
2311 result,
2312 },
2313 ) = query_validation_result.version.expect("expected a version");
2314
2315 let Some(
2316 get_contested_resource_vote_state_response_v0::Result::ContestedResourceContenders(
2317 get_contested_resource_vote_state_response_v0::ContestedResourceContenders {
2318 contenders,
2319 abstain_vote_tally,
2320 lock_vote_tally,
2321 finished_vote_info,
2322 },
2323 ),
2324 ) = result
2325 else {
2326 panic!("expected contenders")
2327 };
2328 (
2329 contenders
2330 .into_iter()
2331 .map(|contender| {
2332 ContenderV0 {
2333 identity_id: contender.identifier.try_into().expect("expected 32 bytes"),
2334 document: contender.document.map(|document_bytes| {
2335 Document::from_bytes(
2336 document_bytes.as_slice(),
2337 domain,
2338 platform_version,
2339 )
2340 .expect("expected to deserialize document")
2341 }),
2342 vote_tally: contender.vote_count,
2343 }
2344 .into()
2345 })
2346 .collect(),
2347 abstain_vote_tally,
2348 lock_vote_tally,
2349 finished_vote_info,
2350 )
2351 }
2352
2353 #[allow(clippy::too_many_arguments)]
2354 pub(in crate::execution) fn get_proved_vote_states(
2355 platform: &TempPlatform<MockCoreRPCLike>,
2356 platform_state: &PlatformState,
2357 dpns_contract: &DataContract,
2358 name: &str,
2359 count: Option<u32>,
2360 allow_include_locked_and_abstaining_vote_tally: bool,
2361 start_at_identifier_info: Option<
2362 get_contested_resource_vote_state_request_v0::StartAtIdentifierInfo,
2363 >,
2364 result_type: ResultType,
2365 platform_version: &PlatformVersion,
2366 ) -> (
2367 Vec<Contender>,
2368 Option<u32>,
2369 Option<u32>,
2370 Option<(ContestedDocumentVotePollWinnerInfo, BlockInfo)>,
2371 ) {
2372 let domain = dpns_contract
2375 .document_type_for_name("domain")
2376 .expect("expected a profile document type");
2377
2378 let config = bincode::config::standard()
2379 .with_big_endian()
2380 .with_no_limit();
2381
2382 let dash_encoded = bincode::encode_to_vec(Value::Text("dash".to_string()), config)
2383 .expect("expected to encode the word dash");
2384
2385 let name_encoded =
2386 bincode::encode_to_vec(Value::Text(convert_to_homograph_safe_chars(name)), config)
2387 .expect("expected to encode the word quantum");
2388
2389 let index_name = "parentNameAndLabel".to_string();
2390
2391 let query_validation_result = platform
2392 .query_contested_resource_vote_state(
2393 GetContestedResourceVoteStateRequest {
2394 version: Some(get_contested_resource_vote_state_request::Version::V0(
2395 GetContestedResourceVoteStateRequestV0 {
2396 contract_id: dpns_contract.id().to_vec(),
2397 document_type_name: domain.name().clone(),
2398 index_name: index_name.clone(),
2399 index_values: vec![dash_encoded.clone(), name_encoded.clone()],
2400 result_type: result_type as i32,
2401 allow_include_locked_and_abstaining_vote_tally,
2402 start_at_identifier_info,
2403 count,
2404 prove: true,
2405 },
2406 )),
2407 },
2408 platform_state,
2409 platform_version,
2410 )
2411 .expect("expected to execute query")
2412 .into_data()
2413 .expect("expected query to be valid");
2414
2415 let get_contested_resource_vote_state_response::Version::V0(
2416 GetContestedResourceVoteStateResponseV0 {
2417 metadata: _,
2418 result,
2419 },
2420 ) = query_validation_result.version.expect("expected a version");
2421
2422 let Some(get_contested_resource_vote_state_response_v0::Result::Proof(proof)) = result
2423 else {
2424 panic!("expected contenders")
2425 };
2426
2427 let resolved_contested_document_vote_poll_drive_query =
2428 ResolvedContestedDocumentVotePollDriveQuery {
2429 vote_poll: ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed {
2430 contract: DataContractResolvedInfo::BorrowedDataContract(dpns_contract),
2431 document_type_name: domain.name().clone(),
2432 index_name: index_name.clone(),
2433 index_values: vec![
2434 Value::Text("dash".to_string()),
2435 Value::Text(convert_to_homograph_safe_chars(name)),
2436 ],
2437 },
2438 result_type: ContestedDocumentVotePollDriveQueryResultType::try_from(
2439 result_type as i32,
2440 )
2441 .expect("expected valid result type"),
2442 offset: None,
2443 limit: count.map(|a| a as u16),
2444 start_at: None,
2445 allow_include_locked_and_abstaining_vote_tally,
2446 };
2447
2448 let (_, result) = resolved_contested_document_vote_poll_drive_query
2449 .verify_vote_poll_vote_state_proof(proof.grovedb_proof.as_ref(), platform_version)
2450 .expect("expected to verify proof");
2451
2452 let abstaining_vote_tally = result.abstaining_vote_tally;
2453 let lock_vote_tally = result.locked_vote_tally;
2454
2455 let contenders = result.contenders;
2456 let finished_vote_info = result.winner;
2457 (
2458 contenders
2459 .into_iter()
2460 .map(|contender| {
2461 ContenderV0 {
2462 identity_id: contender.identity_id(),
2463 document: contender
2464 .serialized_document()
2465 .as_ref()
2466 .map(|document_bytes| {
2467 Document::from_bytes(
2468 document_bytes.as_slice(),
2469 domain,
2470 platform_version,
2471 )
2472 .expect("expected to deserialize document")
2473 }),
2474 vote_tally: contender.vote_tally(),
2475 }
2476 .into()
2477 })
2478 .collect(),
2479 abstaining_vote_tally,
2480 lock_vote_tally,
2481 finished_vote_info,
2482 )
2483 }
2484
2485 pub(in crate::execution) fn create_token_contract_with_owner_identity(
2486 platform: &mut TempPlatform<MockCoreRPCLike>,
2487 identity_id: Identifier,
2488 token_configuration_modification: Option<impl FnOnce(&mut TokenConfiguration)>,
2489 contract_start_time: Option<TimestampMillis>,
2490 add_groups: Option<BTreeMap<GroupContractPosition, Group>>,
2491 contract_start_block: Option<BlockHeight>,
2492 platform_version: &PlatformVersion,
2493 ) -> (DataContract, Identifier) {
2494 let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1);
2495
2496 let basic_token_contract = setup_contract(
2497 &platform.drive,
2498 "tests/supporting_files/contract/basic-token/basic-token.json",
2499 Some(data_contract_id.to_buffer()),
2500 Some(identity_id.to_buffer()),
2501 Some(|data_contract: &mut DataContract| {
2502 data_contract.set_created_at_epoch(Some(0));
2503 data_contract.set_created_at(Some(contract_start_time.unwrap_or_default()));
2504 data_contract
2505 .set_created_at_block_height(Some(contract_start_block.unwrap_or_default()));
2506 if let Some(token_configuration_modification) = token_configuration_modification {
2507 let token_configuration = data_contract
2508 .token_configuration_mut(0)
2509 .expect("expected token configuration");
2510 token_configuration_modification(token_configuration);
2511 }
2512 if let Some(add_groups) = add_groups {
2513 data_contract.set_groups(add_groups);
2514 }
2515 }),
2516 None,
2517 Some(platform_version),
2518 );
2519
2520 let token_id = calculate_token_id(data_contract_id.as_bytes(), 0);
2521
2522 (basic_token_contract, token_id.into())
2523 }
2524
2525 pub(in crate::execution) fn create_card_game_internal_token_contract_with_owner_identity_burn_tokens(
2526 platform: &mut TempPlatform<MockCoreRPCLike>,
2527 identity_id: Identifier,
2528 platform_version: &PlatformVersion,
2529 ) -> (DataContract, Identifier, Identifier) {
2530 let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1);
2531
2532 let basic_token_contract = setup_contract(
2533 &platform.drive,
2534 "tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency-burn-tokens.json",
2535 Some(data_contract_id.to_buffer()),
2536 Some(identity_id.to_buffer()),
2537 Some(|data_contract: &mut DataContract| {
2538 data_contract.set_created_at_epoch(Some(0));
2539 data_contract.set_created_at(Some(0));
2540 data_contract.set_created_at_block_height(Some(0));
2541 }),
2542 None,
2543 Some(platform_version),
2544 );
2545
2546 let token_id = calculate_token_id(data_contract_id.as_bytes(), 0);
2547 let token_id_2 = calculate_token_id(data_contract_id.as_bytes(), 1);
2548
2549 (basic_token_contract, token_id.into(), token_id_2.into())
2550 }
2551
2552 pub(in crate::execution) fn create_card_game_internal_token_contract_with_owner_identity_transfer_tokens(
2553 platform: &mut TempPlatform<MockCoreRPCLike>,
2554 identity_id: Identifier,
2555 platform_version: &PlatformVersion,
2556 ) -> (DataContract, Identifier, Identifier) {
2557 let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1);
2558
2559 let basic_token_contract = setup_contract(
2560 &platform.drive,
2561 "tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency.json",
2562 Some(data_contract_id.to_buffer()),
2563 Some(identity_id.to_buffer()),
2564 Some(|data_contract: &mut DataContract| {
2565 data_contract.set_created_at_epoch(Some(0));
2566 data_contract.set_created_at(Some(0));
2567 data_contract.set_created_at_block_height(Some(0));
2568 }),
2569 None,
2570 Some(platform_version),
2571 );
2572
2573 let token_id = calculate_token_id(data_contract_id.as_bytes(), 0);
2574 let token_id_2 = calculate_token_id(data_contract_id.as_bytes(), 1);
2575
2576 (basic_token_contract, token_id.into(), token_id_2.into())
2577 }
2578
2579 pub(in crate::execution) fn create_card_game_external_token_contract_with_owner_identity(
2580 platform: &mut TempPlatform<MockCoreRPCLike>,
2581 token_contract_id: Identifier,
2582 token_contract_position: TokenContractPosition,
2583 token_cost_amount: TokenAmount,
2584 gas_fees_paid_by: GasFeesPaidBy,
2585 identity_id: Identifier,
2586 platform_version: &PlatformVersion,
2587 ) -> DataContract {
2588 let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1);
2589
2590 let basic_token_contract = setup_contract(
2591 &platform.drive,
2592 "tests/supporting_files/contract/crypto-card-game/crypto-card-game-use-external-currency.json",
2593 Some(data_contract_id.to_buffer()),
2594 Some(identity_id.to_buffer()),
2595 Some(|data_contract: &mut DataContract| {
2596 data_contract.set_created_at_epoch(Some(0));
2597 data_contract.set_created_at(Some(0));
2598 data_contract.set_created_at_block_height(Some(0));
2599 let document_type = data_contract.document_types_mut().get_mut("card").expect("expected a document type with name card");
2600 document_type.set_document_creation_token_cost(Some(DocumentActionTokenCost {
2601 contract_id: Some(token_contract_id),
2602 token_contract_position,
2603 token_amount: token_cost_amount,
2604 effect: DocumentActionTokenEffect::TransferTokenToContractOwner,
2605 gas_fees_paid_by,
2606 }));
2607 let gas_fees_paid_by_int: u8 = gas_fees_paid_by.into();
2608 let schema = document_type.schema_mut();
2609 let token_cost = schema.get_mut("tokenCost").expect("expected to get token cost").expect("expected token cost to be set");
2610 let creation_token_cost = token_cost.get_mut("create").expect("expected to get creation token cost").expect("expected creation token cost to be set");
2611 creation_token_cost.set_value("contractId", token_contract_id.into()).expect("expected to set token contract id");
2612 creation_token_cost.set_value("tokenPosition", token_contract_position.into()).expect("expected to set token position");
2613 creation_token_cost.set_value("amount", token_cost_amount.into()).expect("expected to set token amount");
2614 creation_token_cost.set_value("gasFeesPaidBy", gas_fees_paid_by_int.into()).expect("expected to set token amount");
2615 }),
2616 None,
2617 Some(platform_version),
2618 );
2619
2620 basic_token_contract
2621 }
2622
2623 pub(in crate::execution) fn process_test_state_transition<S: PlatformSerializable>(
2624 platform: &mut TempPlatform<MockCoreRPCLike>,
2625 state_transition: S,
2626 platform_state: &PlatformState,
2627 platform_version: &PlatformVersion,
2628 ) -> StateTransitionsProcessingResult {
2629 let Ok(serialized_state_transition) = state_transition.serialize_to_bytes() else {
2630 panic!("expected documents batch serialized state transition")
2631 };
2632
2633 let transaction = platform.drive.grove.start_transaction();
2634
2635 let processing_result = platform
2636 .platform
2637 .process_raw_state_transitions(
2638 &[serialized_state_transition],
2639 platform_state,
2640 &BlockInfo::default(),
2641 &transaction,
2642 platform_version,
2643 false,
2644 None,
2645 )
2646 .expect("expected to process state transition");
2647
2648 platform
2649 .drive
2650 .grove
2651 .commit_transaction(transaction)
2652 .unwrap()
2653 .expect("expected to commit transaction");
2654
2655 processing_result
2656 }
2657
2658 mod keyword_search_contract {
2659 use dpp::consensus::basic::BasicError;
2660 use dpp::consensus::ConsensusError;
2661 use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult::PaidConsensusError;
2662 use super::*;
2663 fn build_random_doc_of_type(
2672 rng: &mut StdRng,
2673 doc_type_name: &str,
2674 identity_id: Identifier,
2675 contract: &DataContract,
2676 platform_version: &PlatformVersion,
2677 ) -> (Document, Bytes32) {
2678 let doc_type = contract
2679 .document_type_for_name(doc_type_name)
2680 .expect("doc type exists");
2681
2682 let entropy = Bytes32::random_with_rng(rng);
2683
2684 let doc = doc_type
2685 .random_document_with_identifier_and_entropy(
2686 rng,
2687 identity_id,
2688 entropy,
2689 DocumentFieldFillType::FillIfNotRequired,
2690 DocumentFieldFillSize::AnyDocumentFillSize,
2691 platform_version,
2692 )
2693 .expect("random doc");
2694
2695 (doc, entropy)
2696 }
2697
2698 #[tokio::test]
2699 async fn should_err_when_creating_contract_keywords_document() {
2700 let platform_version = PlatformVersion::latest();
2701
2702 let mut platform = TestPlatformBuilder::new()
2703 .build_with_mock_rpc()
2704 .set_genesis_state();
2705
2706 let (identity, signer, key) = setup_identity(&mut platform, 42, dash_to_credits!(1.0));
2707
2708 let contract = load_system_data_contract(
2709 SystemDataContract::KeywordSearch,
2710 PlatformVersion::latest(),
2711 )
2712 .expect("expected to load search contract");
2713
2714 let mut rng = StdRng::seed_from_u64(1);
2715 let (doc, entropy) = build_random_doc_of_type(
2716 &mut rng,
2717 "contractKeywords",
2718 identity.id(),
2719 &contract,
2720 platform_version,
2721 );
2722
2723 let transition = BatchTransition::new_document_creation_transition_from_document(
2724 doc,
2725 contract.document_type_for_name("contractKeywords").unwrap(),
2726 entropy.0, &key,
2728 1,
2729 0,
2730 None,
2731 &signer,
2732 platform_version,
2733 None,
2734 )
2735 .await
2736 .expect("batch transition");
2737
2738 let serialized = transition.serialize_to_bytes().unwrap();
2739
2740 let platform_state = platform.state.load();
2741 let processing_result = platform
2742 .platform
2743 .process_raw_state_transitions(
2744 &[serialized],
2745 &platform_state,
2746 &BlockInfo::default(),
2747 &platform.drive.grove.start_transaction(),
2748 platform_version,
2749 false,
2750 None,
2751 )
2752 .expect("processing failed");
2753
2754 let execution_result = processing_result.into_execution_results().remove(0);
2755 assert_matches!(
2756 execution_result,
2757 StateTransitionExecutionResult::PaidConsensusError{ error, .. }
2758 if error.to_string().contains("not allowed because of the document type's creation restriction mode")
2759 );
2760 }
2761
2762 #[tokio::test]
2763 async fn should_err_when_creating_short_description_document() {
2764 let platform_version = PlatformVersion::latest();
2765
2766 let mut platform = TestPlatformBuilder::new()
2767 .build_with_mock_rpc()
2768 .set_genesis_state();
2769
2770 let (identity, signer, key) = setup_identity(&mut platform, 43, dash_to_credits!(1.0));
2771
2772 let contract = load_system_data_contract(
2773 SystemDataContract::KeywordSearch,
2774 PlatformVersion::latest(),
2775 )
2776 .expect("expected to load search contract");
2777
2778 let mut rng = StdRng::seed_from_u64(2);
2779 let (doc, entropy) = build_random_doc_of_type(
2780 &mut rng,
2781 "shortDescription",
2782 identity.id(),
2783 &contract,
2784 platform_version,
2785 );
2786
2787 let transition = BatchTransition::new_document_creation_transition_from_document(
2788 doc,
2789 contract.document_type_for_name("shortDescription").unwrap(),
2790 entropy.0,
2791 &key,
2792 1,
2793 0,
2794 None,
2795 &signer,
2796 platform_version,
2797 None,
2798 )
2799 .await
2800 .expect("batch transition");
2801
2802 let serialized = transition.serialize_to_bytes().unwrap();
2803
2804 let platform_state = platform.state.load();
2805 let processing_result = platform
2806 .platform
2807 .process_raw_state_transitions(
2808 &[serialized],
2809 &platform_state,
2810 &BlockInfo::default(),
2811 &platform.drive.grove.start_transaction(),
2812 platform_version,
2813 false,
2814 None,
2815 )
2816 .expect("processing failed");
2817
2818 let execution_result = processing_result.into_execution_results().remove(0);
2819 assert_matches!(
2820 execution_result,
2821 StateTransitionExecutionResult::PaidConsensusError{ error, .. }
2822 if error.to_string().contains("not allowed because of the document type's creation restriction mode")
2823 );
2824 }
2825
2826 #[tokio::test]
2827 async fn should_err_when_creating_full_description_document() {
2828 let platform_version = PlatformVersion::latest();
2829
2830 let mut platform = TestPlatformBuilder::new()
2831 .build_with_mock_rpc()
2832 .set_genesis_state();
2833
2834 let (identity, signer, key) = setup_identity(&mut platform, 44, dash_to_credits!(1.0));
2835
2836 let contract = load_system_data_contract(
2837 SystemDataContract::KeywordSearch,
2838 PlatformVersion::latest(),
2839 )
2840 .expect("expected to load search contract");
2841
2842 let mut rng = StdRng::seed_from_u64(3);
2843 let (doc, entropy) = build_random_doc_of_type(
2844 &mut rng,
2845 "fullDescription",
2846 identity.id(),
2847 &contract,
2848 platform_version,
2849 );
2850
2851 let transition = BatchTransition::new_document_creation_transition_from_document(
2852 doc,
2853 contract.document_type_for_name("fullDescription").unwrap(),
2854 entropy.0,
2855 &key,
2856 1,
2857 0,
2858 None,
2859 &signer,
2860 platform_version,
2861 None,
2862 )
2863 .await
2864 .expect("batch transition");
2865
2866 let serialized = transition.serialize_to_bytes().unwrap();
2867
2868 let platform_state = platform.state.load();
2869 let processing_result = platform
2870 .platform
2871 .process_raw_state_transitions(
2872 &[serialized],
2873 &platform_state,
2874 &BlockInfo::default(),
2875 &platform.drive.grove.start_transaction(),
2876 platform_version,
2877 false,
2878 None,
2879 )
2880 .expect("processing failed");
2881
2882 let execution_result = processing_result.into_execution_results().remove(0);
2883 assert_matches!(
2884 execution_result,
2885 StateTransitionExecutionResult::PaidConsensusError{ error, .. }
2886 if error.to_string().contains("not allowed because of the document type's creation restriction mode")
2887 );
2888 }
2889
2890 async fn create_contract_with_keywords_and_description(
2897 platform: &mut TempPlatform<MockCoreRPCLike>,
2898 ) -> (Identity, SimpleSigner, IdentityPublicKey) {
2899 let platform_version = PlatformVersion::latest();
2900
2901 let (owner_identity, signer, key) =
2903 setup_identity(platform, 777, dash_to_credits!(1.0));
2904
2905 let mut contract = json_document_to_contract_with_ids(
2907 "tests/supporting_files/contract/keyword_test/keyword_base_contract.json",
2908 Some(owner_identity.id()),
2909 None,
2910 false,
2911 platform_version,
2912 )
2913 .expect("load contract");
2914
2915 contract.set_description(Some("A short description".to_string()));
2917 contract.set_keywords(vec!["graph".into(), "indexing".into()]);
2918
2919 let create_transition = DataContractCreateTransition::new_from_data_contract(
2921 contract,
2922 1,
2923 &owner_identity.clone().into_partial_identity_info(),
2924 key.id(),
2925 &signer,
2926 platform_version,
2927 None,
2928 )
2929 .await
2930 .expect("build transition");
2931
2932 let serialized = create_transition.serialize_to_bytes().unwrap();
2933 let platform_state = platform.state.load();
2934 let tx = platform.drive.grove.start_transaction();
2935
2936 let processing_result = platform
2937 .platform
2938 .process_raw_state_transitions(
2939 &[serialized],
2940 &platform_state,
2941 &BlockInfo::default(),
2942 &tx,
2943 platform_version,
2944 false,
2945 None,
2946 )
2947 .expect("process");
2948
2949 assert_matches!(
2950 processing_result.execution_results().as_slice(),
2951 [StateTransitionExecutionResult::SuccessfulExecution { .. }]
2952 );
2953
2954 platform
2955 .drive
2956 .grove
2957 .commit_transaction(tx)
2958 .unwrap()
2959 .expect("commit");
2960
2961 (owner_identity, signer, key)
2962 }
2963
2964 #[tokio::test]
2965 async fn owner_can_update_short_description_document() {
2966 let platform_version = PlatformVersion::latest();
2967 let mut platform = TestPlatformBuilder::new()
2968 .build_with_mock_rpc()
2969 .set_genesis_state();
2970
2971 let (_owner, signer, key) =
2972 create_contract_with_keywords_and_description(&mut platform).await;
2973
2974 let search_contract =
2976 load_system_data_contract(SystemDataContract::KeywordSearch, platform_version)
2977 .expect("load search contract");
2978
2979 let doc_type = search_contract
2980 .document_type_for_name("shortDescription")
2981 .unwrap();
2982
2983 let query = DriveDocumentQuery::all_items_query(&search_contract, doc_type, None);
2984 let existing_docs = platform
2985 .drive
2986 .query_documents(
2987 query,
2988 None,
2989 false,
2990 None,
2991 Some(platform_version.protocol_version),
2992 )
2993 .expect("query failed");
2994
2995 let mut doc = existing_docs.documents().first().expect("doc").clone();
2996 doc.set_revision(Some(doc.revision().unwrap_or_default() + 1));
2997 doc.set("description", "updated description".into());
2998
2999 let transition = BatchTransition::new_document_replacement_transition_from_document(
3000 doc,
3001 doc_type,
3002 &key,
3003 2,
3004 0,
3005 None,
3006 &signer,
3007 platform_version,
3008 None,
3009 )
3010 .await
3011 .expect("replace");
3012
3013 let serialized = transition.serialize_to_bytes().unwrap();
3014 let platform_state = platform.state.load();
3015
3016 let processing_result = platform
3017 .platform
3018 .process_raw_state_transitions(
3019 &[serialized],
3020 &platform_state,
3021 &BlockInfo::default(),
3022 &platform.drive.grove.start_transaction(),
3023 platform_version,
3024 false,
3025 None,
3026 )
3027 .expect("process");
3028
3029 assert_matches!(
3030 processing_result.into_execution_results().remove(0),
3031 SuccessfulExecution { .. }
3032 );
3033 }
3034
3035 #[tokio::test]
3036 async fn owner_can_not_delete_keyword_document() {
3037 let platform_version = PlatformVersion::latest();
3038 let mut platform = TestPlatformBuilder::new()
3039 .build_with_mock_rpc()
3040 .set_genesis_state();
3041
3042 let (_owner, signer, key) =
3043 create_contract_with_keywords_and_description(&mut platform).await;
3044
3045 let search_contract =
3046 load_system_data_contract(SystemDataContract::KeywordSearch, platform_version)
3047 .expect("load search contract");
3048 let doc_type = search_contract
3049 .document_type_for_name("contractKeywords")
3050 .unwrap();
3051
3052 let query = DriveDocumentQuery::all_items_query(&search_contract, doc_type, None);
3053 let existing_docs = platform
3054 .drive
3055 .query_documents(
3056 query,
3057 None,
3058 false,
3059 None,
3060 Some(platform_version.protocol_version),
3061 )
3062 .expect("query failed");
3063
3064 let doc = existing_docs.documents().first().unwrap().clone();
3065
3066 let transition = BatchTransition::new_document_deletion_transition_from_document(
3067 doc,
3068 doc_type,
3069 &key,
3070 2,
3071 0,
3072 None,
3073 &signer,
3074 platform_version,
3075 None,
3076 )
3077 .await
3078 .expect("delete");
3079
3080 let serialized = transition.serialize_to_bytes().unwrap();
3081 let platform_state = platform.state.load();
3082
3083 let processing_result = platform
3084 .platform
3085 .process_raw_state_transitions(
3086 &[serialized],
3087 &platform_state,
3088 &BlockInfo::default(),
3089 &platform.drive.grove.start_transaction(),
3090 platform_version,
3091 false,
3092 None,
3093 )
3094 .expect("process");
3095 assert_matches!(
3096 processing_result.execution_results().as_slice(),
3097 [PaidConsensusError {
3098 error: ConsensusError::BasicError(
3099 BasicError::InvalidDocumentTransitionActionError { .. }
3100 ),
3101 ..
3102 }]
3103 );
3104 }
3105 }
3106}