Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ bs58 = "0.5.0"
base64 = "0.22.1"
copypasta = "0.10.1"
dash-sdk = { git = "https://github.com/dashpay/platform", branch = "chore/DocumentQueryPartialEq" }
simple-signer = { git = "https://github.com/dashpay/platform", branch = "chore/DocumentQueryPartialEq" }
thiserror = "1"
serde = "1.0.197"
serde_json = "1.0.120"
Expand Down
16 changes: 15 additions & 1 deletion src/model/qualified_identity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use dash_sdk::dashcore_rpc::dashcore::{signer, PubkeyHash};
use dash_sdk::dpp::dashcore::address::Payload;
use dash_sdk::dpp::dashcore::hashes::Hash;
use dash_sdk::dpp::dashcore::{Address, Network, ScriptHash};
use dash_sdk::dpp::data_contract::document_type::accessors::DocumentTypeV0Getters;
use dash_sdk::dpp::data_contract::document_type::DocumentTypeRef;
use dash_sdk::dpp::ed25519_dalek::Signer as EDDSASigner;
use dash_sdk::dpp::identity::accessors::IdentityGettersV0;
use dash_sdk::dpp::identity::hash::IdentityPublicKeyHashMethodsV0;
Expand All @@ -14,7 +16,7 @@ use dash_sdk::dpp::platform_value::BinaryData;
use dash_sdk::dpp::state_transition::errors::InvalidIdentityPublicKeyTypeError;
use dash_sdk::dpp::{bls_signatures, ed25519_dalek, ProtocolError};
use dash_sdk::platform::IdentityPublicKey;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, HashSet};
use std::fmt::{Display, Formatter};

#[derive(Debug, Encode, Decode, PartialEq, Clone, Copy)]
Expand Down Expand Up @@ -176,6 +178,18 @@ impl QualifiedIdentity {
None
}

pub fn document_signing_key(
&self,
document_type: &DocumentTypeRef,
) -> Option<&IdentityPublicKey> {
self.identity.get_first_public_key_matching(
Purpose::AUTHENTICATION,
HashSet::from([document_type.security_level_requirement()]),
HashSet::from(KeyType::all_key_types()),
false,
)
}

