From 6f49a54de0ab95045085df68a2260b21fb5b6964 Mon Sep 17 00:00:00 2001 From: Anna Shaleva Date: Wed, 14 Sep 2022 12:59:39 +0300 Subject: [PATCH] [#266] nns: Keep `isAvailable` in sync with `register` If conflicting records '*.domain' are present on new domain registration, then `isAvailable` should return false for this domain. Ref. https://github.com/nspcc-dev/neofs-contract/pull/175/commits/f25296b17a4dcaca50855c40d44a42bbcf0bb6a1. Signed-off-by: Anna Shaleva --- nns/nns_contract.go | 35 ++++++++++++++++++++++++----------- tests/nns_test.go | 2 ++ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/nns/nns_contract.go b/nns/nns_contract.go index 2979b621..2f642834 100644 --- a/nns/nns_contract.go +++ b/nns/nns_contract.go @@ -224,7 +224,7 @@ func GetPrice() int { // IsAvailable checks whether the provided domain name is available. func IsAvailable(name string) bool { - fragments := splitAndCheck(name, false) + fragments := splitAndCheck(name, true) if fragments == nil { panic("invalid domain name format") } @@ -236,7 +236,27 @@ func IsAvailable(name string) bool { } return true } - return parentExpired(ctx, 0, fragments) + if !parentExpired(ctx, 0, fragments) { + return false + } + return len(getParentConflictingRecord(ctx, name, fragments)) == 0 +} + +// getPrentConflictingRecord returns record of '*.name' format if they are presented. +// These records conflict with domain name to be registered. +func getParentConflictingRecord(ctx storage.Context, name string, fragments []string) string { + parentKey := getTokenKey([]byte(name[len(fragments[0])+1:])) + parentRecKey := append([]byte{prefixRecord}, parentKey...) + it := storage.Find(ctx, parentRecKey, storage.ValuesOnly|storage.DeserializeValues) + suffix := []byte(name) + for iterator.Next(it) { + r := iterator.Value(it).(RecordState) + ind := std.MemorySearchLastIndex([]byte(r.Name), suffix, len(r.Name)) + if ind > 0 && ind+len(suffix) == len(r.Name) { + return r.Name + } + } + return "" } // parentExpired returns true if any domain from fragments doesn't exist or is expired. @@ -290,15 +310,8 @@ func Register(name string, owner interop.Hash160, email string, refresh, retry, ns := std.Deserialize(nsBytes.([]byte)).(NameState) ns.checkAdmin() - parentRecKey := append([]byte{prefixRecord}, parentKey...) - it := storage.Find(ctx, parentRecKey, storage.ValuesOnly|storage.DeserializeValues) - suffix := []byte(name) - for iterator.Next(it) { - r := iterator.Value(it).(RecordState) - ind := std.MemorySearchLastIndex([]byte(r.Name), suffix, len(r.Name)) - if ind > 0 && ind+len(suffix) == len(r.Name) { - panic("parent domain has conflicting records: " + r.Name) - } + if conflict := getParentConflictingRecord(ctx, name, fragments); len(conflict) != 0 { + panic("parent domain has conflicting records: " + conflict) } } diff --git a/tests/nns_test.go b/tests/nns_test.go index 2947b61d..bac6c1d3 100644 --- a/tests/nns_test.go +++ b/tests/nns_test.go @@ -178,11 +178,13 @@ func TestNNSRegisterMulti(t *testing.T) { "another.fs.neo.com", int64(nns.A), "4.3.2.1") c2 = c.WithSigners(acc, acc2) + c2.Invoke(t, stackitem.NewBool(false), "isAvailable", "mainnet.fs.neo.com") c2.InvokeFail(t, "parent domain has conflicting records: something.mainnet.fs.neo.com", "register", args...) c1.Invoke(t, stackitem.Null{}, "deleteRecords", "something.mainnet.fs.neo.com", int64(nns.A)) + c2.Invoke(t, stackitem.NewBool(true), "isAvailable", "mainnet.fs.neo.com") c2.Invoke(t, true, "register", args...) c2 = c.WithSigners(acc2)