diff --git a/nns/nns_contract.go b/nns/nns_contract.go index 7396cc3..94432e3 100644 --- a/nns/nns_contract.go +++ b/nns/nns_contract.go @@ -234,13 +234,10 @@ func IsAvailable(name string) bool { ctx := storage.GetReadOnlyContext() l := len(fragments) if storage.Get(ctx, append([]byte{prefixRoot}, []byte(fragments[l-1])...)) == nil { - if l != 1 { - panic("TLD not found") - } return true } - checkParentExists(ctx, fragments) + checkParent(ctx, fragments) checkAvailableGlobalDomain(ctx, name) return storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(name))...)) == nil } @@ -304,33 +301,27 @@ func extractCnametgt(ctx storage.Context, name, domain string) string { return fragments[0] + "." + globalDomain } -// checkParentExists panics if any domain from fragments doesn't exist or is expired. -func checkParentExists(ctx storage.Context, fragments []string) { - if dom := parentExpired(ctx, fragments); dom != "" { - panic("domain does not exist or is expired: " + dom) - } -} - -// parentExpired returns domain from fragments that doesn't exist or is expired. -// first denotes the deepest subdomain to check. -func parentExpired(ctx storage.Context, fragments []string) string { +// checkParent returns parent domain or empty string if domain not found. +func checkParent(ctx storage.Context, fragments []string) string { now := int64(runtime.GetTime()) last := len(fragments) - 1 name := fragments[last] + parent := "" for i := last; i > 0; i-- { if i != last { name = fragments[i] + "." + name } nsBytes := storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(name))...)) if nsBytes == nil { - return name + continue } ns := std.Deserialize(nsBytes.([]byte)).(NameState) if now >= ns.Expiration { - return name + panic("domain expired: " + name) } + parent = name } - return "" + return parent } // Register registers a new domain with the specified owner and name if it's available. @@ -353,13 +344,17 @@ func register(ctx storage.Context, name string, owner interop.Hash160, email str } storage.Put(ctx, tldKey, 0) } else { - if tldBytes == nil { - panic("TLD not found") + parent := checkParent(ctx, fragments) + if parent == "" { + parent = fragments[len(fragments)-1] + register(ctx, parent, owner, email, refresh, retry, expire, ttl) } - checkParentExists(ctx, fragments) - parentKey := getTokenKey([]byte(name[len(fragments[0])+1:])) + parentKey := getTokenKey([]byte(parent)) nsBytes := storage.Get(ctx, append([]byte{prefixName}, parentKey...)) + if nsBytes == nil { + panic("parent does not exist:" + parent) + } ns := std.Deserialize(nsBytes.([]byte)).(NameState) ns.checkAdmin() @@ -681,7 +676,7 @@ func getNameState(ctx storage.Context, tokenID []byte) NameState { tokenKey := getTokenKey(tokenID) ns := getNameStateWithKey(ctx, tokenKey) fragments := std.StringSplit(string(tokenID), ".") - checkParentExists(ctx, fragments) + checkParent(ctx, fragments) return ns } diff --git a/tests/nns_test.go b/tests/nns_test.go index 3e2dcf6..e3e6072 100644 --- a/tests/nns_test.go +++ b/tests/nns_test.go @@ -266,6 +266,18 @@ func TestDeleteDomain(t *testing.T) { c2.Invoke(t, true, "register", "cn", acc2.ScriptHash(), "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) + + c1.Invoke(t, true, "register", + "gu.bububu.bubu.bu", c.CommitteeHash, + "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) + + c1.Invoke(t, true, "register", + "buu.gu.bububu.bubu.bu", c.CommitteeHash, + "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) + + c1.Invoke(t, true, "register", + "bubu.bu", c.CommitteeHash, + "myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL) } func TestGlobalDomain(t *testing.T) { @@ -335,11 +347,6 @@ func TestNNSRegisterMulti(t *testing.T) { cBoth.Invoke(t, true, "register", args...) c1 := c.WithSigners(acc) - t.Run("parent domain is missing", func(t *testing.T) { - msg := "domain does not exist or is expired: fs.neo.com" - args[0] = "testnet.fs.neo.com" - c1.InvokeFail(t, msg, "register", args...) - }) args[0] = "fs.neo.com" c1.Invoke(t, true, "register", args...) @@ -499,7 +506,6 @@ func TestNNSIsAvailable(t *testing.T) { c := newNNSInvoker(t, false) c.Invoke(t, true, "isAvailable", "com") - c.InvokeFail(t, "TLD not found", "isAvailable", "domain.com") refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104) c.Invoke(t, true, "register", @@ -512,7 +518,6 @@ func TestNNSIsAvailable(t *testing.T) { acc := c.NewAccount(t) c1 := c.WithSigners(c.Committee, acc) - c1.InvokeFail(t, "domain does not exist or is expired: domain.com", "isAvailable", "dom.domain.com") c1.Invoke(t, true, "register", "domain.com", acc.ScriptHash(), "myemail@frostfs.info", refresh, retry, expire, ttl) @@ -524,7 +529,6 @@ func TestNNSIsAvailable(t *testing.T) { c.Invoke(t, false, "isAvailable", "domain.com") c.Invoke(t, true, "isAvailable", "dom.domain.com") - c.InvokeFail(t, "domain does not exist or is expired: dom.domain.com", "isAvailable", "dom.dom.domain.com") c1.Invoke(t, true, "register", "dom.domain.com", acc.ScriptHash(),