[#139] nns: replace root with TLD
Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
edbd137340
commit
e0dbd07f21
3 changed files with 136 additions and 58 deletions
|
@ -64,6 +64,12 @@ const (
|
|||
|
||||
// NotFoundError is returned if container is missing.
|
||||
NotFoundError = "container does not exist"
|
||||
|
||||
// default SOA record field values
|
||||
defaultRefresh = 3600 // 1 hour
|
||||
defaultRetry = 600 // 10 min
|
||||
defaultExpire = 604800 // 1 week
|
||||
defaultTTL = 3600 // 1 hour
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -114,14 +120,18 @@ func _deploy(data interface{}, isUpdate bool) {
|
|||
}
|
||||
|
||||
func registerNiceNameTLD(addrNNS interop.Hash160, nnsRoot string) {
|
||||
iter := contract.Call(addrNNS, "roots", contract.ReadStates).(iterator.Iterator)
|
||||
for iterator.Next(iter) {
|
||||
if iterator.Value(iter).(string) == nnsRoot {
|
||||
runtime.Log("NNS root is already registered: " + nnsRoot)
|
||||
isAvail := contract.Call(addrNNS, "isAvailable", contract.AllowCall|contract.ReadStates,
|
||||
"container").(bool)
|
||||
if !isAvail {
|
||||
return
|
||||
}
|
||||
|
||||
res := contract.Call(addrNNS, "register", contract.All,
|
||||
nnsRoot, common.CommitteeAddress(), "ops@nspcc.ru",
|
||||
defaultRefresh, defaultRetry, defaultExpire, defaultTTL).(bool)
|
||||
if !res {
|
||||
panic("can't register NNS TLD")
|
||||
}
|
||||
contract.Call(addrNNS, "addRoot", contract.All, nnsRoot)
|
||||
}
|
||||
|
||||
// Update method updates contract source code and manifest. Can be invoked
|
||||
|
@ -237,12 +247,6 @@ func PutNamed(container []byte, signature interop.Signature,
|
|||
|
||||
if name != "" {
|
||||
if needRegister {
|
||||
const (
|
||||
defaultRefresh = 3600 // 1 hour
|
||||
defaultRetry = 600 // 10 min
|
||||
defaultExpire = 604800 // 1 week
|
||||
defaultTTL = 3600 // 1 hour
|
||||
)
|
||||
res := contract.Call(nnsContractAddr, "register", contract.All,
|
||||
domain, runtime.GetExecutingScriptHash(), "ops@nspcc.ru",
|
||||
defaultRefresh, defaultRetry, defaultExpire, defaultTTL).(bool)
|
||||
|
|
|
@ -218,22 +218,6 @@ func Transfer(to interop.Hash160, tokenID []byte, data interface{}) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
// AddRoot registers new root.
|
||||
func AddRoot(root string) {
|
||||
checkCommittee()
|
||||
if !checkFragment(root, true) {
|
||||
panic("invalid root format")
|
||||
}
|
||||
var (
|
||||
ctx = storage.GetContext()
|
||||
rootKey = append([]byte{prefixRoot}, []byte(root)...)
|
||||
)
|
||||
if storage.Get(ctx, rootKey) != nil {
|
||||
panic("root already exists")
|
||||
}
|
||||
storage.Put(ctx, rootKey, 0)
|
||||
}
|
||||
|
||||
// Roots returns iterator over a set of NameService roots.
|
||||
func Roots() iterator.Iterator {
|
||||
ctx := storage.GetReadOnlyContext()
|
||||
|
@ -263,15 +247,36 @@ func IsAvailable(name string) bool {
|
|||
panic("invalid domain name format")
|
||||
}
|
||||
ctx := storage.GetReadOnlyContext()
|
||||
if storage.Get(ctx, append([]byte{prefixRoot}, []byte(fragments[1])...)) == nil {
|
||||
panic("root not found")
|
||||
l := len(fragments)
|
||||
if storage.Get(ctx, append([]byte{prefixRoot}, []byte(fragments[l-1])...)) == nil {
|
||||
if l != 1 {
|
||||
panic("TLD not found")
|
||||
}
|
||||
return true
|
||||
}
|
||||
return parentExpired(ctx, 0, fragments)
|
||||
}
|
||||
|
||||
// parentExpired returns true if any domain from fragments doesn't exist or expired.
|
||||
// first denotes the deepest subdomain to check.
|
||||
func parentExpired(ctx storage.Context, first int, fragments []string) bool {
|
||||
now := runtime.GetTime()
|
||||
last := len(fragments) - 1
|
||||
name := fragments[last]
|
||||
for i := last; i >= first; i-- {
|
||||
if i != last {
|
||||
name = fragments[i] + "." + name
|
||||
}
|
||||
nsBytes := storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(name))...))
|
||||
if nsBytes == nil {
|
||||
return true
|
||||
}
|
||||
ns := std.Deserialize(nsBytes.([]byte)).(NameState)
|
||||
return runtime.GetTime() >= ns.Expiration
|
||||
if now >= ns.Expiration {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Register registers new domain with the specified owner and name if it's available.
|
||||
|
@ -280,9 +285,24 @@ func Register(name string, owner interop.Hash160, email string, refresh, retry,
|
|||
if fragments == nil {
|
||||
panic("invalid domain name format")
|
||||
}
|
||||
|
||||
l := len(fragments)
|
||||
tldKey := append([]byte{prefixRoot}, []byte(fragments[l-1])...)
|
||||
ctx := storage.GetContext()
|
||||
if storage.Get(ctx, append([]byte{prefixRoot}, []byte(fragments[1])...)) == nil {
|
||||
panic("root not found")
|
||||
tldBytes := storage.Get(ctx, tldKey)
|
||||
if l == 1 {
|
||||
checkCommittee()
|
||||
if tldBytes != nil {
|
||||
panic("TLD already exists")
|
||||
}
|
||||
storage.Put(ctx, tldKey, 0)
|
||||
} else {
|
||||
if tldBytes == nil {
|
||||
panic("TLD not found")
|
||||
}
|
||||
if parentExpired(ctx, 1, fragments) {
|
||||
panic("one of the parent domains has expired")
|
||||
}
|
||||
}
|
||||
|
||||
if !isValid(owner) {
|
||||
|
@ -701,9 +721,6 @@ func splitAndCheck(name string, allowMultipleFragments bool) []string {
|
|||
}
|
||||
fragments := std.StringSplit(name, ".")
|
||||
l = len(fragments)
|
||||
if l < 2 {
|
||||
return nil
|
||||
}
|
||||
if l > 2 && !allowMultipleFragments {
|
||||
return nil
|
||||
}
|
||||
|
@ -832,6 +849,9 @@ func tokenIDFromName(name string) string {
|
|||
panic("invalid domain name format")
|
||||
}
|
||||
l := len(fragments)
|
||||
if l == 1 {
|
||||
return name
|
||||
}
|
||||
return name[len(name)-(len(fragments[l-1])+len(fragments[l-2])+1):]
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ package tests
|
|||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -29,37 +30,48 @@ func TestNNSGeneric(t *testing.T) {
|
|||
CheckTestInvoke(t, bc, tx, 0)
|
||||
}
|
||||
|
||||
func TestNNSAddRoot(t *testing.T) {
|
||||
func TestNNSRegisterTLD(t *testing.T) {
|
||||
bc := NewChain(t)
|
||||
h := DeployContract(t, bc, nnsPath, nil)
|
||||
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "addRoot", "0com")
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"0com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"email@nspcc.ru", refresh, retry, expire, ttl)
|
||||
AddBlock(t, bc, tx)
|
||||
CheckFault(t, bc, tx.Hash(), "invalid root format")
|
||||
CheckFault(t, bc, tx.Hash(), "invalid domain name format")
|
||||
|
||||
acc := NewAccount(t, bc)
|
||||
tx = PrepareInvoke(t, bc, acc, h, "addRoot", "com")
|
||||
tx = PrepareInvoke(t, bc, acc, h, "register",
|
||||
"com", acc.Contract.ScriptHash(),
|
||||
"email@nspcc.ru", refresh, retry, expire, ttl)
|
||||
AddBlock(t, bc, tx)
|
||||
CheckFault(t, bc, tx.Hash(), "not witnessed by committee")
|
||||
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "addRoot", "com")
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"email@nspcc.ru", refresh, retry, expire, ttl)
|
||||
AddBlock(t, bc, tx)
|
||||
CheckHalt(t, bc, tx.Hash())
|
||||
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "addRoot", "com")
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"email@nspcc.ru", refresh, retry, expire, ttl)
|
||||
AddBlock(t, bc, tx)
|
||||
CheckFault(t, bc, tx.Hash(), "root already exists")
|
||||
CheckFault(t, bc, tx.Hash(), "TLD already exists")
|
||||
}
|
||||
|
||||
func TestNNSRegister(t *testing.T) {
|
||||
bc := NewChain(t)
|
||||
h := DeployContract(t, bc, nnsPath, nil)
|
||||
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "addRoot", "com")
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
AddBlockCheckHalt(t, bc, tx)
|
||||
|
||||
acc := NewAccount(t, bc)
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx = PrepareInvoke(t, bc, []*wallet.Account{CommitteeAcc, acc}, h, "register",
|
||||
"testdomain.com", acc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
|
@ -97,10 +109,12 @@ func TestNNSUpdateSOA(t *testing.T) {
|
|||
bc := NewChain(t)
|
||||
h := DeployContract(t, bc, nnsPath, nil)
|
||||
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "addRoot", "com")
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
AddBlockCheckHalt(t, bc, tx)
|
||||
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"testdomain.com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
|
@ -124,10 +138,12 @@ func TestNNSGetAllRecords(t *testing.T) {
|
|||
bc := NewChain(t)
|
||||
h := DeployContract(t, bc, nnsPath, nil)
|
||||
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "addRoot", "com")
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
AddBlockCheckHalt(t, bc, tx)
|
||||
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"testdomain.com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
|
@ -173,10 +189,12 @@ func TestNNSSetAdmin(t *testing.T) {
|
|||
bc := NewChain(t)
|
||||
h := DeployContract(t, bc, nnsPath, nil)
|
||||
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "addRoot", "com")
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
AddBlockCheckHalt(t, bc, tx)
|
||||
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"testdomain.com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
|
@ -198,15 +216,51 @@ func TestNNSSetAdmin(t *testing.T) {
|
|||
AddBlockCheckHalt(t, bc, tx)
|
||||
}
|
||||
|
||||
func TestNNSIsAvailable(t *testing.T) {
|
||||
bc := NewChain(t)
|
||||
h := DeployContract(t, bc, nnsPath, nil)
|
||||
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "isAvailable", "com")
|
||||
CheckTestInvoke(t, bc, tx, true)
|
||||
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "isAvailable", "domain.com")
|
||||
_, err := TestInvoke(bc, tx)
|
||||
require.Error(t, err)
|
||||
require.True(t, strings.Contains(err.Error(), "TLD not found"))
|
||||
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
AddBlockCheckHalt(t, bc, tx)
|
||||
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "isAvailable", "com")
|
||||
CheckTestInvoke(t, bc, tx, false)
|
||||
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "isAvailable", "domain.com")
|
||||
CheckTestInvoke(t, bc, tx, true)
|
||||
|
||||
acc := NewAccount(t, bc)
|
||||
tx = PrepareInvoke(t, bc, []*wallet.Account{CommitteeAcc, acc}, h, "register",
|
||||
"domain.com", acc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
AddBlockCheckHalt(t, bc, tx)
|
||||
|
||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "isAvailable", "domain.com")
|
||||
CheckTestInvoke(t, bc, tx, false)
|
||||
}
|
||||
|
||||
func TestNNSRenew(t *testing.T) {
|
||||
bc := NewChain(t)
|
||||
h := DeployContract(t, bc, nnsPath, nil)
|
||||
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "addRoot", "com")
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||
"com", CommitteeAcc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
AddBlockCheckHalt(t, bc, tx)
|
||||
|
||||
acc := NewAccount(t, bc)
|
||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||
tx = PrepareInvoke(t, bc, []*wallet.Account{CommitteeAcc, acc}, h, "register",
|
||||
"testdomain.com", acc.Contract.ScriptHash(),
|
||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||
|
|
Loading…
Reference in a new issue