forked from TrueCloudLab/frostfs-contract
[#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 is returned if container is missing.
|
||||||
NotFoundError = "container does not exist"
|
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 (
|
var (
|
||||||
|
@ -114,14 +120,18 @@ func _deploy(data interface{}, isUpdate bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerNiceNameTLD(addrNNS interop.Hash160, nnsRoot string) {
|
func registerNiceNameTLD(addrNNS interop.Hash160, nnsRoot string) {
|
||||||
iter := contract.Call(addrNNS, "roots", contract.ReadStates).(iterator.Iterator)
|
isAvail := contract.Call(addrNNS, "isAvailable", contract.AllowCall|contract.ReadStates,
|
||||||
for iterator.Next(iter) {
|
"container").(bool)
|
||||||
if iterator.Value(iter).(string) == nnsRoot {
|
if !isAvail {
|
||||||
runtime.Log("NNS root is already registered: " + nnsRoot)
|
return
|
||||||
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
|
// 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 name != "" {
|
||||||
if needRegister {
|
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,
|
res := contract.Call(nnsContractAddr, "register", contract.All,
|
||||||
domain, runtime.GetExecutingScriptHash(), "ops@nspcc.ru",
|
domain, runtime.GetExecutingScriptHash(), "ops@nspcc.ru",
|
||||||
defaultRefresh, defaultRetry, defaultExpire, defaultTTL).(bool)
|
defaultRefresh, defaultRetry, defaultExpire, defaultTTL).(bool)
|
||||||
|
|
|
@ -218,22 +218,6 @@ func Transfer(to interop.Hash160, tokenID []byte, data interface{}) bool {
|
||||||
return true
|
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.
|
// Roots returns iterator over a set of NameService roots.
|
||||||
func Roots() iterator.Iterator {
|
func Roots() iterator.Iterator {
|
||||||
ctx := storage.GetReadOnlyContext()
|
ctx := storage.GetReadOnlyContext()
|
||||||
|
@ -263,15 +247,36 @@ func IsAvailable(name string) bool {
|
||||||
panic("invalid domain name format")
|
panic("invalid domain name format")
|
||||||
}
|
}
|
||||||
ctx := storage.GetReadOnlyContext()
|
ctx := storage.GetReadOnlyContext()
|
||||||
if storage.Get(ctx, append([]byte{prefixRoot}, []byte(fragments[1])...)) == nil {
|
l := len(fragments)
|
||||||
panic("root not found")
|
if storage.Get(ctx, append([]byte{prefixRoot}, []byte(fragments[l-1])...)) == nil {
|
||||||
}
|
if l != 1 {
|
||||||
nsBytes := storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(name))...))
|
panic("TLD not found")
|
||||||
if nsBytes == nil {
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
ns := std.Deserialize(nsBytes.([]byte)).(NameState)
|
return parentExpired(ctx, 0, fragments)
|
||||||
return runtime.GetTime() >= ns.Expiration
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
if now >= ns.Expiration {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
@ -280,9 +285,24 @@ func Register(name string, owner interop.Hash160, email string, refresh, retry,
|
||||||
if fragments == nil {
|
if fragments == nil {
|
||||||
panic("invalid domain name format")
|
panic("invalid domain name format")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l := len(fragments)
|
||||||
|
tldKey := append([]byte{prefixRoot}, []byte(fragments[l-1])...)
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
if storage.Get(ctx, append([]byte{prefixRoot}, []byte(fragments[1])...)) == nil {
|
tldBytes := storage.Get(ctx, tldKey)
|
||||||
panic("root not found")
|
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) {
|
if !isValid(owner) {
|
||||||
|
@ -701,9 +721,6 @@ func splitAndCheck(name string, allowMultipleFragments bool) []string {
|
||||||
}
|
}
|
||||||
fragments := std.StringSplit(name, ".")
|
fragments := std.StringSplit(name, ".")
|
||||||
l = len(fragments)
|
l = len(fragments)
|
||||||
if l < 2 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if l > 2 && !allowMultipleFragments {
|
if l > 2 && !allowMultipleFragments {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -832,6 +849,9 @@ func tokenIDFromName(name string) string {
|
||||||
panic("invalid domain name format")
|
panic("invalid domain name format")
|
||||||
}
|
}
|
||||||
l := len(fragments)
|
l := len(fragments)
|
||||||
|
if l == 1 {
|
||||||
|
return name
|
||||||
|
}
|
||||||
return name[len(name)-(len(fragments[l-1])+len(fragments[l-2])+1):]
|
return name[len(name)-(len(fragments[l-1])+len(fragments[l-2])+1):]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package tests
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -29,37 +30,48 @@ func TestNNSGeneric(t *testing.T) {
|
||||||
CheckTestInvoke(t, bc, tx, 0)
|
CheckTestInvoke(t, bc, tx, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNNSAddRoot(t *testing.T) {
|
func TestNNSRegisterTLD(t *testing.T) {
|
||||||
bc := NewChain(t)
|
bc := NewChain(t)
|
||||||
h := DeployContract(t, bc, nnsPath, nil)
|
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)
|
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)
|
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)
|
AddBlock(t, bc, tx)
|
||||||
CheckFault(t, bc, tx.Hash(), "not witnessed by committee")
|
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)
|
AddBlock(t, bc, tx)
|
||||||
CheckHalt(t, bc, tx.Hash())
|
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)
|
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) {
|
func TestNNSRegister(t *testing.T) {
|
||||||
bc := NewChain(t)
|
bc := NewChain(t)
|
||||||
h := DeployContract(t, bc, nnsPath, nil)
|
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)
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
acc := NewAccount(t, bc)
|
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",
|
tx = PrepareInvoke(t, bc, []*wallet.Account{CommitteeAcc, acc}, h, "register",
|
||||||
"testdomain.com", acc.Contract.ScriptHash(),
|
"testdomain.com", acc.Contract.ScriptHash(),
|
||||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||||
|
@ -97,10 +109,12 @@ func TestNNSUpdateSOA(t *testing.T) {
|
||||||
bc := NewChain(t)
|
bc := NewChain(t)
|
||||||
h := DeployContract(t, bc, nnsPath, nil)
|
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)
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
|
||||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||||
"testdomain.com", CommitteeAcc.Contract.ScriptHash(),
|
"testdomain.com", CommitteeAcc.Contract.ScriptHash(),
|
||||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||||
|
@ -124,10 +138,12 @@ func TestNNSGetAllRecords(t *testing.T) {
|
||||||
bc := NewChain(t)
|
bc := NewChain(t)
|
||||||
h := DeployContract(t, bc, nnsPath, nil)
|
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)
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
|
||||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||||
"testdomain.com", CommitteeAcc.Contract.ScriptHash(),
|
"testdomain.com", CommitteeAcc.Contract.ScriptHash(),
|
||||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||||
|
@ -173,10 +189,12 @@ func TestNNSSetAdmin(t *testing.T) {
|
||||||
bc := NewChain(t)
|
bc := NewChain(t)
|
||||||
h := DeployContract(t, bc, nnsPath, nil)
|
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)
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
|
||||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register",
|
||||||
"testdomain.com", CommitteeAcc.Contract.ScriptHash(),
|
"testdomain.com", CommitteeAcc.Contract.ScriptHash(),
|
||||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||||
|
@ -198,15 +216,51 @@ func TestNNSSetAdmin(t *testing.T) {
|
||||||
AddBlockCheckHalt(t, bc, tx)
|
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) {
|
func TestNNSRenew(t *testing.T) {
|
||||||
bc := NewChain(t)
|
bc := NewChain(t)
|
||||||
h := DeployContract(t, bc, nnsPath, nil)
|
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)
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
acc := NewAccount(t, bc)
|
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",
|
tx = PrepareInvoke(t, bc, []*wallet.Account{CommitteeAcc, acc}, h, "register",
|
||||||
"testdomain.com", acc.Contract.ScriptHash(),
|
"testdomain.com", acc.Contract.ScriptHash(),
|
||||||
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
"myemail@nspcc.ru", refresh, retry, expire, ttl)
|
||||||
|
|
Loading…
Reference in a new issue