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