diff --git a/DashSync/shared/Models/DAPI/DSPlatformDocumentsRequest.m b/DashSync/shared/Models/DAPI/DSPlatformDocumentsRequest.m index 1fde02804..5019d61fc 100644 --- a/DashSync/shared/Models/DAPI/DSPlatformDocumentsRequest.m +++ b/DashSync/shared/Models/DAPI/DSPlatformDocumentsRequest.m @@ -57,7 +57,7 @@ + (instancetype)dpnsRequestForUsername:(NSString *)username inDomain:(NSString * + (instancetype)dpnsRequestForUserId:(NSData *)userId { DSPlatformDocumentsRequest *platformDocumentsRequest = [[DSPlatformDocumentsRequest alloc] init]; - platformDocumentsRequest.pathPredicate = [NSPredicate predicateWithFormat:@"records.dashUniqueIdentityId == %@", userId]; + platformDocumentsRequest.pathPredicate = [NSPredicate predicateWithFormat:@"records.identity == %@", userId]; // why not path predicate and then predicate? platformDocumentsRequest.startAt = nil; platformDocumentsRequest.limit = 100; platformDocumentsRequest.queryType = DSPlatformQueryType_RangeOverIndex; @@ -115,7 +115,7 @@ + (instancetype)dashpayRequestForContactRequestsForSendingUserId:(NSData *)userI platformDocumentsRequest.startAtIncluded = false; platformDocumentsRequest.limit = 100; platformDocumentsRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"$createdAt" ascending:YES]]; - platformDocumentsRequest.queryType = DSPlatformQueryType_RangeOverValue; + platformDocumentsRequest.queryType = DSPlatformQueryType_RangeOverValue; // why not over index? platformDocumentsRequest.type = DSPlatformDocumentType_Document; platformDocumentsRequest.tableName = @"contactRequest"; platformDocumentsRequest.prove = DSPROVE_PLATFORM_SINDEXES; @@ -131,7 +131,7 @@ + (instancetype)dashpayRequestForContactRequestsForRecipientUserId:(NSData *)use platformDocumentsRequest.startAtIncluded = false; platformDocumentsRequest.limit = 100; platformDocumentsRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"$createdAt" ascending:YES]]; - platformDocumentsRequest.queryType = DSPlatformQueryType_RangeOverValue; + platformDocumentsRequest.queryType = DSPlatformQueryType_RangeOverValue; // why not over index? platformDocumentsRequest.type = DSPlatformDocumentType_Document; platformDocumentsRequest.tableName = @"contactRequest"; platformDocumentsRequest.prove = DSPROVE_PLATFORM_SINDEXES; @@ -140,7 +140,7 @@ + (instancetype)dashpayRequestForContactRequestsForRecipientUserId:(NSData *)use + (instancetype)dashpayRequestForContactRequestForSendingUserId:(NSData *)userId toRecipientUserId:(NSData *)toUserId { DSPlatformDocumentsRequest *platformDocumentsRequest = [[DSPlatformDocumentsRequest alloc] init]; - platformDocumentsRequest.pathPredicate = [NSPredicate predicateWithFormat:@"%K == %@ && toUserId == %@", @"$ownerId", userId, toUserId]; + platformDocumentsRequest.pathPredicate = [NSPredicate predicateWithFormat:@"%K == %@ && toUserId == %@", @"$ownerId", userId, toUserId]; // why not path predicate and predicate? platformDocumentsRequest.startAt = nil; platformDocumentsRequest.limit = 100; platformDocumentsRequest.type = DSPlatformDocumentType_Document; diff --git a/DashSync/shared/Models/Identity/DSBlockchainIdentity.m b/DashSync/shared/Models/Identity/DSBlockchainIdentity.m index f62ffd288..bfc7b862f 100644 --- a/DashSync/shared/Models/Identity/DSBlockchainIdentity.m +++ b/DashSync/shared/Models/Identity/DSBlockchainIdentity.m @@ -2197,7 +2197,7 @@ - (NSString *)dashpayDomainName { @"normalizedLabel": [username lowercaseString], @"normalizedParentDomainName": domain, @"preorderSalt": [self.usernameSalts objectForKey:usernameFullPath], - @"records": @{@"dashUniqueIdentityId": uint256_data(self.uniqueID)}, + @"records": @{@"identity": uint256_data(self.uniqueID)}, @"subdomainRules": @{@"allowSubdomains": @NO} }; DPDocument *document = [self.dpnsDocumentFactory documentOnTable:@"domain" withDataDictionary:dataDictionary usingEntropy:entropyData error:error]; diff --git a/DashSync/shared/dpns-contract.json b/DashSync/shared/dpns-contract.json index 81692dd88..b620bb79c 100644 --- a/DashSync/shared/dpns-contract.json +++ b/DashSync/shared/dpns-contract.json @@ -1,8 +1,14 @@ { "documents": { "domain": { + "documentsMutable": false, + "canBeDeleted": true, + "transferable": 1, + "tradeMode": 1, + "type": "object", "indices": [ { + "name": "parentNameAndLabel", "properties": [ { "normalizedParentDomainName": "asc" @@ -11,20 +17,24 @@ "normalizedLabel": "asc" } ], - "unique": true + "unique": true, + "contested": { + "fieldMatches": [ + { + "field": "normalizedLabel", + "regexPattern": "^[a-zA-Z01-]{3,19}$" + } + ], + "resolution": 0, + "description": "If the normalized label part of this index is less than 20 characters (all alphabet a-z, A-Z, 0, 1, and -) then a masternode vote contest takes place to give out the name" + } }, { + "name": "identityId", + "nullSearchable": false, "properties": [ { - "records.dashUniqueIdentityId": "asc" - } - ], - "unique": true - }, - { - "properties": [ - { - "records.dashAliasIdentityId": "asc" + "records.identity": "asc" } ] } @@ -32,58 +42,60 @@ "properties": { "label": { "type": "string", - "pattern": "^((?!-)[a-zA-Z0-9-]{0,62}[a-zA-Z0-9])$", + "pattern": "^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$", "minLength": 3, "maxLength": 63, + "position": 0, "description": "Domain label. e.g. 'Bob'." }, "normalizedLabel": { "type": "string", - "pattern": "^((?!-)[a-z0-9-]{0,62}[a-z0-9])$", + "pattern": "^[a-hj-km-np-z0-9][a-hj-km-np-z0-9-]{0,61}[a-hj-km-np-z0-9]$", "maxLength": 63, - "description": "Domain label in lowercase for case-insensitive uniqueness validation. e.g. 'bob'", - "$comment": "Must be equal to the label in lowercase. This property will be deprecated due to case insensitive indices" + "position": 1, + "description": "Domain label converted to lowercase for case-insensitive uniqueness validation. \"o\", \"i\" and \"l\" replaced with \"0\" and \"1\" to mitigate homograph attack. e.g. 'b0b'", + "$comment": "Must be equal to the label in lowercase. \"o\", \"i\" and \"l\" must be replaced with \"0\" and \"1\"." + }, + "parentDomainName": { + "type": "string", + "pattern": "^$|^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]$", + "minLength": 0, + "maxLength": 63, + "position": 2, + "description": "A full parent domain name. e.g. 'dash'." }, "normalizedParentDomainName": { "type": "string", - "pattern": "^$|^((?!-)[a-z0-9-\\.]{0,189}[a-z0-9])$", + "pattern": "^$|^[a-hj-km-np-z0-9][a-hj-km-np-z0-9-\\.]{0,61}[a-hj-km-np-z0-9]$", "minLength": 0, - "maxLength": 190, - "description": "A full parent domain name in lowercase for case-insensitive uniqueness validation. e.g. 'dash'", - "$comment": "Must either be equal to an existing domain or empty to create a top level domain. Only the data contract owner can create top level domains." + "maxLength": 63, + "position": 3, + "description": "A parent domain name in lowercase for case-insensitive uniqueness validation. \"o\", \"i\" and \"l\" replaced with \"0\" and \"1\" to mitigate homograph attack. e.g. 'dash'", + "$comment": "Must either be equal to an existing domain or empty to create a top level domain. \"o\", \"i\" and \"l\" must be replaced with \"0\" and \"1\". Only the data contract owner can create top level domains." }, "preorderSalt": { "type": "array", "byteArray": true, "minItems": 32, "maxItems": 32, + "position": 4, "description": "Salt used in the preorder document" }, "records": { "type": "object", "properties": { - "dashUniqueIdentityId": { - "type": "array", - "byteArray": true, - "minItems": 32, - "maxItems": 32, - "contentMediaType": "application/x.dash.dpp.identifier", - "description": "Identity ID to be used to create the primary name the Identity", - "$comment": "Must be equal to the document owner" - }, - "dashAliasIdentityId": { + "identity": { "type": "array", "byteArray": true, "minItems": 32, "maxItems": 32, + "position": 1, "contentMediaType": "application/x.dash.dpp.identifier", - "description": "Identity ID to be used to create alias names for the Identity", - "$comment": "Must be equal to the document owner" + "description": "Identifier name record that refers to an Identity" } }, - "$comment": "Constraint with max and min properties ensure that only one identity record is used - either a `dashUniqueIdentityId` or a `dashAliasIdentityId`", "minProperties": 1, - "maxProperties": 1, + "position": 5, "additionalProperties": false }, "subdomainRules": { @@ -92,15 +104,22 @@ "allowSubdomains": { "type": "boolean", "description": "This option defines who can create subdomains: true - anyone; false - only the domain owner", - "$comment": "Only the domain owner is allowed to create subdomains for non top-level domains" + "$comment": "Only the domain owner is allowed to create subdomains for non top-level domains", + "position": 0 } }, + "position": 6, "description": "Subdomain rules allow domain owners to define rules for subdomains", "additionalProperties": false, - "required": ["allowSubdomains"] + "required": [ + "allowSubdomains" + ] } }, "required": [ + "$createdAt", + "$updatedAt", + "$transferredAt", "label", "normalizedLabel", "normalizedParentDomainName", @@ -108,12 +127,19 @@ "records", "subdomainRules" ], + "transient": [ + "preorderSalt" + ], "additionalProperties": false, "$comment": "In order to register a domain you need to create a preorder. The preorder step is needed to prevent man-in-the-middle attacks. normalizedLabel + '.' + normalizedParentDomain must not be longer than 253 chars length as defined by RFC 1035. Domain documents are immutable: modification and deletion are restricted" }, "preorder": { + "documentsMutable": false, + "canBeDeleted": true, + "type": "object", "indices": [ { + "name": "saltedHash", "properties": [ { "saltedDomainHash": "asc" @@ -128,6 +154,7 @@ "byteArray": true, "minItems": 32, "maxItems": 32, + "position": 0, "description": "Double sha-256 of the concatenation of a 32 byte random salt and a normalized domain name" } }, @@ -138,4 +165,4 @@ "$comment": "Preorder documents are immutable: modification and deletion are restricted" } } -} +} \ No newline at end of file