nns: allow to register arbitrary-level domains

Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
Evgenii Stratonikov 2021-11-19 16:35:58 +03:00 committed by Alex Vanin
parent 629f9fd90a
commit f12c44fc78
2 changed files with 62 additions and 7 deletions

View file

@ -272,7 +272,7 @@ func parentExpired(ctx storage.Context, first int, fragments []string) bool {
// Register registers new domain with the specified owner and name if it's available. // Register registers new domain with the specified owner and name if it's available.
func Register(name string, owner interop.Hash160, email string, refresh, retry, expire, ttl int) bool { func Register(name string, owner interop.Hash160, email string, refresh, retry, expire, ttl int) bool {
fragments := splitAndCheck(name, false) fragments := splitAndCheck(name, true)
if fragments == nil { if fragments == nil {
panic("invalid domain name format") panic("invalid domain name format")
} }
@ -292,9 +292,9 @@ func Register(name string, owner interop.Hash160, email string, refresh, retry,
panic("TLD not found") panic("TLD not found")
} }
if parentExpired(ctx, 1, fragments) { if parentExpired(ctx, 1, fragments) {
panic("one of the parent domains has expired") panic("one of the parent domains is not registered")
} }
parentKey := getTokenKey([]byte(fragments[1])) parentKey := getTokenKey([]byte(name[len(fragments[0])+1:]))
nsBytes := storage.Get(ctx, append([]byte{prefixName}, parentKey...)) nsBytes := storage.Get(ctx, append([]byte{prefixName}, parentKey...))
ns := std.Deserialize(nsBytes.([]byte)).(NameState) ns := std.Deserialize(nsBytes.([]byte)).(NameState)
ns.checkAdmin() ns.checkAdmin()
@ -851,11 +851,23 @@ func tokenIDFromName(name string) string {
if fragments == nil { if fragments == nil {
panic("invalid domain name format") panic("invalid domain name format")
} }
l := len(fragments)
if l == 1 { ctx := storage.GetReadOnlyContext()
return name sum := 0
l := len(fragments) - 1
for i := 0; i < l; i++ {
tokenKey := getTokenKey([]byte(name[sum:]))
nameKey := append([]byte{prefixName}, tokenKey...)
nsBytes := storage.Get(ctx, nameKey)
if nsBytes != nil {
ns := std.Deserialize(nsBytes.([]byte)).(NameState)
if runtime.GetTime() < ns.Expiration {
return name[sum:]
} }
return name[len(name)-(len(fragments[l-1])+len(fragments[l-2])+1):] }
sum += len(fragments[i]) + 1
}
return name
} }
// resolve resolves provided name using record with the specified type and given // resolve resolves provided name using record with the specified type and given

View file

@ -134,6 +134,49 @@ func TestTLDRecord(t *testing.T) {
c.Invoke(t, result, "resolve", "com", int64(nns.A)) c.Invoke(t, result, "resolve", "com", int64(nns.A))
} }
func TestNNSRegisterMulti(t *testing.T) {
c := newNNSInvoker(t, true)
newArgs := func(domain string, account neotest.Signer) []interface{} {
return []interface{}{
domain, account.ScriptHash(), "doesnt@matter.com",
int64(101), int64(102), int64(103), int64(104),
}
}
acc := c.NewAccount(t)
cBoth := c.WithSigners(c.Committee, acc)
args := newArgs("neo.com", acc)
cBoth.Invoke(t, true, "register", args...)
c1 := c.WithSigners(acc)
t.Run("parent domain is missing", func(t *testing.T) {
msg := "one of the parent domains is not registered"
args[0] = "testnet.fs.neo.com"
c1.InvokeFail(t, msg, "register", args...)
})
args[0] = "fs.neo.com"
c1.Invoke(t, true, "register", args...)
args[0] = "testnet.fs.neo.com"
c1.Invoke(t, true, "register", args...)
acc2 := c.NewAccount(t)
c2 := c.WithSigners(c.Committee, acc2)
args = newArgs("mainnet.fs.neo.com", acc2)
c2.InvokeFail(t, "not witnessed by admin", "register", args...)
c2 = c.WithSigners(acc, acc2)
c2.Invoke(t, true, "register", args...)
c2 = c.WithSigners(acc2)
c2.Invoke(t, stackitem.Null{}, "addRecord",
"cdn.mainnet.fs.neo.com", int64(nns.A), "166.15.14.13")
result := stackitem.NewArray([]stackitem.Item{
stackitem.NewByteArray([]byte("166.15.14.13"))})
c2.Invoke(t, result, "resolve", "cdn.mainnet.fs.neo.com", int64(nns.A))
}
func TestNNSUpdateSOA(t *testing.T) { func TestNNSUpdateSOA(t *testing.T) {
c := newNNSInvoker(t, true) c := newNNSInvoker(t, true)