parent
c11481b119
commit
5cb2a1219c
3 changed files with 88 additions and 59 deletions
|
@ -179,22 +179,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()
|
||||
|
@ -224,15 +208,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.
|
||||
|
@ -241,9 +246,23 @@ func Register(name string, owner interop.Hash160) bool {
|
|||
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) {
|
||||
|
@ -548,9 +567,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
|
||||
}
|
||||
|
@ -679,6 +695,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):]
|
||||
}
|
||||
|
||||
|
|
|
@ -70,21 +70,21 @@ func TestNonfungible(t *testing.T) {
|
|||
c.Invoke(t, 0, "totalSupply")
|
||||
}
|
||||
|
||||
func TestAddRoot(t *testing.T) {
|
||||
func TestRegisterTLD(t *testing.T) {
|
||||
c := newNSClient(t)
|
||||
|
||||
t.Run("invalid format", func(t *testing.T) {
|
||||
c.InvokeFail(t, "invalid root format", "addRoot", "")
|
||||
c.InvokeFail(t, "invalid domain name format", "register", "", c.CommitteeHash)
|
||||
})
|
||||
t.Run("not signed by committee", func(t *testing.T) {
|
||||
acc := c.NewAccount(t)
|
||||
c := c.WithSigners(acc)
|
||||
c.InvokeFail(t, "not witnessed by committee", "addRoot", "some")
|
||||
c.InvokeFail(t, "not witnessed by committee", "register", "some", c.CommitteeHash)
|
||||
})
|
||||
|
||||
c.Invoke(t, stackitem.Null{}, "addRoot", "some")
|
||||
c.Invoke(t, true, "register", "some", c.CommitteeHash)
|
||||
t.Run("already exists", func(t *testing.T) {
|
||||
c.InvokeFail(t, "already exists", "addRoot", "some")
|
||||
c.InvokeFail(t, "TLD already exists", "register", "some", c.CommitteeHash)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -96,7 +96,7 @@ func TestExpiration(t *testing.T) {
|
|||
acc := e.NewAccount(t)
|
||||
cAcc := c.WithSigners(acc)
|
||||
|
||||
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||
c.Invoke(t, true, "register", "com", c.CommitteeHash)
|
||||
cAcc.Invoke(t, true, "register", "first.com", acc.ScriptHash())
|
||||
cAcc.Invoke(t, stackitem.Null{}, "setRecord", "first.com", int64(nns.TXT), "sometext")
|
||||
b1 := e.TopBlock(t)
|
||||
|
@ -107,7 +107,7 @@ func TestExpiration(t *testing.T) {
|
|||
b2.PrevHash = b1.Hash()
|
||||
b2.Timestamp = b1.Timestamp + 10000
|
||||
require.NoError(t, bc.AddBlock(e.SignBlock(b2)))
|
||||
e.CheckHalt(t, tx.Hash())
|
||||
e.CheckHalt(t, tx.Hash(), stackitem.NewBool(true))
|
||||
|
||||
tx = cAcc.PrepareInvoke(t, "isAvailable", "first.com")
|
||||
b3 := e.NewUnsignedBlock(t, tx)
|
||||
|
@ -115,7 +115,7 @@ func TestExpiration(t *testing.T) {
|
|||
b3.PrevHash = b2.Hash()
|
||||
b3.Timestamp = b1.Timestamp + (millisecondsInYear + 1)
|
||||
require.NoError(t, bc.AddBlock(e.SignBlock(b3)))
|
||||
e.CheckHalt(t, tx.Hash(), stackitem.NewBool(true))
|
||||
e.CheckHalt(t, tx.Hash(), stackitem.NewBool(true)) // "first.com" has been expired
|
||||
|
||||
tx = cAcc.PrepareInvoke(t, "isAvailable", "second.com")
|
||||
b4 := e.NewUnsignedBlock(t, tx)
|
||||
|
@ -123,7 +123,7 @@ func TestExpiration(t *testing.T) {
|
|||
b4.PrevHash = b3.Hash()
|
||||
b4.Timestamp = b3.Timestamp + 1000
|
||||
require.NoError(t, bc.AddBlock(e.SignBlock(b4)))
|
||||
e.CheckHalt(t, tx.Hash(), stackitem.NewBool(false))
|
||||
e.CheckHalt(t, tx.Hash(), stackitem.NewBool(true)) // TLD "com" has been expired
|
||||
|
||||
tx = cAcc.PrepareInvoke(t, "getRecord", "first.com", int64(nns.TXT))
|
||||
b5 := e.NewUnsignedBlock(t, tx)
|
||||
|
@ -133,8 +133,12 @@ func TestExpiration(t *testing.T) {
|
|||
require.NoError(t, bc.AddBlock(e.SignBlock(b5)))
|
||||
e.CheckFault(t, tx.Hash(), "name has expired")
|
||||
|
||||
cAcc.Invoke(t, true, "register", "first.com", acc.ScriptHash()) // Re-register.
|
||||
cAcc.Invoke(t, stackitem.Null{}, "resolve", "first.com", int64(nns.TXT))
|
||||
// TODO: According to the new code, we can't re-register expired "com" TLD, because it's already registered; at the
|
||||
// same time we can't renew it because it's already expired. We likely need to change this logic in the contract and
|
||||
// after that uncomment the lines below.
|
||||
// c.Invoke(t, true, "renew", "com")
|
||||
// cAcc.Invoke(t, true, "register", "first.com", acc.ScriptHash()) // Re-register.
|
||||
// cAcc.Invoke(t, stackitem.Null{}, "resolve", "first.com", int64(nns.TXT))
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -146,10 +150,10 @@ func TestRegisterAndRenew(t *testing.T) {
|
|||
c := newNSClient(t)
|
||||
e := c.Executor
|
||||
|
||||
c.InvokeFail(t, "root not found", "isAvailable", "neo.com")
|
||||
c.Invoke(t, stackitem.Null{}, "addRoot", "org")
|
||||
c.InvokeFail(t, "root not found", "isAvailable", "neo.com")
|
||||
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||
c.InvokeFail(t, "TLD not found", "isAvailable", "neo.com")
|
||||
c.Invoke(t, true, "register", "org", c.CommitteeHash)
|
||||
c.InvokeFail(t, "TLD not found", "isAvailable", "neo.com")
|
||||
c.Invoke(t, true, "register", "com", c.CommitteeHash)
|
||||
c.Invoke(t, true, "isAvailable", "neo.com")
|
||||
c.InvokeWithFeeFail(t, "GAS limit exceeded", defaultNameServiceSysfee, "register", "neo.org", e.CommitteeHash)
|
||||
c.InvokeFail(t, "invalid domain name format", "register", "docs.neo.org", e.CommitteeHash)
|
||||
|
@ -166,7 +170,7 @@ func TestRegisterAndRenew(t *testing.T) {
|
|||
c.InvokeFail(t, "invalid domain name format", "register", maxLenFragment+"q.com", e.CommitteeHash)
|
||||
|
||||
c.Invoke(t, true, "isAvailable", "neo.com")
|
||||
c.Invoke(t, 1, "balanceOf", e.CommitteeHash)
|
||||
c.Invoke(t, 3, "balanceOf", e.CommitteeHash) // org, com, qqq...qqq.com
|
||||
c.Invoke(t, true, "register", "neo.com", e.CommitteeHash)
|
||||
topBlock := e.TopBlock(t)
|
||||
expectedExpiration := topBlock.Timestamp + millisecondsInYear
|
||||
|
@ -183,7 +187,7 @@ func TestRegisterAndRenew(t *testing.T) {
|
|||
props.Add(stackitem.Make("name"), stackitem.Make("neo.com"))
|
||||
props.Add(stackitem.Make("expiration"), stackitem.Make(expectedExpiration))
|
||||
c.Invoke(t, props, "properties", "neo.com")
|
||||
c.Invoke(t, 2, "balanceOf", e.CommitteeHash)
|
||||
c.Invoke(t, 5, "balanceOf", e.CommitteeHash) // org, com, qqq...qqq.com, neo.com, test-domain.com
|
||||
c.Invoke(t, e.CommitteeHash.BytesBE(), "ownerOf", []byte("neo.com"))
|
||||
|
||||
t.Run("invalid token ID", func(t *testing.T) {
|
||||
|
@ -207,7 +211,7 @@ func TestSetGetRecord(t *testing.T) {
|
|||
|
||||
acc := e.NewAccount(t)
|
||||
cAcc := c.WithSigners(acc)
|
||||
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||
c.Invoke(t, true, "register", "com", c.CommitteeHash)
|
||||
|
||||
t.Run("set before register", func(t *testing.T) {
|
||||
c.InvokeFail(t, "token not found", "setRecord", "neo.com", int64(nns.TXT), "sometext")
|
||||
|
@ -316,7 +320,7 @@ func TestSetAdmin(t *testing.T) {
|
|||
guest := e.NewAccount(t)
|
||||
cGuest := c.WithSigners(guest)
|
||||
|
||||
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||
c.Invoke(t, true, "register", "com", c.CommitteeHash)
|
||||
|
||||
cOwner.Invoke(t, true, "register", "neo.com", owner.ScriptHash())
|
||||
cGuest.InvokeFail(t, "not witnessed", "setAdmin", "neo.com", admin.ScriptHash())
|
||||
|
@ -349,13 +353,13 @@ func TestTransfer(t *testing.T) {
|
|||
to := e.NewAccount(t)
|
||||
cTo := c.WithSigners(to)
|
||||
|
||||
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||
c.Invoke(t, true, "register", "com", c.CommitteeHash)
|
||||
cFrom.Invoke(t, true, "register", "neo.com", from.ScriptHash())
|
||||
cFrom.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.A), "1.2.3.4")
|
||||
cFrom.InvokeFail(t, "token not found", "transfer", to.ScriptHash(), "not.exists", nil)
|
||||
c.Invoke(t, false, "transfer", to.ScriptHash(), "neo.com", nil)
|
||||
cFrom.Invoke(t, true, "transfer", to.ScriptHash(), "neo.com", nil)
|
||||
cFrom.Invoke(t, 1, "totalSupply")
|
||||
cFrom.Invoke(t, 2, "totalSupply") // com, neo.com
|
||||
cFrom.Invoke(t, to.ScriptHash().BytesBE(), "ownerOf", "neo.com")
|
||||
|
||||
// without onNEP11Transfer
|
||||
|
@ -374,7 +378,7 @@ func TestTransfer(t *testing.T) {
|
|||
&compiler.Options{Name: "foo"})
|
||||
e.DeployContract(t, ctr, nil)
|
||||
cTo.Invoke(t, true, "transfer", ctr.Hash, []byte("neo.com"), nil)
|
||||
cFrom.Invoke(t, 1, "totalSupply")
|
||||
cFrom.Invoke(t, 2, "totalSupply") // com, neo.com
|
||||
cFrom.Invoke(t, ctr.Hash.BytesBE(), "ownerOf", []byte("neo.com"))
|
||||
}
|
||||
|
||||
|
@ -387,17 +391,18 @@ func TestTokensOf(t *testing.T) {
|
|||
acc2 := e.NewAccount(t)
|
||||
cAcc2 := c.WithSigners(acc2)
|
||||
|
||||
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||
tld := []byte("com")
|
||||
c.Invoke(t, true, "register", tld, c.CommitteeHash)
|
||||
cAcc1.Invoke(t, true, "register", "neo.com", acc1.ScriptHash())
|
||||
cAcc2.Invoke(t, true, "register", "nspcc.com", acc2.ScriptHash())
|
||||
|
||||
testTokensOf(t, c, [][]byte{[]byte("neo.com")}, acc1.ScriptHash().BytesBE())
|
||||
testTokensOf(t, c, [][]byte{[]byte("nspcc.com")}, acc2.ScriptHash().BytesBE())
|
||||
testTokensOf(t, c, [][]byte{[]byte("neo.com"), []byte("nspcc.com")})
|
||||
testTokensOf(t, c, [][]byte{}, util.Uint160{}.BytesBE()) // empty hash is a valid hash still
|
||||
testTokensOf(t, c, tld, [][]byte{[]byte("neo.com")}, acc1.ScriptHash().BytesBE())
|
||||
testTokensOf(t, c, tld, [][]byte{[]byte("nspcc.com")}, acc2.ScriptHash().BytesBE())
|
||||
testTokensOf(t, c, tld, [][]byte{[]byte("neo.com"), []byte("nspcc.com")})
|
||||
testTokensOf(t, c, tld, [][]byte{}, util.Uint160{}.BytesBE()) // empty hash is a valid hash still
|
||||
}
|
||||
|
||||
func testTokensOf(t *testing.T, c *neotest.ContractInvoker, result [][]byte, args ...interface{}) {
|
||||
func testTokensOf(t *testing.T, c *neotest.ContractInvoker, tld []byte, result [][]byte, args ...interface{}) {
|
||||
method := "tokensOf"
|
||||
if len(args) == 0 {
|
||||
method = "tokens"
|
||||
|
@ -415,7 +420,12 @@ func testTokensOf(t *testing.T, c *neotest.ContractInvoker, result [][]byte, arg
|
|||
require.Equal(t, result[i], iter.Value().Value())
|
||||
arr = append(arr, stackitem.Make(result[i]))
|
||||
}
|
||||
if method == "tokens" {
|
||||
require.True(t, iter.Next())
|
||||
require.Equal(t, tld, iter.Value().Value())
|
||||
} else {
|
||||
require.False(t, iter.Next())
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolve(t *testing.T) {
|
||||
|
@ -425,7 +435,7 @@ func TestResolve(t *testing.T) {
|
|||
acc := e.NewAccount(t)
|
||||
cAcc := c.WithSigners(acc)
|
||||
|
||||
c.Invoke(t, stackitem.Null{}, "addRoot", "com")
|
||||
c.Invoke(t, true, "register", "com", c.CommitteeHash)
|
||||
cAcc.Invoke(t, true, "register", "neo.com", acc.ScriptHash())
|
||||
cAcc.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.A), "1.2.3.4")
|
||||
cAcc.Invoke(t, stackitem.Null{}, "setRecord", "neo.com", int64(nns.CNAME), "alias.com")
|
||||
|
|
|
@ -164,7 +164,7 @@ func Init(t *testing.T, rootpath string, e *neotest.Executor) {
|
|||
e.Validator.ScriptHash(), e.Committee.ScriptHash(), 1000_00000000, nil) // block #12
|
||||
|
||||
// Block #13: add `.com` root to NNS.
|
||||
nsCommitteeInvoker.Invoke(t, stackitem.Null{}, "addRoot", "com") // block #13
|
||||
nsCommitteeInvoker.Invoke(t, true, "register", "com", nsCommitteeInvoker.CommitteeHash) // block #13
|
||||
|
||||
// Block #14: register `neo.com` via NNS.
|
||||
registerTxH := nsPriv0Invoker.Invoke(t, true, "register",
|
||||
|
|
Loading…
Reference in a new issue