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) 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 .expect("expected to create and sign data contract create transition");
873
874 let state_transition_bytes = state_transition
876 .serialize_to_bytes()
877 .expect("expected to serialize state transition");
878
879 let transaction = platform.drive.grove.start_transaction();
880
881 let processing_result = platform
882 .platform
883 .process_raw_state_transitions(
884 &[state_transition_bytes],
885 platform_state,
886 &BlockInfo::default(),
887 &transaction,
888 platform_version,
889 false,
890 None,
891 )
892 .expect("expected to process state transition");
893
894 platform
895 .drive
896 .grove
897 .commit_transaction(transaction)
898 .unwrap()
899 .expect("expected to commit transaction");
900
901 let execution_result = processing_result.into_execution_results().remove(0);
902 assert_matches!(execution_result, SuccessfulExecution { .. });
903
904 data_contract
905 }
906
907 pub(in crate::execution) fn create_dpns_name_contest_give_key_info(
908 platform: &mut TempPlatform<MockCoreRPCLike>,
909 platform_state: &PlatformState,
910 seed: u64,
911 name: &str,
912 platform_version: &PlatformVersion,
913 ) -> (
914 (
915 Identity,
916 SimpleSigner,
917 IdentityPublicKey,
918 (Document, Bytes32),
919 (Document, Bytes32),
920 ),
921 (
922 Identity,
923 SimpleSigner,
924 IdentityPublicKey,
925 (Document, Bytes32),
926 (Document, Bytes32),
927 ),
928 Arc<DataContract>,
929 ) {
930 let mut rng = StdRng::seed_from_u64(seed);
931
932 let identity_1_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
933
934 let identity_2_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
935
936 let (identity_1_info, identity_2_info) = if identity_1_info.0.id() < identity_2_info.0.id()
938 {
939 (identity_1_info, identity_2_info)
940 } else {
941 (identity_2_info, identity_1_info)
942 };
943
944 let ((preorder_document_1, document_1), (preorder_document_2, document_2), dpns_contract) =
945 create_dpns_name_contest_on_identities(
946 platform,
947 &identity_1_info,
948 &identity_2_info,
949 platform_state,
950 rng,
951 name,
952 None,
953 false,
954 platform_version,
955 );
956
957 let (identity_1, signer_1, identity_key_1) = identity_1_info;
958
959 let (identity_2, signer_2, identity_key_2) = identity_2_info;
960
961 (
962 (
963 identity_1,
964 signer_1,
965 identity_key_1,
966 preorder_document_1,
967 document_1,
968 ),
969 (
970 identity_2,
971 signer_2,
972 identity_key_2,
973 preorder_document_2,
974 document_2,
975 ),
976 dpns_contract,
977 )
978 }
979
980 pub(in crate::execution) fn create_dpns_identity_name_contest(
981 platform: &mut TempPlatform<MockCoreRPCLike>,
982 platform_state: &PlatformState,
983 seed: u64,
984 name: &str,
985 platform_version: &PlatformVersion,
986 ) -> (Identity, Identity, Arc<DataContract>) {
987 let mut rng = StdRng::seed_from_u64(seed);
988
989 let identity_1_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
990
991 let identity_2_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
992
993 let (identity_1_info, identity_2_info) = if identity_1_info.0.id() < identity_2_info.0.id()
995 {
996 (identity_1_info, identity_2_info)
997 } else {
998 (identity_2_info, identity_1_info)
999 };
1000
1001 let (_, _, dpns_contract) = create_dpns_name_contest_on_identities(
1002 platform,
1003 &identity_1_info,
1004 &identity_2_info,
1005 platform_state,
1006 rng,
1007 name,
1008 None,
1009 false,
1010 platform_version,
1011 );
1012 (identity_1_info.0, identity_2_info.0, dpns_contract)
1013 }
1014
1015 pub(in crate::execution) fn create_dpns_identity_name_contest_skip_creating_identities(
1017 platform: &mut TempPlatform<MockCoreRPCLike>,
1018 platform_state: &PlatformState,
1019 seed: u64,
1020 name: &str,
1021 nonce_offset: Option<IdentityNonce>,
1022 platform_version: &PlatformVersion,
1023 ) -> (Identity, Identity, Arc<DataContract>) {
1024 let mut rng = StdRng::seed_from_u64(seed);
1025
1026 let identity_1_info = setup_identity_without_adding_it(rng.gen(), dash_to_credits!(0.5));
1027
1028 let identity_2_info = setup_identity_without_adding_it(rng.gen(), dash_to_credits!(0.5));
1029
1030 let (identity_1_info, identity_2_info) = if identity_1_info.0.id() < identity_2_info.0.id()
1032 {
1033 (identity_1_info, identity_2_info)
1034 } else {
1035 (identity_2_info, identity_1_info)
1036 };
1037
1038 let (_, _, dpns_contract) = create_dpns_name_contest_on_identities(
1039 platform,
1040 &identity_1_info,
1041 &identity_2_info,
1042 platform_state,
1043 rng,
1044 name,
1045 nonce_offset,
1046 true, platform_version,
1048 );
1049 (identity_1_info.0, identity_2_info.0, dpns_contract)
1050 }
1051
1052 pub(in crate::execution) fn create_dpns_contract_name_contest(
1053 platform: &mut TempPlatform<MockCoreRPCLike>,
1054 platform_state: &PlatformState,
1055 seed: u64,
1056 name: &str,
1057 platform_version: &PlatformVersion,
1058 ) -> (Identity, Identity, DataContract) {
1059 let mut rng = StdRng::seed_from_u64(seed);
1060
1061 let identity_1_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
1062
1063 let identity_2_info = setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
1064
1065 let (identity_1_info, identity_2_info) = if identity_1_info.0.id() < identity_2_info.0.id()
1067 {
1068 (identity_1_info, identity_2_info)
1069 } else {
1070 (identity_2_info, identity_1_info)
1071 };
1072
1073 let dashpay_contract = setup_contract(
1074 &platform.drive,
1075 "tests/supporting_files/contract/dashpay/dashpay-contract-all-mutable.json",
1076 None,
1077 None,
1078 None::<fn(&mut DataContract)>,
1079 None,
1080 None,
1081 );
1082
1083 let card_game = setup_contract(
1084 &platform.drive,
1085 "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase.json",
1086 None,
1087 None,
1088 None::<fn(&mut DataContract)>,
1089 None,
1090 None,
1091 );
1092
1093 let (_, _, dpns_contract) = create_dpns_name_contest_on_identities_for_contract_records(
1094 platform,
1095 &identity_1_info,
1096 &identity_2_info,
1097 &dashpay_contract,
1098 &card_game,
1099 platform_state,
1100 rng,
1101 name,
1102 platform_version,
1103 );
1104 (identity_1_info.0, identity_2_info.0, dpns_contract)
1105 }
1106
1107 #[allow(clippy::too_many_arguments)]
1108 fn create_dpns_name_contest_on_identities(
1109 platform: &mut TempPlatform<MockCoreRPCLike>,
1110 identity_1: &(Identity, SimpleSigner, IdentityPublicKey),
1111 identity_2: &(Identity, SimpleSigner, IdentityPublicKey),
1112 platform_state: &PlatformState,
1113 mut rng: StdRng,
1114 name: &str,
1115 nonce_offset: Option<IdentityNonce>,
1116 skip_preorder: bool,
1117 platform_version: &PlatformVersion,
1118 ) -> (
1119 ((Document, Bytes32), (Document, Bytes32)),
1120 ((Document, Bytes32), (Document, Bytes32)),
1121 Arc<DataContract>,
1122 ) {
1123 let (identity_1, signer_1, key_1) = identity_1;
1124
1125 let (identity_2, signer_2, key_2) = identity_2;
1126
1127 let dpns = platform.drive.cache.system_data_contracts.load_dpns();
1128 let dpns_contract = dpns.clone();
1129
1130 let preorder = dpns_contract
1131 .document_type_for_name("preorder")
1132 .expect("expected a profile document type");
1133
1134 assert!(!preorder.documents_mutable());
1135 assert!(preorder.documents_can_be_deleted());
1136 assert!(!preorder.documents_transferable().is_transferable());
1137
1138 let domain = dpns_contract
1139 .document_type_for_name("domain")
1140 .expect("expected a profile document type");
1141
1142 assert!(!domain.documents_mutable());
1143 assert!(domain.documents_can_be_deleted());
1145 assert!(domain.documents_transferable().is_transferable());
1146
1147 let entropy = Bytes32::random_with_rng(&mut rng);
1148
1149 let mut preorder_document_1 = preorder
1150 .random_document_with_identifier_and_entropy(
1151 &mut rng,
1152 identity_1.id(),
1153 entropy,
1154 DocumentFieldFillType::FillIfNotRequired,
1155 DocumentFieldFillSize::AnyDocumentFillSize,
1156 platform_version,
1157 )
1158 .expect("expected a random document");
1159
1160 let mut preorder_document_2 = preorder
1161 .random_document_with_identifier_and_entropy(
1162 &mut rng,
1163 identity_2.id(),
1164 entropy,
1165 DocumentFieldFillType::FillIfNotRequired,
1166 DocumentFieldFillSize::AnyDocumentFillSize,
1167 platform_version,
1168 )
1169 .expect("expected a random document");
1170
1171 let mut document_1 = domain
1172 .random_document_with_identifier_and_entropy(
1173 &mut rng,
1174 identity_1.id(),
1175 entropy,
1176 DocumentFieldFillType::FillIfNotRequired,
1177 DocumentFieldFillSize::AnyDocumentFillSize,
1178 platform_version,
1179 )
1180 .expect("expected a random document");
1181
1182 let mut document_2 = domain
1183 .random_document_with_identifier_and_entropy(
1184 &mut rng,
1185 identity_2.id(),
1186 entropy,
1187 DocumentFieldFillType::FillIfNotRequired,
1188 DocumentFieldFillSize::AnyDocumentFillSize,
1189 platform_version,
1190 )
1191 .expect("expected a random document");
1192
1193 document_1.set("parentDomainName", "dash".into());
1194 document_1.set("normalizedParentDomainName", "dash".into());
1195 document_1.set("label", name.into());
1196 document_1.set(
1197 "normalizedLabel",
1198 convert_to_homograph_safe_chars(name).into(),
1199 );
1200 document_1.set("records.identity", document_1.owner_id().into());
1201 document_1.set("subdomainRules.allowSubdomains", false.into());
1202
1203 document_2.set("parentDomainName", "dash".into());
1204 document_2.set("normalizedParentDomainName", "dash".into());
1205 document_2.set("label", name.into());
1206 document_2.set(
1207 "normalizedLabel",
1208 convert_to_homograph_safe_chars(name).into(),
1209 );
1210 document_2.set("records.identity", document_2.owner_id().into());
1211 document_2.set("subdomainRules.allowSubdomains", false.into());
1212
1213 let salt_1: [u8; 32] = rng.gen();
1214 let salt_2: [u8; 32] = rng.gen();
1215
1216 let mut salted_domain_buffer_1: Vec<u8> = vec![];
1217 salted_domain_buffer_1.extend(salt_1);
1218 salted_domain_buffer_1.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes());
1219
1220 let salted_domain_hash_1 = hash_double(salted_domain_buffer_1);
1221
1222 let mut salted_domain_buffer_2: Vec<u8> = vec![];
1223 salted_domain_buffer_2.extend(salt_2);
1224 salted_domain_buffer_2.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes());
1225
1226 let salted_domain_hash_2 = hash_double(salted_domain_buffer_2);
1227
1228 preorder_document_1.set("saltedDomainHash", salted_domain_hash_1.into());
1229 preorder_document_2.set("saltedDomainHash", salted_domain_hash_2.into());
1230
1231 document_1.set("preorderSalt", salt_1.into());
1232 document_2.set("preorderSalt", salt_2.into());
1233
1234 let documents_batch_create_preorder_transition_1 =
1235 BatchTransition::new_document_creation_transition_from_document(
1236 preorder_document_1.clone(),
1237 preorder,
1238 entropy.0,
1239 key_1,
1240 2 + nonce_offset.unwrap_or_default(),
1241 0,
1242 None,
1243 signer_1,
1244 platform_version,
1245 None,
1246 )
1247 .expect("expect to create documents batch transition");
1248
1249 let documents_batch_create_serialized_preorder_transition_1 =
1250 documents_batch_create_preorder_transition_1
1251 .serialize_to_bytes()
1252 .expect("expected documents batch serialized state transition");
1253
1254 let documents_batch_create_preorder_transition_2 =
1255 BatchTransition::new_document_creation_transition_from_document(
1256 preorder_document_2.clone(),
1257 preorder,
1258 entropy.0,
1259 key_2,
1260 2 + nonce_offset.unwrap_or_default(),
1261 0,
1262 None,
1263 signer_2,
1264 platform_version,
1265 None,
1266 )
1267 .expect("expect to create documents batch transition");
1268
1269 let documents_batch_create_serialized_preorder_transition_2 =
1270 documents_batch_create_preorder_transition_2
1271 .serialize_to_bytes()
1272 .expect("expected documents batch serialized state transition");
1273
1274 let documents_batch_create_transition_1 =
1275 BatchTransition::new_document_creation_transition_from_document(
1276 document_1.clone(),
1277 domain,
1278 entropy.0,
1279 key_1,
1280 3 + nonce_offset.unwrap_or_default(),
1281 0,
1282 None,
1283 signer_1,
1284 platform_version,
1285 None,
1286 )
1287 .expect("expect to create documents batch transition");
1288
1289 let documents_batch_create_serialized_transition_1 = documents_batch_create_transition_1
1290 .serialize_to_bytes()
1291 .expect("expected documents batch serialized state transition");
1292
1293 let documents_batch_create_transition_2 =
1294 BatchTransition::new_document_creation_transition_from_document(
1295 document_2.clone(),
1296 domain,
1297 entropy.0,
1298 key_2,
1299 3 + nonce_offset.unwrap_or_default(),
1300 0,
1301 None,
1302 signer_2,
1303 platform_version,
1304 None,
1305 )
1306 .expect("expect to create documents batch transition");
1307
1308 let documents_batch_create_serialized_transition_2 = documents_batch_create_transition_2
1309 .serialize_to_bytes()
1310 .expect("expected documents batch serialized state transition");
1311
1312 if !skip_preorder {
1313 let transaction = platform.drive.grove.start_transaction();
1314
1315 let processing_result = platform
1316 .platform
1317 .process_raw_state_transitions(
1318 &[
1319 documents_batch_create_serialized_preorder_transition_1.clone(),
1320 documents_batch_create_serialized_preorder_transition_2.clone(),
1321 ],
1322 platform_state,
1323 &BlockInfo::default_with_time(
1324 platform_state
1325 .last_committed_block_time_ms()
1326 .unwrap_or_default()
1327 + 3000,
1328 ),
1329 &transaction,
1330 platform_version,
1331 false,
1332 None,
1333 )
1334 .expect("expected to process state transition");
1335
1336 platform
1337 .drive
1338 .grove
1339 .commit_transaction(transaction)
1340 .unwrap()
1341 .expect("expected to commit transaction");
1342
1343 let successful_count = processing_result
1344 .execution_results()
1345 .iter()
1346 .filter(|result| {
1347 assert_matches!(
1348 result,
1349 StateTransitionExecutionResult::SuccessfulExecution { .. }
1350 );
1351 true
1352 })
1353 .count();
1354
1355 assert_eq!(successful_count, 2);
1356 }
1357
1358 let transaction = platform.drive.grove.start_transaction();
1359
1360 let processing_result = platform
1361 .platform
1362 .process_raw_state_transitions(
1363 &[
1364 documents_batch_create_serialized_transition_1.clone(),
1365 documents_batch_create_serialized_transition_2.clone(),
1366 ],
1367 platform_state,
1368 &BlockInfo::default_with_time(
1369 platform_state
1370 .last_committed_block_time_ms()
1371 .unwrap_or_default()
1372 + 3000,
1373 ),
1374 &transaction,
1375 platform_version,
1376 false,
1377 None,
1378 )
1379 .expect("expected to process state transition");
1380
1381 platform
1382 .drive
1383 .grove
1384 .commit_transaction(transaction)
1385 .unwrap()
1386 .expect("expected to commit transaction");
1387
1388 let successful_count = processing_result
1389 .execution_results()
1390 .iter()
1391 .filter(|result| {
1392 assert_matches!(
1393 result,
1394 StateTransitionExecutionResult::SuccessfulExecution { .. }
1395 );
1396 true
1397 })
1398 .count();
1399
1400 assert_eq!(successful_count, 2);
1401 (
1402 ((preorder_document_1, entropy), (document_1, entropy)),
1403 ((preorder_document_2, entropy), (document_2, entropy)),
1404 dpns_contract,
1405 )
1406 }
1407
1408 #[allow(clippy::too_many_arguments)]
1409 fn create_dpns_name_contest_on_identities_for_contract_records(
1410 platform: &mut TempPlatform<MockCoreRPCLike>,
1411 identity_1: &(Identity, SimpleSigner, IdentityPublicKey),
1412 identity_2: &(Identity, SimpleSigner, IdentityPublicKey),
1413 contract_1: &DataContract,
1414 contract_2: &DataContract,
1415 platform_state: &PlatformState,
1416 mut rng: StdRng,
1417 name: &str,
1418 platform_version: &PlatformVersion,
1419 ) -> (
1420 ((Document, Bytes32), (Document, Bytes32)),
1421 ((Document, Bytes32), (Document, Bytes32)),
1422 DataContract,
1423 ) {
1424 let (identity_1, signer_1, key_1) = identity_1;
1425
1426 let (identity_2, signer_2, key_2) = identity_2;
1427
1428 let dpns_contract = setup_contract(
1429 &platform.drive,
1430 "tests/supporting_files/contract/dpns/dpns-contract-contested-unique-index-with-contract-id.json",
1431 None,
1432 None,
1433 None::<fn(&mut DataContract)>,
1434 None,
1435 None,
1436 );
1437
1438 let preorder = dpns_contract
1439 .document_type_for_name("preorder")
1440 .expect("expected a profile document type");
1441
1442 assert!(!preorder.documents_mutable());
1443 assert!(preorder.documents_can_be_deleted());
1444 assert!(!preorder.documents_transferable().is_transferable());
1445
1446 let domain = dpns_contract
1447 .document_type_for_name("domain")
1448 .expect("expected a profile document type");
1449
1450 assert!(!domain.documents_mutable());
1451 assert!(domain.documents_can_be_deleted());
1453 assert!(domain.documents_transferable().is_transferable());
1454
1455 let entropy = Bytes32::random_with_rng(&mut rng);
1456
1457 let mut preorder_document_1 = preorder
1458 .random_document_with_identifier_and_entropy(
1459 &mut rng,
1460 identity_1.id(),
1461 entropy,
1462 DocumentFieldFillType::FillIfNotRequired,
1463 DocumentFieldFillSize::AnyDocumentFillSize,
1464 platform_version,
1465 )
1466 .expect("expected a random document");
1467
1468 let mut preorder_document_2 = preorder
1469 .random_document_with_identifier_and_entropy(
1470 &mut rng,
1471 identity_2.id(),
1472 entropy,
1473 DocumentFieldFillType::FillIfNotRequired,
1474 DocumentFieldFillSize::AnyDocumentFillSize,
1475 platform_version,
1476 )
1477 .expect("expected a random document");
1478
1479 let mut document_1 = domain
1480 .random_document_with_identifier_and_entropy(
1481 &mut rng,
1482 identity_1.id(),
1483 entropy,
1484 DocumentFieldFillType::FillIfNotRequired,
1485 DocumentFieldFillSize::AnyDocumentFillSize,
1486 platform_version,
1487 )
1488 .expect("expected a random document");
1489
1490 let mut document_2 = domain
1491 .random_document_with_identifier_and_entropy(
1492 &mut rng,
1493 identity_2.id(),
1494 entropy,
1495 DocumentFieldFillType::FillIfNotRequired,
1496 DocumentFieldFillSize::AnyDocumentFillSize,
1497 platform_version,
1498 )
1499 .expect("expected a random document");
1500
1501 document_1.set("parentDomainName", "dash".into());
1502 document_1.set("normalizedParentDomainName", "dash".into());
1503 document_1.set("label", name.into());
1504 document_1.set(
1505 "normalizedLabel",
1506 convert_to_homograph_safe_chars(name).into(),
1507 );
1508 document_1.remove("records.identity");
1509 document_1.set("records.contract", contract_1.id().into());
1510 document_1.set("subdomainRules.allowSubdomains", false.into());
1511
1512 document_2.set("parentDomainName", "dash".into());
1513 document_2.set("normalizedParentDomainName", "dash".into());
1514 document_2.set("label", name.into());
1515 document_2.set(
1516 "normalizedLabel",
1517 convert_to_homograph_safe_chars(name).into(),
1518 );
1519 document_2.remove("records.identity");
1520 document_2.set("records.contract", contract_2.id().into());
1521 document_2.set("subdomainRules.allowSubdomains", false.into());
1522
1523 let salt_1: [u8; 32] = rng.gen();
1524 let salt_2: [u8; 32] = rng.gen();
1525
1526 let mut salted_domain_buffer_1: Vec<u8> = vec![];
1527 salted_domain_buffer_1.extend(salt_1);
1528 salted_domain_buffer_1.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes());
1529
1530 let salted_domain_hash_1 = hash_double(salted_domain_buffer_1);
1531
1532 let mut salted_domain_buffer_2: Vec<u8> = vec![];
1533 salted_domain_buffer_2.extend(salt_2);
1534 salted_domain_buffer_2.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes());
1535
1536 let salted_domain_hash_2 = hash_double(salted_domain_buffer_2);
1537
1538 preorder_document_1.set("saltedDomainHash", salted_domain_hash_1.into());
1539 preorder_document_2.set("saltedDomainHash", salted_domain_hash_2.into());
1540
1541 document_1.set("preorderSalt", salt_1.into());
1542 document_2.set("preorderSalt", salt_2.into());
1543
1544 let documents_batch_create_preorder_transition_1 =
1545 BatchTransition::new_document_creation_transition_from_document(
1546 preorder_document_1.clone(),
1547 preorder,
1548 entropy.0,
1549 key_1,
1550 2,
1551 0,
1552 None,
1553 signer_1,
1554 platform_version,
1555 None,
1556 )
1557 .expect("expect to create documents batch transition");
1558
1559 let documents_batch_create_serialized_preorder_transition_1 =
1560 documents_batch_create_preorder_transition_1
1561 .serialize_to_bytes()
1562 .expect("expected documents batch serialized state transition");
1563
1564 let documents_batch_create_preorder_transition_2 =
1565 BatchTransition::new_document_creation_transition_from_document(
1566 preorder_document_2.clone(),
1567 preorder,
1568 entropy.0,
1569 key_2,
1570 2,
1571 0,
1572 None,
1573 signer_2,
1574 platform_version,
1575 None,
1576 )
1577 .expect("expect to create documents batch transition");
1578
1579 let documents_batch_create_serialized_preorder_transition_2 =
1580 documents_batch_create_preorder_transition_2
1581 .serialize_to_bytes()
1582 .expect("expected documents batch serialized state transition");
1583
1584 let documents_batch_create_transition_1 =
1585 BatchTransition::new_document_creation_transition_from_document(
1586 document_1.clone(),
1587 domain,
1588 entropy.0,
1589 key_1,
1590 3,
1591 0,
1592 None,
1593 signer_1,
1594 platform_version,
1595 None,
1596 )
1597 .expect("expect to create documents batch transition");
1598
1599 let documents_batch_create_serialized_transition_1 = documents_batch_create_transition_1
1600 .serialize_to_bytes()
1601 .expect("expected documents batch serialized state transition");
1602
1603 let documents_batch_create_transition_2 =
1604 BatchTransition::new_document_creation_transition_from_document(
1605 document_2.clone(),
1606 domain,
1607 entropy.0,
1608 key_2,
1609 3,
1610 0,
1611 None,
1612 signer_2,
1613 platform_version,
1614 None,
1615 )
1616 .expect("expect to create documents batch transition");
1617
1618 let documents_batch_create_serialized_transition_2 = documents_batch_create_transition_2
1619 .serialize_to_bytes()
1620 .expect("expected documents batch serialized state transition");
1621
1622 let transaction = platform.drive.grove.start_transaction();
1623
1624 let processing_result = platform
1625 .platform
1626 .process_raw_state_transitions(
1627 &[
1628 documents_batch_create_serialized_preorder_transition_1.clone(),
1629 documents_batch_create_serialized_preorder_transition_2.clone(),
1630 ],
1631 platform_state,
1632 &BlockInfo::default_with_time(
1633 platform_state
1634 .last_committed_block_time_ms()
1635 .unwrap_or_default()
1636 + 3000,
1637 ),
1638 &transaction,
1639 platform_version,
1640 false,
1641 None,
1642 )
1643 .expect("expected to process state transition");
1644
1645 platform
1646 .drive
1647 .grove
1648 .commit_transaction(transaction)
1649 .unwrap()
1650 .expect("expected to commit transaction");
1651
1652 assert_eq!(processing_result.valid_count(), 2);
1653
1654 let transaction = platform.drive.grove.start_transaction();
1655
1656 let processing_result = platform
1657 .platform
1658 .process_raw_state_transitions(
1659 &[
1660 documents_batch_create_serialized_transition_1.clone(),
1661 documents_batch_create_serialized_transition_2.clone(),
1662 ],
1663 platform_state,
1664 &BlockInfo::default_with_time(
1665 platform_state
1666 .last_committed_block_time_ms()
1667 .unwrap_or_default()
1668 + 3000,
1669 ),
1670 &transaction,
1671 platform_version,
1672 false,
1673 None,
1674 )
1675 .expect("expected to process state transition");
1676
1677 platform
1678 .drive
1679 .grove
1680 .commit_transaction(transaction)
1681 .unwrap()
1682 .expect("expected to commit transaction");
1683
1684 assert_eq!(processing_result.valid_count(), 2);
1685 (
1686 ((preorder_document_1, entropy), (document_1, entropy)),
1687 ((preorder_document_2, entropy), (document_2, entropy)),
1688 dpns_contract,
1689 )
1690 }
1691
1692 pub(in crate::execution) fn add_contender_to_dpns_name_contest(
1693 platform: &mut TempPlatform<MockCoreRPCLike>,
1694 platform_state: &PlatformState,
1695 seed: u64,
1696 name: &str,
1697 expect_err: Option<&str>,
1698 platform_version: &PlatformVersion,
1699 ) -> Identity {
1700 let mut rng = StdRng::seed_from_u64(seed);
1701
1702 let (identity_1, signer_1, key_1) =
1703 setup_identity(platform, rng.gen(), dash_to_credits!(0.5));
1704
1705 let dpns = platform.drive.cache.system_data_contracts.load_dpns();
1706 let dpns_contract = dpns.clone();
1707
1708 let preorder = dpns_contract
1709 .document_type_for_name("preorder")
1710 .expect("expected a profile document type");
1711
1712 let domain = dpns_contract
1713 .document_type_for_name("domain")
1714 .expect("expected a profile document type");
1715
1716 let entropy = Bytes32::random_with_rng(&mut rng);
1717
1718 let mut preorder_document_1 = preorder
1719 .random_document_with_identifier_and_entropy(
1720 &mut rng,
1721 identity_1.id(),
1722 entropy,
1723 DocumentFieldFillType::FillIfNotRequired,
1724 DocumentFieldFillSize::AnyDocumentFillSize,
1725 platform_version,
1726 )
1727 .expect("expected a random document");
1728
1729 let mut document_1 = domain
1730 .random_document_with_identifier_and_entropy(
1731 &mut rng,
1732 identity_1.id(),
1733 entropy,
1734 DocumentFieldFillType::FillIfNotRequired,
1735 DocumentFieldFillSize::AnyDocumentFillSize,
1736 platform_version,
1737 )
1738 .expect("expected a random document");
1739
1740 document_1.set("parentDomainName", "dash".into());
1741 document_1.set("normalizedParentDomainName", "dash".into());
1742 document_1.set("label", name.into());
1743 document_1.set(
1744 "normalizedLabel",
1745 convert_to_homograph_safe_chars(name).into(),
1746 );
1747 document_1.set("records.identity", document_1.owner_id().into());
1748 document_1.set("subdomainRules.allowSubdomains", false.into());
1749
1750 let salt_1: [u8; 32] = rng.gen();
1751
1752 let mut salted_domain_buffer_1: Vec<u8> = vec![];
1753 salted_domain_buffer_1.extend(salt_1);
1754 salted_domain_buffer_1.extend((convert_to_homograph_safe_chars(name) + ".dash").as_bytes());
1755
1756 let salted_domain_hash_1 = hash_double(salted_domain_buffer_1);
1757
1758 preorder_document_1.set("saltedDomainHash", salted_domain_hash_1.into());
1759
1760 document_1.set("preorderSalt", salt_1.into());
1761
1762 let documents_batch_create_preorder_transition_1 =
1763 BatchTransition::new_document_creation_transition_from_document(
1764 preorder_document_1,
1765 preorder,
1766 entropy.0,
1767 &key_1,
1768 2,
1769 0,
1770 None,
1771 &signer_1,
1772 platform_version,
1773 None,
1774 )
1775 .expect("expect to create documents batch transition");
1776
1777 let documents_batch_create_serialized_preorder_transition_1 =
1778 documents_batch_create_preorder_transition_1
1779 .serialize_to_bytes()
1780 .expect("expected documents batch serialized state transition");
1781
1782 let documents_batch_create_transition_1 =
1783 BatchTransition::new_document_creation_transition_from_document(
1784 document_1,
1785 domain,
1786 entropy.0,
1787 &key_1,
1788 3,
1789 0,
1790 None,
1791 &signer_1,
1792 platform_version,
1793 None,
1794 )
1795 .expect("expect to create documents batch transition");
1796
1797 let documents_batch_create_serialized_transition_1 = documents_batch_create_transition_1
1798 .serialize_to_bytes()
1799 .expect("expected documents batch serialized state transition");
1800
1801 let transaction = platform.drive.grove.start_transaction();
1802
1803 let processing_result = platform
1804 .platform
1805 .process_raw_state_transitions(
1806 &[documents_batch_create_serialized_preorder_transition_1.clone()],
1807 platform_state,
1808 &BlockInfo::default_with_time(
1809 platform_state
1810 .last_committed_block_time_ms()
1811 .unwrap_or_default()
1812 + 3000,
1813 ),
1814 &transaction,
1815 platform_version,
1816 false,
1817 None,
1818 )
1819 .expect("expected to process state transition");
1820
1821 platform
1822 .drive
1823 .grove
1824 .commit_transaction(transaction)
1825 .unwrap()
1826 .expect("expected to commit transaction");
1827
1828 assert_eq!(processing_result.valid_count(), 1);
1829
1830 let transaction = platform.drive.grove.start_transaction();
1831
1832 let processing_result = platform
1833 .platform
1834 .process_raw_state_transitions(
1835 &[documents_batch_create_serialized_transition_1.clone()],
1836 platform_state,
1837 &BlockInfo::default_with_time(
1838 platform_state
1839 .last_committed_block_time_ms()
1840 .unwrap_or_default()
1841 + 3000,
1842 ),
1843 &transaction,
1844 platform_version,
1845 false,
1846 None,
1847 )
1848 .expect("expected to process state transition");
1849
1850 platform
1851 .drive
1852 .grove
1853 .commit_transaction(transaction)
1854 .unwrap()
1855 .expect("expected to commit transaction");
1856
1857 if let Some(expected_err) = expect_err {
1858 let result = processing_result.into_execution_results().remove(0);
1859
1860 let StateTransitionExecutionResult::PaidConsensusError {
1861 error: consensus_error,
1862 ..
1863 } = result
1864 else {
1865 panic!("expected a paid consensus error");
1866 };
1867 assert_eq!(consensus_error.to_string(), expected_err);
1868 } else {
1869 assert_eq!(processing_result.valid_count(), 1);
1870 }
1871 identity_1
1872 }
1873
1874 pub(in crate::execution) fn verify_dpns_name_contest(
1875 platform: &mut TempPlatform<MockCoreRPCLike>,
1876 platform_state: &Guard<Arc<PlatformState>>,
1877 dpns_contract: &DataContract,
1878 identity_1: &Identity,
1879 identity_2: &Identity,
1880 name: &str,
1881 platform_version: &PlatformVersion,
1882 ) {
1883 let domain = dpns_contract
1886 .document_type_for_name("domain")
1887 .expect("expected a profile document type");
1888
1889 let config = bincode::config::standard()
1890 .with_big_endian()
1891 .with_no_limit();
1892
1893 let dash_encoded = bincode::encode_to_vec(Value::Text("dash".to_string()), config)
1894 .expect("expected to encode the word dash");
1895
1896 let quantum_encoded =
1897 bincode::encode_to_vec(Value::Text(convert_to_homograph_safe_chars(name)), config)
1898 .expect("expected to encode the word quantum");
1899
1900 let index_name = "parentNameAndLabel".to_string();
1901
1902 let query_validation_result = platform
1903 .query_contested_resource_vote_state(
1904 GetContestedResourceVoteStateRequest {
1905 version: Some(get_contested_resource_vote_state_request::Version::V0(
1906 GetContestedResourceVoteStateRequestV0 {
1907 contract_id: dpns_contract.id().to_vec(),
1908 document_type_name: domain.name().clone(),
1909 index_name: index_name.clone(),
1910 index_values: vec![dash_encoded.clone(), quantum_encoded.clone()],
1911 result_type: ResultType::DocumentsAndVoteTally as i32,
1912 allow_include_locked_and_abstaining_vote_tally: true,
1913 start_at_identifier_info: None,
1914 count: None,
1915 prove: false,
1916 },
1917 )),
1918 },
1919 platform_state,
1920 platform_version,
1921 )
1922 .expect("expected to execute query")
1923 .into_data()
1924 .expect("expected query to be valid");
1925
1926 let get_contested_resource_vote_state_response::Version::V0(
1927 GetContestedResourceVoteStateResponseV0 {
1928 metadata: _,
1929 result,
1930 },
1931 ) = query_validation_result.version.expect("expected a version");
1932
1933 let Some(
1934 get_contested_resource_vote_state_response_v0::Result::ContestedResourceContenders(
1935 get_contested_resource_vote_state_response_v0::ContestedResourceContenders {
1936 contenders,
1937 ..
1938 },
1939 ),
1940 ) = result
1941 else {
1942 panic!("expected contenders")
1943 };
1944
1945 assert_eq!(contenders.len(), 2);
1946
1947 let first_contender = contenders.first().unwrap();
1948
1949 let second_contender = contenders.last().unwrap();
1950
1951 let first_contender_document = Document::from_bytes(
1952 first_contender
1953 .document
1954 .as_ref()
1955 .expect("expected a document")
1956 .as_slice(),
1957 domain,
1958 platform_version,
1959 )
1960 .expect("expected to get document");
1961
1962 let second_contender_document = Document::from_bytes(
1963 second_contender
1964 .document
1965 .as_ref()
1966 .expect("expected a document")
1967 .as_slice(),
1968 domain,
1969 platform_version,
1970 )
1971 .expect("expected to get document");
1972
1973 assert_ne!(first_contender_document, second_contender_document);
1974
1975 assert_eq!(first_contender.identifier, identity_1.id().to_vec());
1976
1977 assert_eq!(second_contender.identifier, identity_2.id().to_vec());
1978
1979 assert_eq!(first_contender.vote_count, Some(0));
1980
1981 assert_eq!(second_contender.vote_count, Some(0));
1982
1983 let GetContestedResourceVoteStateResponse { version } = platform
1984 .query_contested_resource_vote_state(
1985 GetContestedResourceVoteStateRequest {
1986 version: Some(get_contested_resource_vote_state_request::Version::V0(
1987 GetContestedResourceVoteStateRequestV0 {
1988 contract_id: dpns_contract.id().to_vec(),
1989 document_type_name: domain.name().clone(),
1990 index_name: "parentNameAndLabel".to_string(),
1991 index_values: vec![dash_encoded, quantum_encoded],
1992 result_type: ResultType::DocumentsAndVoteTally as i32,
1993 allow_include_locked_and_abstaining_vote_tally: true,
1994 start_at_identifier_info: None,
1995 count: None,
1996 prove: true,
1997 },
1998 )),
1999 },
2000 platform_state,
2001 platform_version,
2002 )
2003 .expect("expected to execute query")
2004 .into_data()
2005 .expect("expected query to be valid");
2006
2007 let get_contested_resource_vote_state_response::Version::V0(
2008 GetContestedResourceVoteStateResponseV0 {
2009 metadata: _,
2010 result,
2011 },
2012 ) = version.expect("expected a version");
2013
2014 let Some(get_contested_resource_vote_state_response_v0::Result::Proof(proof)) = result
2015 else {
2016 panic!("expected contenders")
2017 };
2018
2019 let resolved_contested_document_vote_poll_drive_query =
2020 ResolvedContestedDocumentVotePollDriveQuery {
2021 vote_poll: ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed {
2022 contract: DataContractResolvedInfo::BorrowedDataContract(dpns_contract),
2023 document_type_name: domain.name().clone(),
2024 index_name: index_name.clone(),
2025 index_values: vec![
2026 Value::Text("dash".to_string()),
2027 Value::Text(convert_to_homograph_safe_chars(name)),
2028 ],
2029 },
2030 result_type: DocumentsAndVoteTally,
2031 offset: None,
2032 limit: None,
2033 start_at: None,
2034 allow_include_locked_and_abstaining_vote_tally: true,
2035 };
2036
2037 let (_, result) = resolved_contested_document_vote_poll_drive_query
2038 .verify_vote_poll_vote_state_proof(proof.grovedb_proof.as_ref(), platform_version)
2039 .expect("expected to verify proof");
2040
2041 let contenders = result.contenders;
2042
2043 assert_eq!(contenders.len(), 2);
2044
2045 let first_contender = contenders.first().unwrap();
2046
2047 let second_contender = contenders.last().unwrap();
2048
2049 let first_contender_document = Document::from_bytes(
2050 first_contender
2051 .serialized_document()
2052 .as_ref()
2053 .expect("expected a document")
2054 .as_slice(),
2055 domain,
2056 platform_version,
2057 )
2058 .expect("expected to get document");
2059
2060 let second_contender_document = Document::from_bytes(
2061 second_contender
2062 .serialized_document()
2063 .as_ref()
2064 .expect("expected a document")
2065 .as_slice(),
2066 domain,
2067 platform_version,
2068 )
2069 .expect("expected to get document");
2070
2071 assert_ne!(first_contender_document, second_contender_document);
2072
2073 assert_eq!(first_contender.identity_id(), identity_1.id());
2074
2075 assert_eq!(second_contender.identity_id(), identity_2.id());
2076
2077 assert_eq!(first_contender.vote_tally(), Some(0));
2078
2079 assert_eq!(second_contender.vote_tally(), Some(0));
2080 }
2081
2082 #[allow(clippy::too_many_arguments)]
2083 pub(in crate::execution) fn perform_vote(
2084 platform: &mut TempPlatform<MockCoreRPCLike>,
2085 platform_state: &Guard<Arc<PlatformState>>,
2086 dpns_contract: &DataContract,
2087 resource_vote_choice: ResourceVoteChoice,
2088 name: &str,
2089 signer: &SimpleSigner,
2090 pro_tx_hash: Identifier,
2091 voting_key: &IdentityPublicKey,
2092 nonce: IdentityNonce,
2093 expect_error: Option<&str>,
2094 platform_version: &PlatformVersion,
2095 ) {
2096 let vote = Vote::ResourceVote(ResourceVote::V0(ResourceVoteV0 {
2099 vote_poll: VotePoll::ContestedDocumentResourceVotePoll(
2100 ContestedDocumentResourceVotePoll {
2101 contract_id: dpns_contract.id(),
2102 document_type_name: "domain".to_string(),
2103 index_name: "parentNameAndLabel".to_string(),
2104 index_values: vec![
2105 Value::Text("dash".to_string()),
2106 Value::Text(convert_to_homograph_safe_chars(name)),
2107 ],
2108 },
2109 ),
2110 resource_vote_choice,
2111 }));
2112
2113 let masternode_vote_transition = MasternodeVoteTransition::try_from_vote_with_signer(
2114 vote,
2115 signer,
2116 pro_tx_hash,
2117 voting_key,
2118 nonce,
2119 platform_version,
2120 None,
2121 )
2122 .expect("expected to make transition vote");
2123
2124 let masternode_vote_serialized_transition = masternode_vote_transition
2125 .serialize_to_bytes()
2126 .expect("expected documents batch serialized state transition");
2127
2128 let transaction = platform.drive.grove.start_transaction();
2129
2130 let processing_result = platform
2131 .platform
2132 .process_raw_state_transitions(
2133 &[masternode_vote_serialized_transition.clone()],
2134 platform_state,
2135 &BlockInfo::default(),
2136 &transaction,
2137 platform_version,
2138 false,
2139 None,
2140 )
2141 .expect("expected to process state transition");
2142
2143 platform
2144 .drive
2145 .grove
2146 .commit_transaction(transaction)
2147 .unwrap()
2148 .expect("expected to commit transaction");
2149
2150 let execution_result = processing_result.into_execution_results().remove(0);
2151 if let Some(error_msg) = expect_error {
2152 assert_matches!(execution_result, UnpaidConsensusError(..));
2153 let UnpaidConsensusError(consensus_error) = execution_result else {
2154 panic!()
2155 };
2156 assert_eq!(consensus_error.to_string(), error_msg)
2157 } else {
2158 assert_matches!(execution_result, SuccessfulExecution { .. });
2159 }
2160 }
2161
2162 #[allow(clippy::too_many_arguments)]
2163 pub(in crate::execution) fn perform_votes(
2164 platform: &mut TempPlatform<MockCoreRPCLike>,
2165 dpns_contract: &DataContract,
2166 resource_vote_choice: ResourceVoteChoice,
2167 name: &str,
2168 count: u64,
2169 start_seed: u64,
2170 nonce_offset: Option<IdentityNonce>,
2171 platform_version: &PlatformVersion,
2172 ) -> Vec<(Identifier, Identity, SimpleSigner, IdentityPublicKey)> {
2173 let mut masternode_infos = vec![];
2174 for i in 0..count {
2175 let (pro_tx_hash_bytes, voting_identity, signer, voting_key) =
2176 setup_masternode_voting_identity(platform, start_seed + i, platform_version);
2177
2178 let platform_state = platform.state.load();
2179
2180 perform_vote(
2181 platform,
2182 &platform_state,
2183 dpns_contract,
2184 resource_vote_choice,
2185 name,
2186 &signer,
2187 pro_tx_hash_bytes,
2188 &voting_key,
2189 1 + nonce_offset.unwrap_or_default(),
2190 None,
2191 platform_version,
2192 );
2193
2194 masternode_infos.push((pro_tx_hash_bytes, voting_identity, signer, voting_key));
2195 }
2196 masternode_infos
2197 }
2198
2199 pub(in crate::execution) fn perform_votes_multi(
2200 platform: &mut TempPlatform<MockCoreRPCLike>,
2201 dpns_contract: &DataContract,
2202 resource_vote_choices: Vec<(ResourceVoteChoice, u64)>,
2203 name: &str,
2204 start_seed: u64,
2205 nonce_offset: Option<IdentityNonce>,
2206 platform_version: &PlatformVersion,
2207 ) -> BTreeMap<ResourceVoteChoice, Vec<(Identifier, Identity, SimpleSigner, IdentityPublicKey)>>
2208 {
2209 let mut count_aggregate = start_seed;
2210 let mut masternodes_by_vote_choice = BTreeMap::new();
2211 for (resource_vote_choice, count) in resource_vote_choices.into_iter() {
2212 let masternode_infos = perform_votes(
2213 platform,
2214 dpns_contract,
2215 resource_vote_choice,
2216 name,
2217 count,
2218 count_aggregate,
2219 nonce_offset,
2220 platform_version,
2221 );
2222 masternodes_by_vote_choice.insert(resource_vote_choice, masternode_infos);
2223 count_aggregate += count;
2224 }
2225 masternodes_by_vote_choice
2226 }
2227
2228 #[allow(clippy::too_many_arguments)]
2229 pub(in crate::execution) fn get_vote_states(
2230 platform: &TempPlatform<MockCoreRPCLike>,
2231 platform_state: &PlatformState,
2232 dpns_contract: &DataContract,
2233 name: &str,
2234 count: Option<u32>,
2235 allow_include_locked_and_abstaining_vote_tally: bool,
2236 start_at_identifier_info: Option<
2237 get_contested_resource_vote_state_request_v0::StartAtIdentifierInfo,
2238 >,
2239 result_type: ResultType,
2240 platform_version: &PlatformVersion,
2241 ) -> (
2242 Vec<Contender>,
2243 Option<u32>,
2244 Option<u32>,
2245 Option<FinishedVoteInfo>,
2246 ) {
2247 let domain = dpns_contract
2250 .document_type_for_name("domain")
2251 .expect("expected a profile document type");
2252
2253 let config = bincode::config::standard()
2254 .with_big_endian()
2255 .with_no_limit();
2256
2257 let dash_encoded = bincode::encode_to_vec(Value::Text("dash".to_string()), config)
2258 .expect("expected to encode the word dash");
2259
2260 let name_encoded =
2261 bincode::encode_to_vec(Value::Text(convert_to_homograph_safe_chars(name)), config)
2262 .expect("expected to encode the word quantum");
2263
2264 let index_name = "parentNameAndLabel".to_string();
2265
2266 let query_validation_result = platform
2267 .query_contested_resource_vote_state(
2268 GetContestedResourceVoteStateRequest {
2269 version: Some(get_contested_resource_vote_state_request::Version::V0(
2270 GetContestedResourceVoteStateRequestV0 {
2271 contract_id: dpns_contract.id().to_vec(),
2272 document_type_name: domain.name().clone(),
2273 index_name: index_name.clone(),
2274 index_values: vec![dash_encoded.clone(), name_encoded.clone()],
2275 result_type: result_type as i32,
2276 allow_include_locked_and_abstaining_vote_tally,
2277 start_at_identifier_info,
2278 count,
2279 prove: false,
2280 },
2281 )),
2282 },
2283 platform_state,
2284 platform_version,
2285 )
2286 .expect("expected to execute query")
2287 .into_data()
2288 .expect("expected query to be valid");
2289
2290 let get_contested_resource_vote_state_response::Version::V0(
2291 GetContestedResourceVoteStateResponseV0 {
2292 metadata: _,
2293 result,
2294 },
2295 ) = query_validation_result.version.expect("expected a version");
2296
2297 let Some(
2298 get_contested_resource_vote_state_response_v0::Result::ContestedResourceContenders(
2299 get_contested_resource_vote_state_response_v0::ContestedResourceContenders {
2300 contenders,
2301 abstain_vote_tally,
2302 lock_vote_tally,
2303 finished_vote_info,
2304 },
2305 ),
2306 ) = result
2307 else {
2308 panic!("expected contenders")
2309 };
2310 (
2311 contenders
2312 .into_iter()
2313 .map(|contender| {
2314 ContenderV0 {
2315 identity_id: contender.identifier.try_into().expect("expected 32 bytes"),
2316 document: contender.document.map(|document_bytes| {
2317 Document::from_bytes(
2318 document_bytes.as_slice(),
2319 domain,
2320 platform_version,
2321 )
2322 .expect("expected to deserialize document")
2323 }),
2324 vote_tally: contender.vote_count,
2325 }
2326 .into()
2327 })
2328 .collect(),
2329 abstain_vote_tally,
2330 lock_vote_tally,
2331 finished_vote_info,
2332 )
2333 }
2334
2335 #[allow(clippy::too_many_arguments)]
2336 pub(in crate::execution) fn get_proved_vote_states(
2337 platform: &TempPlatform<MockCoreRPCLike>,
2338 platform_state: &PlatformState,
2339 dpns_contract: &DataContract,
2340 name: &str,
2341 count: Option<u32>,
2342 allow_include_locked_and_abstaining_vote_tally: bool,
2343 start_at_identifier_info: Option<
2344 get_contested_resource_vote_state_request_v0::StartAtIdentifierInfo,
2345 >,
2346 result_type: ResultType,
2347 platform_version: &PlatformVersion,
2348 ) -> (
2349 Vec<Contender>,
2350 Option<u32>,
2351 Option<u32>,
2352 Option<(ContestedDocumentVotePollWinnerInfo, BlockInfo)>,
2353 ) {
2354 let domain = dpns_contract
2357 .document_type_for_name("domain")
2358 .expect("expected a profile document type");
2359
2360 let config = bincode::config::standard()
2361 .with_big_endian()
2362 .with_no_limit();
2363
2364 let dash_encoded = bincode::encode_to_vec(Value::Text("dash".to_string()), config)
2365 .expect("expected to encode the word dash");
2366
2367 let name_encoded =
2368 bincode::encode_to_vec(Value::Text(convert_to_homograph_safe_chars(name)), config)
2369 .expect("expected to encode the word quantum");
2370
2371 let index_name = "parentNameAndLabel".to_string();
2372
2373 let query_validation_result = platform
2374 .query_contested_resource_vote_state(
2375 GetContestedResourceVoteStateRequest {
2376 version: Some(get_contested_resource_vote_state_request::Version::V0(
2377 GetContestedResourceVoteStateRequestV0 {
2378 contract_id: dpns_contract.id().to_vec(),
2379 document_type_name: domain.name().clone(),
2380 index_name: index_name.clone(),
2381 index_values: vec![dash_encoded.clone(), name_encoded.clone()],
2382 result_type: result_type as i32,
2383 allow_include_locked_and_abstaining_vote_tally,
2384 start_at_identifier_info,
2385 count,
2386 prove: true,
2387 },
2388 )),
2389 },
2390 platform_state,
2391 platform_version,
2392 )
2393 .expect("expected to execute query")
2394 .into_data()
2395 .expect("expected query to be valid");
2396
2397 let get_contested_resource_vote_state_response::Version::V0(
2398 GetContestedResourceVoteStateResponseV0 {
2399 metadata: _,
2400 result,
2401 },
2402 ) = query_validation_result.version.expect("expected a version");
2403
2404 let Some(get_contested_resource_vote_state_response_v0::Result::Proof(proof)) = result
2405 else {
2406 panic!("expected contenders")
2407 };
2408
2409 let resolved_contested_document_vote_poll_drive_query =
2410 ResolvedContestedDocumentVotePollDriveQuery {
2411 vote_poll: ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed {
2412 contract: DataContractResolvedInfo::BorrowedDataContract(dpns_contract),
2413 document_type_name: domain.name().clone(),
2414 index_name: index_name.clone(),
2415 index_values: vec![
2416 Value::Text("dash".to_string()),
2417 Value::Text(convert_to_homograph_safe_chars(name)),
2418 ],
2419 },
2420 result_type: ContestedDocumentVotePollDriveQueryResultType::try_from(
2421 result_type as i32,
2422 )
2423 .expect("expected valid result type"),
2424 offset: None,
2425 limit: count.map(|a| a as u16),
2426 start_at: None,
2427 allow_include_locked_and_abstaining_vote_tally,
2428 };
2429
2430 let (_, result) = resolved_contested_document_vote_poll_drive_query
2431 .verify_vote_poll_vote_state_proof(proof.grovedb_proof.as_ref(), platform_version)
2432 .expect("expected to verify proof");
2433
2434 let abstaining_vote_tally = result.abstaining_vote_tally;
2435 let lock_vote_tally = result.locked_vote_tally;
2436
2437 let contenders = result.contenders;
2438 let finished_vote_info = result.winner;
2439 (
2440 contenders
2441 .into_iter()
2442 .map(|contender| {
2443 ContenderV0 {
2444 identity_id: contender.identity_id(),
2445 document: contender
2446 .serialized_document()
2447 .as_ref()
2448 .map(|document_bytes| {
2449 Document::from_bytes(
2450 document_bytes.as_slice(),
2451 domain,
2452 platform_version,
2453 )
2454 .expect("expected to deserialize document")
2455 }),
2456 vote_tally: contender.vote_tally(),
2457 }
2458 .into()
2459 })
2460 .collect(),
2461 abstaining_vote_tally,
2462 lock_vote_tally,
2463 finished_vote_info,
2464 )
2465 }
2466
2467 pub(in crate::execution) fn create_token_contract_with_owner_identity(
2468 platform: &mut TempPlatform<MockCoreRPCLike>,
2469 identity_id: Identifier,
2470 token_configuration_modification: Option<impl FnOnce(&mut TokenConfiguration)>,
2471 contract_start_time: Option<TimestampMillis>,
2472 add_groups: Option<BTreeMap<GroupContractPosition, Group>>,
2473 contract_start_block: Option<BlockHeight>,
2474 platform_version: &PlatformVersion,
2475 ) -> (DataContract, Identifier) {
2476 let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1);
2477
2478 let basic_token_contract = setup_contract(
2479 &platform.drive,
2480 "tests/supporting_files/contract/basic-token/basic-token.json",
2481 Some(data_contract_id.to_buffer()),
2482 Some(identity_id.to_buffer()),
2483 Some(|data_contract: &mut DataContract| {
2484 data_contract.set_created_at_epoch(Some(0));
2485 data_contract.set_created_at(Some(contract_start_time.unwrap_or_default()));
2486 data_contract
2487 .set_created_at_block_height(Some(contract_start_block.unwrap_or_default()));
2488 if let Some(token_configuration_modification) = token_configuration_modification {
2489 let token_configuration = data_contract
2490 .token_configuration_mut(0)
2491 .expect("expected token configuration");
2492 token_configuration_modification(token_configuration);
2493 }
2494 if let Some(add_groups) = add_groups {
2495 data_contract.set_groups(add_groups);
2496 }
2497 }),
2498 None,
2499 Some(platform_version),
2500 );
2501
2502 let token_id = calculate_token_id(data_contract_id.as_bytes(), 0);
2503
2504 (basic_token_contract, token_id.into())
2505 }
2506
2507 pub(in crate::execution) fn create_card_game_internal_token_contract_with_owner_identity_burn_tokens(
2508 platform: &mut TempPlatform<MockCoreRPCLike>,
2509 identity_id: Identifier,
2510 platform_version: &PlatformVersion,
2511 ) -> (DataContract, Identifier, Identifier) {
2512 let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1);
2513
2514 let basic_token_contract = setup_contract(
2515 &platform.drive,
2516 "tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency-burn-tokens.json",
2517 Some(data_contract_id.to_buffer()),
2518 Some(identity_id.to_buffer()),
2519 Some(|data_contract: &mut DataContract| {
2520 data_contract.set_created_at_epoch(Some(0));
2521 data_contract.set_created_at(Some(0));
2522 data_contract.set_created_at_block_height(Some(0));
2523 }),
2524 None,
2525 Some(platform_version),
2526 );
2527
2528 let token_id = calculate_token_id(data_contract_id.as_bytes(), 0);
2529 let token_id_2 = calculate_token_id(data_contract_id.as_bytes(), 1);
2530
2531 (basic_token_contract, token_id.into(), token_id_2.into())
2532 }
2533
2534 pub(in crate::execution) fn create_card_game_internal_token_contract_with_owner_identity_transfer_tokens(
2535 platform: &mut TempPlatform<MockCoreRPCLike>,
2536 identity_id: Identifier,
2537 platform_version: &PlatformVersion,
2538 ) -> (DataContract, Identifier, Identifier) {
2539 let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1);
2540
2541 let basic_token_contract = setup_contract(
2542 &platform.drive,
2543 "tests/supporting_files/contract/crypto-card-game/crypto-card-game-in-game-currency.json",
2544 Some(data_contract_id.to_buffer()),
2545 Some(identity_id.to_buffer()),
2546 Some(|data_contract: &mut DataContract| {
2547 data_contract.set_created_at_epoch(Some(0));
2548 data_contract.set_created_at(Some(0));
2549 data_contract.set_created_at_block_height(Some(0));
2550 }),
2551 None,
2552 Some(platform_version),
2553 );
2554
2555 let token_id = calculate_token_id(data_contract_id.as_bytes(), 0);
2556 let token_id_2 = calculate_token_id(data_contract_id.as_bytes(), 1);
2557
2558 (basic_token_contract, token_id.into(), token_id_2.into())
2559 }
2560
2561 pub(in crate::execution) fn create_card_game_external_token_contract_with_owner_identity(
2562 platform: &mut TempPlatform<MockCoreRPCLike>,
2563 token_contract_id: Identifier,
2564 token_contract_position: TokenContractPosition,
2565 token_cost_amount: TokenAmount,
2566 gas_fees_paid_by: GasFeesPaidBy,
2567 identity_id: Identifier,
2568 platform_version: &PlatformVersion,
2569 ) -> DataContract {
2570 let data_contract_id = DataContract::generate_data_contract_id_v0(identity_id, 1);
2571
2572 let basic_token_contract = setup_contract(
2573 &platform.drive,
2574 "tests/supporting_files/contract/crypto-card-game/crypto-card-game-use-external-currency.json",
2575 Some(data_contract_id.to_buffer()),
2576 Some(identity_id.to_buffer()),
2577 Some(|data_contract: &mut DataContract| {
2578 data_contract.set_created_at_epoch(Some(0));
2579 data_contract.set_created_at(Some(0));
2580 data_contract.set_created_at_block_height(Some(0));
2581 let document_type = data_contract.document_types_mut().get_mut("card").expect("expected a document type with name card");
2582 document_type.set_document_creation_token_cost(Some(DocumentActionTokenCost {
2583 contract_id: Some(token_contract_id),
2584 token_contract_position,
2585 token_amount: token_cost_amount,
2586 effect: DocumentActionTokenEffect::TransferTokenToContractOwner,
2587 gas_fees_paid_by,
2588 }));
2589 let gas_fees_paid_by_int: u8 = gas_fees_paid_by.into();
2590 let schema = document_type.schema_mut();
2591 let token_cost = schema.get_mut("tokenCost").expect("expected to get token cost").expect("expected token cost to be set");
2592 let creation_token_cost = token_cost.get_mut("create").expect("expected to get creation token cost").expect("expected creation token cost to be set");
2593 creation_token_cost.set_value("contractId", token_contract_id.into()).expect("expected to set token contract id");
2594 creation_token_cost.set_value("tokenPosition", token_contract_position.into()).expect("expected to set token position");
2595 creation_token_cost.set_value("amount", token_cost_amount.into()).expect("expected to set token amount");
2596 creation_token_cost.set_value("gasFeesPaidBy", gas_fees_paid_by_int.into()).expect("expected to set token amount");
2597 }),
2598 None,
2599 Some(platform_version),
2600 );
2601
2602 basic_token_contract
2603 }
2604
2605 pub(in crate::execution) fn process_test_state_transition<S: PlatformSerializable>(
2606 platform: &mut TempPlatform<MockCoreRPCLike>,
2607 state_transition: S,
2608 platform_state: &PlatformState,
2609 platform_version: &PlatformVersion,
2610 ) -> StateTransitionsProcessingResult {
2611 let Ok(serialized_state_transition) = state_transition.serialize_to_bytes() else {
2612 panic!("expected documents batch serialized state transition")
2613 };
2614
2615 let transaction = platform.drive.grove.start_transaction();
2616
2617 let processing_result = platform
2618 .platform
2619 .process_raw_state_transitions(
2620 &[serialized_state_transition],
2621 platform_state,
2622 &BlockInfo::default(),
2623 &transaction,
2624 platform_version,
2625 false,
2626 None,
2627 )
2628 .expect("expected to process state transition");
2629
2630 platform
2631 .drive
2632 .grove
2633 .commit_transaction(transaction)
2634 .unwrap()
2635 .expect("expected to commit transaction");
2636
2637 processing_result
2638 }
2639
2640 mod keyword_search_contract {
2641 use dpp::consensus::basic::BasicError;
2642 use dpp::consensus::ConsensusError;
2643 use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult::PaidConsensusError;
2644 use super::*;
2645 fn build_random_doc_of_type(
2654 rng: &mut StdRng,
2655 doc_type_name: &str,
2656 identity_id: Identifier,
2657 contract: &DataContract,
2658 platform_version: &PlatformVersion,
2659 ) -> (Document, Bytes32) {
2660 let doc_type = contract
2661 .document_type_for_name(doc_type_name)
2662 .expect("doc type exists");
2663
2664 let entropy = Bytes32::random_with_rng(rng);
2665
2666 let doc = doc_type
2667 .random_document_with_identifier_and_entropy(
2668 rng,
2669 identity_id,
2670 entropy,
2671 DocumentFieldFillType::FillIfNotRequired,
2672 DocumentFieldFillSize::AnyDocumentFillSize,
2673 platform_version,
2674 )
2675 .expect("random doc");
2676
2677 (doc, entropy)
2678 }
2679
2680 #[test]
2681 fn should_err_when_creating_contract_keywords_document() {
2682 let platform_version = PlatformVersion::latest();
2683
2684 let mut platform = TestPlatformBuilder::new()
2685 .build_with_mock_rpc()
2686 .set_genesis_state();
2687
2688 let (identity, signer, key) = setup_identity(&mut platform, 42, dash_to_credits!(1.0));
2689
2690 let contract = load_system_data_contract(
2691 SystemDataContract::KeywordSearch,
2692 PlatformVersion::latest(),
2693 )
2694 .expect("expected to load search contract");
2695
2696 let mut rng = StdRng::seed_from_u64(1);
2697 let (doc, entropy) = build_random_doc_of_type(
2698 &mut rng,
2699 "contractKeywords",
2700 identity.id(),
2701 &contract,
2702 platform_version,
2703 );
2704
2705 let transition = BatchTransition::new_document_creation_transition_from_document(
2706 doc,
2707 contract.document_type_for_name("contractKeywords").unwrap(),
2708 entropy.0, &key,
2710 1,
2711 0,
2712 None,
2713 &signer,
2714 platform_version,
2715 None,
2716 )
2717 .expect("batch transition");
2718
2719 let serialized = transition.serialize_to_bytes().unwrap();
2720
2721 let platform_state = platform.state.load();
2722 let processing_result = platform
2723 .platform
2724 .process_raw_state_transitions(
2725 &[serialized],
2726 &platform_state,
2727 &BlockInfo::default(),
2728 &platform.drive.grove.start_transaction(),
2729 platform_version,
2730 false,
2731 None,
2732 )
2733 .expect("processing failed");
2734
2735 let execution_result = processing_result.into_execution_results().remove(0);
2736 assert_matches!(
2737 execution_result,
2738 StateTransitionExecutionResult::PaidConsensusError{ error, .. }
2739 if error.to_string().contains("not allowed because of the document type's creation restriction mode")
2740 );
2741 }
2742
2743 #[test]
2744 fn should_err_when_creating_short_description_document() {
2745 let platform_version = PlatformVersion::latest();
2746
2747 let mut platform = TestPlatformBuilder::new()
2748 .build_with_mock_rpc()
2749 .set_genesis_state();
2750
2751 let (identity, signer, key) = setup_identity(&mut platform, 43, dash_to_credits!(1.0));
2752
2753 let contract = load_system_data_contract(
2754 SystemDataContract::KeywordSearch,
2755 PlatformVersion::latest(),
2756 )
2757 .expect("expected to load search contract");
2758
2759 let mut rng = StdRng::seed_from_u64(2);
2760 let (doc, entropy) = build_random_doc_of_type(
2761 &mut rng,
2762 "shortDescription",
2763 identity.id(),
2764 &contract,
2765 platform_version,
2766 );
2767
2768 let transition = BatchTransition::new_document_creation_transition_from_document(
2769 doc,
2770 contract.document_type_for_name("shortDescription").unwrap(),
2771 entropy.0,
2772 &key,
2773 1,
2774 0,
2775 None,
2776 &signer,
2777 platform_version,
2778 None,
2779 )
2780 .expect("batch transition");
2781
2782 let serialized = transition.serialize_to_bytes().unwrap();
2783
2784 let platform_state = platform.state.load();
2785 let processing_result = platform
2786 .platform
2787 .process_raw_state_transitions(
2788 &[serialized],
2789 &platform_state,
2790 &BlockInfo::default(),
2791 &platform.drive.grove.start_transaction(),
2792 platform_version,
2793 false,
2794 None,
2795 )
2796 .expect("processing failed");
2797
2798 let execution_result = processing_result.into_execution_results().remove(0);
2799 assert_matches!(
2800 execution_result,
2801 StateTransitionExecutionResult::PaidConsensusError{ error, .. }
2802 if error.to_string().contains("not allowed because of the document type's creation restriction mode")
2803 );
2804 }
2805
2806 #[test]
2807 fn should_err_when_creating_full_description_document() {
2808 let platform_version = PlatformVersion::latest();
2809
2810 let mut platform = TestPlatformBuilder::new()
2811 .build_with_mock_rpc()
2812 .set_genesis_state();
2813
2814 let (identity, signer, key) = setup_identity(&mut platform, 44, dash_to_credits!(1.0));
2815
2816 let contract = load_system_data_contract(
2817 SystemDataContract::KeywordSearch,
2818 PlatformVersion::latest(),
2819 )
2820 .expect("expected to load search contract");
2821
2822 let mut rng = StdRng::seed_from_u64(3);
2823 let (doc, entropy) = build_random_doc_of_type(
2824 &mut rng,
2825 "fullDescription",
2826 identity.id(),
2827 &contract,
2828 platform_version,
2829 );
2830
2831 let transition = BatchTransition::new_document_creation_transition_from_document(
2832 doc,
2833 contract.document_type_for_name("fullDescription").unwrap(),
2834 entropy.0,
2835 &key,
2836 1,
2837 0,
2838 None,
2839 &signer,
2840 platform_version,
2841 None,
2842 )
2843 .expect("batch transition");
2844
2845 let serialized = transition.serialize_to_bytes().unwrap();
2846
2847 let platform_state = platform.state.load();
2848 let processing_result = platform
2849 .platform
2850 .process_raw_state_transitions(
2851 &[serialized],
2852 &platform_state,
2853 &BlockInfo::default(),
2854 &platform.drive.grove.start_transaction(),
2855 platform_version,
2856 false,
2857 None,
2858 )
2859 .expect("processing failed");
2860
2861 let execution_result = processing_result.into_execution_results().remove(0);
2862 assert_matches!(
2863 execution_result,
2864 StateTransitionExecutionResult::PaidConsensusError{ error, .. }
2865 if error.to_string().contains("not allowed because of the document type's creation restriction mode")
2866 );
2867 }
2868
2869 fn create_contract_with_keywords_and_description(
2876 platform: &mut TempPlatform<MockCoreRPCLike>,
2877 ) -> (Identity, SimpleSigner, IdentityPublicKey) {
2878 let platform_version = PlatformVersion::latest();
2879
2880 let (owner_identity, signer, key) =
2882 setup_identity(platform, 777, dash_to_credits!(1.0));
2883
2884 let mut contract = json_document_to_contract_with_ids(
2886 "tests/supporting_files/contract/keyword_test/keyword_base_contract.json",
2887 Some(owner_identity.id()),
2888 None,
2889 false,
2890 platform_version,
2891 )
2892 .expect("load contract");
2893
2894 contract.set_description(Some("A short description".to_string()));
2896 contract.set_keywords(vec!["graph".into(), "indexing".into()]);
2897
2898 let create_transition = DataContractCreateTransition::new_from_data_contract(
2900 contract,
2901 1,
2902 &owner_identity.clone().into_partial_identity_info(),
2903 key.id(),
2904 &signer,
2905 platform_version,
2906 None,
2907 )
2908 .expect("build transition");
2909
2910 let serialized = create_transition.serialize_to_bytes().unwrap();
2911 let platform_state = platform.state.load();
2912 let tx = platform.drive.grove.start_transaction();
2913
2914 let processing_result = platform
2915 .platform
2916 .process_raw_state_transitions(
2917 &[serialized],
2918 &platform_state,
2919 &BlockInfo::default(),
2920 &tx,
2921 platform_version,
2922 false,
2923 None,
2924 )
2925 .expect("process");
2926
2927 assert_matches!(
2928 processing_result.execution_results().as_slice(),
2929 [StateTransitionExecutionResult::SuccessfulExecution { .. }]
2930 );
2931
2932 platform
2933 .drive
2934 .grove
2935 .commit_transaction(tx)
2936 .unwrap()
2937 .expect("commit");
2938
2939 (owner_identity, signer, key)
2940 }
2941
2942 #[test]
2943 fn owner_can_update_short_description_document() {
2944 let platform_version = PlatformVersion::latest();
2945 let mut platform = TestPlatformBuilder::new()
2946 .build_with_mock_rpc()
2947 .set_genesis_state();
2948
2949 let (_owner, signer, key) =
2950 create_contract_with_keywords_and_description(&mut platform);
2951
2952 let search_contract =
2954 load_system_data_contract(SystemDataContract::KeywordSearch, platform_version)
2955 .expect("load search contract");
2956
2957 let doc_type = search_contract
2958 .document_type_for_name("shortDescription")
2959 .unwrap();
2960
2961 let query = DriveDocumentQuery::all_items_query(&search_contract, doc_type, None);
2962 let existing_docs = platform
2963 .drive
2964 .query_documents(
2965 query,
2966 None,
2967 false,
2968 None,
2969 Some(platform_version.protocol_version),
2970 )
2971 .expect("query failed");
2972
2973 let mut doc = existing_docs.documents().first().expect("doc").clone();
2974 doc.set_revision(Some(doc.revision().unwrap_or_default() + 1));
2975 doc.set("description", "updated description".into());
2976
2977 let transition = BatchTransition::new_document_replacement_transition_from_document(
2978 doc,
2979 doc_type,
2980 &key,
2981 2,
2982 0,
2983 None,
2984 &signer,
2985 platform_version,
2986 None,
2987 )
2988 .expect("replace");
2989
2990 let serialized = transition.serialize_to_bytes().unwrap();
2991 let platform_state = platform.state.load();
2992
2993 let processing_result = platform
2994 .platform
2995 .process_raw_state_transitions(
2996 &[serialized],
2997 &platform_state,
2998 &BlockInfo::default(),
2999 &platform.drive.grove.start_transaction(),
3000 platform_version,
3001 false,
3002 None,
3003 )
3004 .expect("process");
3005
3006 assert_matches!(
3007 processing_result.into_execution_results().remove(0),
3008 SuccessfulExecution { .. }
3009 );
3010 }
3011
3012 #[test]
3013 fn owner_can_not_delete_keyword_document() {
3014 let platform_version = PlatformVersion::latest();
3015 let mut platform = TestPlatformBuilder::new()
3016 .build_with_mock_rpc()
3017 .set_genesis_state();
3018
3019 let (_owner, signer, key) =
3020 create_contract_with_keywords_and_description(&mut platform);
3021
3022 let search_contract =
3023 load_system_data_contract(SystemDataContract::KeywordSearch, platform_version)
3024 .expect("load search contract");
3025 let doc_type = search_contract
3026 .document_type_for_name("contractKeywords")
3027 .unwrap();
3028
3029 let query = DriveDocumentQuery::all_items_query(&search_contract, doc_type, None);
3030 let existing_docs = platform
3031 .drive
3032 .query_documents(
3033 query,
3034 None,
3035 false,
3036 None,
3037 Some(platform_version.protocol_version),
3038 )
3039 .expect("query failed");
3040
3041 let doc = existing_docs.documents().first().unwrap().clone();
3042
3043 let transition = BatchTransition::new_document_deletion_transition_from_document(
3044 doc,
3045 doc_type,
3046 &key,
3047 2,
3048 0,
3049 None,
3050 &signer,
3051 platform_version,
3052 None,
3053 )
3054 .expect("delete");
3055
3056 let serialized = transition.serialize_to_bytes().unwrap();
3057 let platform_state = platform.state.load();
3058
3059 let processing_result = platform
3060 .platform
3061 .process_raw_state_transitions(
3062 &[serialized],
3063 &platform_state,
3064 &BlockInfo::default(),
3065 &platform.drive.grove.start_transaction(),
3066 platform_version,
3067 false,
3068 None,
3069 )
3070 .expect("process");
3071 assert_matches!(
3072 processing_result.execution_results().as_slice(),
3073 [PaidConsensusError {
3074 error: ConsensusError::BasicError(
3075 BasicError::InvalidDocumentTransitionActionError { .. }
3076 ),
3077 ..
3078 }]
3079 );
3080 }
3081 }
3082}