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
2 changes: 1 addition & 1 deletion packages/iota-names/Move.lock
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ dependencies = [
]

[move.toolchain-version]
compiler-version = "1.5.0-rc"
compiler-version = "1.6.1-rc"
edition = "2024"
flavor = "iota"

Expand Down
58 changes: 53 additions & 5 deletions packages/iota-names/sources/registry.move
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use iota::clock::Clock;
use iota::table::{Self, Table};
use iota::vec_map::VecMap;
use iota_names::name::Name;
use iota_names::iota_names::AdminCap;
use iota_names::iota_names::{AdminCap, IotaNames};
use iota_names::name_registration::{Self as nft, NameRegistration};
use iota_names::name_record::{Self, NameRecord};
use iota_names::subname_registration::{Self, SubnameRegistration};
Expand Down Expand Up @@ -332,16 +332,48 @@ public fun has_record(self: &Registry, name: Name): bool {
self.registry.contains(name)
}

/// Checks whether the given `name` is registered in the `Registry`.
public fun has_unexpired_record(self: &Registry, name: Name, clock: &Clock): bool {
self.registry.contains(name) && !self.registry[name].has_expired(clock)
}

/// Returns the `NameRecord` associated with the given name or None.
public fun lookup(self: &Registry, name: Name): Option<NameRecord> {
if (self.registry.contains(name)) {
let record = &self.registry[name];
some(*record)
if (self.has_record(name)) {
some(self.registry[name])
} else {
none()
}
}

/// Returns the `NameRecord` associated with the given name and ensures that it is not expired,
/// or None otherwise.
public fun lookup_unexpired(self: &Registry, name: Name, clock: &Clock): Option<NameRecord> {
if (self.has_unexpired_record(name, clock)) {
some(self.registry[name])
} else {
none()
}
}

/// Returns the address associated with the given name if one is set and the record is not expired,
/// or None otherwise.
public fun lookup_address(self: &Registry, name: Name, clock: &Clock): Option<address> {
if (self.has_unexpired_record(name, clock)) {
self.registry[name].target_address()
} else {
none()
}
}

/// Returns the address associated with the given name if one is set and the record is not expired.
/// This function is callable from PTBs unlike `lookup_address`.
public fun resolve_address(iota_names: &IotaNames, name: Name, clock: &Clock): address {
let mut address = iota_names.registry<Registry>().lookup_address(name, clock);
assert!(address.is_some(), ERecordNotFound);
address.extract()
}

/// Returns the `name` associated with the given address or None.
public fun reverse_lookup(self: &Registry, address: address): Option<Name> {
if (self.reverse_registry.contains(address)) {
Expand All @@ -351,6 +383,22 @@ public fun reverse_lookup(self: &Registry, address: address): Option<Name> {
}
}

/// Returns the `name` associated with the given address and ensures it is not expired,
/// or None otherwise.
public fun reverse_lookup_unexpired(self: &Registry, address: address, clock: &Clock): Option<Name> {
if (self.reverse_registry.contains(address)) {
let name = self.reverse_registry[address];

if (self.registry[name].has_expired(clock)) {
return none()
};

some(name)
} else {
none()
}
}

/// Asserts that the provided NFT:
/// 1. Matches the ID in the corresponding `Record`
/// 2. Has not expired (does not take into account the grace period)
Expand Down Expand Up @@ -500,7 +548,7 @@ fun handle_invalidate_reverse_record(
// === Test Functions ===

#[test_only]
use iota_names::iota_names::{add_registry, IotaNames};
use iota_names::iota_names::add_registry;

#[test_only]
public fun init_for_testing(cap: &AdminCap, iota_names: &mut IotaNames, ctx: &mut TxContext) {
Expand Down
54 changes: 48 additions & 6 deletions packages/iota-names/tests/unit/registry_tests.move
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ fun set_target_address() {
registry.set_target_address(name, some(@0x2));

// try to find a record and then get a record
let mut search = registry.lookup(name);
let mut search = registry.lookup_unexpired(name, &clock);
let record = registry.remove_record_for_testing(name);

// make sure the search is a success
Expand Down Expand Up @@ -355,7 +355,7 @@ fun set_reverse_lookup() {
registry.set_reverse_lookup(@0xB0B, name);

// search for the reverse_lookup record
let mut search = registry::reverse_lookup(&registry, @0xB0B);
let mut search = registry.reverse_lookup_unexpired(@0xB0B, &clock);

assert!(option::is_some(&search), 0);
assert!(option::extract(&mut search) == name, 0);
Expand Down Expand Up @@ -827,6 +827,48 @@ fun test_lookup_nonexistent() {
wrapup(registry, clock);
}

#[test]
fun test_lookup_expired() {
let mut ctx = tx_context::dummy();
let (mut registry, mut clock, _name) = setup(&mut ctx);

let expired_name = name::new(utf8(b"expired.iota"));
let nft = registry.add_record(expired_name, 1, &clock, &mut ctx);

// Move time forward so record expires
clock::increment_for_testing(&mut clock, constants::year_ms() + 1);

assert!(registry.lookup_unexpired(expired_name, &clock).is_none());
assert!(registry.lookup_address(expired_name, &clock).is_none());

let _ = registry.remove_record_for_testing(expired_name);

burn_nfts(vector[nft]);
wrapup(registry, clock);
}

#[test]
fun test_reverse_lookup_expired() {
let mut ctx = tx_context::dummy();
let (mut registry, mut clock, _name) = setup(&mut ctx);

let expired_name = name::new(utf8(b"expired.iota"));
let nft = registry.add_record(expired_name, 1, &clock, &mut ctx);
registry.set_target_address(expired_name, some(@0xB0B));
registry.set_reverse_lookup(@0xB0B, expired_name);

// Move time forward so record expires
clock::increment_for_testing(&mut clock, constants::year_ms() + 1);

assert!(registry.reverse_lookup_unexpired(@0xB0B, &clock).is_none());

registry.unset_reverse_lookup(@0xB0B);
let _ = registry.remove_record_for_testing(expired_name);

burn_nfts(vector[nft]);
wrapup(registry, clock);
}

#[test]
fun test_reverse_lookup_nonexistent() {
let mut ctx = tx_context::dummy();
Expand All @@ -848,13 +890,13 @@ fun test_unset_target_address() {

// Set a target address first
registry.set_target_address(name, some(@0x123));
let record = registry.lookup(name).destroy_some();
assert_eq(record.target_address(), some(@0x123));
let target_address = registry.lookup_address(name, &clock);
assert_eq(target_address, some(@0x123));

// Now unset it
registry.set_target_address(name, none());
let record = registry.lookup(name).destroy_some();
assert_eq(record.target_address(), none());
let target_address = registry.lookup_address(name, &clock);
assert_eq(target_address, none());

let _ = registry.remove_record_for_testing(name);
burn_nfts(vector[nft]);
Expand Down
Loading