diff --git a/nns/nns_contract.go b/nns/nns_contract.go index 152a6fd0..7a672884 100644 --- a/nns/nns_contract.go +++ b/nns/nns_contract.go @@ -514,7 +514,12 @@ func getTokenKey(tokenID []byte) []byte { // getNameState returns domain name state by the specified tokenID. func getNameState(ctx storage.Context, tokenID []byte) NameState { tokenKey := getTokenKey(tokenID) - return getNameStateWithKey(ctx, tokenKey) + ns := getNameStateWithKey(ctx, tokenKey) + fragments := std.StringSplit(string(tokenID), ".") + if parentExpired(ctx, 1, fragments) { + panic("parent domain has expired") + } + return ns } // getNameStateWithKey returns domain name state by the specified token key. diff --git a/tests/basic.go b/tests/basic.go index eb5e4145..5fac96d1 100644 --- a/tests/basic.go +++ b/tests/basic.go @@ -211,6 +211,10 @@ func addNetworkFee(bc *core.Blockchain, tx *transaction.Transaction, sender *wal // AddBlock creates a new block from provided transactions and adds it on bc. func AddBlock(t *testing.T, bc *core.Blockchain, txs ...*transaction.Transaction) *block.Block { + return addCustomBlock(t, bc, nil, txs...) +} + +func addCustomBlock(t *testing.T, bc *core.Blockchain, blockFunc func(*block.Block), txs ...*transaction.Transaction) *block.Block { lastBlock, err := bc.GetBlock(bc.GetHeaderHash(int(bc.BlockHeight()))) require.NoError(t, err) b := &block.Block{ @@ -226,6 +230,9 @@ func AddBlock(t *testing.T, bc *core.Blockchain, txs ...*transaction.Transaction b.PrevHash = lastBlock.Hash() b.Index = bc.BlockHeight() + 1 b.RebuildMerkleRoot() + if blockFunc != nil { + blockFunc(b) + } sign := CommitteeAcc.PrivateKey().SignHashable(uint32(netmode.UnitTestNet), b) b.Script.InvocationScript = append([]byte{byte(opcode.PUSHDATA1), 64}, sign...) diff --git a/tests/nns_test.go b/tests/nns_test.go index 665b3373..ecbf45d5 100644 --- a/tests/nns_test.go +++ b/tests/nns_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/nspcc-dev/neo-go/pkg/core/block" "github.com/nspcc-dev/neo-go/pkg/core/interop/storage" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/wallet" @@ -16,6 +17,8 @@ import ( const nnsPath = "../nns" +const msPerYear = 365 * 24 * time.Hour / time.Millisecond + func TestNNSGeneric(t *testing.T) { bc := NewChain(t) h := DeployContract(t, bc, nnsPath, nil) @@ -192,6 +195,36 @@ func TestNNSGetAllRecords(t *testing.T) { require.False(t, iter.Next()) } +func TestExpiration(t *testing.T) { + bc := NewChain(t) + h := DeployContract(t, bc, nnsPath, nil) + + 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) + b := AddBlockCheckHalt(t, bc, tx) + + tx = PrepareInvoke(t, bc, CommitteeAcc, h, "register", + "testdomain.com", CommitteeAcc.Contract.ScriptHash(), + "myemail@nspcc.ru", refresh, retry, expire, ttl) + AddBlockCheckHalt(t, bc, tx) + + addCustomBlock(t, bc, func(curr *block.Block) { + curr.Timestamp = b.Timestamp + uint64(msPerYear) - 1 + }) + + tx = PrepareInvoke(t, bc, CommitteeAcc, h, "getAllRecords", "testdomain.com") + _, err := TestInvoke(bc, tx) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "parent domain has expired")) + + tx = PrepareInvoke(t, bc, CommitteeAcc, h, "ownerOf", "testdomain.com") + _, err = TestInvoke(bc, tx) + require.Error(t, err) + require.True(t, strings.Contains(err.Error(), "parent domain has expired"), err.Error()) +} + func TestNNSSetAdmin(t *testing.T) { bc := NewChain(t) h := DeployContract(t, bc, nnsPath, nil) @@ -276,8 +309,6 @@ func TestNNSRenew(t *testing.T) { tx = PrepareInvoke(t, bc, acc, h, "renew", "testdomain.com") AddBlockCheckHalt(t, bc, tx) - const msPerYear = 365 * 24 * time.Hour / time.Millisecond - tx = PrepareInvoke(t, bc, acc, h, "properties", "testdomain.com") CheckTestInvoke(t, bc, tx, stackitem.NewMapWithValue([]stackitem.MapElement{ {stackitem.Make("name"), stackitem.Make("testdomain.com")},