Skip to content

Commit

Permalink
NameService: Keep isAvailable and renew in sync with register
Browse files Browse the repository at this point in the history
If conflicting records '*.domain' are present on new domain
registration, then `isAvailable` should return false for this
domain. `renew` should be aware of multy-fragment domains. Ref.
nspcc-dev/neofs-contract@f25296b.
  • Loading branch information
AnnaShaleva committed Sep 15, 2022
1 parent 0dcb11c commit 132c454
Showing 1 changed file with 20 additions and 10 deletions.
30 changes: 20 additions & 10 deletions src/NameService/NameService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -177,15 +177,17 @@ public static bool IsAvailable(string name)
StorageContext context = Storage.CurrentContext;
StorageMap rootMap = new(context, Prefix_Root);
StorageMap nameMap = new(context, Prefix_Name);
string[] fragments = SplitAndCheck(name, false);
StorageMap recordMap = new(context, Prefix_Record);
string[] fragments = SplitAndCheck(name, true);
if (fragments is null) throw new FormatException("The format of the name is incorrect.");
if (rootMap[fragments[^1]] is null) {
if (fragments.Length != 1) throw new InvalidOperationException("The TLD is not found");
return true;
}
long price = GetPrice((byte)fragments[0].Length);
if (price < 0) return false;
return parentExpired(nameMap, 0, fragments);
if (!parentExpired(nameMap, 0, fragments)) return false;
return getParentConflictingRecord(recordMap, name, fragments).Length == 0;
}

public static bool Register(string name, UInt160 owner, string email, int refresh, int retry, int expire, int ttl)
Expand All @@ -210,13 +212,8 @@ public static bool Register(string name, UInt160 owner, string email, int refres
NameState parent = (NameState)StdLib.Deserialize(nameMap[parentKey]);
parent.CheckAdmin();

ByteString suffix = name;
var parentRecords = (Iterator<RecordState>)recordMap.Find(parentKey, FindOptions.ValuesOnly | FindOptions.DeserializeValues);
foreach (var r in parentRecords)
{
int idx = StdLib.MemorySearch(r.Name, suffix, r.Name.Length, true);
if (idx > 0 && idx + suffix.Length == r.Name.Length) throw new InvalidOperationException("Parent domain has conflicting records: " + r.Name + ".");
}
string conflict = getParentConflictingRecord(recordMap, name, fragments);
if (conflict.Length != 0) throw new InvalidOperationException("Parent domain has conflicting records: " + conflict + ".");
}
if (!Runtime.CheckWitness(owner)) throw new InvalidOperationException("Not wtnessed by owner.");
long price = GetPrice((byte)fragments[0].Length);
Expand Down Expand Up @@ -318,7 +315,7 @@ public static ulong Renew(string name, byte years)
{
if (years < 1 || years > 10) throw new ArgumentException("The argument `years` is out of range.");
if (name.Length > NameMaxLength) throw new FormatException("The format of the name is incorrect.");
string[] fragments = SplitAndCheck(name, false);
string[] fragments = SplitAndCheck(name, true);
if (fragments is null) throw new FormatException("The format of the name is incorrect.");
long price = GetPrice((byte)fragments[0].Length);
if (price < 0)
Expand Down Expand Up @@ -757,5 +754,18 @@ private static bool parentExpired(StorageMap nameMap, int first, string[] fragme
}
return false;
}

private static string getParentConflictingRecord(StorageMap recordMap, string name, string[] fragments)
{
ByteString parentKey = GetKey(name.Substring(fragments[0].Length+1));
ByteString suffix = name;
var parentRecords = (Iterator<RecordState>)recordMap.Find(parentKey, FindOptions.ValuesOnly | FindOptions.DeserializeValues);
foreach (var r in parentRecords)
{
int idx = StdLib.MemorySearch(r.Name, suffix, r.Name.Length, true);
if (idx > 0 && idx + suffix.Length == r.Name.Length) return r.Name;
}
return "";
}
}
}

0 comments on commit 132c454

Please sign in to comment.