1use std::time::{Duration, SystemTime, UNIX_EPOCH};
5
6use iota_sdk_types::{Address, MoveStruct, ObjectId};
7use iota_types::{collection_types::VecMap, dynamic_field::Field, id::ID, object::Object};
8use serde::{Deserialize, Serialize};
9
10use crate::{constants::IOTA_NAMES_LEAF_EXPIRATION_TIMESTAMP, error::IotaNamesError, name::Name};
11
12#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
14pub struct Table {
15 pub id: ObjectId,
16 pub size: u64,
17}
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct Registry {
21 registry: Table,
24 reverse_registry: Table,
27}
28
29#[derive(Debug, Serialize, Deserialize)]
30pub struct RegistryEntry {
31 pub id: ObjectId,
32 pub name: Name,
33 pub name_record: NameRecord,
34}
35
36#[derive(Debug, Serialize, Deserialize)]
37pub struct ReverseRegistryEntry {
38 pub id: ObjectId,
39 pub address: Address,
40 pub name: Name,
41}
42
43#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
45pub struct NameRecord {
46 pub nft_id: ID,
54 pub expiration_timestamp_ms: u64,
56 pub target_address: Option<Address>,
58 pub data: VecMap<String, String>,
60}
61
62impl TryFrom<Object> for NameRecord {
63 type Error = IotaNamesError;
64
65 fn try_from(object: Object) -> Result<Self, IotaNamesError> {
66 object
67 .to_rust::<Field<Name, Self>>()
68 .map(|record| record.value)
69 .map_err(|_| IotaNamesError::MalformedObject(object.id()))
70 }
71}
72
73impl TryFrom<MoveStruct> for NameRecord {
74 type Error = IotaNamesError;
75
76 fn try_from(object: MoveStruct) -> Result<Self, IotaNamesError> {
77 object
78 .to_rust::<Field<Name, Self>>()
79 .map(|record| record.value)
80 .map_err(|_| IotaNamesError::MalformedObject(object.id()))
81 }
82}
83
84impl NameRecord {
85 pub fn is_leaf_record(&self) -> bool {
88 self.expiration_timestamp_ms == IOTA_NAMES_LEAF_EXPIRATION_TIMESTAMP
89 }
90
91 pub fn is_valid_leaf_parent(&self, child: &NameRecord) -> bool {
95 self.nft_id == child.nft_id
96 }
97
98 pub fn is_node_expired(&self, checkpoint_timestamp_ms: u64) -> bool {
101 self.expiration_timestamp_ms < checkpoint_timestamp_ms
102 }
103
104 pub fn expiration_time(&self) -> SystemTime {
106 UNIX_EPOCH + Duration::from_millis(self.expiration_timestamp_ms)
107 }
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn expirations() {
116 let system_time: u64 = 100;
117
118 let mut name = NameRecord {
119 nft_id: iota_types::id::ID::new(ObjectId::random()),
120 data: VecMap { contents: vec![] },
121 target_address: Some(Address::random()),
122 expiration_timestamp_ms: system_time + 10,
123 };
124
125 assert!(!name.is_node_expired(system_time));
126
127 name.expiration_timestamp_ms = system_time - 10;
128
129 assert!(name.is_node_expired(system_time));
130 }
131}