Compare commits
5 commits
Author | SHA1 | Date | |
---|---|---|---|
2865d8dd2e | |||
ed82cd42e1 | |||
dc1cb8c297 | |||
820bd283c1 | |||
9632ef8970 |
33 changed files with 221 additions and 1033 deletions
|
@ -13,7 +13,7 @@ jobs:
|
||||||
- name: Setup Go
|
- name: Setup Go
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v3
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.21'
|
||||||
|
|
||||||
- name: Run commit format checker
|
- name: Run commit format checker
|
||||||
uses: https://git.frostfs.info/TrueCloudLab/dco-go@v3
|
uses: https://git.frostfs.info/TrueCloudLab/dco-go@v3
|
||||||
|
|
|
@ -7,7 +7,7 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go_versions: [ '1.22', '1.23' ]
|
go_versions: [ '1.21', '1.22' ]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
* @carpawell @fyrchik @cthulhu-rider
|
0
.forgejo/logo.svg → .github/logo.svg
vendored
0
.forgejo/logo.svg → .github/logo.svg
vendored
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -8,17 +8,7 @@ Changelog for FrostFS Contract
|
||||||
### Removed
|
### Removed
|
||||||
### Updated
|
### Updated
|
||||||
### Fixed
|
### Fixed
|
||||||
|
### Updating from v0.18.0
|
||||||
## [0.20.0]
|
|
||||||
|
|
||||||
### Added
|
|
||||||
- Add `ListFullSubjects` method to the frostfsid RPC client (#107)
|
|
||||||
- Add `ListChainNames` method to the policy contract (#105)
|
|
||||||
- Add `DeleteRecord` method to the nns contract (#114)
|
|
||||||
- Emit notification on record changes in nns contract (#109)
|
|
||||||
|
|
||||||
### Updated
|
|
||||||
- neo-go to v0.106.3
|
|
||||||
|
|
||||||
## [0.18.0] - 2023-09-14 - Academy of Sciences Glacier
|
## [0.18.0] - 2023-09-14 - Academy of Sciences Glacier
|
||||||
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
.forgejo/.* @potyarkin
|
|
||||||
Makefile @potyarkin
|
|
||||||
frostfsid/client/.* @dkirillov
|
|
||||||
.* @TrueCloudLab/storage-core-developers @TrueCloudLab/storage-core-committers @TrueCloudLab/storage-service-developers @TrueCloudLab/storage-service-committers
|
|
||||||
tests/.* @fyrchik
|
|
|
@ -1,5 +1,5 @@
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./.forgejo/logo.svg" width="500px" alt="FrostFS">
|
<img src="./.github/logo.svg" width="500px" alt="FrostFS">
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://frostfs.info">FrostFS</a> related smart contracts.
|
<a href="https://frostfs.info">FrostFS</a> related smart contracts.
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
v0.20.0
|
v0.19.1
|
||||||
|
|
|
@ -4,15 +4,15 @@ import "github.com/nspcc-dev/neo-go/pkg/interop/native/std"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
major = 0
|
major = 0
|
||||||
minor = 20
|
minor = 19
|
||||||
patch = 0
|
patch = 1
|
||||||
|
|
||||||
// Versions from which an update should be performed.
|
// Versions from which an update should be performed.
|
||||||
// These should be used in a group (so prevMinor can be equal to minor if there are
|
// These should be used in a group (so prevMinor can be equal to minor if there are
|
||||||
// any migration routines.
|
// any migration routines.
|
||||||
prevMajor = 0
|
prevMajor = 0
|
||||||
prevMinor = 19
|
prevMinor = 18
|
||||||
prevPatch = 3
|
prevPatch = 0
|
||||||
|
|
||||||
Version = major*1_000_000 + minor*1_000 + patch
|
Version = major*1_000_000 + minor*1_000 + patch
|
||||||
|
|
||||||
|
|
|
@ -1,84 +0,0 @@
|
||||||
package commonclient
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/waiter"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
|
||||||
)
|
|
||||||
|
|
||||||
const alreadyExistsError = "already exists"
|
|
||||||
|
|
||||||
type WaiterOptions struct {
|
|
||||||
// IgnoreAlreadyExistsError controls behavior for "already exists" error:
|
|
||||||
// - If set to true, it indicates that "already exists" error is not a problem, we should
|
|
||||||
// wait for transaction as usual (this is the behavior of neo-go [waiter.PollingBased]).
|
|
||||||
// - If set to false, it indicates that "already exists" should be reported as an error.
|
|
||||||
IgnoreAlreadyExistsError bool
|
|
||||||
|
|
||||||
// VerifyExecResults controls whether waiter should ensure that transaction successfully
|
|
||||||
// enters blockchain block.
|
|
||||||
VerifyExecResults bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// Waiter is a decorator on top of the standard [waiter.Waiter].
|
|
||||||
// It provides additional behavior (controlled by [WaiterOptions]) on top of the standard
|
|
||||||
// functionality of awaiting transactions.
|
|
||||||
type Waiter struct {
|
|
||||||
waiter waiter.Waiter
|
|
||||||
options WaiterOptions
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ waiter.Waiter = (*Waiter)(nil)
|
|
||||||
|
|
||||||
// NewWaiter decorates the specified waiter in a new [Waiter] instance.
|
|
||||||
func NewWaiter(waiter waiter.Waiter, options WaiterOptions) *Waiter {
|
|
||||||
return &Waiter{
|
|
||||||
waiter: waiter,
|
|
||||||
options: options,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait allows to wait until transaction will be accepted to the chain.
|
|
||||||
func (w *Waiter) Wait(h util.Uint256, vub uint32, err error) (*state.AppExecResult, error) {
|
|
||||||
if !w.options.IgnoreAlreadyExistsError && errIsAlreadyExists(err) {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result, err := w.waiter.Wait(h, vub, err)
|
|
||||||
return w.examineExecResult(result, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// WaitAny waits until at least one of the specified transactions will be accepted
|
|
||||||
// to the chain.
|
|
||||||
func (w *Waiter) WaitAny(ctx context.Context, vub uint32, hashes ...util.Uint256) (*state.AppExecResult, error) {
|
|
||||||
result, err := w.waiter.WaitAny(ctx, vub, hashes...)
|
|
||||||
return w.examineExecResult(result, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *Waiter) examineExecResult(result *state.AppExecResult, err error) (*state.AppExecResult, error) {
|
|
||||||
if !w.options.VerifyExecResults || err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.Execution.VMState != vmstate.Fault {
|
|
||||||
// Transaction didn't fail, so we just return result "as is"
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transaction failed, we extract VM exception from it and report as an error
|
|
||||||
if result.FaultException != "" {
|
|
||||||
return result, fmt.Errorf("%s", result.FaultException)
|
|
||||||
}
|
|
||||||
return result, fmt.Errorf("transaction failed, stack=%v", result.Stack)
|
|
||||||
}
|
|
||||||
|
|
||||||
func errIsAlreadyExists(err error) bool {
|
|
||||||
if err == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return strings.Contains(strings.ToLower(err.Error()), alreadyExistsError)
|
|
||||||
}
|
|
|
@ -1,135 +0,0 @@
|
||||||
package commonclient
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/vmstate"
|
|
||||||
"github.com/stretchr/testify/mock"
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
type mockWaiter struct {
|
|
||||||
mock.Mock
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *mockWaiter) successfulResult(txHash util.Uint256) *state.AppExecResult {
|
|
||||||
return &state.AppExecResult{
|
|
||||||
Container: txHash,
|
|
||||||
Execution: state.Execution{
|
|
||||||
Trigger: trigger.Application,
|
|
||||||
VMState: vmstate.Halt,
|
|
||||||
GasConsumed: 100500,
|
|
||||||
Stack: nil,
|
|
||||||
Events: nil,
|
|
||||||
FaultException: "",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *mockWaiter) failedResult(txHash util.Uint256, exception string) *state.AppExecResult {
|
|
||||||
return &state.AppExecResult{
|
|
||||||
Container: txHash,
|
|
||||||
Execution: state.Execution{
|
|
||||||
Trigger: trigger.Application,
|
|
||||||
VMState: vmstate.Fault,
|
|
||||||
GasConsumed: 100500,
|
|
||||||
Stack: nil,
|
|
||||||
Events: nil,
|
|
||||||
FaultException: exception,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mockWaiter) Wait(h util.Uint256, vub uint32, err error) (*state.AppExecResult, error) {
|
|
||||||
args := m.Called(h, vub, err)
|
|
||||||
result := args.Get(0)
|
|
||||||
if result == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return result.(*state.AppExecResult), args.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *mockWaiter) WaitAny(ctx context.Context, vub uint32, hashes ...util.Uint256) (*state.AppExecResult, error) {
|
|
||||||
args := m.Called(ctx, vub, hashes)
|
|
||||||
result := args.Get(0)
|
|
||||||
if result == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return result.(*state.AppExecResult), args.Error(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestWaiter(t *testing.T) {
|
|
||||||
txHash := util.Uint256{}
|
|
||||||
vub := uint32(100)
|
|
||||||
|
|
||||||
t.Run("ignore already exists error", func(t *testing.T) {
|
|
||||||
sendErr := fmt.Errorf("transaction already exists")
|
|
||||||
mw := &mockWaiter{}
|
|
||||||
mw.On("Wait", txHash, vub, mock.Anything).Return(mw.successfulResult(txHash), nil)
|
|
||||||
|
|
||||||
waiter := NewWaiter(mw, WaiterOptions{IgnoreAlreadyExistsError: true})
|
|
||||||
_, err := waiter.Wait(txHash, vub, sendErr)
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("report already exists error", func(t *testing.T) {
|
|
||||||
sendErr := fmt.Errorf("transaction already exists")
|
|
||||||
mw := &mockWaiter{}
|
|
||||||
mw.On("Wait", txHash, vub, mock.Anything).Return(mw.successfulResult(txHash), nil)
|
|
||||||
|
|
||||||
waiter := NewWaiter(mw, WaiterOptions{IgnoreAlreadyExistsError: false})
|
|
||||||
_, err := waiter.Wait(txHash, vub, sendErr)
|
|
||||||
|
|
||||||
require.Error(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("report wait error when transaction error is ignored", func(t *testing.T) {
|
|
||||||
waitErr := fmt.Errorf("mock error")
|
|
||||||
mw := &mockWaiter{}
|
|
||||||
mw.On("Wait", txHash, vub, nil).Return(nil, waitErr)
|
|
||||||
|
|
||||||
waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: false})
|
|
||||||
_, err := waiter.Wait(txHash, vub, nil)
|
|
||||||
|
|
||||||
require.ErrorIs(t, err, waitErr)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("report wait error when transaction error is verified", func(t *testing.T) {
|
|
||||||
waitErr := fmt.Errorf("mock error")
|
|
||||||
mw := &mockWaiter{}
|
|
||||||
mw.On("Wait", txHash, vub, nil).Return(nil, waitErr)
|
|
||||||
|
|
||||||
waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: true})
|
|
||||||
_, err := waiter.Wait(txHash, vub, nil)
|
|
||||||
|
|
||||||
require.ErrorIs(t, err, waitErr)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("ignore error from transaction", func(t *testing.T) {
|
|
||||||
txError := "mock error"
|
|
||||||
mw := &mockWaiter{}
|
|
||||||
mw.On("Wait", txHash, vub, nil).Return(mw.failedResult(txHash, txError), nil)
|
|
||||||
|
|
||||||
waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: false})
|
|
||||||
_, err := waiter.Wait(txHash, vub, nil)
|
|
||||||
|
|
||||||
require.NoError(t, err)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("examine error from transaction", func(t *testing.T) {
|
|
||||||
txError := "mock error"
|
|
||||||
mw := &mockWaiter{}
|
|
||||||
mw.On("Wait", txHash, vub, nil).Return(mw.failedResult(txHash, txError), nil)
|
|
||||||
|
|
||||||
waiter := NewWaiter(mw, WaiterOptions{VerifyExecResults: true})
|
|
||||||
_, err := waiter.Wait(txHash, vub, nil)
|
|
||||||
|
|
||||||
require.ErrorContains(t, err, txError)
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -15,42 +15,44 @@ Domains:
|
||||||
- `sweden`
|
- `sweden`
|
||||||
- `animals.org`
|
- `animals.org`
|
||||||
|
|
||||||
|
![](img/GUDZ-2.png)
|
||||||
|
|
||||||
It is necessary to associate the domain zones `.poland` and `.sweden` into the global zone `.animals`.
|
It is necessary to associate the domain zones `.poland` and `.sweden` into the global zone `.animals`.
|
||||||
|
|
||||||
![](img/GUDZ.png)
|
![](img/GUDZ-1.png)
|
||||||
|
|
||||||
Create domains:
|
Create domains:
|
||||||
|
|
||||||
```
|
```
|
||||||
frostfs-adm morph nns register --name="poland" --email="email@email.email"
|
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"
|
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"
|
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"
|
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:
|
Add the `cnametgt` records:
|
||||||
|
|
||||||
```
|
```
|
||||||
frostfs-adm morph nns add-record --name="poland" --data="cnametgt=animals.org" --type="txt"
|
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"
|
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:
|
Create a domain with mapping to the global zone:
|
||||||
|
|
||||||
```
|
```
|
||||||
frostfs-adm morph nns register --name="bober.poland" --email="email@email.email"
|
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
|
Add any `TXT` record
|
||||||
|
|
||||||
```
|
```
|
||||||
frostfs-adm morph nns add-record --name="bober.poland" --data="CID" --type="txt"
|
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
|
Verify that the created domain has alias in the global zone
|
||||||
|
|
||||||
```
|
```
|
||||||
frostfs-adm morph nns tokens -v
|
frostfs-adm morph nns tokens -v --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
|
|
||||||
balance.frostfs
|
balance.frostfs
|
||||||
animals.org
|
animals.org
|
||||||
|
@ -63,7 +65,7 @@ policy.frostfs
|
||||||
alphabet0.frostfs
|
alphabet0.frostfs
|
||||||
sweden
|
sweden
|
||||||
frostfsid.frostfs
|
frostfsid.frostfs
|
||||||
bober.animals.org (CNAME: bober.poland)
|
bober.animals.org (CNAME: bober.sweden)
|
||||||
netmap.frostfs
|
netmap.frostfs
|
||||||
frostfs
|
frostfs
|
||||||
poland
|
poland
|
||||||
|
@ -72,25 +74,25 @@ bober.poland
|
||||||
|
|
||||||
Create of a conflicting domain
|
Create of a conflicting domain
|
||||||
```
|
```
|
||||||
frostfs-adm morph nns register --name="bober.sweden" --email="email@email.email"
|
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.poland
|
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**
|
**Disable GUDZ**
|
||||||
Delete `cnametgt` records
|
Delete `cnametgt` records
|
||||||
|
|
||||||
```
|
```
|
||||||
frostfs-adm morph nns delete-records --type=txt --name=poland
|
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`
|
Create `hamster.poland` and `hamster.sweden`
|
||||||
```
|
```
|
||||||
frostfs-adm morph nns register --name="hamster.poland" --email="email@email.email"
|
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"
|
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
|
`hamster.poland` and `hamster.sweden` does not have alias
|
||||||
```
|
```
|
||||||
frostfs-adm morph nns tokens -v
|
frostfs-adm morph nns tokens -v --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
balance.frostfs
|
balance.frostfs
|
||||||
animals.org
|
animals.org
|
||||||
group.frostfs
|
group.frostfs
|
||||||
|
@ -112,12 +114,12 @@ hamster.poland
|
||||||
Delete global alias of `bober.poland`
|
Delete global alias of `bober.poland`
|
||||||
|
|
||||||
```
|
```
|
||||||
frostfs-adm morph nns delete-records --name="bober.poland" --type="txt"
|
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
|
frostfs-adm morph nns tokens -v --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
balance.frostfs
|
balance.frostfs
|
||||||
animals.org
|
animals.org
|
||||||
group.frostfs
|
group.frostfs
|
||||||
|
@ -137,11 +139,11 @@ hamster.poland
|
||||||
```
|
```
|
||||||
Delete `bober.poland`
|
Delete `bober.poland`
|
||||||
```
|
```
|
||||||
frostfs-adm morph nns delete --name="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
|
frostfs-adm morph nns tokens -v --config /home/achuprov/Documents/work/frostfs-dev-env/frostfs-adm.yml
|
||||||
balance.frostfs
|
balance.frostfs
|
||||||
animals.org
|
animals.org
|
||||||
group.frostfs
|
group.frostfs
|
||||||
|
|
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 |
|
@ -1,137 +1,145 @@
|
||||||
<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.14">
|
<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">
|
<diagram name="Page-1" id="N1NjK5oQ_tQiBXsDL3WT">
|
||||||
<mxGraphModel dx="989" dy="917" 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">
|
<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>
|
<root>
|
||||||
<mxCell id="0" />
|
<mxCell id="0" />
|
||||||
<mxCell id="1" parent="0" />
|
<mxCell id="1" parent="0" />
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-1" value=".ns" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-1" value=".ns" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="130" y="160" width="120" height="60" as="geometry" />
|
<mxGeometry x="130" y="170" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-2" value=".org" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-2" value=".org" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="440" y="160" width="120" height="60" as="geometry" />
|
<mxGeometry x="440" y="170" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-3" value=".sweden" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-3" value=".sweden" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="250" y="280" width="120" height="60" as="geometry" />
|
<mxGeometry x="250" y="290" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-4" value=".poland" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-4" value=".poland" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="10" y="280" width="120" height="60" as="geometry" />
|
<mxGeometry x="10" y="290" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-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;" edge="1" parent="1" source="l_qLPBR5nCWAv8Wbn5Wl-1" target="l_qLPBR5nCWAv8Wbn5Wl-4">
|
<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">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="260" y="480" as="sourcePoint" />
|
<mxPoint x="260" y="490" as="sourcePoint" />
|
||||||
<mxPoint x="310" y="430" as="targetPoint" />
|
<mxPoint x="310" y="440" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-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;" edge="1" parent="1" source="l_qLPBR5nCWAv8Wbn5Wl-1" target="l_qLPBR5nCWAv8Wbn5Wl-3">
|
<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">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="200" y="230" as="sourcePoint" />
|
<mxPoint x="200" y="240" as="sourcePoint" />
|
||||||
<mxPoint x="80" y="290" as="targetPoint" />
|
<mxPoint x="80" y="300" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-7" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-7" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="10" y="400" width="120" height="60" as="geometry" />
|
<mxGeometry x="10" y="410" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-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;" edge="1" parent="1" source="l_qLPBR5nCWAv8Wbn5Wl-4" target="l_qLPBR5nCWAv8Wbn5Wl-7">
|
<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">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="190" y="450" as="sourcePoint" />
|
<mxPoint x="190" y="460" as="sourcePoint" />
|
||||||
<mxPoint x="70" y="390" as="targetPoint" />
|
<mxPoint x="70" y="400" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-9" value="bober" style="rounded=0;whiteSpace=wrap;html=1;dashed=1;strokeColor=#FF6666;" vertex="1" parent="1">
|
<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="400" width="120" height="60" as="geometry" />
|
<mxGeometry x="250" y="410" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-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;" edge="1" parent="1" target="l_qLPBR5nCWAv8Wbn5Wl-9">
|
<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">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="310" y="340" as="sourcePoint" />
|
<mxPoint x="310" y="350" as="sourcePoint" />
|
||||||
<mxPoint x="310" y="390" as="targetPoint" />
|
<mxPoint x="310" y="400" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-11" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="XWaVog-Y-J4dgFkAMOIC-11" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="440" y="400" width="120" height="60" as="geometry" />
|
<mxGeometry x="440" y="410" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-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;" edge="1" parent="1" target="l_qLPBR5nCWAv8Wbn5Wl-11">
|
<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">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="500" y="340" as="sourcePoint" />
|
<mxPoint x="500" y="350" as="sourcePoint" />
|
||||||
<mxPoint x="500" y="390" as="targetPoint" />
|
<mxPoint x="500" y="400" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-13" 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;" vertex="1" parent="1">
|
<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="310" width="80" height="30" as="geometry" />
|
<mxGeometry x="30" y="320" width="80" height="30" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-14" value=".<span lang="en" class="Y2IQFc">animals</span>" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<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="280" width="120" height="60" as="geometry" />
|
<mxGeometry x="440" y="290" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-15" 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;" edge="1" parent="1">
|
<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">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="499.76" y="220" as="sourcePoint" />
|
<mxPoint x="499.76" y="230" as="sourcePoint" />
|
||||||
<mxPoint x="499.76" y="280" as="targetPoint" />
|
<mxPoint x="499.76" y="290" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-16" 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;" vertex="1" parent="1">
|
<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="310" width="80" height="30" as="geometry" />
|
<mxGeometry x="270" y="320" width="80" height="30" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-17" value="" style="shape=umlDestroy;whiteSpace=wrap;html=1;strokeWidth=3;targetShapes=umlLifeline;strokeColor=#FF6666;" vertex="1" parent="1">
|
<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="350" width="35" height="40" as="geometry" />
|
<mxGeometry x="292.5" y="360" width="35" height="40" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-18" 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;" vertex="1" parent="1">
|
<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="100" width="150" height="30" as="geometry" />
|
<mxGeometry x="425" y="110" width="150" height="30" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="l_qLPBR5nCWAv8Wbn5Wl-19" 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;" vertex="1" parent="1">
|
<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="430" width="70" height="30" as="geometry" />
|
<mxGeometry x="465" y="440" width="70" height="30" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-1" value=".ns" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
</root>
|
||||||
<mxGeometry x="130" y="-240" width="120" height="60" as="geometry" />
|
</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>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-2" value=".org" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="lPu7oo0X9kSJSLjapO69-2" value=".org" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="440" y="-240" width="120" height="60" as="geometry" />
|
<mxGeometry x="440" y="-250" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-3" value=".sweden" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="lPu7oo0X9kSJSLjapO69-3" value=".sweden" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="250" y="-120" width="120" height="60" as="geometry" />
|
<mxGeometry x="250" y="-130" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-4" value=".poland" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="lPu7oo0X9kSJSLjapO69-4" value=".poland" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="10" y="-120" width="120" height="60" as="geometry" />
|
<mxGeometry x="10" y="-130" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-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;" edge="1" parent="1" source="Z9nLDmrU-mAa8Hye4rHX-1" target="Z9nLDmrU-mAa8Hye4rHX-4">
|
<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">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="260" y="80" as="sourcePoint" />
|
<mxPoint x="260" y="70" as="sourcePoint" />
|
||||||
<mxPoint x="310" y="30" as="targetPoint" />
|
<mxPoint x="310" y="20" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-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;" edge="1" parent="1" source="Z9nLDmrU-mAa8Hye4rHX-1" target="Z9nLDmrU-mAa8Hye4rHX-3">
|
<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">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="200" y="-170" as="sourcePoint" />
|
<mxPoint x="200" y="-180" as="sourcePoint" />
|
||||||
<mxPoint x="80" y="-110" as="targetPoint" />
|
<mxPoint x="80" y="-120" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-7" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="lPu7oo0X9kSJSLjapO69-7" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="10" width="120" height="60" as="geometry" />
|
<mxGeometry x="10" y="-10" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-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;" edge="1" parent="1" source="Z9nLDmrU-mAa8Hye4rHX-4" target="Z9nLDmrU-mAa8Hye4rHX-7">
|
<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">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="190" y="50" as="sourcePoint" />
|
<mxPoint x="190" y="40" as="sourcePoint" />
|
||||||
<mxPoint x="70" y="-10" as="targetPoint" />
|
<mxPoint x="70" y="-20" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-9" value=".<span lang="en" class="Y2IQFc">animals</span>" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<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="-120" width="120" height="60" as="geometry" />
|
<mxGeometry x="440" y="-130" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-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;" edge="1" parent="1">
|
<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">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="499.76" y="-180" as="sourcePoint" />
|
<mxPoint x="499.76" y="-190" as="sourcePoint" />
|
||||||
<mxPoint x="499.76" y="-120" as="targetPoint" />
|
<mxPoint x="499.76" y="-130" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-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;" edge="1" parent="1">
|
<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">
|
<mxGeometry width="50" height="50" relative="1" as="geometry">
|
||||||
<mxPoint x="309.71000000000004" y="-60" as="sourcePoint" />
|
<mxPoint x="309.71000000000004" y="-70" as="sourcePoint" />
|
||||||
<mxPoint x="309.71000000000004" as="targetPoint" />
|
<mxPoint x="309.71000000000004" y="-10" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-12" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
<mxCell id="lPu7oo0X9kSJSLjapO69-12" value="bober" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
|
||||||
<mxGeometry x="250" width="120" height="60" as="geometry" />
|
<mxGeometry x="250" y="-10" width="120" height="60" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="Z9nLDmrU-mAa8Hye4rHX-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;" vertex="1" parent="1">
|
<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="390" y="-300" width="180" height="30" as="geometry" />
|
<mxGeometry x="380" y="-310" width="180" height="30" as="geometry" />
|
||||||
</mxCell>
|
</mxCell>
|
||||||
</root>
|
</root>
|
||||||
</mxGraphModel>
|
</mxGraphModel>
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 69 KiB |
|
@ -23,13 +23,11 @@ import (
|
||||||
type (
|
type (
|
||||||
Client struct {
|
Client struct {
|
||||||
act *actor.Actor
|
act *actor.Actor
|
||||||
waiter waiter.Waiter
|
|
||||||
contract util.Uint160
|
contract util.Uint160
|
||||||
}
|
}
|
||||||
|
|
||||||
Options struct {
|
Options struct {
|
||||||
ProxyContract util.Uint160
|
ProxyContract util.Uint160
|
||||||
Waiter commonclient.WaiterOptions
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -96,7 +94,6 @@ const (
|
||||||
createSubjectMethod = "createSubject"
|
createSubjectMethod = "createSubject"
|
||||||
getSubjectMethod = "getSubject"
|
getSubjectMethod = "getSubject"
|
||||||
getSubjectExtendedMethod = "getSubjectExtended"
|
getSubjectExtendedMethod = "getSubjectExtended"
|
||||||
getSubjectKVMethod = "getSubjectKV"
|
|
||||||
listSubjectsMethod = "listSubjects"
|
listSubjectsMethod = "listSubjects"
|
||||||
addSubjectKeyMethod = "addSubjectKey"
|
addSubjectKeyMethod = "addSubjectKey"
|
||||||
removeSubjectKeyMethod = "removeSubjectKey"
|
removeSubjectKeyMethod = "removeSubjectKey"
|
||||||
|
@ -154,21 +151,17 @@ func New(ra actor.RPCActor, acc *wallet.Account, contract util.Uint160, opt Opti
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("init actor: %w", err)
|
return nil, fmt.Errorf("init actor: %w", err)
|
||||||
}
|
}
|
||||||
wtr := commonclient.NewWaiter(act, opt.Waiter)
|
|
||||||
|
|
||||||
return &Client{
|
return &Client{
|
||||||
act: act,
|
act: act,
|
||||||
waiter: wtr,
|
|
||||||
contract: contract,
|
contract: contract,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSimple creates a new Client using existing actor.Actor and default waiter options.
|
// NewSimple creates a new Client using exising actor.Actor.
|
||||||
func NewSimple(act *actor.Actor, contract util.Uint160) *Client {
|
func NewSimple(act *actor.Actor, contract util.Uint160) *Client {
|
||||||
wtr := commonclient.NewWaiter(act, commonclient.WaiterOptions{})
|
|
||||||
return &Client{
|
return &Client{
|
||||||
act: act,
|
act: act,
|
||||||
waiter: wtr,
|
|
||||||
contract: contract,
|
contract: contract,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -267,11 +260,6 @@ func (c Client) GetSubjectExtended(addr util.Uint160) (*SubjectExtended, error)
|
||||||
return ParseSubjectExtended(items)
|
return ParseSubjectExtended(items)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSubjectKV invokes `getSubjectKV` method of contract.
|
|
||||||
func (c Client) GetSubjectKV(addr util.Uint160, name string) (string, error) {
|
|
||||||
return unwrap.UTF8String(c.act.Call(c.contract, getSubjectKVMethod, addr, name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListSubjects gets all subjects.
|
// ListSubjects gets all subjects.
|
||||||
func (c Client) ListSubjects() ([]util.Uint160, error) {
|
func (c Client) ListSubjects() ([]util.Uint160, error) {
|
||||||
return UnwrapArrayOfUint160(commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listSubjectsMethod))
|
return UnwrapArrayOfUint160(commonclient.ReadIteratorItems(c.act, iteratorBatchSize, c.contract, listSubjectsMethod))
|
||||||
|
@ -613,14 +601,18 @@ func (c Client) ListNonEmptyNamespaces() ([]string, error) {
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait waits until the specified transaction is accepted to the chain.
|
// Wait invokes underlying wait method on actor.Actor.
|
||||||
|
// Notice that "already exists" err value is treated as an error by this routine unlike actor.Waiter.
|
||||||
func (c Client) Wait(tx util.Uint256, vub uint32, err error) (*state.AppExecResult, error) {
|
func (c Client) Wait(tx util.Uint256, vub uint32, err error) (*state.AppExecResult, error) {
|
||||||
return c.Waiter().Wait(tx, vub, err)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return c.act.Wait(tx, vub, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Waiter returns underlying waiter.Waiter.
|
// Waiter returns underlying waiter.Waiter.
|
||||||
func (c Client) Waiter() waiter.Waiter {
|
func (c Client) Waiter() waiter.Waiter {
|
||||||
return c.waiter
|
return c.act
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseGroupID fetch groupID from stack after creating group method invocation.
|
// ParseGroupID fetch groupID from stack after creating group method invocation.
|
||||||
|
|
|
@ -7,7 +7,6 @@ safemethods:
|
||||||
- "getGroupByName"
|
- "getGroupByName"
|
||||||
- "getNamespace"
|
- "getNamespace"
|
||||||
- "getNamespaceExtended"
|
- "getNamespaceExtended"
|
||||||
- "getSubjectKV"
|
|
||||||
- "getSubject"
|
- "getSubject"
|
||||||
- "getSubjectExtended"
|
- "getSubjectExtended"
|
||||||
- "getSubjectByKey"
|
- "getSubjectByKey"
|
||||||
|
|
|
@ -20,7 +20,6 @@ FrostFSID contract does not produce notifications to process.
|
||||||
| `G` + [ RIPEMD160 of namespace ] + [ 8 byte group id ] + [ subject address ] | []byte{1} | subject that belongs to the group |
|
| `G` + [ RIPEMD160 of namespace ] + [ 8 byte group id ] + [ subject address ] | []byte{1} | subject that belongs to the group |
|
||||||
| `c` | Int | group id counter |
|
| `c` | Int | group id counter |
|
||||||
| `m` + [ RIPEMD160 of namespace ] + [ RIPEMD160 of subject name ] | Serialized group id int | group name to group id index |
|
| `m` + [ RIPEMD160 of namespace ] + [ RIPEMD160 of subject name ] | Serialized group id int | group name to group id index |
|
||||||
| `A` + [ subject address ] | bool | means that the wallet has been used |
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -96,7 +96,6 @@ const (
|
||||||
groupSubjectsKeysPrefix = 'G'
|
groupSubjectsKeysPrefix = 'G'
|
||||||
groupCounterKey = 'c'
|
groupCounterKey = 'c'
|
||||||
namespaceGroupsNamesPrefix = 'm'
|
namespaceGroupsNamesPrefix = 'm'
|
||||||
addressPrefix = 'A'
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func _deploy(data any, isUpdate bool) {
|
func _deploy(data any, isUpdate bool) {
|
||||||
|
@ -113,27 +112,6 @@ func _deploy(data any, isUpdate bool) {
|
||||||
storage.Put(ctx, adminKey, args.admin)
|
storage.Put(ctx, adminKey, args.admin)
|
||||||
}
|
}
|
||||||
|
|
||||||
if isUpdate {
|
|
||||||
it := storage.Find(ctx, subjectKeysPrefix, storage.ValuesOnly)
|
|
||||||
for iterator.Next(it) {
|
|
||||||
subjectRaw := iterator.Value(it)
|
|
||||||
subject := std.Deserialize(subjectRaw.([]byte)).(Subject)
|
|
||||||
address := addressKey(contract.CreateStandardAccount(subject.PrimaryKey))
|
|
||||||
if storage.Get(ctx, address) != nil {
|
|
||||||
panic("frostfsid contract contains duplicate keys")
|
|
||||||
}
|
|
||||||
storage.Put(ctx, address, true)
|
|
||||||
|
|
||||||
for i := 0; i < len(subject.AdditionalKeys); i++ {
|
|
||||||
address = addressKey(contract.CreateStandardAccount(subject.AdditionalKeys[i]))
|
|
||||||
if storage.Get(ctx, address) != nil {
|
|
||||||
panic("frostfsid contract contains duplicate keys")
|
|
||||||
}
|
|
||||||
storage.Put(ctx, address, true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
storage.Put(ctx, groupCounterKey, 0)
|
storage.Put(ctx, groupCounterKey, 0)
|
||||||
storage.Put(ctx, namespaceKey(""), std.Serialize(Namespace{}))
|
storage.Put(ctx, namespaceKey(""), std.Serialize(Namespace{}))
|
||||||
|
|
||||||
|
@ -204,11 +182,6 @@ func CreateSubject(ns string, key interop.PublicKey) {
|
||||||
panic("key is occupied")
|
panic("key is occupied")
|
||||||
}
|
}
|
||||||
|
|
||||||
allAddressKey := addressKey(addr)
|
|
||||||
if storage.Get(ctx, allAddressKey) != nil {
|
|
||||||
panic("key is occupied by another additional key")
|
|
||||||
}
|
|
||||||
|
|
||||||
nsKey := namespaceKey(ns)
|
nsKey := namespaceKey(ns)
|
||||||
data = storage.Get(ctx, nsKey).([]byte)
|
data = storage.Get(ctx, nsKey).([]byte)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
|
@ -224,7 +197,6 @@ func CreateSubject(ns string, key interop.PublicKey) {
|
||||||
|
|
||||||
nsSubjKey := namespaceSubjectKey(ns, addr)
|
nsSubjKey := namespaceSubjectKey(ns, addr)
|
||||||
storage.Put(ctx, nsSubjKey, []byte{1})
|
storage.Put(ctx, nsSubjKey, []byte{1})
|
||||||
storage.Put(ctx, allAddressKey, true)
|
|
||||||
|
|
||||||
runtime.Notify("CreateSubject", interop.Hash160(addr))
|
runtime.Notify("CreateSubject", interop.Hash160(addr))
|
||||||
}
|
}
|
||||||
|
@ -241,11 +213,6 @@ func AddSubjectKey(addr interop.Hash160, key interop.PublicKey) {
|
||||||
panic("incorrect public key length")
|
panic("incorrect public key length")
|
||||||
}
|
}
|
||||||
|
|
||||||
addressKey := addressKey(contract.CreateStandardAccount(key))
|
|
||||||
if storage.Get(ctx, addressKey) != nil {
|
|
||||||
panic("key is occupied")
|
|
||||||
}
|
|
||||||
|
|
||||||
saKey := subjectAdditionalKey(key, addr)
|
saKey := subjectAdditionalKey(key, addr)
|
||||||
data := storage.Get(ctx, saKey).([]byte)
|
data := storage.Get(ctx, saKey).([]byte)
|
||||||
if data != nil {
|
if data != nil {
|
||||||
|
@ -263,7 +230,6 @@ func AddSubjectKey(addr interop.Hash160, key interop.PublicKey) {
|
||||||
subject.AdditionalKeys = append(subject.AdditionalKeys, key)
|
subject.AdditionalKeys = append(subject.AdditionalKeys, key)
|
||||||
|
|
||||||
storage.Put(ctx, sKey, std.Serialize(subject))
|
storage.Put(ctx, sKey, std.Serialize(subject))
|
||||||
storage.Put(ctx, addressKey, true)
|
|
||||||
runtime.Notify("AddSubjectKey", addr, key)
|
runtime.Notify("AddSubjectKey", addr, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,7 +269,6 @@ func RemoveSubjectKey(addr interop.Hash160, key interop.PublicKey) {
|
||||||
subject.AdditionalKeys = additionalKeys
|
subject.AdditionalKeys = additionalKeys
|
||||||
|
|
||||||
storage.Put(ctx, sKey, std.Serialize(subject))
|
storage.Put(ctx, sKey, std.Serialize(subject))
|
||||||
storage.Delete(ctx, addressKey(contract.CreateStandardAccount(key)))
|
|
||||||
runtime.Notify("RemoveSubjectKey", addr, key)
|
runtime.Notify("RemoveSubjectKey", addr, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,7 +362,6 @@ func DeleteSubject(addr interop.Hash160) {
|
||||||
|
|
||||||
for i := 0; i < len(subj.AdditionalKeys); i++ {
|
for i := 0; i < len(subj.AdditionalKeys); i++ {
|
||||||
storage.Delete(ctx, subjectAdditionalKey(subj.AdditionalKeys[i], addr))
|
storage.Delete(ctx, subjectAdditionalKey(subj.AdditionalKeys[i], addr))
|
||||||
storage.Delete(ctx, addressKey(contract.CreateStandardAccount(subj.AdditionalKeys[i])))
|
|
||||||
}
|
}
|
||||||
storage.Delete(ctx, sKey)
|
storage.Delete(ctx, sKey)
|
||||||
|
|
||||||
|
@ -417,12 +381,7 @@ func GetSubject(addr interop.Hash160) Subject {
|
||||||
sKey := subjectKeyFromAddr(addr)
|
sKey := subjectKeyFromAddr(addr)
|
||||||
data := storage.Get(ctx, sKey).([]byte)
|
data := storage.Get(ctx, sKey).([]byte)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
a := getPrimaryAddr(ctx, addr)
|
panic("subject not found")
|
||||||
sKey = subjectKeyFromAddr(a)
|
|
||||||
data = storage.Get(ctx, sKey).([]byte)
|
|
||||||
if data == nil {
|
|
||||||
panic("subject not found")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return std.Deserialize(data).(Subject)
|
return std.Deserialize(data).(Subject)
|
||||||
|
@ -474,22 +433,18 @@ func GetSubjectByKey(key interop.PublicKey) Subject {
|
||||||
return std.Deserialize(data).(Subject)
|
return std.Deserialize(data).(Subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := getPrimaryAddr(ctx, contract.CreateStandardAccount(key))
|
saPrefix := subjectAdditionalPrefix(key)
|
||||||
sKey = subjectKeyFromAddr(addr)
|
|
||||||
data = storage.Get(ctx, sKey).([]byte)
|
|
||||||
if data != nil {
|
|
||||||
return std.Deserialize(data).(Subject)
|
|
||||||
}
|
|
||||||
|
|
||||||
panic("subject not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getPrimaryAddr(ctx storage.Context, addr interop.Hash160) interop.Hash160 {
|
|
||||||
saPrefix := append([]byte{additionalKeysPrefix}, addr...)
|
|
||||||
it := storage.Find(ctx, saPrefix, storage.KeysOnly|storage.RemovePrefix)
|
it := storage.Find(ctx, saPrefix, storage.KeysOnly|storage.RemovePrefix)
|
||||||
if iterator.Next(it) {
|
for iterator.Next(it) {
|
||||||
return iterator.Value(it).([]byte)
|
addr := iterator.Value(it).([]byte)
|
||||||
|
sKey = subjectKeyFromAddr(addr)
|
||||||
|
data = storage.Get(ctx, sKey).([]byte)
|
||||||
|
if data != nil {
|
||||||
|
return std.Deserialize(data).(Subject)
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("subject not found")
|
panic("subject not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,34 +472,6 @@ func GetSubjectKeyByName(ns, name string) interop.PublicKey {
|
||||||
return subjKey
|
return subjKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSubjectKV GetSubjectKey returns the value associated with the key for the subject.
|
|
||||||
func GetSubjectKV(addr interop.Hash160, name string) string {
|
|
||||||
if len(addr) != interop.Hash160Len {
|
|
||||||
panic("incorrect address length")
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx := storage.GetReadOnlyContext()
|
|
||||||
sKey := subjectKeyFromAddr(addr)
|
|
||||||
data := storage.Get(ctx, sKey).([]byte)
|
|
||||||
if data == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
sbj := std.Deserialize(data).(Subject)
|
|
||||||
|
|
||||||
if sbj.KV == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
for k, v := range sbj.KV {
|
|
||||||
if k == name {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListSubjects() iterator.Iterator {
|
func ListSubjects() iterator.Iterator {
|
||||||
ctx := storage.GetReadOnlyContext()
|
ctx := storage.GetReadOnlyContext()
|
||||||
return storage.Find(ctx, []byte{subjectKeysPrefix}, storage.KeysOnly|storage.RemovePrefix)
|
return storage.Find(ctx, []byte{subjectKeysPrefix}, storage.KeysOnly|storage.RemovePrefix)
|
||||||
|
@ -1074,7 +1001,3 @@ func idToBytes(itemID int) []byte {
|
||||||
zeros := make([]byte, 8-ln)
|
zeros := make([]byte, 8-ln)
|
||||||
return append(b, zeros...)
|
return append(b, zeros...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func addressKey(address []byte) []byte {
|
|
||||||
return append([]byte{addressPrefix}, address...)
|
|
||||||
}
|
|
||||||
|
|
3
go.mod
3
go.mod
|
@ -1,6 +1,6 @@
|
||||||
module git.frostfs.info/TrueCloudLab/frostfs-contract
|
module git.frostfs.info/TrueCloudLab/frostfs-contract
|
||||||
|
|
||||||
go 1.22
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
|
@ -36,7 +36,6 @@ require (
|
||||||
github.com/prometheus/procfs v0.12.0 // indirect
|
github.com/prometheus/procfs v0.12.0 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/stretchr/objx v0.5.2 // indirect
|
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect
|
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect
|
||||||
github.com/twmb/murmur3 v1.1.8 // indirect
|
github.com/twmb/murmur3 v1.1.8 // indirect
|
||||||
github.com/urfave/cli/v2 v2.27.2 // indirect
|
github.com/urfave/cli/v2 v2.27.2 // indirect
|
||||||
|
|
22
go.sum
22
go.sum
|
@ -1,5 +1,4 @@
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4=
|
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12 h1:npHgfD4Tl2WJS3AJaMUi5ynGDPUBfkg3U3fCzDyXZ+4=
|
||||||
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20221202181307-76fa05c21b12/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
|
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
github.com/bits-and-blooms/bitset v1.8.0 h1:FD+XqgOZDUxxZ8hzoBFuV9+cGWY9CslN6d5MS5JVb4c=
|
||||||
|
@ -7,7 +6,6 @@ github.com/bits-and-blooms/bitset v1.8.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
|
github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
|
||||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
|
||||||
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
|
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
|
||||||
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
|
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
|
||||||
github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb h1:f0BMgIjhZy4lSRHCXFbQst85f5agZAjtDMixQqBWNpc=
|
github.com/consensys/gnark-crypto v0.12.2-0.20231013160410-1f65e75b6dfb h1:f0BMgIjhZy4lSRHCXFbQst85f5agZAjtDMixQqBWNpc=
|
||||||
|
@ -19,7 +17,6 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
|
||||||
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
|
github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA=
|
||||||
github.com/frankban/quicktest v1.14.5/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
|
@ -31,14 +28,12 @@ github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:W
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
|
||||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
@ -50,13 +45,9 @@ github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU
|
||||||
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
|
||||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|
||||||
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
|
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
|
||||||
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
|
|
||||||
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
|
github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY=
|
||||||
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
|
github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU=
|
||||||
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
|
github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU=
|
||||||
|
@ -67,19 +58,15 @@ github.com/nspcc-dev/dbft v0.2.0/go.mod h1:oFE6paSC/yfFh9mcNU6MheMGOYXK9+sPiRk3Y
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 h1:mD9hU3v+zJcnHAVmHnZKt3I++tvn30gBj2rP2PocZMk=
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 h1:mD9hU3v+zJcnHAVmHnZKt3I++tvn30gBj2rP2PocZMk=
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2/go.mod h1:U5VfmPNM88P4RORFb6KSUVBdJBDhlqggJZYGXGPxOcc=
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2/go.mod h1:U5VfmPNM88P4RORFb6KSUVBdJBDhlqggJZYGXGPxOcc=
|
||||||
github.com/nspcc-dev/hrw/v2 v2.0.1 h1:CxYUkBeJvNfMEn2lHhrV6FjY8pZPceSxXUtMVq0BUOU=
|
github.com/nspcc-dev/hrw/v2 v2.0.1 h1:CxYUkBeJvNfMEn2lHhrV6FjY8pZPceSxXUtMVq0BUOU=
|
||||||
github.com/nspcc-dev/hrw/v2 v2.0.1/go.mod h1:iZAs5hT2q47EGq6AZ0FjaUI6ggntOi7vrY4utfzk5VA=
|
|
||||||
github.com/nspcc-dev/neo-go v0.106.3 h1:HEyhgkjQY+HfBzotMJ12xx2VuOUphkngZ4kEkjvXDtE=
|
github.com/nspcc-dev/neo-go v0.106.3 h1:HEyhgkjQY+HfBzotMJ12xx2VuOUphkngZ4kEkjvXDtE=
|
||||||
github.com/nspcc-dev/neo-go v0.106.3/go.mod h1:3vEwJ2ld12N7HRGCaH/l/7EwopplC/+8XdIdPDNmD/M=
|
github.com/nspcc-dev/neo-go v0.106.3/go.mod h1:3vEwJ2ld12N7HRGCaH/l/7EwopplC/+8XdIdPDNmD/M=
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec h1:vDrbVXF2+2uP0RlkZmem3QYATcXCu9BzzGGCNsNcK7Q=
|
||||||
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240727093519-1a48f1ce43ec/go.mod h1:/vrbWSHc7YS1KSYhVOyyeucXW/e+1DkVBOgnBEXUCeY=
|
||||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 h1:arN0Ypn+jawZpu1BND7TGRn44InAVIqKygndsx0y2no=
|
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4 h1:arN0Ypn+jawZpu1BND7TGRn44InAVIqKygndsx0y2no=
|
||||||
github.com/nspcc-dev/neofs-api-go/v2 v2.14.1-0.20240305074711-35bc78d84dc4/go.mod h1:7Tm1NKEoUVVIUlkVwFrPh7GG5+Lmta2m7EGr4oVpBd8=
|
|
||||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12 h1:mdxtlSU2I4oVZ/7AXTLKyz8uUPbDWikZw4DM8gvrddA=
|
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12 h1:mdxtlSU2I4oVZ/7AXTLKyz8uUPbDWikZw4DM8gvrddA=
|
||||||
github.com/nspcc-dev/neofs-sdk-go v1.0.0-rc.12/go.mod h1:JdsEM1qgNukrWqgOBDChcYp8oY4XUzidcKaxY4hNJvQ=
|
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM=
|
github.com/nspcc-dev/rfc6979 v0.2.1 h1:8wWxkamHWFmO790GsewSoKUSJjVnL1fmdRpokU/RgRM=
|
||||||
github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc=
|
github.com/nspcc-dev/rfc6979 v0.2.1/go.mod h1:Tk7h5kyUWkhjyO3zUgFFhy1v2vQv3BvQEntakdtqrWc=
|
||||||
github.com/nspcc-dev/tzhash v1.7.2 h1:iRXoa9TJqH/DQO7FFcqpq9BdruF9E7/xnFGlIghl5J4=
|
github.com/nspcc-dev/tzhash v1.7.2 h1:iRXoa9TJqH/DQO7FFcqpq9BdruF9E7/xnFGlIghl5J4=
|
||||||
github.com/nspcc-dev/tzhash v1.7.2/go.mod h1:oHiH0qwmTsZkeVs7pvCS5cVXUaLhXxSFvnmnZ++ijm4=
|
|
||||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||||
|
@ -105,8 +92,6 @@ github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDN
|
||||||
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
|
||||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
|
||||||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
|
||||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs=
|
github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs=
|
||||||
|
@ -120,7 +105,6 @@ github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQut
|
||||||
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
|
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
|
||||||
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
|
||||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||||
|
@ -130,7 +114,6 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
|
||||||
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
||||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
|
||||||
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
|
||||||
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||||
|
@ -141,7 +124,6 @@ golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
@ -167,9 +149,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c h1:NUsgEN92SQQqzfA+YtqYNqYmB3DMMYLlIwUZAQFVFbo=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240221002015-b0ce06bbee7c/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY=
|
|
||||||
google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
|
google.golang.org/grpc v1.62.0 h1:HQKZ/fa1bXkX1oFOvSjmZEUL8wLSaZTjCcLAlmZRtdk=
|
||||||
google.golang.org/grpc v1.62.0/go.mod h1:IWTG0VlJLCh1SkC58F7np9ka9mx/WNkjl4PGJaiq+QE=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
@ -180,14 +160,12 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm
|
||||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
|
rsc.io/tmplfunc v0.0.3 h1:53XFQh69AfOa8Tw0Jm7t+GV7KZhOi6jzsCzTtKbMvzU=
|
||||||
|
|
|
@ -44,32 +44,3 @@ The committee makes new tokens (domains), sets, and charges a fee for issuance.
|
||||||
## Globally Unique Domain Zone
|
## Globally Unique Domain Zone
|
||||||
|
|
||||||
For more information, see [here](../docs/globally-unique-domain-zone.md).
|
For more information, see [here](../docs/globally-unique-domain-zone.md).
|
||||||
|
|
||||||
## NNS and Frostfsid
|
|
||||||
|
|
||||||
You can register a TLD domain without a committee signature using Frostfsid. To do this, create a new wallet
|
|
||||||
```
|
|
||||||
neo-go wallet init -w newwallet/wallet.json
|
|
||||||
```
|
|
||||||
|
|
||||||
Get wallet address:
|
|
||||||
```
|
|
||||||
neo-go wallet dump-keys -w newwallet/wallet.json
|
|
||||||
[subject-address]
|
|
||||||
[subject-key]
|
|
||||||
```
|
|
||||||
|
|
||||||
Create a subject in `FrostfsID`:
|
|
||||||
```
|
|
||||||
frostfs-adm morph frostfsid create-subject --subject-key="[subject-key]"
|
|
||||||
```
|
|
||||||
|
|
||||||
Grant permissions to the wallet:
|
|
||||||
```
|
|
||||||
frostfs-adm morph nns give-privilege --subject-address="[subject-address]"
|
|
||||||
```
|
|
||||||
|
|
||||||
Register domain:
|
|
||||||
```
|
|
||||||
neo-go contract invokefunction [NNS-hash] register "subdomain.domain" hash160:[subject-address] "email@frostfs.info" 10000 1000 1000 1000 -- [subject-address]:Global
|
|
||||||
```
|
|
|
@ -2,7 +2,6 @@ name: "NameService"
|
||||||
supportedstandards: ["NEP-11"]
|
supportedstandards: ["NEP-11"]
|
||||||
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf",
|
safemethods: ["balanceOf", "decimals", "symbol", "totalSupply", "tokensOf", "ownerOf",
|
||||||
"tokens", "properties", "roots", "getPrice", "isAvailable", "getRecords",
|
"tokens", "properties", "roots", "getPrice", "isAvailable", "getRecords",
|
||||||
"getAllRecords",
|
|
||||||
"resolve", "version"]
|
"resolve", "version"]
|
||||||
events:
|
events:
|
||||||
- name: RegisterDomain
|
- name: RegisterDomain
|
||||||
|
@ -15,12 +14,6 @@ events:
|
||||||
type: String
|
type: String
|
||||||
- name: type
|
- name: type
|
||||||
type: Integer
|
type: Integer
|
||||||
- name: DeleteRecord
|
|
||||||
parameters:
|
|
||||||
- name: name
|
|
||||||
type: String
|
|
||||||
- name: type
|
|
||||||
type: Integer
|
|
||||||
- name: DeleteRecords
|
- name: DeleteRecords
|
||||||
parameters:
|
parameters:
|
||||||
- name: name
|
- name: name
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
package nns
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/contract"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/management"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/native/std"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/interop/storage"
|
|
||||||
)
|
|
||||||
|
|
||||||
const FrostfsIDNNSName = "frostfsid.frostfs"
|
|
||||||
|
|
||||||
const (
|
|
||||||
FrostfsIDNNSTLDPermissionKey = "nns-allow-register-tld"
|
|
||||||
FrostfsIDTLDRegistrationAllowed = "allow"
|
|
||||||
)
|
|
||||||
|
|
||||||
func checkFrostfsID(ctx storage.Context, addr interop.Hash160) bool {
|
|
||||||
if len(addr) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
frostfsIDAddress := getRecordsByType(ctx, []byte(tokenIDFromName(FrostfsIDNNSName)), FrostfsIDNNSName, TXT)
|
|
||||||
if len(frostfsIDAddress) < 2 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
decodedBytes := std.Base58Decode([]byte(frostfsIDAddress[1]))
|
|
||||||
|
|
||||||
if len(decodedBytes) < 21 || management.GetContract(decodedBytes[1:21]) == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if res := contract.Call(decodedBytes[1:21], "getSubjectKV", contract.ReadOnly, addr, FrostfsIDNNSTLDPermissionKey).(string); res == FrostfsIDTLDRegistrationAllowed {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -41,14 +41,9 @@ const (
|
||||||
// prefixRecord contains map from (token key + hash160(token name) + record type)
|
// prefixRecord contains map from (token key + hash160(token name) + record type)
|
||||||
// to record.
|
// to record.
|
||||||
prefixRecord byte = 0x22
|
prefixRecord byte = 0x22
|
||||||
// prefixGlobalDomain contains a flag indicating that this domain was created using GlobalDomain.
|
//prefixGlobalDomain contains a flag indicating that this domain was created using GlobalDomain.
|
||||||
// This is necessary to distinguish it from regular CNAME records.
|
//This is necessary to distinguish it from regular CNAME records.
|
||||||
prefixGlobalDomain byte = 0x23
|
prefixGlobalDomain byte = 0x23
|
||||||
// prefixCountSubDomains contains information about the number of domains in the zone.
|
|
||||||
// If it is nil, it will definitely be calculated on the first removal.
|
|
||||||
prefixCountSubDomains byte = 0x24
|
|
||||||
// prefixAutoCreated contains a flag indicating whether the TLD domain was created automatically.
|
|
||||||
prefixAutoCreated = 0x25
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Values constraints.
|
// Values constraints.
|
||||||
|
@ -79,7 +74,7 @@ const (
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// Cnametgt is a special TXT record ensuring all created subdomains point to the global domain - the value of this variable.
|
// Cnametgt is a special TXT record ensuring all created subdomains point to the global domain - the value of this variable.
|
||||||
// It is guaranteed that two domains cannot point to the same global domain.
|
//It is guaranteed that two domains cannot point to the same global domain.
|
||||||
Cnametgt = "cnametgt"
|
Cnametgt = "cnametgt"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -239,10 +234,13 @@ func IsAvailable(name string) bool {
|
||||||
ctx := storage.GetReadOnlyContext()
|
ctx := storage.GetReadOnlyContext()
|
||||||
l := len(fragments)
|
l := len(fragments)
|
||||||
if storage.Get(ctx, append([]byte{prefixRoot}, []byte(fragments[l-1])...)) == nil {
|
if storage.Get(ctx, append([]byte{prefixRoot}, []byte(fragments[l-1])...)) == nil {
|
||||||
|
if l != 1 {
|
||||||
|
panic("TLD not found")
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
checkParent(ctx, fragments)
|
checkParentExists(ctx, fragments)
|
||||||
checkAvailableGlobalDomain(ctx, name)
|
checkAvailableGlobalDomain(ctx, name)
|
||||||
return storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(name))...)) == nil
|
return storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(name))...)) == nil
|
||||||
}
|
}
|
||||||
|
@ -306,27 +304,33 @@ func extractCnametgt(ctx storage.Context, name, domain string) string {
|
||||||
return fragments[0] + "." + globalDomain
|
return fragments[0] + "." + globalDomain
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkParent returns parent domain or empty string if domain not found.
|
// checkParentExists panics if any domain from fragments doesn't exist or is expired.
|
||||||
func checkParent(ctx storage.Context, fragments []string) string {
|
func checkParentExists(ctx storage.Context, fragments []string) {
|
||||||
|
if dom := parentExpired(ctx, fragments); dom != "" {
|
||||||
|
panic("domain does not exist or is expired: " + dom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parentExpired returns domain from fragments that doesn't exist or is expired.
|
||||||
|
// first denotes the deepest subdomain to check.
|
||||||
|
func parentExpired(ctx storage.Context, fragments []string) string {
|
||||||
now := int64(runtime.GetTime())
|
now := int64(runtime.GetTime())
|
||||||
last := len(fragments) - 1
|
last := len(fragments) - 1
|
||||||
name := fragments[last]
|
name := fragments[last]
|
||||||
parent := ""
|
|
||||||
for i := last; i > 0; i-- {
|
for i := last; i > 0; i-- {
|
||||||
if i != last {
|
if i != last {
|
||||||
name = fragments[i] + "." + name
|
name = fragments[i] + "." + name
|
||||||
}
|
}
|
||||||
nsBytes := storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(name))...))
|
nsBytes := storage.Get(ctx, append([]byte{prefixName}, getTokenKey([]byte(name))...))
|
||||||
if nsBytes == nil {
|
if nsBytes == nil {
|
||||||
continue
|
return name
|
||||||
}
|
}
|
||||||
ns := std.Deserialize(nsBytes.([]byte)).(NameState)
|
ns := std.Deserialize(nsBytes.([]byte)).(NameState)
|
||||||
if now >= ns.Expiration {
|
if now >= ns.Expiration {
|
||||||
panic("domain expired: " + name)
|
return name
|
||||||
}
|
}
|
||||||
parent = name
|
|
||||||
}
|
}
|
||||||
return parent
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register registers a new domain with the specified owner and name if it's available.
|
// Register registers a new domain with the specified owner and name if it's available.
|
||||||
|
@ -338,31 +342,24 @@ func Register(name string, owner interop.Hash160, email string, refresh, retry,
|
||||||
// Register registers a new domain with the specified owner and name if it's available.
|
// Register registers a new domain with the specified owner and name if it's available.
|
||||||
func register(ctx storage.Context, name string, owner interop.Hash160, email string, refresh, retry, expire, ttl int) bool {
|
func register(ctx storage.Context, name string, owner interop.Hash160, email string, refresh, retry, expire, ttl int) bool {
|
||||||
fragments := splitAndCheck(name)
|
fragments := splitAndCheck(name)
|
||||||
countZone := len(fragments)
|
l := len(fragments)
|
||||||
rootZone := []byte(fragments[countZone-1])
|
tldKey := append([]byte{prefixRoot}, []byte(fragments[l-1])...)
|
||||||
tldKey := append([]byte{prefixRoot}, rootZone...)
|
|
||||||
|
|
||||||
tldBytes := storage.Get(ctx, tldKey)
|
tldBytes := storage.Get(ctx, tldKey)
|
||||||
if countZone == 1 {
|
if l == 1 {
|
||||||
checkCommitteeAndFrostfsID(ctx, owner)
|
checkCommittee()
|
||||||
if tldBytes != nil {
|
if tldBytes != nil {
|
||||||
panic("TLD already exists")
|
panic("TLD already exists")
|
||||||
}
|
}
|
||||||
storage.Put(ctx, tldKey, 0)
|
storage.Put(ctx, tldKey, 0)
|
||||||
} else {
|
} else {
|
||||||
parent := checkParent(ctx, fragments)
|
if tldBytes == nil {
|
||||||
if parent == "" {
|
panic("TLD not found")
|
||||||
parent = fragments[len(fragments)-1]
|
|
||||||
|
|
||||||
storage.Put(ctx, append([]byte{prefixAutoCreated}, rootZone...), true)
|
|
||||||
register(ctx, parent, owner, email, refresh, retry, expire, ttl)
|
|
||||||
}
|
}
|
||||||
|
checkParentExists(ctx, fragments)
|
||||||
|
|
||||||
parentKey := getTokenKey([]byte(parent))
|
parentKey := getTokenKey([]byte(name[len(fragments[0])+1:]))
|
||||||
nsBytes := storage.Get(ctx, append([]byte{prefixName}, parentKey...))
|
nsBytes := storage.Get(ctx, append([]byte{prefixName}, parentKey...))
|
||||||
if nsBytes == nil {
|
|
||||||
panic("parent does not exist:" + parent)
|
|
||||||
}
|
|
||||||
ns := std.Deserialize(nsBytes.([]byte)).(NameState)
|
ns := std.Deserialize(nsBytes.([]byte)).(NameState)
|
||||||
ns.checkAdmin()
|
ns.checkAdmin()
|
||||||
|
|
||||||
|
@ -406,7 +403,6 @@ func register(ctx storage.Context, name string, owner interop.Hash160, email str
|
||||||
}
|
}
|
||||||
checkAvailableGlobalDomain(ctx, name)
|
checkAvailableGlobalDomain(ctx, name)
|
||||||
|
|
||||||
updateSubdDomainCounter(ctx, rootZone, countZone)
|
|
||||||
putNameStateWithKey(ctx, tokenKey, ns)
|
putNameStateWithKey(ctx, tokenKey, ns)
|
||||||
putSoaRecord(ctx, name, email, refresh, retry, expire, ttl)
|
putSoaRecord(ctx, name, email, refresh, retry, expire, ttl)
|
||||||
updateBalance(ctx, []byte(name), owner, +1)
|
updateBalance(ctx, []byte(name), owner, +1)
|
||||||
|
@ -513,12 +509,16 @@ 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)
|
||||||
globalDomain := globalDomainRaw.(string)
|
if globalDomainRaw != nil {
|
||||||
if globalDomainRaw != nil && globalDomain != "" {
|
globalDomain := globalDomainRaw.(string)
|
||||||
deleteDomain(ctx, globalDomain)
|
if globalDomain != "" {
|
||||||
|
deleteDomain(ctx, globalDomain)
|
||||||
|
}
|
||||||
|
storage.Delete(ctx, globalDomainKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recordsKey := getRecordsKeyByType(tokenID, name, typ)
|
recordsKey := getRecordsKeyByType(tokenID, name, typ)
|
||||||
|
@ -531,74 +531,20 @@ func deleteRecords(ctx storage.Context, name string, typ RecordType) {
|
||||||
runtime.Notify("DeleteRecords", name, typ)
|
runtime.Notify("DeleteRecords", name, typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRecord delete a record of the specified type by data in the provided domain.
|
|
||||||
// Returns false if the record was not found.
|
|
||||||
func DeleteRecord(name string, typ RecordType, data string) bool {
|
|
||||||
tokenID := []byte(tokenIDFromName(name))
|
|
||||||
if !checkBaseRecords(typ, data) {
|
|
||||||
panic("invalid record data")
|
|
||||||
}
|
|
||||||
ctx := storage.GetContext()
|
|
||||||
ns := getNameState(ctx, tokenID)
|
|
||||||
ns.checkAdmin()
|
|
||||||
return deleteRecord(ctx, tokenID, name, typ, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteRecord(ctx storage.Context, tokenId []byte, name string, typ RecordType, data string) bool {
|
|
||||||
recordsKey := getRecordsKeyByType(tokenId, name, typ)
|
|
||||||
|
|
||||||
var previousKey any
|
|
||||||
it := storage.Find(ctx, recordsKey, storage.KeysOnly)
|
|
||||||
for iterator.Next(it) {
|
|
||||||
key := iterator.Value(it).([]byte)
|
|
||||||
ss := storage.Get(ctx, key).([]byte)
|
|
||||||
|
|
||||||
ns := std.Deserialize(ss).(RecordState)
|
|
||||||
if ns.Name == name && ns.Type == typ && ns.Data == data {
|
|
||||||
previousKey = key
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if previousKey != nil {
|
|
||||||
data := storage.Get(ctx, key)
|
|
||||||
storage.Put(ctx, previousKey, data)
|
|
||||||
previousKey = key
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if previousKey == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
storage.Delete(ctx, previousKey)
|
|
||||||
runtime.Notify("DeleteRecord", name, typ)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteDomain deletes the domain with the given name.
|
// DeleteDomain deletes the domain with the given name.
|
||||||
func DeleteDomain(name string) {
|
func DeleteDomain(name string) {
|
||||||
ctx := storage.GetContext()
|
ctx := storage.GetContext()
|
||||||
deleteDomain(ctx, name)
|
deleteDomain(ctx, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func countSubdomains(name string) int {
|
func deleteDomain(ctx storage.Context, name string) {
|
||||||
countSubDomains := 0
|
|
||||||
it := Tokens()
|
it := Tokens()
|
||||||
for iterator.Next(it) {
|
for iterator.Next(it) {
|
||||||
domain := iterator.Value(it)
|
domain := iterator.Value(it)
|
||||||
if std.MemorySearch([]byte(domain.(string)), []byte(name)) > 0 {
|
if std.MemorySearch([]byte(domain.(string)), []byte(name)) > 0 {
|
||||||
countSubDomains = countSubDomains + 1
|
panic("can't delete a domain that has subdomains")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return countSubDomains
|
|
||||||
}
|
|
||||||
|
|
||||||
func deleteDomain(ctx storage.Context, name string) {
|
|
||||||
fragments := splitAndCheck(name)
|
|
||||||
parent := []byte(fragments[len(fragments)-1])
|
|
||||||
countSubDomainsKey := append([]byte{prefixCountSubDomains}, parent...)
|
|
||||||
autoCreatedPrefix := append([]byte{prefixAutoCreated}, parent...)
|
|
||||||
|
|
||||||
nsKey := append([]byte{prefixName}, getTokenKey([]byte(name))...)
|
nsKey := append([]byte{prefixName}, getTokenKey([]byte(name))...)
|
||||||
nsRaw := storage.Get(ctx, nsKey)
|
nsRaw := storage.Get(ctx, nsKey)
|
||||||
if nsRaw == nil {
|
if nsRaw == nil {
|
||||||
|
@ -608,45 +554,11 @@ func deleteDomain(ctx storage.Context, name string) {
|
||||||
ns := std.Deserialize(nsRaw.([]byte)).(NameState)
|
ns := std.Deserialize(nsRaw.([]byte)).(NameState)
|
||||||
ns.checkAdmin()
|
ns.checkAdmin()
|
||||||
|
|
||||||
countSubDomain := 0
|
|
||||||
countSubDomainRaw := storage.Get(ctx, countSubDomainsKey)
|
|
||||||
if countSubDomainRaw != nil {
|
|
||||||
countSubDomain = common.FromFixedWidth64(countSubDomainRaw.([]byte))
|
|
||||||
} else {
|
|
||||||
countSubDomain = countSubdomains(fragments[len(fragments)-1])
|
|
||||||
}
|
|
||||||
|
|
||||||
if countSubDomain > 1 && len(fragments) == 1 {
|
|
||||||
panic("can't delete TLD domain that has subdomains")
|
|
||||||
}
|
|
||||||
|
|
||||||
countSubDomain = countSubDomain - 1
|
|
||||||
storage.Put(ctx, countSubDomainsKey, common.ToFixedWidth64(countSubDomain))
|
|
||||||
|
|
||||||
globalNSKey := append([]byte{prefixGlobalDomain}, getTokenKey([]byte(name))...)
|
|
||||||
globalDomainRaw := storage.Get(ctx, globalNSKey)
|
|
||||||
globalDomain := globalDomainRaw.(string)
|
|
||||||
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, nsKey)
|
storage.Delete(ctx, nsKey)
|
||||||
storage.Delete(ctx, append([]byte{prefixRoot}, []byte(name)...))
|
|
||||||
|
|
||||||
isAutoCreated := storage.Get(ctx, autoCreatedPrefix)
|
|
||||||
if countSubDomain == 1 && isAutoCreated != nil && isAutoCreated.(bool) {
|
|
||||||
deleteDomain(ctx, fragments[len(fragments)-1])
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(fragments) == 1 {
|
|
||||||
storage.Delete(ctx, countSubDomainsKey)
|
|
||||||
storage.Delete(ctx, autoCreatedPrefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
runtime.Notify("DeleteDomain", name)
|
runtime.Notify("DeleteDomain", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -720,7 +632,7 @@ func getNameState(ctx storage.Context, tokenID []byte) NameState {
|
||||||
tokenKey := getTokenKey(tokenID)
|
tokenKey := getTokenKey(tokenID)
|
||||||
ns := getNameStateWithKey(ctx, tokenKey)
|
ns := getNameStateWithKey(ctx, tokenKey)
|
||||||
fragments := std.StringSplit(string(tokenID), ".")
|
fragments := std.StringSplit(string(tokenID), ".")
|
||||||
checkParent(ctx, fragments)
|
checkParentExists(ctx, fragments)
|
||||||
return ns
|
return ns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -924,14 +836,6 @@ func isValid(address interop.Hash160) bool {
|
||||||
return address != nil && len(address) == interop.Hash160Len
|
return address != nil && len(address) == interop.Hash160Len
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkCommitteeAndFrostfsID panics if the script container is not signed by the committee.
|
|
||||||
// or if the owner does not have permission in FrostfsID.
|
|
||||||
func checkCommitteeAndFrostfsID(ctx storage.Context, owner interop.Hash160) {
|
|
||||||
if !checkFrostfsID(ctx, owner) {
|
|
||||||
checkCommittee()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// checkCommittee panics if the script container is not signed by the committee.
|
// checkCommittee panics if the script container is not signed by the committee.
|
||||||
func checkCommittee() {
|
func checkCommittee() {
|
||||||
committee := neo.GetCommittee()
|
committee := neo.GetCommittee()
|
||||||
|
@ -1174,16 +1078,3 @@ func getAllRecords(ctx storage.Context, name string) iterator.Iterator {
|
||||||
recordsKey := getRecordsKey(tokenID, name)
|
recordsKey := getRecordsKey(tokenID, name)
|
||||||
return storage.Find(ctx, recordsKey, storage.ValuesOnly|storage.DeserializeValues)
|
return storage.Find(ctx, recordsKey, storage.ValuesOnly|storage.DeserializeValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateSubdDomainCounter(ctx storage.Context, rootZone []byte, countZone int) {
|
|
||||||
countSubDomain := 0
|
|
||||||
delInfoRaw := storage.Get(ctx, append([]byte{prefixCountSubDomains}, rootZone...))
|
|
||||||
if delInfoRaw != nil {
|
|
||||||
countSubDomain = common.FromFixedWidth64(delInfoRaw.([]byte))
|
|
||||||
}
|
|
||||||
|
|
||||||
if delInfoRaw != nil || countZone == 1 {
|
|
||||||
countSubDomain = countSubDomain + 1
|
|
||||||
storage.Put(ctx, append([]byte{prefixCountSubDomains}, rootZone...), common.ToFixedWidth64(countSubDomain))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -222,11 +222,6 @@ func (c *ContractReader) GetSubjectExtended(addr util.Uint160) ([]stackitem.Item
|
||||||
return unwrap.Array(c.invoker.Call(c.hash, "getSubjectExtended", addr))
|
return unwrap.Array(c.invoker.Call(c.hash, "getSubjectExtended", addr))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetSubjectKV invokes `getSubjectKV` method of contract.
|
|
||||||
func (c *ContractReader) GetSubjectKV(addr util.Uint160, name string) (string, error) {
|
|
||||||
return unwrap.UTF8String(c.invoker.Call(c.hash, "getSubjectKV", addr, name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSubjectKeyByName invokes `getSubjectKeyByName` method of contract.
|
// GetSubjectKeyByName invokes `getSubjectKeyByName` method of contract.
|
||||||
func (c *ContractReader) GetSubjectKeyByName(ns string, name string) (*keys.PublicKey, error) {
|
func (c *ContractReader) GetSubjectKeyByName(ns string, name string) (*keys.PublicKey, error) {
|
||||||
return unwrap.PublicKey(c.invoker.Call(c.hash, "getSubjectKeyByName", ns, name))
|
return unwrap.PublicKey(c.invoker.Call(c.hash, "getSubjectKeyByName", ns, name))
|
||||||
|
|
|
@ -29,12 +29,6 @@ type AddRecordEvent struct {
|
||||||
Type *big.Int
|
Type *big.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRecordEvent represents "DeleteRecord" event emitted by the contract.
|
|
||||||
type DeleteRecordEvent struct {
|
|
||||||
Name string
|
|
||||||
Type *big.Int
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRecordsEvent represents "DeleteRecords" event emitted by the contract.
|
// DeleteRecordsEvent represents "DeleteRecords" event emitted by the contract.
|
||||||
type DeleteRecordsEvent struct {
|
type DeleteRecordsEvent struct {
|
||||||
Name string
|
Name string
|
||||||
|
@ -91,20 +85,6 @@ func New(actor Actor, hash util.Uint160) *Contract {
|
||||||
return &Contract{ContractReader{nep11ndt.NonDivisibleReader, actor, hash}, nep11ndt.BaseWriter, actor, hash}
|
return &Contract{ContractReader{nep11ndt.NonDivisibleReader, actor, hash}, nep11ndt.BaseWriter, actor, hash}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetAllRecords invokes `getAllRecords` method of contract.
|
|
||||||
func (c *ContractReader) GetAllRecords(name string) (uuid.UUID, result.Iterator, error) {
|
|
||||||
return unwrap.SessionIterator(c.invoker.Call(c.hash, "getAllRecords", name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllRecordsExpanded is similar to GetAllRecords (uses the same contract
|
|
||||||
// method), but can be useful if the server used doesn't support sessions and
|
|
||||||
// doesn't expand iterators. It creates a script that will get the specified
|
|
||||||
// number of result items from the iterator right in the VM and return them to
|
|
||||||
// you. It's only limited by VM stack and GAS available for RPC invocations.
|
|
||||||
func (c *ContractReader) GetAllRecordsExpanded(name string, _numOfIteratorItems int) ([]stackitem.Item, error) {
|
|
||||||
return unwrap.Array(c.invoker.CallAndExpandIterator(c.hash, "getAllRecords", _numOfIteratorItems, name))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPrice invokes `getPrice` method of contract.
|
// GetPrice invokes `getPrice` method of contract.
|
||||||
func (c *ContractReader) GetPrice() (*big.Int, error) {
|
func (c *ContractReader) GetPrice() (*big.Int, error) {
|
||||||
return unwrap.BigInt(c.invoker.Call(c.hash, "getPrice"))
|
return unwrap.BigInt(c.invoker.Call(c.hash, "getPrice"))
|
||||||
|
@ -188,44 +168,6 @@ func (c *Contract) DeleteDomainUnsigned(name string) (*transaction.Transaction,
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "deleteDomain", nil, name)
|
return c.actor.MakeUnsignedCall(c.hash, "deleteDomain", nil, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Contract) scriptForDeleteRecord(name string, typ *big.Int, data string) ([]byte, error) {
|
|
||||||
return smartcontract.CreateCallWithAssertScript(c.hash, "deleteRecord", name, typ, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRecord creates a transaction invoking `deleteRecord` method of the contract.
|
|
||||||
// This transaction is signed and immediately sent to the network.
|
|
||||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
|
||||||
func (c *Contract) DeleteRecord(name string, typ *big.Int, data string) (util.Uint256, uint32, error) {
|
|
||||||
script, err := c.scriptForDeleteRecord(name, typ, data)
|
|
||||||
if err != nil {
|
|
||||||
return util.Uint256{}, 0, err
|
|
||||||
}
|
|
||||||
return c.actor.SendRun(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRecordTransaction creates a transaction invoking `deleteRecord` method of the contract.
|
|
||||||
// This transaction is signed, but not sent to the network, instead it's
|
|
||||||
// returned to the caller.
|
|
||||||
func (c *Contract) DeleteRecordTransaction(name string, typ *big.Int, data string) (*transaction.Transaction, error) {
|
|
||||||
script, err := c.scriptForDeleteRecord(name, typ, data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c.actor.MakeRun(script)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRecordUnsigned creates a transaction invoking `deleteRecord` method of the contract.
|
|
||||||
// This transaction is not signed, it's simply returned to the caller.
|
|
||||||
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
|
||||||
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
|
||||||
func (c *Contract) DeleteRecordUnsigned(name string, typ *big.Int, data string) (*transaction.Transaction, error) {
|
|
||||||
script, err := c.scriptForDeleteRecord(name, typ, data)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return c.actor.MakeUnsignedRun(script, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRecords creates a transaction invoking `deleteRecords` method of the contract.
|
// DeleteRecords creates a transaction invoking `deleteRecords` method of the contract.
|
||||||
// This transaction is signed and immediately sent to the network.
|
// This transaction is signed and immediately sent to the network.
|
||||||
// The values returned are its hash, ValidUntilBlock value and error if any.
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
|
@ -248,6 +190,28 @@ func (c *Contract) DeleteRecordsUnsigned(name string, typ *big.Int) (*transactio
|
||||||
return c.actor.MakeUnsignedCall(c.hash, "deleteRecords", nil, name, typ)
|
return c.actor.MakeUnsignedCall(c.hash, "deleteRecords", nil, name, typ)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAllRecords creates a transaction invoking `getAllRecords` method of the contract.
|
||||||
|
// This transaction is signed and immediately sent to the network.
|
||||||
|
// The values returned are its hash, ValidUntilBlock value and error if any.
|
||||||
|
func (c *Contract) GetAllRecords(name string) (util.Uint256, uint32, error) {
|
||||||
|
return c.actor.SendCall(c.hash, "getAllRecords", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllRecordsTransaction creates a transaction invoking `getAllRecords` method of the contract.
|
||||||
|
// This transaction is signed, but not sent to the network, instead it's
|
||||||
|
// returned to the caller.
|
||||||
|
func (c *Contract) GetAllRecordsTransaction(name string) (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeCall(c.hash, "getAllRecords", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllRecordsUnsigned creates a transaction invoking `getAllRecords` method of the contract.
|
||||||
|
// This transaction is not signed, it's simply returned to the caller.
|
||||||
|
// Any fields of it that do not affect fees can be changed (ValidUntilBlock,
|
||||||
|
// Nonce), fee values (NetworkFee, SystemFee) can be increased as well.
|
||||||
|
func (c *Contract) GetAllRecordsUnsigned(name string) (*transaction.Transaction, error) {
|
||||||
|
return c.actor.MakeUnsignedCall(c.hash, "getAllRecords", nil, name)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Contract) scriptForRegister(name string, owner util.Uint160, email string, refresh *big.Int, retry *big.Int, expire *big.Int, ttl *big.Int) ([]byte, error) {
|
func (c *Contract) scriptForRegister(name string, owner util.Uint160, email string, refresh *big.Int, retry *big.Int, expire *big.Int, ttl *big.Int) ([]byte, error) {
|
||||||
return smartcontract.CreateCallWithAssertScript(c.hash, "register", name, owner, email, refresh, retry, expire, ttl)
|
return smartcontract.CreateCallWithAssertScript(c.hash, "register", name, owner, email, refresh, retry, expire, ttl)
|
||||||
}
|
}
|
||||||
|
@ -546,73 +510,6 @@ func (e *AddRecordEvent) FromStackItem(item *stackitem.Array) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRecordEventsFromApplicationLog retrieves a set of all emitted events
|
|
||||||
// with "DeleteRecord" name from the provided [result.ApplicationLog].
|
|
||||||
func DeleteRecordEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteRecordEvent, error) {
|
|
||||||
if log == nil {
|
|
||||||
return nil, errors.New("nil application log")
|
|
||||||
}
|
|
||||||
|
|
||||||
var res []*DeleteRecordEvent
|
|
||||||
for i, ex := range log.Executions {
|
|
||||||
for j, e := range ex.Events {
|
|
||||||
if e.Name != "DeleteRecord" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
event := new(DeleteRecordEvent)
|
|
||||||
err := event.FromStackItem(e.Item)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to deserialize DeleteRecordEvent from stackitem (execution #%d, event #%d): %w", i, j, err)
|
|
||||||
}
|
|
||||||
res = append(res, event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromStackItem converts provided [stackitem.Array] to DeleteRecordEvent or
|
|
||||||
// returns an error if it's not possible to do to so.
|
|
||||||
func (e *DeleteRecordEvent) FromStackItem(item *stackitem.Array) error {
|
|
||||||
if item == nil {
|
|
||||||
return errors.New("nil item")
|
|
||||||
}
|
|
||||||
arr, ok := item.Value().([]stackitem.Item)
|
|
||||||
if !ok {
|
|
||||||
return errors.New("not an array")
|
|
||||||
}
|
|
||||||
if len(arr) != 2 {
|
|
||||||
return errors.New("wrong number of structure elements")
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
index = -1
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
index++
|
|
||||||
e.Name, err = func(item stackitem.Item) (string, error) {
|
|
||||||
b, err := item.TryBytes()
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
if !utf8.Valid(b) {
|
|
||||||
return "", errors.New("not a UTF-8 string")
|
|
||||||
}
|
|
||||||
return string(b), nil
|
|
||||||
}(arr[index])
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Name: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
index++
|
|
||||||
e.Type, err = arr[index].TryInteger()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("field Type: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteRecordsEventsFromApplicationLog retrieves a set of all emitted events
|
// DeleteRecordsEventsFromApplicationLog retrieves a set of all emitted events
|
||||||
// with "DeleteRecords" name from the provided [result.ApplicationLog].
|
// with "DeleteRecords" name from the provided [result.ApplicationLog].
|
||||||
func DeleteRecordsEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteRecordsEvent, error) {
|
func DeleteRecordsEventsFromApplicationLog(log *result.ApplicationLog) ([]*DeleteRecordsEvent, error) {
|
||||||
|
|
|
@ -238,13 +238,6 @@ func TestFrostFSID_SubjectManagement(t *testing.T) {
|
||||||
subj = parseSubject(t, s)
|
subj = parseSubject(t, s)
|
||||||
require.True(t, subjKey.PublicKey().Equal(&subj.PrimaryKey), "keys must be the same")
|
require.True(t, subjKey.PublicKey().Equal(&subj.PrimaryKey), "keys must be the same")
|
||||||
|
|
||||||
t.Run("with GetSubject", func(t *testing.T) {
|
|
||||||
s, err = anonInvoker.TestInvoke(t, getSubjectMethod, subjKey.PublicKey().GetScriptHash())
|
|
||||||
require.NoError(t, err)
|
|
||||||
subj = parseSubject(t, s)
|
|
||||||
require.True(t, subjKey.PublicKey().Equal(&subj.PrimaryKey), "keys must be the same")
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("remove subject key", func(t *testing.T) {
|
t.Run("remove subject key", func(t *testing.T) {
|
||||||
anonInvoker.InvokeFail(t, notWitnessedError, removeSubjectKeyMethod, subjKeyAddr, subjNewKey.PublicKey().Bytes())
|
anonInvoker.InvokeFail(t, notWitnessedError, removeSubjectKeyMethod, subjKeyAddr, subjNewKey.PublicKey().Bytes())
|
||||||
invoker.Invoke(t, stackitem.Null{}, removeSubjectKeyMethod, subjKeyAddr, subjNewKey.PublicKey().Bytes())
|
invoker.Invoke(t, stackitem.Null{}, removeSubjectKeyMethod, subjKeyAddr, subjNewKey.PublicKey().Bytes())
|
||||||
|
@ -611,44 +604,6 @@ func TestFrostFSID_GroupManagement(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdditionalKeyFromPrimarySubject(t *testing.T) {
|
|
||||||
f := newFrostFSIDInvoker(t)
|
|
||||||
invoker := f.OwnerInvoker()
|
|
||||||
|
|
||||||
subjAPrimaryKey, err := keys.NewPrivateKey()
|
|
||||||
require.NoError(t, err)
|
|
||||||
subjAKeyAddr := subjAPrimaryKey.PublicKey().GetScriptHash()
|
|
||||||
|
|
||||||
subjBPrimaryKey, err := keys.NewPrivateKey()
|
|
||||||
require.NoError(t, err)
|
|
||||||
subjBKeyAddr := subjBPrimaryKey.PublicKey().GetScriptHash()
|
|
||||||
|
|
||||||
subjCPrimaryKey, err := keys.NewPrivateKey()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
subjDPrimaryKey, err := keys.NewPrivateKey()
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjAPrimaryKey.PublicKey().Bytes())
|
|
||||||
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, createSubjectMethod, defaultNamespace, subjBPrimaryKey.PublicKey().Bytes())
|
|
||||||
|
|
||||||
invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjBKeyAddr, subjAPrimaryKey.PublicKey().Bytes())
|
|
||||||
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjAKeyAddr, subjCPrimaryKey.PublicKey().Bytes())
|
|
||||||
invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjBKeyAddr, subjCPrimaryKey.PublicKey().Bytes())
|
|
||||||
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
|
|
||||||
|
|
||||||
invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjBKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, removeSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjBKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
|
|
||||||
|
|
||||||
invoker.InvokeFail(t, "key is occupied", addSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, deleteSubjectMethod, subjBKeyAddr)
|
|
||||||
invoker.Invoke(t, stackitem.Null{}, addSubjectKeyMethod, subjAKeyAddr, subjDPrimaryKey.PublicKey().Bytes())
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkPublicKeyResult(t *testing.T, s *vm.Stack, err error, key *keys.PrivateKey) {
|
func checkPublicKeyResult(t *testing.T, s *vm.Stack, err error, key *keys.PrivateKey) {
|
||||||
if key == nil {
|
if key == nil {
|
||||||
require.ErrorContains(t, err, "not found")
|
require.ErrorContains(t, err, "not found")
|
||||||
|
|
|
@ -12,12 +12,10 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
"github.com/nspcc-dev/neo-go/pkg/core/interop/storage"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/encoding/address"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/neotest"
|
"github.com/nspcc-dev/neo-go/pkg/neotest"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/rpcclient/gas"
|
"github.com/nspcc-dev/neo-go/pkg/rpcclient/gas"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,7 +23,8 @@ const nnsPath = "../nns"
|
||||||
|
|
||||||
const msPerYear = 365 * 24 * time.Hour / time.Millisecond
|
const msPerYear = 365 * 24 * time.Hour / time.Millisecond
|
||||||
|
|
||||||
func deployNNS(t *testing.T, e *neotest.Executor, addRoot bool) *neotest.ContractInvoker {
|
func newNNSInvoker(t *testing.T, addRoot bool) *neotest.ContractInvoker {
|
||||||
|
e := newExecutor(t)
|
||||||
ctr := neotest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml"))
|
ctr := neotest.CompileFile(t, e.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml"))
|
||||||
e.DeployContract(t, ctr, nil)
|
e.DeployContract(t, ctr, nil)
|
||||||
|
|
||||||
|
@ -40,28 +39,6 @@ func deployNNS(t *testing.T, e *neotest.Executor, addRoot bool) *neotest.Contrac
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func newNNSInvoker(t *testing.T, addRoot bool) *neotest.ContractInvoker {
|
|
||||||
e := newExecutor(t)
|
|
||||||
return deployNNS(t, e, addRoot)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newNNSInvokerWithFrostfsID(t *testing.T, addRoot bool) (*neotest.ContractInvoker, *neotest.ContractInvoker) {
|
|
||||||
e := newExecutor(t)
|
|
||||||
c := deployNNS(t, e, addRoot)
|
|
||||||
|
|
||||||
frostfdID := deployFrostFSIDContract(t, e, e.CommitteeHash)
|
|
||||||
c.Invoke(t, true, "register",
|
|
||||||
nns.FrostfsIDNNSName, c.CommitteeHash,
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
|
|
||||||
c.Invoke(t, stackitem.Null{}, "addRecord",
|
|
||||||
nns.FrostfsIDNNSName, int64(nns.TXT), frostfdID.StringLE())
|
|
||||||
|
|
||||||
c.Invoke(t, stackitem.Null{}, "addRecord",
|
|
||||||
nns.FrostfsIDNNSName, int64(nns.TXT), address.Uint160ToString(frostfdID))
|
|
||||||
return e.NewInvoker(c.Hash), e.CommitteeInvoker(frostfdID)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNNSGeneric(t *testing.T) {
|
func TestNNSGeneric(t *testing.T) {
|
||||||
c := newNNSInvoker(t, false)
|
c := newNNSInvoker(t, false)
|
||||||
|
|
||||||
|
@ -123,18 +100,6 @@ func TestNNSRegister(t *testing.T) {
|
||||||
"com", accTop.ScriptHash(),
|
"com", accTop.ScriptHash(),
|
||||||
"myemail@frostfs.info", refresh, retry, expire, ttl)
|
"myemail@frostfs.info", refresh, retry, expire, ttl)
|
||||||
|
|
||||||
c1.Invoke(t, true, "register",
|
|
||||||
"aa.bb.zz", accTop.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", refresh, retry, expire, ttl)
|
|
||||||
|
|
||||||
c1.InvokeFail(t, "TLD already exists", "register",
|
|
||||||
"zz", accTop.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", refresh, retry, expire, ttl)
|
|
||||||
|
|
||||||
c1.Invoke(t, true, "register",
|
|
||||||
"xx.bb.zz", accTop.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", refresh, retry, expire, ttl)
|
|
||||||
|
|
||||||
acc := c.NewAccount(t)
|
acc := c.NewAccount(t)
|
||||||
c2 := c.WithSigners(c.Committee, acc)
|
c2 := c.WithSigners(c.Committee, acc)
|
||||||
c2.InvokeFail(t, "not witnessed by admin", "register",
|
c2.InvokeFail(t, "not witnessed by admin", "register",
|
||||||
|
@ -177,10 +142,8 @@ func TestNNSRegister(t *testing.T) {
|
||||||
|
|
||||||
cAcc := c.WithSigners(acc)
|
cAcc := c.WithSigners(acc)
|
||||||
|
|
||||||
expected = stackitem.NewArray([]stackitem.Item{
|
expected = stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte("testdomain.com")),
|
||||||
stackitem.NewByteArray([]byte("testdomain.com")),
|
stackitem.NewBigInteger(big.NewInt(int64(nns.TXT)))})
|
||||||
stackitem.NewBigInteger(big.NewInt(int64(nns.TXT))),
|
|
||||||
})
|
|
||||||
tx = cAcc.Invoke(t, stackitem.Null{}, "addRecord",
|
tx = cAcc.Invoke(t, stackitem.Null{}, "addRecord",
|
||||||
"testdomain.com", int64(nns.TXT), "first TXT record")
|
"testdomain.com", int64(nns.TXT), "first TXT record")
|
||||||
c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "AddRecord", Item: expected})
|
c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "AddRecord", Item: expected})
|
||||||
|
@ -196,10 +159,8 @@ func TestNNSRegister(t *testing.T) {
|
||||||
})
|
})
|
||||||
c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT))
|
c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT))
|
||||||
|
|
||||||
expected = stackitem.NewArray([]stackitem.Item{
|
expected = stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte("testdomain.com")),
|
||||||
stackitem.NewByteArray([]byte("testdomain.com")),
|
stackitem.NewBigInteger(big.NewInt(int64(nns.TXT)))})
|
||||||
stackitem.NewBigInteger(big.NewInt(int64(nns.TXT))),
|
|
||||||
})
|
|
||||||
tx = cAcc.Invoke(t, stackitem.Null{}, "setRecord",
|
tx = cAcc.Invoke(t, stackitem.Null{}, "setRecord",
|
||||||
"testdomain.com", int64(nns.TXT), int64(0), "replaced first")
|
"testdomain.com", int64(nns.TXT), int64(0), "replaced first")
|
||||||
c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "AddRecord", Item: expected})
|
c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "AddRecord", Item: expected})
|
||||||
|
@ -211,60 +172,15 @@ func TestNNSRegister(t *testing.T) {
|
||||||
c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT))
|
c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT))
|
||||||
|
|
||||||
tx = cAcc.Invoke(t, stackitem.Null{}, "deleteRecords", "testdomain.com", int64(nns.TXT))
|
tx = cAcc.Invoke(t, stackitem.Null{}, "deleteRecords", "testdomain.com", int64(nns.TXT))
|
||||||
expected = stackitem.NewArray([]stackitem.Item{
|
expected = stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte("testdomain.com")),
|
||||||
stackitem.NewByteArray([]byte("testdomain.com")),
|
stackitem.NewBigInteger(big.NewInt(int64(nns.TXT)))})
|
||||||
stackitem.NewBigInteger(big.NewInt(int64(nns.TXT))),
|
|
||||||
})
|
|
||||||
c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "DeleteRecords", Item: expected})
|
c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "DeleteRecords", Item: expected})
|
||||||
|
|
||||||
c.Invoke(t, stackitem.Null{}, "getRecords", "testdomain.com", int64(nns.TXT))
|
c.Invoke(t, stackitem.Null{}, "getRecords", "testdomain.com", int64(nns.TXT))
|
||||||
|
|
||||||
cAcc.Invoke(t, stackitem.Null{}, "addRecord",
|
|
||||||
"testdomain.com", int64(nns.TXT), "rec1")
|
|
||||||
|
|
||||||
cAcc.Invoke(t, stackitem.Null{}, "addRecord",
|
|
||||||
"testdomain.com", int64(nns.TXT), "rec2")
|
|
||||||
|
|
||||||
cAcc.Invoke(t, stackitem.Null{}, "addRecord",
|
|
||||||
"testdomain.com", int64(nns.TXT), "rec3")
|
|
||||||
|
|
||||||
cAcc.Invoke(t, stackitem.Null{}, "addRecord",
|
|
||||||
"testdomain.com", int64(nns.TXT), "rec4")
|
|
||||||
|
|
||||||
cAcc.Invoke(t, false, "deleteRecord",
|
|
||||||
"testdomain.com", int64(nns.TXT), "rec9999")
|
|
||||||
|
|
||||||
cAcc.Invoke(t, true, "deleteRecord",
|
|
||||||
"testdomain.com", int64(nns.TXT), "rec1")
|
|
||||||
|
|
||||||
expected = stackitem.NewArray([]stackitem.Item{
|
|
||||||
stackitem.NewByteArray([]byte("rec2")),
|
|
||||||
stackitem.NewByteArray([]byte("rec3")),
|
|
||||||
stackitem.NewByteArray([]byte("rec4")),
|
|
||||||
})
|
|
||||||
c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT))
|
|
||||||
|
|
||||||
cAcc.Invoke(t, true, "deleteRecord",
|
|
||||||
"testdomain.com", int64(nns.TXT), "rec4")
|
|
||||||
|
|
||||||
cAcc.Invoke(t, true, "deleteRecord",
|
|
||||||
"testdomain.com", int64(nns.TXT), "rec2")
|
|
||||||
|
|
||||||
expected = stackitem.NewArray([]stackitem.Item{
|
|
||||||
stackitem.NewByteArray([]byte("rec3")),
|
|
||||||
})
|
|
||||||
c.Invoke(t, expected, "getRecords", "testdomain.com", int64(nns.TXT))
|
|
||||||
|
|
||||||
cAcc.Invoke(t, true, "deleteRecord",
|
|
||||||
"testdomain.com", int64(nns.TXT), "rec3")
|
|
||||||
|
|
||||||
c.Invoke(t, stackitem.Null{}, "getRecords", "testdomain.com", int64(nns.TXT))
|
|
||||||
|
|
||||||
tx = cAcc.Invoke(t, stackitem.Null{}, "deleteDomain", "testdomain.com")
|
tx = cAcc.Invoke(t, stackitem.Null{}, "deleteDomain", "testdomain.com")
|
||||||
expected = stackitem.NewArray([]stackitem.Item{
|
expected = stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte("testdomain.com")),
|
||||||
stackitem.NewByteArray([]byte("testdomain.com")),
|
stackitem.NewBigInteger(big.NewInt(int64(nns.CNAME)))})
|
||||||
stackitem.NewBigInteger(big.NewInt(int64(nns.CNAME))),
|
|
||||||
})
|
|
||||||
c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "DeleteRecords", Item: expected})
|
c.CheckTxNotificationEvent(t, tx, 0, state.NotificationEvent{ScriptHash: c.Hash, Name: "DeleteRecords", Item: expected})
|
||||||
|
|
||||||
expected = stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte("testdomain.com"))})
|
expected = stackitem.NewArray([]stackitem.Item{stackitem.NewByteArray([]byte("testdomain.com"))})
|
||||||
|
@ -294,46 +210,15 @@ func TestDeleteDomain(t *testing.T) {
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
||||||
|
|
||||||
c1.InvokeFail(t, "domain not found", "deleteDomain", "ru")
|
c1.InvokeFail(t, "domain not found", "deleteDomain", "ru")
|
||||||
c1.InvokeFail(t, "can't delete TLD domain that has subdomains", "deleteDomain", "com")
|
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, stackitem.Null{}, "deleteDomain", "testdomain.com")
|
||||||
|
|
||||||
c1.Invoke(t, true, "register",
|
|
||||||
"aa.bb.zz", acc1.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
|
|
||||||
c1.InvokeFail(t, "TLD already exists", "register",
|
|
||||||
"zz", acc1.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
|
|
||||||
c1.Invoke(t, stackitem.Null{}, "deleteDomain", "aa.bb.zz")
|
|
||||||
|
|
||||||
c1.Invoke(t, true, "register",
|
|
||||||
"zz", acc1.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
|
|
||||||
c1.Invoke(t, true, "register",
|
c1.Invoke(t, true, "register",
|
||||||
"cn", acc1.ScriptHash(),
|
"cn", acc1.ScriptHash(),
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
||||||
|
|
||||||
c2.InvokeFail(t, "not witnessed by admin", "deleteDomain", "cn")
|
c2.InvokeFail(t, "not witnessed by admin", "deleteDomain", "cn")
|
||||||
|
|
||||||
c1.Invoke(t, stackitem.Null{}, "deleteDomain", "cn")
|
|
||||||
|
|
||||||
c2.Invoke(t, true, "register",
|
|
||||||
"cn", acc2.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
|
|
||||||
c1.Invoke(t, true, "register",
|
|
||||||
"gu.bububu.bubu.bu", c.CommitteeHash,
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
|
|
||||||
c1.Invoke(t, true, "register",
|
|
||||||
"buu.gu.bububu.bubu.bu", c.CommitteeHash,
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
|
|
||||||
c1.Invoke(t, true, "register",
|
|
||||||
"bubu.bu", c.CommitteeHash,
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGlobalDomain(t *testing.T) {
|
func TestGlobalDomain(t *testing.T) {
|
||||||
|
@ -379,7 +264,6 @@ func TestGlobalDomain(t *testing.T) {
|
||||||
|
|
||||||
c.InvokeFail(t, "global domain is already taken", "isAvailable", "dom.testdomain.com")
|
c.InvokeFail(t, "global domain is already taken", "isAvailable", "dom.testdomain.com")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTLDRecord(t *testing.T) {
|
func TestTLDRecord(t *testing.T) {
|
||||||
c := newNNSInvoker(t, true)
|
c := newNNSInvoker(t, true)
|
||||||
c.Invoke(t, stackitem.Null{}, "addRecord",
|
c.Invoke(t, stackitem.Null{}, "addRecord",
|
||||||
|
@ -404,6 +288,11 @@ func TestNNSRegisterMulti(t *testing.T) {
|
||||||
cBoth.Invoke(t, true, "register", args...)
|
cBoth.Invoke(t, true, "register", args...)
|
||||||
|
|
||||||
c1 := c.WithSigners(acc)
|
c1 := c.WithSigners(acc)
|
||||||
|
t.Run("parent domain is missing", func(t *testing.T) {
|
||||||
|
msg := "domain does not exist or is expired: fs.neo.com"
|
||||||
|
args[0] = "testnet.fs.neo.com"
|
||||||
|
c1.InvokeFail(t, msg, "register", args...)
|
||||||
|
})
|
||||||
|
|
||||||
args[0] = "fs.neo.com"
|
args[0] = "fs.neo.com"
|
||||||
c1.Invoke(t, true, "register", args...)
|
c1.Invoke(t, true, "register", args...)
|
||||||
|
@ -559,44 +448,11 @@ func TestNNSSetAdmin(t *testing.T) {
|
||||||
"testdomain.com", int64(nns.TXT), "will be added")
|
"testdomain.com", int64(nns.TXT), "will be added")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNNS_Frostfsid(t *testing.T) {
|
|
||||||
nnsInv, f := newNNSInvokerWithFrostfsID(t, false)
|
|
||||||
|
|
||||||
acc, err := wallet.NewAccount()
|
|
||||||
require.NoError(t, err)
|
|
||||||
nnsUserInv := nnsInv.NewInvoker(nnsInv.Hash, newSigner(t, nnsInv, acc))
|
|
||||||
|
|
||||||
nnsUserInv.InvokeFail(t, "not witnessed by committee", "register",
|
|
||||||
"ddd", acc.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
|
|
||||||
nnsUserInv.InvokeFail(t, "not witnessed by committee", "register",
|
|
||||||
"testdomain.kz", acc.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
|
|
||||||
f.Invoke(t, stackitem.Null{}, createSubjectMethod, "", acc.PrivateKey().PublicKey().Bytes())
|
|
||||||
|
|
||||||
nnsUserInv.InvokeFail(t, "not witnessed by committee", "register",
|
|
||||||
"testdomain.kz", acc.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
|
|
||||||
f.Invoke(t, stackitem.Null{}, setSubjectKVMethod, acc.ScriptHash(), nns.FrostfsIDNNSTLDPermissionKey, nns.FrostfsIDTLDRegistrationAllowed)
|
|
||||||
|
|
||||||
nnsUserInv.Invoke(t, true, "register",
|
|
||||||
"testdomain.kz", acc.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
|
|
||||||
f.Invoke(t, stackitem.Null{}, deleteSubjectKVMethod, acc.ScriptHash(), nns.FrostfsIDNNSTLDPermissionKey)
|
|
||||||
|
|
||||||
nnsUserInv.InvokeFail(t, "not witnessed by committee", "register",
|
|
||||||
"testdomain.uz", acc.ScriptHash(),
|
|
||||||
"myemail@frostfs.info", defaultRefresh, defaultRetry, defaultExpire, defaultTTL)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNNSIsAvailable(t *testing.T) {
|
func TestNNSIsAvailable(t *testing.T) {
|
||||||
c := newNNSInvoker(t, false)
|
c := newNNSInvoker(t, false)
|
||||||
|
|
||||||
c.Invoke(t, true, "isAvailable", "com")
|
c.Invoke(t, true, "isAvailable", "com")
|
||||||
|
c.InvokeFail(t, "TLD not found", "isAvailable", "domain.com")
|
||||||
|
|
||||||
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
refresh, retry, expire, ttl := int64(101), int64(102), int64(103), int64(104)
|
||||||
c.Invoke(t, true, "register",
|
c.Invoke(t, true, "register",
|
||||||
|
@ -609,6 +465,7 @@ func TestNNSIsAvailable(t *testing.T) {
|
||||||
acc := c.NewAccount(t)
|
acc := c.NewAccount(t)
|
||||||
c1 := c.WithSigners(c.Committee, acc)
|
c1 := c.WithSigners(c.Committee, acc)
|
||||||
|
|
||||||
|
c1.InvokeFail(t, "domain does not exist or is expired: domain.com", "isAvailable", "dom.domain.com")
|
||||||
c1.Invoke(t, true, "register",
|
c1.Invoke(t, true, "register",
|
||||||
"domain.com", acc.ScriptHash(),
|
"domain.com", acc.ScriptHash(),
|
||||||
"myemail@frostfs.info", refresh, retry, expire, ttl)
|
"myemail@frostfs.info", refresh, retry, expire, ttl)
|
||||||
|
@ -620,6 +477,7 @@ func TestNNSIsAvailable(t *testing.T) {
|
||||||
c.Invoke(t, false, "isAvailable", "domain.com")
|
c.Invoke(t, false, "isAvailable", "domain.com")
|
||||||
|
|
||||||
c.Invoke(t, true, "isAvailable", "dom.domain.com")
|
c.Invoke(t, true, "isAvailable", "dom.domain.com")
|
||||||
|
c.InvokeFail(t, "domain does not exist or is expired: dom.domain.com", "isAvailable", "dom.dom.domain.com")
|
||||||
|
|
||||||
c1.Invoke(t, true, "register",
|
c1.Invoke(t, true, "register",
|
||||||
"dom.domain.com", acc.ScriptHash(),
|
"dom.domain.com", acc.ScriptHash(),
|
||||||
|
|
Loading…
Reference in a new issue