pub fn available_withdrawal_keys(&self) -> Vec<&IdentityPublicKey> {
let mut keys = vec![];

Expand Down
2 changes: 1 addition & 1 deletion src/platform/identity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub struct IdentityRegistrationInfo {

#[derive(Debug, Clone, PartialEq)]
pub struct RegisterDpnsNameInput {
pub identity_id_input: Identifier,
pub qualified_identity: QualifiedIdentity,
pub name_input: String,
}

Expand Down
212 changes: 91 additions & 121 deletions src/platform/identity/register_dpns_name.rs
Original file line number Diff line number Diff line change
@@ -1,31 +1,29 @@
use std::collections::{BTreeMap, HashSet};
use std::collections::BTreeMap;

use crate::{context::AppContext, model::qualified_identity::EncryptedPrivateKeyTarget};
use crate::{context::AppContext, model::qualified_identity::QualifiedIdentity};
use dash_sdk::{
dpp::{
data_contract::{
accessors::v0::DataContractV0Getters, document_type::accessors::DocumentTypeV0Getters,
},
document::{DocumentV0, DocumentV0Getters, DocumentV0Setters},
identity::{accessors::IdentityGettersV0, KeyType, Purpose, SecurityLevel},
document::DocumentV0,
identity::accessors::IdentityGettersV0,
platform_value::Bytes32,
state_transition::documents_batch_transition::{
methods::v0::DocumentsBatchTransitionMethodsV0, DocumentsBatchTransition,
},
util::{hash::hash_double, strings::convert_to_homograph_safe_chars},
version::PlatformVersion,
},
platform::{
transition::{
broadcast::BroadcastStateTransition, put_document::PutDocument,
put_settings::PutSettings,
},
Document, Identity,
Document,
},
RequestSettings, Sdk,
};
use rand::{rngs::StdRng, Rng, SeedableRng};
use simple_signer::signer::SimpleSigner;

use super::RegisterDpnsNameInput;
impl AppContext {
Expand All @@ -35,14 +33,9 @@ impl AppContext {
input: RegisterDpnsNameInput,
) -> Result<(), String> {
let mut rng = StdRng::from_entropy();
let platform_version = PlatformVersion::latest();
let dpns_contract = self.dpns_contract.clone();

let qualified_identities = self.load_local_qualified_identities().unwrap_or_default();
let qualified_identity = qualified_identities
.iter()
.find(|identity| identity.identity.id() == input.identity_id_input)
.expect("Expected to find the identity in qualified identities vec");
let qualified_identity = input.qualified_identity;

let entropy = Bytes32::random_with_rng(&mut rng);
let preorder_document_type = dpns_contract
Expand All @@ -65,10 +58,20 @@ impl AppContext {
entropy.as_slice(),
);

let mut preorder_document = Document::V0(DocumentV0 {
let salt: [u8; 32] = rng.gen();
let mut salted_domain_buffer: Vec<u8> = vec![];
salted_domain_buffer.extend(salt);
salted_domain_buffer
.extend((convert_to_homograph_safe_chars(&input.name_input) + ".dash").as_bytes());
let salted_domain_hash = hash_double(salted_domain_buffer);

let preorder_document = Document::V0(DocumentV0 {
id: preorder_id,
owner_id: input.identity_id_input,
properties: BTreeMap::new(),
owner_id: qualified_identity.identity.id(),
properties: BTreeMap::from([(
"saltedDomainHash".to_string(),
salted_domain_hash.into(),
)]),
revision: None,
created_at: None,
updated_at: None,
Expand All @@ -80,10 +83,37 @@ impl AppContext {
updated_at_core_block_height: None,
transferred_at_core_block_height: None,
});
let mut domain_document = Document::V0(DocumentV0 {
let domain_document = Document::V0(DocumentV0 {
id: domain_id,
owner_id: input.identity_id_input,
properties: BTreeMap::new(),
owner_id: qualified_identity.identity.id(),
properties: BTreeMap::from([
("parentDomainName".to_string(), "dash".into()),
("normalizedParentDomainName".to_string(), "dash".into()),
("label".to_string(), input.name_input.clone().into()),
(
"normalizedLabel".to_string(),
convert_to_homograph_safe_chars(&input.name_input).into(),
),
("preorderSalt".to_string(), salt.into()),
(
"records".to_string(),
BTreeMap::from([(
"identity".to_string(),
Into::<dash_sdk::dpp::platform_value::Value>::into(
qualified_identity.identity.id(),
),
)])
.into(),
),
(
"subdomainRules".to_string(),
BTreeMap::from([(
"allowSubdomains".to_string(),
Into::<dash_sdk::dpp::platform_value::Value>::into(false),
)])
.into(),
),
]),
revision: None,
created_at: None,
updated_at: None,
Expand All @@ -96,28 +126,16 @@ impl AppContext {
transferred_at_core_block_height: None,
});

let salt: [u8; 32] = rng.gen();
let mut salted_domain_buffer: Vec<u8> = vec![];
salted_domain_buffer.extend(salt);
salted_domain_buffer
.extend((convert_to_homograph_safe_chars(&input.name_input) + ".dash").as_bytes());
let salted_domain_hash = hash_double(salted_domain_buffer);

preorder_document.set("saltedDomainHash", salted_domain_hash.into());
domain_document.set("parentDomainName", "dash".into());
domain_document.set("normalizedParentDomainName", "dash".into());
domain_document.set("label", input.name_input.clone().into());
domain_document.set(
"normalizedLabel",
convert_to_homograph_safe_chars(&input.name_input).into(),
);
domain_document.set("records.identity", domain_document.owner_id().into());
domain_document.set("subdomainRules.allowSubdomains", false.into());
domain_document.set("preorderSalt", salt.into());
let public_key = qualified_identity
.document_signing_key(&preorder_document_type)
.ok_or(
"Identity doesn't have an authentication key for signing document transitions"
.to_string(),
)?;

let identity_contract_nonce = match sdk
.get_identity_contract_nonce(
input.identity_id_input,
qualified_identity.identity.id(),
dpns_contract.id(),
true,
Some(PutSettings {
Expand All @@ -132,40 +150,6 @@ impl AppContext {
Err(e) => return Err(e.to_string()),
};

// Get signer from loaded_identity
// Convert loaded_identity to SimpleSigner
let signer = {
let mut new_signer = SimpleSigner::default();
let Identity::V0(identity_v0) = &qualified_identity.identity;
for (key_id, public_key) in &identity_v0.public_keys {
let identity_key_tuple =
(EncryptedPrivateKeyTarget::PrivateKeyOnMainIdentity, *key_id);
if let Some(private_key_bytes) = qualified_identity
.encrypted_private_keys
.get(&identity_key_tuple)
{
new_signer
.private_keys
.insert(public_key.clone(), private_key_bytes.1.clone());
}
}
new_signer
};

let public_key =
match qualified_identity.identity.get_first_public_key_matching(
Purpose::AUTHENTICATION,
HashSet::from([SecurityLevel::CRITICAL]),
HashSet::from([KeyType::ECDSA_SECP256K1, KeyType::BLS12_381]),
false,
) {
Some(key) => key,
None => return Err(
"Identity doesn't have an authentication key for signing document transitions"
.to_string(),
),
};

let preorder_transition =
DocumentsBatchTransition::new_document_creation_transition_from_document(
preorder_document.clone(),
Expand All @@ -174,8 +158,8 @@ impl AppContext {
public_key,
identity_contract_nonce,
0,
&signer,
&platform_version,
&qualified_identity,
&sdk.version(),
None,
None,
None,
Expand All @@ -187,19 +171,11 @@ impl AppContext {
domain_document.clone(),
domain_document_type,
entropy.0,
qualified_identity
.identity
.get_first_public_key_matching(
Purpose::AUTHENTICATION,
HashSet::from([SecurityLevel::CRITICAL]),
HashSet::from([KeyType::ECDSA_SECP256K1, KeyType::BLS12_381]),
false,
)
.expect("expected to get a signing key"),
public_key,
identity_contract_nonce + 1,
0,
&signer,
&platform_version,
&qualified_identity,
&sdk.version(),
None,
None,
None,
Expand All @@ -211,48 +187,42 @@ impl AppContext {
.await
.map_err(|e| e.to_string())?;

let _preorder_document =
match <dash_sdk::platform::Document as PutDocument<SimpleSigner>>::wait_for_response::<
'_,
'_,
'_,
>(
&preorder_document,
sdk,
preorder_transition,
dpns_contract.clone().into(),
)
.await
{
Ok(document) => document,
Err(e) => {
return Err(format!("Preorder document failed to process: {e}"));
}
};
let _preorder_document = match <dash_sdk::platform::Document as PutDocument<
QualifiedIdentity,
>>::wait_for_response::<'_, '_, '_>(
&preorder_document,
sdk,
preorder_transition,
dpns_contract.clone().into(),
)
.await
{
Ok(document) => document,
Err(e) => {
return Err(format!("Preorder document failed to process: {e}"));
}
};

domain_transition
.broadcast(sdk)
.await
.map_err(|e| e.to_string())?;

let _domain_document =
match <dash_sdk::platform::Document as PutDocument<SimpleSigner>>::wait_for_response::<
'_,
'_,
'_,
>(
&domain_document,
sdk,
domain_transition,
dpns_contract.into(),
)
.await
{
Ok(document) => document,
Err(e) => {
return Err(format!("Domain document failed to process: {e}"));
}
};
let _domain_document = match <dash_sdk::platform::Document as PutDocument<
QualifiedIdentity,
>>::wait_for_response::<'_, '_, '_>(
&domain_document,
sdk,
domain_transition,
dpns_contract.into(),
)
.await
{
Ok(document) => document,
Err(e) => {
return Err(format!("Domain document failed to process: {e}"));
}
};

Ok(())
}
Expand Down
Loading