diff --git a/nns/nns_contract.go b/nns/nns_contract.go index e34148f8..4f7f4faa 100644 --- a/nns/nns_contract.go +++ b/nns/nns_contract.go @@ -57,6 +57,9 @@ const ( maxDomainNameLength = 255 // maxTXTRecordLength is the maximum length of the TXT domain record. maxTXTRecordLength = 255 + // maxRecordID is the maximum value of record ID (the upper bound for the number + // of records with the same type). + maxRecordID = 255 ) // Other constants. @@ -582,6 +585,9 @@ func addRecord(ctx storage.Context, tokenId []byte, name string, typ RecordType, panic("record already exists") } } + if id > maxRecordID { + panic("maximum number of records reached") + } if typ == CNAME && id != 0 { panic("you shouldn't have more than one CNAME record") diff --git a/tests/nns_test.go b/tests/nns_test.go index 6b1b69d1..381217c7 100644 --- a/tests/nns_test.go +++ b/tests/nns_test.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" "path" + "strconv" "strings" "testing" "time" @@ -17,7 +18,10 @@ import ( const nnsPath = "../nns" -const msPerYear = 365 * 24 * time.Hour / time.Millisecond +const ( + msPerYear = 365 * 24 * time.Hour / time.Millisecond + maxRecordID = 255 // value from the contract. +) func newNNSInvoker(t *testing.T, addRoot bool) *neotest.ContractInvoker { e := newExecutor(t) @@ -400,3 +404,19 @@ func TestNNSResolve(t *testing.T) { // Empty result. c.Invoke(t, stackitem.NewArray([]stackitem.Item{}), "resolve", "test.com", int64(nns.CNAME)) } + +func TestNNSAddRecord(t *testing.T) { + c := newNNSInvoker(t, true) + + refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104) + c.Invoke(t, true, "register", + "testdomain.com", c.CommitteeHash, + "myemail@nspcc.ru", refresh, retry, expire, ttl) + for i := 0; i <= maxRecordID+1; i++ { + if i == maxRecordID+1 { + c.InvokeFail(t, "maximum number of records reached", "addRecord", "testdomain.com", int64(nns.TXT), strconv.Itoa(i)) + } else { + c.Invoke(t, stackitem.Null{}, "addRecord", "testdomain.com", int64(nns.TXT), strconv.Itoa(i)) + } + } +}