Compare commits
5 commits
Author | SHA1 | Date | |
---|---|---|---|
2865d8dd2e | |||
ed82cd42e1 | |||
dc1cb8c297 | |||
820bd283c1 | |||
9632ef8970 |
7 changed files with 411 additions and 16 deletions
162
docs/globally-unique-domain-zone.md
Normal file
162
docs/globally-unique-domain-zone.md
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
# Globally unique domain zone
|
||||||
|
|
||||||
|
**Make sure you understand the [basic concepts](../nns/README.md) of `NNS`.**
|
||||||
|
|
||||||
|
`Globally Unique Domains Zone` (`GUDZ`) is an extension of `NNS` that ensures unique names across multiple domain zones. When this option is enabled, all newly created domains will automatically receive a corresponding alias in the designated global zone. Deleting a domain will also remove its alias from the global zone.
|
||||||
|
|
||||||
|
It's important to note that this feature is not retroactive: domains created before this option is enabled will not receive a global alias. Likewise, if the option is later disabled, domains that already have a `GUDZ` alias will retain their records. To fully disable `GUDZ`, all domains must be recreated with the option turned off.
|
||||||
|
|
||||||
|
To enable `GUDZ`, add a `cnametgt=$(global domain)` `TXT` record that specifies the global zone.
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
|
||||||
|
Domains:
|
||||||
|
- `poland`
|
||||||
|
- `sweden`
|
||||||
|
- `animals.org`
|
||||||
|
|
||||||
|
![](img/GUDZ-2.png)
|
||||||
|
|
||||||
|
It is necessary to associate the domain zones `.poland` and `.sweden` into the global zone `.animals`.
|
||||||
|
|
||||||
|
![](img/GUDZ-1.png)
|
||||||
|
|
||||||
|
Create domains:
|
||||||
|
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns register --name="poland" --email="email@email.email" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
frostfs-adm morph nns register --name="sweden" --email="email@email.email" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
frostfs-adm morph nns register --name="org" --email="email@email.email" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
frostfs-adm morph nns register --name="animals.org" --email="email@email.email" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Add the `cnametgt` records:
|
||||||
|
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns add-record --name="poland" --data="cnametgt=animals.org" --type="txt" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
frostfs-adm morph nns add-record --name="sweden" --data="cnametgt=animals.org" --type="txt" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Create a domain with mapping to the global zone:
|
||||||
|
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns register --name="bober.poland" --email="email@email.email" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Add any `TXT` record
|
||||||
|
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns add-record --name="bober.poland" --data="CID" --type="txt" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
Verify that the created domain has alias in the global zone
|
||||||
|
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns tokens -v --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
|
||||||
|
balance.frostfs
|
||||||
|
animals.org
|
||||||
|
group.frostfs
|
||||||
|
container
|
||||||
|
org
|
||||||
|
container.frostfs
|
||||||
|
proxy.frostfs
|
||||||
|
policy.frostfs
|
||||||
|
alphabet0.frostfs
|
||||||
|
sweden
|
||||||
|
frostfsid.frostfs
|
||||||
|
bober.animals.org (CNAME: bober.sweden)
|
||||||
|
netmap.frostfs
|
||||||
|
frostfs
|
||||||
|
poland
|
||||||
|
bober.poland
|
||||||
|
```
|
||||||
|
|
||||||
|
Create of a conflicting domain
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns register --name="bober.sweden" --email="email@email.email" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
|
||||||
|
unable to register domain: script failed (FAULT state) due to an error: at instruction 1263 (THROW): unhandled exception: "global domain is already taken: bober.animals.org. Domain: bober.sweden
|
||||||
|
```
|
||||||
|
|
||||||
|
**Disable GUDZ**
|
||||||
|
Delete `cnametgt` records
|
||||||
|
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns delete-records --type=txt --name=poland --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
```
|
||||||
|
Create `hamster.poland` and `hamster.sweden`
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns register --name="hamster.poland" --email="email@email.email" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
frostfs-adm morph nns register --name="hamster.sweden" --email="email@email.email" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
```
|
||||||
|
`hamster.poland` and `hamster.sweden` does not have alias
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns tokens -v --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
balance.frostfs
|
||||||
|
animals.org
|
||||||
|
group.frostfs
|
||||||
|
container
|
||||||
|
org
|
||||||
|
container.frostfs
|
||||||
|
proxy.frostfs
|
||||||
|
policy.frostfs
|
||||||
|
alphabet0.frostfs
|
||||||
|
sweden
|
||||||
|
frostfsid.frostfs
|
||||||
|
bober.animals.org (CNAME: bober.poland)
|
||||||
|
netmap.frostfs
|
||||||
|
frostfs
|
||||||
|
poland
|
||||||
|
bober.poland
|
||||||
|
hamster.poland
|
||||||
|
```
|
||||||
|
Delete global alias of `bober.poland`
|
||||||
|
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns delete-records --name="bober.poland" --type="txt" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns tokens -v --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
balance.frostfs
|
||||||
|
animals.org
|
||||||
|
group.frostfs
|
||||||
|
container
|
||||||
|
org
|
||||||
|
container.frostfs
|
||||||
|
proxy.frostfs
|
||||||
|
policy.frostfs
|
||||||
|
alphabet0.frostfs
|
||||||
|
sweden
|
||||||
|
frostfsid.frostfs
|
||||||
|
netmap.frostfs
|
||||||
|
frostfs
|
||||||
|
poland
|
||||||
|
bober.poland
|
||||||
|
hamster.poland
|
||||||
|
```
|
||||||
|
Delete `bober.poland`
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns delete --name="bober.poland" --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
frostfs-adm morph nns tokens -v --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
balance.frostfs
|
||||||
|
animals.org
|
||||||
|
group.frostfs
|
||||||
|
container
|
||||||
|
org
|
||||||
|
container.frostfs
|
||||||
|
proxy.frostfs
|
||||||
|
policy.frostfs
|
||||||
|
alphabet0.frostfs
|
||||||
|
sweden
|
||||||
|
frostfsid.frostfs
|
||||||
|
netmap.frostfs
|
||||||
|
frostfs
|
||||||
|
poland
|
||||||
|
hamster.poland
|
||||||
|
```
|
BIN
docs/img/GUDZ-1.png
Normal file
BIN
docs/img/GUDZ-1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
BIN
docs/img/GUDZ-2.png
Normal file
BIN
docs/img/GUDZ-2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
147
docs/img/GUDZ.drawio
Normal file
147
docs/img/GUDZ.drawio
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:129.0) Gecko/20100101 Firefox/129.0" version="24.7.10" pages="2">
|
||||||
|
<diagram name="Page-1" id="N1NjK5oQ_tQiBXsDL3WT">
|
||||||
|
<mxGraphModel dx="1185" dy="634" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="0" />
|
||||||
|
<mxCell id="1" parent="0" />
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-1" value=".ns" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="130" y="170" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-2" value=".org" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="170" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-3" value=".sweden" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="250" y="290" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-4" value=".poland" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="10" y="290" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-5" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="XWaVog-Y-J4dgFkAMOIC-1" target="XWaVog-Y-J4dgFkAMOIC-4" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="260" y="490" as="sourcePoint" />
|
||||||
|
<mxPoint x="310" y="440" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-6" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="XWaVog-Y-J4dgFkAMOIC-1" target="XWaVog-Y-J4dgFkAMOIC-3" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="200" y="240" as="sourcePoint" />
|
||||||
|
<mxPoint x="80" y="300" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-7" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="10" y="410" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-8" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="XWaVog-Y-J4dgFkAMOIC-4" target="XWaVog-Y-J4dgFkAMOIC-7" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="190" y="460" as="sourcePoint" />
|
||||||
|
<mxPoint x="70" y="400" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-9" value="bober" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;strokeColor=#FF6666;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="250" y="410" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-10" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;dashed=1;fillColor=#f8cecc;strokeColor=#FF6666;" parent="1" target="XWaVog-Y-J4dgFkAMOIC-9" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="310" y="350" as="sourcePoint" />
|
||||||
|
<mxPoint x="310" y="400" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-11" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="410" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-12" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" target="XWaVog-Y-J4dgFkAMOIC-11" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="500" y="350" as="sourcePoint" />
|
||||||
|
<mxPoint x="500" y="400" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-14" value="<font style="font-size: 5px;">TXT cnametgt=animals.org</font>" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="30" y="320" width="80" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-15" value=".<span lang="en" class="Y2IQFc">animals</span>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="290" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-16" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="499.76" y="230" as="sourcePoint" />
|
||||||
|
<mxPoint x="499.76" y="290" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-17" value="<font style="font-size: 5px;">TXT cnametgt=</font><font style="font-size: 5px;">animals.org</font>" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="270" y="320" width="80" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-18" value="" style="shape=umlDestroy;whiteSpace=wrap;html=1;strokeWidth=3;targetShapes=umlLifeline;strokeColor=#FF6666;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="292.5" y="360" width="35" height="40" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-52" value="<span style="white-space: pre-wrap;" data-src-align="0:10" class="EzKURWReUAB5oZgtQNkl">[ global</span><span style="white-space: pre-wrap;"> </span><span style="white-space: pre-wrap;" data-src-align="11:8" class="EzKURWReUAB5oZgtQNkl">domain</span><span style="white-space: pre-wrap;"> </span><span style="white-space: pre-wrap;" data-src-align="20:4" class="EzKURWReUAB5oZgtQNkl">zone ]</span>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="425" y="110" width="150" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="if11Tw9RqGJKQk6h89ln-2" value="<font style="font-size: 5px;">CNAME bober</font><font style="font-size: 5px;">.</font><font style="font-size: 5px;">poland</font>" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="465" y="440" width="70" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
<diagram id="6GukL70CSGlZ9N7Ng9Eu" name="Page-2">
|
||||||
|
<mxGraphModel dx="2074" dy="1510" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
|
||||||
|
<root>
|
||||||
|
<mxCell id="0" />
|
||||||
|
<mxCell id="1" parent="0" />
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-1" value=".ns" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="130" y="-250" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-2" value=".org" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="-250" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-3" value=".sweden" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="250" y="-130" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-4" value=".poland" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="10" y="-130" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-5" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="lPu7oo0X9kSJSLjapO69-1" target="lPu7oo0X9kSJSLjapO69-4" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="260" y="70" as="sourcePoint" />
|
||||||
|
<mxPoint x="310" y="20" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-6" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="lPu7oo0X9kSJSLjapO69-1" target="lPu7oo0X9kSJSLjapO69-3" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="200" y="-180" as="sourcePoint" />
|
||||||
|
<mxPoint x="80" y="-120" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-7" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="10" y="-10" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-8" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" source="lPu7oo0X9kSJSLjapO69-4" target="lPu7oo0X9kSJSLjapO69-7" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="190" y="40" as="sourcePoint" />
|
||||||
|
<mxPoint x="70" y="-20" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-9" value=".<span lang="en" class="Y2IQFc">animals</span>" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="440" y="-130" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-10" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="499.76" y="-190" as="sourcePoint" />
|
||||||
|
<mxPoint x="499.76" y="-130" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-11" value="" style="endArrow=classic;html=1;rounded=0;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" parent="1" edge="1">
|
||||||
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
|
<mxPoint x="309.71000000000004" y="-70" as="sourcePoint" />
|
||||||
|
<mxPoint x="309.71000000000004" y="-10" as="targetPoint" />
|
||||||
|
</mxGeometry>
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-12" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="250" y="-10" width="120" height="60" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
<mxCell id="lPu7oo0X9kSJSLjapO69-13" value="<span style="white-space: pre-wrap;" data-src-align="0:10" class="EzKURWReUAB5oZgtQNkl">[ without global</span><span style="white-space: pre-wrap;"> </span><span style="white-space: pre-wrap;" data-src-align="11:8" class="EzKURWReUAB5oZgtQNkl">domain</span><span style="white-space: pre-wrap;"> </span><span style="white-space: pre-wrap;" data-src-align="20:4" class="EzKURWReUAB5oZgtQNkl">zone ]</span>" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" parent="1" vertex="1">
|
||||||
|
<mxGeometry x="380" y="-310" width="180" height="30" as="geometry" />
|
||||||
|
</mxCell>
|
||||||
|
</root>
|
||||||
|
</mxGraphModel>
|
||||||
|
</diagram>
|
||||||
|
</mxfile>
|
46
nns/README.md
Normal file
46
nns/README.md
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
# NNS
|
||||||
|
NNS - Neo Name Service is a service that allows manage a domain name as a digital asset (NFT). It has an interface similar to `DNS` but has significant differences in its internal structure.
|
||||||
|
|
||||||
|
## Entities:
|
||||||
|
|
||||||
|
- Domain
|
||||||
|
- Record
|
||||||
|
- Owner
|
||||||
|
- Committee
|
||||||
|
|
||||||
|
### Domain
|
||||||
|
|
||||||
|
Domain is string that satisfies the following requirements:
|
||||||
|
- Length from 2 to 255 characters.
|
||||||
|
- Root domain must start with a letter.
|
||||||
|
- All other fragments must start and end with a letter or digit.
|
||||||
|
|
||||||
|
Domain has owner, a registration period, and may optionally have records.
|
||||||
|
|
||||||
|
A fee established by the committee is charged upon domain registration. After registration, the owner can manage this asset (add/delete records, transfer ownership to another owner) until the end of the domain registration period.
|
||||||
|
|
||||||
|
### Record
|
||||||
|
|
||||||
|
A record is a pair of values `<type, string>`.
|
||||||
|
|
||||||
|
Supported record types:
|
||||||
|
|
||||||
|
| Type | Description |
|
||||||
|
|-------|-------------------------------------------|
|
||||||
|
| A | Represents address record type |
|
||||||
|
| AAA | Represents IPv6 address record type |
|
||||||
|
| TXT | Represents text record type |
|
||||||
|
| CNAME | Represents canonical name record type |
|
||||||
|
| SOA | Represents start of authority record type |
|
||||||
|
|
||||||
|
### Owner
|
||||||
|
|
||||||
|
An owner is a wallet that has the right to manage this NFT (domain).
|
||||||
|
|
||||||
|
### Committee
|
||||||
|
|
||||||
|
The committee makes new tokens (domains), sets, and charges a fee for issuance.
|
||||||
|
|
||||||
|
## Globally Unique Domain Zone
|
||||||
|
|
||||||
|
For more information, see [here](../docs/globally-unique-domain-zone.md).
|
|
@ -509,13 +509,17 @@ func deleteRecords(ctx storage.Context, name string, typ RecordType) {
|
||||||
tokenID := []byte(tokenIDFromName(name))
|
tokenID := []byte(tokenIDFromName(name))
|
||||||
ns := getNameState(ctx, tokenID)
|
ns := getNameState(ctx, tokenID)
|
||||||
ns.checkAdmin()
|
ns.checkAdmin()
|
||||||
|
if typ == TXT {
|
||||||
globalDomainStorage := append([]byte{prefixGlobalDomain}, getTokenKey([]byte(name))...)
|
globalDomainKey := append([]byte{prefixGlobalDomain}, getTokenKey([]byte(name))...)
|
||||||
globalDomainRaw := storage.Get(ctx, globalDomainStorage)
|
globalDomainRaw := storage.Get(ctx, globalDomainKey)
|
||||||
|
if globalDomainRaw != nil {
|
||||||
globalDomain := globalDomainRaw.(string)
|
globalDomain := globalDomainRaw.(string)
|
||||||
if globalDomainRaw != nil && globalDomain != "" {
|
if globalDomain != "" {
|
||||||
deleteDomain(ctx, globalDomain)
|
deleteDomain(ctx, globalDomain)
|
||||||
}
|
}
|
||||||
|
storage.Delete(ctx, globalDomainKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
recordsKey := getRecordsKeyByType(tokenID, name, typ)
|
recordsKey := getRecordsKeyByType(tokenID, name, typ)
|
||||||
records := storage.Find(ctx, recordsKey, storage.KeysOnly)
|
records := storage.Find(ctx, recordsKey, storage.KeysOnly)
|
||||||
|
@ -534,23 +538,27 @@ func DeleteDomain(name string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func deleteDomain(ctx storage.Context, name string) {
|
func deleteDomain(ctx storage.Context, name string) {
|
||||||
nameKey := append([]byte{prefixName}, getTokenKey([]byte(name))...)
|
it := Tokens()
|
||||||
tldBytes := storage.Get(ctx, nameKey)
|
for iterator.Next(it) {
|
||||||
if tldBytes == nil {
|
domain := iterator.Value(it)
|
||||||
return
|
if std.MemorySearch([]byte(domain.(string)), []byte(name)) > 0 {
|
||||||
|
panic("can't delete a domain that has subdomains")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nsKey := append([]byte{prefixName}, getTokenKey([]byte(name))...)
|
||||||
|
nsRaw := storage.Get(ctx, nsKey)
|
||||||
|
if nsRaw == nil {
|
||||||
|
panic("domain not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
globalDomainRaw := storage.Get(ctx, append([]byte{prefixGlobalDomain}, getTokenKey([]byte(name))...))
|
ns := std.Deserialize(nsRaw.([]byte)).(NameState)
|
||||||
globalDomain := globalDomainRaw.(string)
|
ns.checkAdmin()
|
||||||
if globalDomainRaw != nil && globalDomain != "" {
|
|
||||||
deleteDomain(ctx, globalDomain)
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteRecords(ctx, name, CNAME)
|
deleteRecords(ctx, name, CNAME)
|
||||||
deleteRecords(ctx, name, TXT)
|
deleteRecords(ctx, name, TXT)
|
||||||
deleteRecords(ctx, name, A)
|
deleteRecords(ctx, name, A)
|
||||||
deleteRecords(ctx, name, AAAA)
|
deleteRecords(ctx, name, AAAA)
|
||||||
storage.Delete(ctx, nameKey)
|
storage.Delete(ctx, nsKey)
|
||||||
runtime.Notify("DeleteDomain", name)
|
runtime.Notify("DeleteDomain", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -189,6 +189,38 @@ func TestNNSRegister(t *testing.T) {
|
||||||
c.InvokeFail(t, "token not found", "getRecords", "testdomain.com", int64(nns.SOA))
|
c.InvokeFail(t, "token not found", "getRecords", "testdomain.com", int64(nns.SOA))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestDeleteDomain(t *testing.T) {
|
||||||
|
c := newNNSInvoker(t, false)
|
||||||
|
|
||||||
|
acc1 := c.NewAccount(t)
|
||||||
|
c1 := c.WithSigners(c.Committee, acc1)
|
||||||
|
|
||||||
|
acc2 := c.NewAccount(t)
|
||||||
|
c2 := c.WithSigners(c.Committee, acc2)
|
||||||
|
c1.Invoke(t, true, "register",
|
||||||
|
"com", acc1.ScriptHash(),
|
||||||
|
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
||||||
|
|
||||||
|
c1.Invoke(t, true, "register",
|
||||||
|
"testdomain.com", acc1.ScriptHash(),
|
||||||
|
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
||||||
|
|
||||||
|
c1.Invoke(t, true, "register",
|
||||||
|
"domik.testdomain.com", acc1.ScriptHash(),
|
||||||
|
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
||||||
|
|
||||||
|
c1.InvokeFail(t, "domain not found", "deleteDomain", "ru")
|
||||||
|
c1.InvokeFail(t, "can't delete a domain that has subdomains", "deleteDomain", "testdomain.com")
|
||||||
|
c1.Invoke(t, stackitem.Null{}, "deleteDomain", "domik.testdomain.com")
|
||||||
|
c1.Invoke(t, stackitem.Null{}, "deleteDomain", "testdomain.com")
|
||||||
|
|
||||||
|
c1.Invoke(t, true, "register",
|
||||||
|
"cn", acc1.ScriptHash(),
|
||||||
|
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
||||||
|
|
||||||
|
c2.InvokeFail(t, "not witnessed by admin", "deleteDomain", "cn")
|
||||||
|
}
|
||||||
|
|
||||||
func TestGlobalDomain(t *testing.T) {
|
func TestGlobalDomain(t *testing.T) {
|
||||||
c := newNNSInvoker(t, false)
|
c := newNNSInvoker(t, false)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue