# Nom - Name Registry DNA ERD, Entry Structures, Validations ###### tags: `Technical Specification` ### Diagram for Links/Paths/Entries **Instruction for reading** - **Solid borders:** DHT Entry - **Dashed borders:** Path - **Solid arrows:** Represent a `Link`s - **Dashed arrows(only between Entries):** Indicates that the Entry contains the EntryHash of the Entry being pointed to #### Link Structrure for Rival DNA entries ```mermaid graph TD subgraph Rival DNA Namespace NamespaceProp Nametype Entries classDef dash stroke-dasharray: 5 5 subgraph Entry Links subgraph Hardcoded Path .("hash_entry('all_namespace')"):::dash %% Hardcoded Path end subgraph Namespace Entry DevHub .("hash_entry('all_namespace')")-->DevHub end subgraph FreeNameAllotment Entry DevHub-->|name_type_eh|FreeNameAllotment_1st DevHub-->|name_type_eh|FreeNameAllotment_2nd end subgraph Nametype Entry DevHub_Nametype_Nickname_V1 DevHub_Nametype_Nickname_V2 DevHub_Nametype_Nickname_V1-->DevHub_Nametype_Nickname_V2 DevHub_Nametype_Nickname_V1-.->DevHub DevHub_Nametype_Nickname_V2-.->DevHub end subgraph Namespace Props Entry DevHubNamespaceProps_V1 DevHubNamespaceProps_V2 DevHubNamespaceProps_V3 DevHub -->|"metadata"|DevHubNamespaceProps_V3 DevHubNamespaceProps_V1 -->DevHubNamespaceProps_V2 DevHubNamespaceProps_V2 -->DevHubNamespaceProps_V3 end subgraph agents alice-->|maintainer|DevHubNamespaceProps_V1 end DevHubNamespaceProps_V1 -.-> DevHub_Nametype_Nickname_V1 DevHubNamespaceProps_V2 -.-> DevHub_Nametype_Nickname_V1 DevHubNamespaceProps_V3 -.-> DevHub_Nametype_Nickname_V2 end end ``` #### Link Structure for Paths for the Name Registration ```mermaid graph TD classDef dash stroke-dasharray: 5 5 classDef update fill:#8abd00 subgraph Nom DNA Paths to Name subgraph Root Component .("hash_entry('Nom')"):::dash end subgraph Global Namespace GlobalNamespace:::dash Elsa_the_Global:::dash Elsa_the_Global Agentname:::dash .("hash_entry('Nom')")-->GlobalNamespace GlobalNamespace-->|agent_bound|Agentname Agentname-->Elsa_the_Global end subgraph Devhub Namespace DevHubInitialDNAHash:::dash Charlie_Chaplin:::dash Username:::dash Orgname:::dash .("hash_entry('Nom')")-->DevHubInitialDNAHash DevHubInitialDNAHash-->|agent_bound|Username DevHubInitialDNAHash-->Orgname Username-->Charlie_Chaplin end subgraph Kizuna Namespace KizunaInitialDNAHash:::dash Bob_the_Magnificent:::dash mushroom_farmer_community:::dash Nickname:::dash Groups:::dash KizunaInitialDNAHash-->|agent_bound|Nickname KizunaInitialDNAHash-->Groups .("hash_entry('Nom')")-->KizunaInitialDNAHash Nickname-->Bob_the_Magnificent Bob_the_Magnificent-->Bob_Name_Registration_V1 Bob_the_Magnificent-->Bob_BindNameToClientAppAgent_V1 Groups-->mushroom_farmer_community end end ``` #### Updating Name Registration and Name Binding ```mermaid graph TD subgraph Kizuna Namespace classDef dash stroke-dasharray: 5 5 KizunaInitialDNAHash:::dash Bob_the_Magnificent:::dash Nickname:::dash KizunaInitialDNAHash-->|agent_bound|Nickname .("hash_entry('Nom')"):::dash-->KizunaInitialDNAHash Nickname-->Bob_the_Magnificent Bob_Name_Registration_V1 Bob_the_Magnificent-->Bob_Name_Registration_V2 Bob_BindNameToClientAppAgent_V1 Bob_the_Magnificent-->Bob_BindNameToClientAppAgent_V2 end ``` ### Entries #### Namespace Entries ```rust= // Create // Update is invalid // Delete is invalid #[hdk_entry] struct Namespace { origin_dna: HoloHash<Dna>, // immutable. How do we verify that this is actually a dna hash? or at least that it is a hash to prevent junk data being put here which can potentially cause collusion? global_name_reg_opt_in: bool, // immutable ttl: u8 // time to live. expressed in years binding_public_key: String } #[hdk_entry] struct FreeNameAllotment { namespace: EntryHash, nametype: EntryHash, qty: u32 // bundle of free names purchased } // Create // - the origin_dna hash should match the origin_dna hash in Namespace entry // - the author of this entry is the same as the author of the previous entry (which is the Namespace) // - 1 =< organization name string length >= 50 // 1 =< display name >= 50 // - organization email must conform to regex // - name types and agent name type field cannot be empty // Update // - origin_dna (the first item in dna_versions) must be the same compared to the prev entry // - Updates can only be done by the previous entry's maintainers or creator // - creator field must be the same with the previous entry // - the Path (Vec<u8>) in the name types vector should match the path name // - get the name type eh found in name types field and make sure that the path in index 0 matches // Delete is invalid #[hdk_entry] struct NamespaceProperties { // Q: why ActionHash? namespace: ActionHash display_name: string, dna_versions: Vec<HoloHash<Dna>>, // index 0 is the initial DNA hash org_detail: Organization, // The new NameType entry is the prev_action so // we can get it in validation to see if it exist name_types: Vec<(Vec<u8>, EntryHash)>, // we separate the names for agents for ease in validation agent_name_type: Option<u8>, // index of the agent name type in name types vector // list of agents that can create NameType entries within this namespace and modify this property entry maintainers: Vec<AgentPubKey>, ownership_proof: Option<Signature>, // must be verified using the public binding key to create the first maintainer } pub struct Organization { name: String, email: String, country: String, province: String, city: String, contact_no: String, } ``` #### Nametype Entries ```rust= // For NameType and AgentHandleNameType // Create // - Namespace entry must exist // - reg_duration > 0 // - purchase price >= 100 (minimum 1USD) // Update // - path_name should be constant // - Namespace entry should be constant // - reserved_names should be constant // - regex should be constant // Delete is invalid #[hdk_entry] pub struct NameType { path: Path, // immutable namespace: EntryHash, // immutable reserved_names: Vec<Vec<u8>>, // immutable valid_name_structure_regex: ???, // immutable // path_component + name allow us to change the name in the UI // (e.g. path: handle -> name: nickname) w/o breaking the pathing display_name: string, // name presented in UI ttl: u8, purchase_price: u32, // payment portal would need to check the current exchange rate of other currencies to accept currencies other than USD. This can be set to 0 which means that the names in this name type is pre-paid by the namespace owner. prev_name_type_eh: Option<EntryHash> } // #[hdk_entry] // pub struct AgentHandleNameType { // path_component: Component, // name: string, // name presented in UI // // path_component + name allow us to change the name in the UI // // (e.g. path: handle -> name: nickname) w/o breaking the pathing // namespace: EntryHash, // // to check that the author was at some point a maintainer of the namespace (proof of membership) // namespace_property: EntryHash, // ttl: u8, // purchase_price: u32, // min 100 = 1USD; payment portal would need to check the current exchange rate of other currencies to accept currencies other than USD. // reserved_names: Vec<Vec<u8>>, // with_roles: bool, // regex: ??? // version: u16 // } // progenitor (not one of the witnesses) of the DNA must commit this entry in init() // renewable based on ttl #[hdk_entry] pub struct GlobalNameType { path_component_name: Component, presented_name: string, purchase_price: u32, regex: ??? } ``` #### Name Registration Entries ```rust= // Create // - payment_proof_sig must be verified with the PubKey from DNA property // - `get(namespace_hash)` -> Namespace must exist // - `get(nametype_hash)` -> name bytes should not // be in NameType.reserved_names // - `get_remote_agent_state` -> iterate through `NameRegistration` entries for at least 4 witnesses (also iterate through `GlobalNameRegistration` if the namespace opted in to global name registry) // - couponData's serial_number must not have been used in previous entries // - name must not be found in previous NameRegistration entries *or* // - name can be found in a previous NameRegistration entry as long as // - previous registration must be expired (beyond ttl+grace) // Update(Renew) // - `get(namespace_hash)` -> Namespace must exist // - `get(nametype_hash)` -> name bytes should not be in NameType.reserved_names // - `get_remote_agent_state` -> iterate through `NameRegistration` entries // - couponData's serial_number must not have been used in previous entries // - name must be found in a previous NameRegistration entry *and* // - previous registration is not yet expired (beyond ttl+grace) *and* // - author of new registration must be the same as the author of the previous registration // Delete is invalid (??) #[hdk_entry] struct NameRegistration { namespace: HoloHash<EntryHash>, name_type: EntryHash, // NameType spec that is the latest version (display price and ttl) name: Vec<u8>, binding_public_key: String } // Create // - payment_proof_sig must be verified with the PubKey from DNA property // - `get(nametype_hash)` -> name bytes should not be in NameType.reserved_names // - `get_remote_agent_state` -> iterate through `NameRegistration` and `GlobalNameRegistration` entries // - couponData's serial_number must not have been used in previous entries // - name must not be found in previous NameRegistration entries *or* // - name can be found in a previous NameRegistration entry as long as // - previous registration must be expired (beyond ttl+grace) // Update // - `get(nametype_hash)` -> name bytes should not be in NameType.reserved_names // - `get_local_agent_state` -> iterate through `NameRegistration` and `GlobalNameRegistration` entries // - couponData's serial_number must not have been used in previous entries // - name must be found in a previous NameRegistration entry *and* // - previous registration is not yet expired (beyond ttl+grace) *and* // - author of new registration must be the same as the author of the previous registration // Delete is invalid (??) // NOTE: We should build a reclamation mechanism for unused global names that have been unused for a year #[hdk_entry] struct GlobalNameRegistration { namespace: HoloHash<EntryHash>, name_type: EntryHash name: Vec<u8>, initial_binding_public_key: String } #[hdk_entry] struct GlobalNameTransfer { name_registration: EntryHash, // denominated in USD transfer_price: String, // This is the binding key found in the old name // registration entry authorizing the transfer of // global name. authorization_by_previous_owner: Signature, new_binding_public_key: String } #[hdk_entry] struct BindNameToClientAppAgent { name_registration: EntryHash, (original?)dna_hash: HoloHash<Dna>, agent_pub_key: AgentPubKey, expiry_date: Timestamp, // Signing of AgentPubKey using the binding private key found in UserCredential (verified using the binding public key found in the NameRegistration) ownership_proof: Signature } #[hdk_entry] // private entry in registration's node struct UserCredential { email: String, binding_public_key: String, // encrypted with the user's password hash at the time of account creation. encrypted_private_key: String } // outstanding issues // Art mentioned that looping through the source chain of witnesses in the validation will be very slow. However, what other ways do we have to validate the uniqueness of the name if we are not going to look at the source chain of at least 4 witnesses? (Check the mattermost chat) // ---- // we can create a function to police the payment node // from creating conflicting coupons if we are willing // to store the coupons as private entries. This gives // a person an ability to report binding conflicts. // What if we get the local time of the witness nodes // instead of the local time of the server? This way // there is no way for the payment node to cheat on the // timestamp. And it is in the interest of witness to protect the integrity of the coupons so they are incentivized to provided the timestamp that is accurate. // How do we recover lost password? ``` #### Link Validation ##### Namespace -> NamespaceProperties ##### NamespaceProperties -> NameType ##### Rival.Handle -> GlobalNameRegistration ##### Rival.<DNA_Hash>.<Name_Type> -> NameRegistration - **Create** - The author of the path is the reservation node's pubkey - Question: Is the Path - The same ##### NamePath -> NameRegistrationReceipt ##### NamePath -> GlobalNameRegistrationReceipt