core: move NNS record types to a separate package

We need this to avoid `native` dependency in RPC client.
This commit is contained in:
Anna Shaleva 2021-03-24 13:16:38 +03:00
parent 347f7ed576
commit a2a9d7ff05
5 changed files with 101 additions and 96 deletions

View file

@ -9,6 +9,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/core/native"
"github.com/nspcc-dev/neo-go/pkg/core/native/nnsrecords"
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
"github.com/nspcc-dev/neo-go/pkg/interop/native/crypto"
"github.com/nspcc-dev/neo-go/pkg/interop/native/gas"
@ -77,10 +78,10 @@ func TestRoleManagementRole(t *testing.T) {
}
func TestNameServiceRecordType(t *testing.T) {
require.EqualValues(t, native.RecordTypeA, nameservice.TypeA)
require.EqualValues(t, native.RecordTypeCNAME, nameservice.TypeCNAME)
require.EqualValues(t, native.RecordTypeTXT, nameservice.TypeTXT)
require.EqualValues(t, native.RecordTypeAAAA, nameservice.TypeAAAA)
require.EqualValues(t, nnsrecords.A, nameservice.TypeA)
require.EqualValues(t, nnsrecords.CNAME, nameservice.TypeCNAME)
require.EqualValues(t, nnsrecords.TXT, nameservice.TypeTXT)
require.EqualValues(t, nnsrecords.AAAA, nameservice.TypeAAAA)
}
func TestCryptoLibNamedCurve(t *testing.T) {

View file

@ -15,6 +15,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/runtime"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/native/nnsrecords"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
@ -42,17 +43,6 @@ type nameState struct {
Admin util.Uint160
}
// RecordType represents name record type.
type RecordType byte
// Pre-defined record types.
const (
RecordTypeA RecordType = 1
RecordTypeCNAME RecordType = 5
RecordTypeTXT RecordType = 16
RecordTypeAAAA RecordType = 28
)
const (
nameServiceID = -10
@ -448,19 +438,19 @@ func (n *NameService) setRecord(ic *interop.Context, args []stackitem.Item) stac
return stackitem.Null{}
}
func checkName(rt RecordType, name string) {
func checkName(rt nnsrecords.Type, name string) {
var valid bool
switch rt {
case RecordTypeA:
case nnsrecords.A:
// We can't rely on `len(ip) == net.IPv4len` because
// IPv4 can be parsed to mapped representation.
valid = ipv4Regex.MatchString(name) &&
net.ParseIP(name) != nil
case RecordTypeCNAME:
case nnsrecords.CNAME:
valid = matchName(name)
case RecordTypeTXT:
case nnsrecords.TXT:
valid = utf8.RuneCountInString(name) <= 255
case RecordTypeAAAA:
case nnsrecords.AAAA:
valid = ipv6Regex.MatchString(name) &&
net.ParseIP(name) != nil
}
@ -513,7 +503,7 @@ func (n *NameService) resolve(ic *interop.Context, args []stackitem.Item) stacki
return stackitem.NewByteArray([]byte(result))
}
func (n *NameService) resolveInternal(ic *interop.Context, name string, t RecordType, redirect int) (string, bool) {
func (n *NameService) resolveInternal(ic *interop.Context, name string, t nnsrecords.Type, redirect int) (string, bool) {
if redirect < 0 {
panic("invalid redirect")
}
@ -521,26 +511,26 @@ func (n *NameService) resolveInternal(ic *interop.Context, name string, t Record
if data, ok := records[t]; ok {
return data, true
}
data, ok := records[RecordTypeCNAME]
data, ok := records[nnsrecords.CNAME]
if !ok {
return "", false
}
return n.resolveInternal(ic, data, t, redirect-1)
}
func (n *NameService) getRecordsInternal(d dao.DAO, name string) map[RecordType]string {
func (n *NameService) getRecordsInternal(d dao.DAO, name string) map[nnsrecords.Type]string {
domain := toDomain(name)
key := makeRecordKey(domain, name, 0)
key = key[:len(key)-1]
res := make(map[RecordType]string)
res := make(map[nnsrecords.Type]string)
d.Seek(n.ID, key, func(k, v []byte) {
rt := RecordType(k[len(k)-1])
rt := nnsrecords.Type(k[len(k)-1])
res[rt] = string(v)
})
return res
}
func makeRecordKey(domain, name string, rt RecordType) []byte {
func makeRecordKey(domain, name string, rt nnsrecords.Type) []byte {
key := make([]byte, 1+util.Uint160Size+util.Uint160Size+1)
key[0] = prefixRecord
i := 1
@ -647,7 +637,7 @@ func toDomain(name string) string {
return domain
}
func toRecordType(item stackitem.Item) RecordType {
func toRecordType(item stackitem.Item) nnsrecords.Type {
bi, err := item.TryInteger()
if err != nil || !bi.IsInt64() {
panic("invalid record type")
@ -656,8 +646,8 @@ func toRecordType(item stackitem.Item) RecordType {
if val > math.MaxUint8 {
panic("invalid record type")
}
switch rt := RecordType(val); rt {
case RecordTypeA, RecordTypeCNAME, RecordTypeTXT, RecordTypeAAAA:
switch rt := nnsrecords.Type(val); rt {
case nnsrecords.A, nnsrecords.CNAME, nnsrecords.TXT, nnsrecords.AAAA:
return rt
default:
panic("invalid record type")

View file

@ -3,6 +3,7 @@ package native
import (
"testing"
"github.com/nspcc-dev/neo-go/pkg/core/native/nnsrecords"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest/standard"
"github.com/stretchr/testify/require"
@ -36,45 +37,45 @@ func TestParseDomain(t *testing.T) {
func TestNameService_CheckName(t *testing.T) {
// tests are got from the C# implementation
testCases := []struct {
Type RecordType
Type nnsrecords.Type
Name string
ShouldFail bool
}{
{Type: RecordTypeA, Name: "0.0.0.0"},
{Type: RecordTypeA, Name: "10.10.10.10"},
{Type: RecordTypeA, Name: "255.255.255.255"},
{Type: RecordTypeA, Name: "192.168.1.1"},
{Type: RecordTypeA, Name: "1a", ShouldFail: true},
{Type: RecordTypeA, Name: "256.0.0.0", ShouldFail: true},
{Type: RecordTypeA, Name: "01.01.01.01", ShouldFail: true},
{Type: RecordTypeA, Name: "00.0.0.0", ShouldFail: true},
{Type: RecordTypeA, Name: "0.0.0.-1", ShouldFail: true},
{Type: RecordTypeA, Name: "0.0.0.0.1", ShouldFail: true},
{Type: RecordTypeA, Name: "11111111.11111111.11111111.11111111", ShouldFail: true},
{Type: RecordTypeA, Name: "11111111.11111111.11111111.11111111", ShouldFail: true},
{Type: RecordTypeA, Name: "ff.ff.ff.ff", ShouldFail: true},
{Type: RecordTypeA, Name: "0.0.256", ShouldFail: true},
{Type: RecordTypeA, Name: "0.0.0", ShouldFail: true},
{Type: RecordTypeA, Name: "0.257", ShouldFail: true},
{Type: RecordTypeA, Name: "1.1", ShouldFail: true},
{Type: RecordTypeA, Name: "257", ShouldFail: true},
{Type: RecordTypeA, Name: "1", ShouldFail: true},
{Type: RecordTypeAAAA, Name: "2001:db8::8:800:200c:417a"},
{Type: RecordTypeAAAA, Name: "ff01::101"},
{Type: RecordTypeAAAA, Name: "::1"},
{Type: RecordTypeAAAA, Name: "::"},
{Type: RecordTypeAAAA, Name: "2001:db8:0:0:8:800:200c:417a"},
{Type: RecordTypeAAAA, Name: "ff01:0:0:0:0:0:0:101"},
{Type: RecordTypeAAAA, Name: "0:0:0:0:0:0:0:1"},
{Type: RecordTypeAAAA, Name: "0:0:0:0:0:0:0:0"},
{Type: RecordTypeAAAA, Name: "2001:DB8::8:800:200C:417A", ShouldFail: true},
{Type: RecordTypeAAAA, Name: "FF01::101", ShouldFail: true},
{Type: RecordTypeAAAA, Name: "fF01::101", ShouldFail: true},
{Type: RecordTypeAAAA, Name: "2001:DB8:0:0:8:800:200C:417A", ShouldFail: true},
{Type: RecordTypeAAAA, Name: "FF01:0:0:0:0:0:0:101", ShouldFail: true},
{Type: RecordTypeAAAA, Name: "::ffff:1.01.1.01", ShouldFail: true},
{Type: RecordTypeAAAA, Name: "2001:DB8:0:0:8:800:200C:4Z", ShouldFail: true},
{Type: RecordTypeAAAA, Name: "::13.1.68.3", ShouldFail: true},
{Type: nnsrecords.A, Name: "0.0.0.0"},
{Type: nnsrecords.A, Name: "10.10.10.10"},
{Type: nnsrecords.A, Name: "255.255.255.255"},
{Type: nnsrecords.A, Name: "192.168.1.1"},
{Type: nnsrecords.A, Name: "1a", ShouldFail: true},
{Type: nnsrecords.A, Name: "256.0.0.0", ShouldFail: true},
{Type: nnsrecords.A, Name: "01.01.01.01", ShouldFail: true},
{Type: nnsrecords.A, Name: "00.0.0.0", ShouldFail: true},
{Type: nnsrecords.A, Name: "0.0.0.-1", ShouldFail: true},
{Type: nnsrecords.A, Name: "0.0.0.0.1", ShouldFail: true},
{Type: nnsrecords.A, Name: "11111111.11111111.11111111.11111111", ShouldFail: true},
{Type: nnsrecords.A, Name: "11111111.11111111.11111111.11111111", ShouldFail: true},
{Type: nnsrecords.A, Name: "ff.ff.ff.ff", ShouldFail: true},
{Type: nnsrecords.A, Name: "0.0.256", ShouldFail: true},
{Type: nnsrecords.A, Name: "0.0.0", ShouldFail: true},
{Type: nnsrecords.A, Name: "0.257", ShouldFail: true},
{Type: nnsrecords.A, Name: "1.1", ShouldFail: true},
{Type: nnsrecords.A, Name: "257", ShouldFail: true},
{Type: nnsrecords.A, Name: "1", ShouldFail: true},
{Type: nnsrecords.AAAA, Name: "2001:db8::8:800:200c:417a"},
{Type: nnsrecords.AAAA, Name: "ff01::101"},
{Type: nnsrecords.AAAA, Name: "::1"},
{Type: nnsrecords.AAAA, Name: "::"},
{Type: nnsrecords.AAAA, Name: "2001:db8:0:0:8:800:200c:417a"},
{Type: nnsrecords.AAAA, Name: "ff01:0:0:0:0:0:0:101"},
{Type: nnsrecords.AAAA, Name: "0:0:0:0:0:0:0:1"},
{Type: nnsrecords.AAAA, Name: "0:0:0:0:0:0:0:0"},
{Type: nnsrecords.AAAA, Name: "2001:DB8::8:800:200C:417A", ShouldFail: true},
{Type: nnsrecords.AAAA, Name: "FF01::101", ShouldFail: true},
{Type: nnsrecords.AAAA, Name: "fF01::101", ShouldFail: true},
{Type: nnsrecords.AAAA, Name: "2001:DB8:0:0:8:800:200C:417A", ShouldFail: true},
{Type: nnsrecords.AAAA, Name: "FF01:0:0:0:0:0:0:101", ShouldFail: true},
{Type: nnsrecords.AAAA, Name: "::ffff:1.01.1.01", ShouldFail: true},
{Type: nnsrecords.AAAA, Name: "2001:DB8:0:0:8:800:200C:4Z", ShouldFail: true},
{Type: nnsrecords.AAAA, Name: "::13.1.68.3", ShouldFail: true},
}
for _, testCase := range testCases {
if testCase.ShouldFail {

View file

@ -0,0 +1,12 @@
package nnsrecords
// Type represents name record type.
type Type byte
// Pre-defined record types.
const (
A Type = 1
CNAME Type = 5
TXT Type = 16
AAAA Type = 28
)

View file

@ -7,6 +7,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/core/block"
"github.com/nspcc-dev/neo-go/pkg/core/interop/interopnames"
"github.com/nspcc-dev/neo-go/pkg/core/native"
"github.com/nspcc-dev/neo-go/pkg/core/native/nnsrecords"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
@ -67,7 +68,7 @@ func TestExpiration(t *testing.T) {
true, "first.com", acc.Contract.ScriptHash())
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, acc,
"setRecord", stackitem.Null{}, "first.com", int64(native.RecordTypeTXT), "sometext")
"setRecord", stackitem.Null{}, "first.com", int64(nnsrecords.TXT), "sometext")
b1 := bc.topBlock.Load().(*block.Block)
tx, err := prepareContractMethodInvokeGeneric(bc, defaultRegisterSysfee, bc.contracts.NameService.Hash,
@ -108,7 +109,7 @@ func TestExpiration(t *testing.T) {
checkResult(t, &aer[0], stackitem.NewBool(false))
tx, err = prepareContractMethodInvokeGeneric(bc, defaultNameServiceSysfee, bc.contracts.NameService.Hash,
"getRecord", acc, "first.com", int64(native.RecordTypeTXT))
"getRecord", acc, "first.com", int64(nnsrecords.TXT))
require.NoError(t, err)
b5 := newBlockCustom(bc.GetConfig(), func(b *block.Block) {
b.Index = b4.Index + 1
@ -182,36 +183,36 @@ func TestSetGetRecord(t *testing.T) {
testNameServiceInvoke(t, bc, "addRoot", stackitem.Null{}, "com")
t.Run("set before register", func(t *testing.T) {
testNameServiceInvoke(t, bc, "setRecord", nil, "neo.com", int64(native.RecordTypeTXT), "sometext")
testNameServiceInvoke(t, bc, "setRecord", nil, "neo.com", int64(nnsrecords.TXT), "sometext")
})
testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, true, "register",
true, "neo.com", testchain.CommitteeScriptHash())
t.Run("invalid parameters", func(t *testing.T) {
testNameServiceInvoke(t, bc, "setRecord", nil, "neo.com", int64(0xFF), "1.2.3.4")
testNameServiceInvoke(t, bc, "setRecord", nil, "neo.com", int64(native.RecordTypeA), "not.an.ip.address")
testNameServiceInvoke(t, bc, "setRecord", nil, "neo.com", int64(nnsrecords.A), "not.an.ip.address")
})
t.Run("invalid witness", func(t *testing.T) {
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, acc, "setRecord", nil,
"neo.com", int64(native.RecordTypeA), "1.2.3.4")
"neo.com", int64(nnsrecords.A), "1.2.3.4")
})
testNameServiceInvoke(t, bc, "getRecord", stackitem.Null{}, "neo.com", int64(native.RecordTypeA))
testNameServiceInvoke(t, bc, "setRecord", stackitem.Null{}, "neo.com", int64(native.RecordTypeA), "1.2.3.4")
testNameServiceInvoke(t, bc, "getRecord", "1.2.3.4", "neo.com", int64(native.RecordTypeA))
testNameServiceInvoke(t, bc, "setRecord", stackitem.Null{}, "neo.com", int64(native.RecordTypeA), "1.2.3.4")
testNameServiceInvoke(t, bc, "getRecord", "1.2.3.4", "neo.com", int64(native.RecordTypeA))
testNameServiceInvoke(t, bc, "setRecord", stackitem.Null{}, "neo.com", int64(native.RecordTypeAAAA), "2001:0000:1f1f:0000:0000:0100:11a0:addf")
testNameServiceInvoke(t, bc, "setRecord", stackitem.Null{}, "neo.com", int64(native.RecordTypeCNAME), "nspcc.ru")
testNameServiceInvoke(t, bc, "setRecord", stackitem.Null{}, "neo.com", int64(native.RecordTypeTXT), "sometext")
testNameServiceInvoke(t, bc, "getRecord", stackitem.Null{}, "neo.com", int64(nnsrecords.A))
testNameServiceInvoke(t, bc, "setRecord", stackitem.Null{}, "neo.com", int64(nnsrecords.A), "1.2.3.4")
testNameServiceInvoke(t, bc, "getRecord", "1.2.3.4", "neo.com", int64(nnsrecords.A))
testNameServiceInvoke(t, bc, "setRecord", stackitem.Null{}, "neo.com", int64(nnsrecords.A), "1.2.3.4")
testNameServiceInvoke(t, bc, "getRecord", "1.2.3.4", "neo.com", int64(nnsrecords.A))
testNameServiceInvoke(t, bc, "setRecord", stackitem.Null{}, "neo.com", int64(nnsrecords.AAAA), "2001:0000:1f1f:0000:0000:0100:11a0:addf")
testNameServiceInvoke(t, bc, "setRecord", stackitem.Null{}, "neo.com", int64(nnsrecords.CNAME), "nspcc.ru")
testNameServiceInvoke(t, bc, "setRecord", stackitem.Null{}, "neo.com", int64(nnsrecords.TXT), "sometext")
// Delete record.
t.Run("invalid witness", func(t *testing.T) {
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, acc, "setRecord", nil,
"neo.com", int64(native.RecordTypeCNAME))
"neo.com", int64(nnsrecords.CNAME))
})
testNameServiceInvoke(t, bc, "getRecord", "nspcc.ru", "neo.com", int64(native.RecordTypeCNAME))
testNameServiceInvoke(t, bc, "deleteRecord", stackitem.Null{}, "neo.com", int64(native.RecordTypeCNAME))
testNameServiceInvoke(t, bc, "getRecord", stackitem.Null{}, "neo.com", int64(native.RecordTypeCNAME))
testNameServiceInvoke(t, bc, "getRecord", "1.2.3.4", "neo.com", int64(native.RecordTypeA))
testNameServiceInvoke(t, bc, "getRecord", "nspcc.ru", "neo.com", int64(nnsrecords.CNAME))
testNameServiceInvoke(t, bc, "deleteRecord", stackitem.Null{}, "neo.com", int64(nnsrecords.CNAME))
testNameServiceInvoke(t, bc, "getRecord", stackitem.Null{}, "neo.com", int64(nnsrecords.CNAME))
testNameServiceInvoke(t, bc, "getRecord", "1.2.3.4", "neo.com", int64(nnsrecords.A))
}
func TestSetAdmin(t *testing.T) {
@ -239,20 +240,20 @@ func TestSetAdmin(t *testing.T) {
t.Run("set and delete by admin", func(t *testing.T) {
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, admin, "setRecord", stackitem.Null{},
"neo.com", int64(native.RecordTypeTXT), "sometext")
"neo.com", int64(nnsrecords.TXT), "sometext")
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, guest, "deleteRecord", nil,
"neo.com", int64(native.RecordTypeTXT))
"neo.com", int64(nnsrecords.TXT))
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, admin, "deleteRecord", stackitem.Null{},
"neo.com", int64(native.RecordTypeTXT))
"neo.com", int64(nnsrecords.TXT))
})
t.Run("set admin to null", func(t *testing.T) {
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, admin, "setRecord", stackitem.Null{},
"neo.com", int64(native.RecordTypeTXT), "sometext")
"neo.com", int64(nnsrecords.TXT), "sometext")
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, owner, "setAdmin", stackitem.Null{},
"neo.com", nil)
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, admin, "deleteRecord", nil,
"neo.com", int64(native.RecordTypeTXT))
"neo.com", int64(nnsrecords.TXT))
})
}
@ -267,7 +268,7 @@ func TestTransfer(t *testing.T) {
testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, from, "register",
true, "neo.com", from.PrivateKey().GetScriptHash())
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, from, "setRecord", stackitem.Null{},
"neo.com", int64(native.RecordTypeA), "1.2.3.4")
"neo.com", int64(nnsrecords.A), "1.2.3.4")
testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, from, "transfer",
nil, to.Contract.ScriptHash().BytesBE(), []byte("not.exists"))
testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, true, "transfer",
@ -355,23 +356,23 @@ func TestResolve(t *testing.T) {
testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, acc, "register",
true, "neo.com", acc.PrivateKey().GetScriptHash())
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, acc, "setRecord", stackitem.Null{},
"neo.com", int64(native.RecordTypeA), "1.2.3.4")
"neo.com", int64(nnsrecords.A), "1.2.3.4")
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, acc, "setRecord", stackitem.Null{},
"neo.com", int64(native.RecordTypeCNAME), "alias.com")
"neo.com", int64(nnsrecords.CNAME), "alias.com")
testNameServiceInvokeAux(t, bc, defaultRegisterSysfee, acc, "register",
true, "alias.com", acc.PrivateKey().GetScriptHash())
testNameServiceInvokeAux(t, bc, defaultNameServiceSysfee, acc, "setRecord", stackitem.Null{},
"alias.com", int64(native.RecordTypeTXT), "sometxt")
"alias.com", int64(nnsrecords.TXT), "sometxt")
testNameServiceInvoke(t, bc, "resolve", "1.2.3.4",
"neo.com", int64(native.RecordTypeA))
"neo.com", int64(nnsrecords.A))
testNameServiceInvoke(t, bc, "resolve", "alias.com",
"neo.com", int64(native.RecordTypeCNAME))
"neo.com", int64(nnsrecords.CNAME))
testNameServiceInvoke(t, bc, "resolve", "sometxt",
"neo.com", int64(native.RecordTypeTXT))
"neo.com", int64(nnsrecords.TXT))
testNameServiceInvoke(t, bc, "resolve", stackitem.Null{},
"neo.com", int64(native.RecordTypeAAAA))
"neo.com", int64(nnsrecords.AAAA))
}
const (